The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netinet/libalias/alias.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2001 Charles Mott <cm@linktel.net>
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD$");
   31 
   32 /*
   33     Alias.c provides supervisory control for the functions of the
   34     packet aliasing software.  It consists of routines to monitor
   35     TCP connection state, protocol-specific aliasing routines,
   36     fragment handling and the following outside world functional
   37     interfaces: SaveFragmentPtr, GetFragmentPtr, FragmentAliasIn,
   38     PacketAliasIn and PacketAliasOut.
   39 
   40     The other C program files are briefly described. The data
   41     structure framework which holds information needed to translate
   42     packets is encapsulated in alias_db.c.  Data is accessed by
   43     function calls, so other segments of the program need not know
   44     about the underlying data structures.  Alias_ftp.c contains
   45     special code for modifying the ftp PORT command used to establish
   46     data connections, while alias_irc.c does the same for IRC
   47     DCC. Alias_util.c contains a few utility routines.
   48 
   49     Version 1.0 August, 1996  (cjm)
   50 
   51     Version 1.1 August 20, 1996  (cjm)
   52         PPP host accepts incoming connections for ports 0 to 1023.
   53         (Gary Roberts pointed out the need to handle incoming
   54          connections.)
   55 
   56     Version 1.2 September 7, 1996 (cjm)
   57         Fragment handling error in alias_db.c corrected.
   58         (Tom Torrance helped fix this problem.)
   59 
   60     Version 1.4 September 16, 1996 (cjm)
   61         - A more generalized method for handling incoming
   62           connections, without the 0-1023 restriction, is
   63           implemented in alias_db.c
   64         - Improved ICMP support in alias.c.  Traceroute
   65           packet streams can now be correctly aliased.
   66         - TCP connection closing logic simplified in
   67           alias.c and now allows for additional 1 minute
   68           "grace period" after FIN or RST is observed.
   69 
   70     Version 1.5 September 17, 1996 (cjm)
   71         Corrected error in handling incoming UDP packets with 0 checksum.
   72         (Tom Torrance helped fix this problem.)
   73 
   74     Version 1.6 September 18, 1996 (cjm)
   75         Simplified ICMP aliasing scheme.  Should now support
   76         traceroute from Win95 as well as FreeBSD.
   77 
   78     Version 1.7 January 9, 1997 (cjm)
   79         - Out-of-order fragment handling.
   80         - IP checksum error fixed for ftp transfers
   81           from aliasing host.
   82         - Integer return codes added to all
   83           aliasing/de-aliasing functions.
   84         - Some obsolete comments cleaned up.
   85         - Differential checksum computations for
   86           IP header (TCP, UDP and ICMP were already
   87           differential).
   88 
   89     Version 2.1 May 1997 (cjm)
   90         - Added support for outgoing ICMP error
   91           messages.
   92         - Added two functions PacketAliasIn2()
   93           and PacketAliasOut2() for dynamic address
   94           control (e.g. round-robin allocation of
   95           incoming packets).
   96 
   97     Version 2.2 July 1997 (cjm)
   98         - Rationalized API function names to begin
   99           with "PacketAlias..."
  100         - Eliminated PacketAliasIn2() and
  101           PacketAliasOut2() as poorly conceived.
  102 
  103     Version 2.3 Dec 1998 (dillon)
  104         - Major bounds checking additions, see FreeBSD/CVS
  105 
  106     Version 3.1 May, 2000 (salander)
  107         - Added hooks to handle PPTP.
  108 
  109     Version 3.2 July, 2000 (salander and satoh)
  110         - Added PacketUnaliasOut routine.
  111         - Added hooks to handle RTSP/RTP.
  112 
  113     See HISTORY file for additional revisions.
  114 */
  115 
  116 #ifdef _KERNEL
  117 #include <sys/param.h>
  118 #include <sys/systm.h>
  119 #include <sys/mbuf.h>
  120 #include <sys/sysctl.h>
  121 #else
  122 #include <sys/types.h>
  123 #include <stdlib.h>
  124 #include <stdio.h>
  125 #include <ctype.h>
  126 #include <dlfcn.h>
  127 #include <errno.h>
  128 #include <string.h>
  129 #endif
  130 
  131 #include <netinet/in_systm.h>
  132 #include <netinet/in.h>
  133 #include <netinet/ip.h>
  134 #include <netinet/ip_icmp.h>
  135 #include <netinet/tcp.h>
  136 #include <netinet/udp.h>
  137 
  138 #ifdef _KERNEL
  139 #include <netinet/libalias/alias.h>
  140 #include <netinet/libalias/alias_local.h>
  141 #include <netinet/libalias/alias_mod.h>
  142 #else
  143 #include <err.h>
  144 #include "alias.h"
  145 #include "alias_local.h"
  146 #include "alias_mod.h"
  147 #endif
  148 
  149 /*
  150  * Define libalias SYSCTL Node
  151  */
  152 #ifdef SYSCTL_NODE
  153 
  154 SYSCTL_DECL(_net_inet);
  155 SYSCTL_DECL(_net_inet_ip);
  156 SYSCTL_NODE(_net_inet_ip, OID_AUTO, alias, CTLFLAG_RW | CTLFLAG_MPSAFE, NULL,
  157     "Libalias sysctl API");
  158 
  159 #endif
  160 
  161 static __inline int
  162 twowords(void *p)
  163 {
  164         uint8_t *c = p;
  165 
  166 #if BYTE_ORDER == LITTLE_ENDIAN
  167         uint16_t s1 = ((uint16_t)c[1] << 8) + (uint16_t)c[0];
  168         uint16_t s2 = ((uint16_t)c[3] << 8) + (uint16_t)c[2];
  169 #else
  170         uint16_t s1 = ((uint16_t)c[0] << 8) + (uint16_t)c[1];
  171         uint16_t s2 = ((uint16_t)c[2] << 8) + (uint16_t)c[3];
  172 #endif
  173         return (s1 + s2);
  174 }
  175 
  176 /* TCP Handling Routines
  177 
  178     TcpMonitorIn()  -- These routines monitor TCP connections, and
  179     TcpMonitorOut()    delete a link when a connection is closed.
  180 
  181 These routines look for SYN, FIN and RST flags to determine when TCP
  182 connections open and close.  When a TCP connection closes, the data
  183 structure containing packet aliasing information is deleted after
  184 a timeout period.
  185 */
  186 
  187 /* Local prototypes */
  188 static void     TcpMonitorIn(u_char, struct alias_link *);
  189 
  190 static void     TcpMonitorOut(u_char, struct alias_link *);
  191 
  192 static void
  193 TcpMonitorIn(u_char th_flags, struct alias_link *lnk)
  194 {
  195         switch (GetStateIn(lnk)) {
  196         case ALIAS_TCP_STATE_NOT_CONNECTED:
  197                 if (th_flags & TH_RST)
  198                         SetStateIn(lnk, ALIAS_TCP_STATE_DISCONNECTED);
  199                 else if (th_flags & TH_SYN)
  200                         SetStateIn(lnk, ALIAS_TCP_STATE_CONNECTED);
  201                 break;
  202         case ALIAS_TCP_STATE_CONNECTED:
  203                 if (th_flags & (TH_FIN | TH_RST))
  204                         SetStateIn(lnk, ALIAS_TCP_STATE_DISCONNECTED);
  205                 break;
  206         }
  207 }
  208 
  209 static void
  210 TcpMonitorOut(u_char th_flags, struct alias_link *lnk)
  211 {
  212         switch (GetStateOut(lnk)) {
  213         case ALIAS_TCP_STATE_NOT_CONNECTED:
  214                 if (th_flags & TH_RST)
  215                         SetStateOut(lnk, ALIAS_TCP_STATE_DISCONNECTED);
  216                 else if (th_flags & TH_SYN)
  217                         SetStateOut(lnk, ALIAS_TCP_STATE_CONNECTED);
  218                 break;
  219         case ALIAS_TCP_STATE_CONNECTED:
  220                 if (th_flags & (TH_FIN | TH_RST))
  221                         SetStateOut(lnk, ALIAS_TCP_STATE_DISCONNECTED);
  222                 break;
  223         }
  224 }
  225 
  226 /* Protocol Specific Packet Aliasing Routines
  227 
  228     IcmpAliasIn(), IcmpAliasIn1(), IcmpAliasIn2()
  229     IcmpAliasOut(), IcmpAliasOut1(), IcmpAliasOut2()
  230     ProtoAliasIn(), ProtoAliasOut()
  231     UdpAliasIn(), UdpAliasOut()
  232     TcpAliasIn(), TcpAliasOut()
  233 
  234 These routines handle protocol specific details of packet aliasing.
  235 One may observe a certain amount of repetitive arithmetic in these
  236 functions, the purpose of which is to compute a revised checksum
  237 without actually summing over the entire data packet, which could be
  238 unnecessarily time consuming.
  239 
  240 The purpose of the packet aliasing routines is to replace the source
  241 address of the outgoing packet and then correctly put it back for
  242 any incoming packets.  For TCP and UDP, ports are also re-mapped.
  243 
  244 For ICMP echo/timestamp requests and replies, the following scheme
  245 is used: the ID number is replaced by an alias for the outgoing
  246 packet.
  247 
  248 ICMP error messages are handled by looking at the IP fragment
  249 in the data section of the message.
  250 
  251 For TCP and UDP protocols, a port number is chosen for an outgoing
  252 packet, and then incoming packets are identified by IP address and
  253 port numbers.  For TCP packets, there is additional logic in the event
  254 that sequence and ACK numbers have been altered (as in the case for
  255 FTP data port commands).
  256 
  257 The port numbers used by the packet aliasing module are not true
  258 ports in the Unix sense.  No sockets are actually bound to ports.
  259 They are more correctly thought of as placeholders.
  260 
  261 All packets go through the aliasing mechanism, whether they come from
  262 the gateway machine or other machines on a local area network.
  263 */
  264 
  265 /* Local prototypes */
  266 static int      IcmpAliasIn1(struct libalias *, struct ip *);
  267 static int      IcmpAliasIn2(struct libalias *, struct ip *);
  268 static int      IcmpAliasIn(struct libalias *, struct ip *);
  269 
  270 static int      IcmpAliasOut1(struct libalias *, struct ip *, int create);
  271 static int      IcmpAliasOut2(struct libalias *, struct ip *);
  272 static int      IcmpAliasOut(struct libalias *, struct ip *, int create);
  273 
  274 static int      ProtoAliasIn(struct libalias *la, struct in_addr ip_src,
  275                     struct ip *pip, u_char ip_p, u_short *ip_sum);
  276 static int      ProtoAliasOut(struct libalias *la, struct ip *pip,
  277                     struct in_addr ip_dst, u_char ip_p, u_short *ip_sum,
  278                     int create);
  279 
  280 static int      UdpAliasIn(struct libalias *, struct ip *);
  281 static int      UdpAliasOut(struct libalias *, struct ip *, int, int create);
  282 
  283 static int      TcpAliasIn(struct libalias *, struct ip *);
  284 static int      TcpAliasOut(struct libalias *, struct ip *, int, int create);
  285 
  286 /*
  287     De-alias incoming echo and timestamp replies.
  288     Alias incoming echo and timestamp requests.
  289 */
  290 static int
  291 IcmpAliasIn1(struct libalias *la, struct ip *pip)
  292 {
  293         struct alias_link *lnk;
  294         struct icmp *ic;
  295 
  296         LIBALIAS_LOCK_ASSERT(la);
  297         ic = (struct icmp *)ip_next(pip);
  298 
  299         /* Get source address from ICMP data field and restore original data */
  300         lnk = FindIcmpIn(la, pip->ip_src, pip->ip_dst, ic->icmp_id, 1);
  301         if (lnk != NULL) {
  302                 u_short original_id;
  303                 int accumulate;
  304 
  305                 original_id = GetOriginalPort(lnk);
  306 
  307                 /* Adjust ICMP checksum */
  308                 accumulate = ic->icmp_id;
  309                 accumulate -= original_id;
  310                 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
  311 
  312                 /* Put original sequence number back in */
  313                 ic->icmp_id = original_id;
  314 
  315                 /* Put original address back into IP header */
  316                 {
  317                         struct in_addr original_address;
  318 
  319                         original_address = GetOriginalAddress(lnk);
  320                         DifferentialChecksum(&pip->ip_sum,
  321                             &original_address, &pip->ip_dst, 2);
  322                         pip->ip_dst = original_address;
  323                 }
  324 
  325                 return (PKT_ALIAS_OK);
  326         }
  327         return (PKT_ALIAS_IGNORED);
  328 }
  329 
  330 /*
  331     Alias incoming ICMP error messages containing
  332     IP header and first 64 bits of datagram.
  333 */
  334 static int
  335 IcmpAliasIn2(struct libalias *la, struct ip *pip)
  336 {
  337         struct ip *ip;
  338         struct icmp *ic, *ic2;
  339         struct udphdr *ud;
  340         struct tcphdr *tc;
  341         struct alias_link *lnk;
  342 
  343         LIBALIAS_LOCK_ASSERT(la);
  344         ic = (struct icmp *)ip_next(pip);
  345         ip = &ic->icmp_ip;
  346 
  347         ud = (struct udphdr *)ip_next(ip);
  348         tc = (struct tcphdr *)ip_next(ip);
  349         ic2 = (struct icmp *)ip_next(ip);
  350 
  351         if (ip->ip_p == IPPROTO_UDP)
  352                 lnk = FindUdpTcpIn(la, ip->ip_dst, ip->ip_src,
  353                     ud->uh_dport, ud->uh_sport,
  354                     IPPROTO_UDP, 0);
  355         else if (ip->ip_p == IPPROTO_TCP)
  356                 lnk = FindUdpTcpIn(la, ip->ip_dst, ip->ip_src,
  357                     tc->th_dport, tc->th_sport,
  358                     IPPROTO_TCP, 0);
  359         else if (ip->ip_p == IPPROTO_ICMP) {
  360                 if (ic2->icmp_type == ICMP_ECHO || ic2->icmp_type == ICMP_TSTAMP)
  361                         lnk = FindIcmpIn(la, ip->ip_dst, ip->ip_src, ic2->icmp_id, 0);
  362                 else
  363                         lnk = NULL;
  364         } else
  365                 lnk = NULL;
  366 
  367         if (lnk != NULL) {
  368                 if (ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP) {
  369                         int accumulate, accumulate2;
  370                         struct in_addr original_address;
  371                         u_short original_port;
  372 
  373                         original_address = GetOriginalAddress(lnk);
  374                         original_port = GetOriginalPort(lnk);
  375 
  376                         /* Adjust ICMP checksum */
  377                         accumulate = twowords(&ip->ip_src);
  378                         accumulate -= twowords(&original_address);
  379                         accumulate += ud->uh_sport;
  380                         accumulate -= original_port;
  381                         accumulate2 = accumulate;
  382                         accumulate2 += ip->ip_sum;
  383                         ADJUST_CHECKSUM(accumulate, ip->ip_sum);
  384                         accumulate2 -= ip->ip_sum;
  385                         ADJUST_CHECKSUM(accumulate2, ic->icmp_cksum);
  386 
  387                         /* Un-alias address in IP header */
  388                         DifferentialChecksum(&pip->ip_sum,
  389                             &original_address, &pip->ip_dst, 2);
  390                         pip->ip_dst = original_address;
  391 
  392                         /* Un-alias address and port number of
  393                          * original IP packet fragment contained
  394                          * in ICMP data section */
  395                         ip->ip_src = original_address;
  396                         ud->uh_sport = original_port;
  397                 } else if (ip->ip_p == IPPROTO_ICMP) {
  398                         int accumulate, accumulate2;
  399                         struct in_addr original_address;
  400                         u_short original_id;
  401 
  402                         original_address = GetOriginalAddress(lnk);
  403                         original_id = GetOriginalPort(lnk);
  404 
  405                         /* Adjust ICMP checksum */
  406                         accumulate = twowords(&ip->ip_src);
  407                         accumulate -= twowords(&original_address);
  408                         accumulate += ic2->icmp_id;
  409                         accumulate -= original_id;
  410                         accumulate2 = accumulate;
  411                         accumulate2 += ip->ip_sum;
  412                         ADJUST_CHECKSUM(accumulate, ip->ip_sum);
  413                         accumulate2 -= ip->ip_sum;
  414                         ADJUST_CHECKSUM(accumulate2, ic->icmp_cksum);
  415 
  416                         /* Un-alias address in IP header */
  417                         DifferentialChecksum(&pip->ip_sum,
  418                             &original_address, &pip->ip_dst, 2);
  419                         pip->ip_dst = original_address;
  420 
  421                         /* Un-alias address of original IP packet and
  422                          * sequence number of embedded ICMP datagram */
  423                         ip->ip_src = original_address;
  424                         ic2->icmp_id = original_id;
  425                 }
  426                 return (PKT_ALIAS_OK);
  427         }
  428         return (PKT_ALIAS_IGNORED);
  429 }
  430 
  431 static int
  432 IcmpAliasIn(struct libalias *la, struct ip *pip)
  433 {
  434         struct icmp *ic;
  435         int iresult;
  436         size_t dlen;
  437 
  438         LIBALIAS_LOCK_ASSERT(la);
  439 
  440         dlen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
  441         if (dlen < ICMP_MINLEN)
  442                 return (PKT_ALIAS_IGNORED);
  443 
  444         /* Return if proxy-only mode is enabled */
  445         if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
  446                 return (PKT_ALIAS_OK);
  447 
  448         ic = (struct icmp *)ip_next(pip);
  449 
  450         iresult = PKT_ALIAS_IGNORED;
  451         switch (ic->icmp_type) {
  452         case ICMP_ECHOREPLY:
  453         case ICMP_TSTAMPREPLY:
  454                 if (ic->icmp_code == 0) {
  455                         iresult = IcmpAliasIn1(la, pip);
  456                 }
  457                 break;
  458         case ICMP_UNREACH:
  459         case ICMP_SOURCEQUENCH:
  460         case ICMP_TIMXCEED:
  461         case ICMP_PARAMPROB:
  462                 if (dlen < ICMP_ADVLENMIN ||
  463                     dlen < (size_t)ICMP_ADVLEN(ic))
  464                         return (PKT_ALIAS_IGNORED);
  465                 iresult = IcmpAliasIn2(la, pip);
  466                 break;
  467         case ICMP_ECHO:
  468         case ICMP_TSTAMP:
  469                 iresult = IcmpAliasIn1(la, pip);
  470                 break;
  471         }
  472         return (iresult);
  473 }
  474 
  475 /*
  476     Alias outgoing echo and timestamp requests.
  477     De-alias outgoing echo and timestamp replies.
  478 */
  479 static int
  480 IcmpAliasOut1(struct libalias *la, struct ip *pip, int create)
  481 {
  482         struct alias_link *lnk;
  483         struct icmp *ic;
  484 
  485         LIBALIAS_LOCK_ASSERT(la);
  486         ic = (struct icmp *)ip_next(pip);
  487 
  488         /* Save overwritten data for when echo packet returns */
  489         lnk = FindIcmpOut(la, pip->ip_src, pip->ip_dst, ic->icmp_id, create);
  490         if (lnk != NULL) {
  491                 u_short alias_id;
  492                 int accumulate;
  493 
  494                 alias_id = GetAliasPort(lnk);
  495 
  496                 /* Since data field is being modified, adjust ICMP checksum */
  497                 accumulate = ic->icmp_id;
  498                 accumulate -= alias_id;
  499                 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
  500 
  501                 /* Alias sequence number */
  502                 ic->icmp_id = alias_id;
  503 
  504                 /* Change source address */
  505                 {
  506                         struct in_addr alias_address;
  507 
  508                         alias_address = GetAliasAddress(lnk);
  509                         DifferentialChecksum(&pip->ip_sum,
  510                             &alias_address, &pip->ip_src, 2);
  511                         pip->ip_src = alias_address;
  512                 }
  513 
  514                 return (PKT_ALIAS_OK);
  515         }
  516         return (PKT_ALIAS_IGNORED);
  517 }
  518 
  519 /*
  520     Alias outgoing ICMP error messages containing
  521     IP header and first 64 bits of datagram.
  522 */
  523 static int
  524 IcmpAliasOut2(struct libalias *la, struct ip *pip)
  525 {
  526         struct ip *ip;
  527         struct icmp *ic, *ic2;
  528         struct udphdr *ud;
  529         struct tcphdr *tc;
  530         struct alias_link *lnk;
  531 
  532         LIBALIAS_LOCK_ASSERT(la);
  533         ic = (struct icmp *)ip_next(pip);
  534         ip = &ic->icmp_ip;
  535 
  536         ud = (struct udphdr *)ip_next(ip);
  537         tc = (struct tcphdr *)ip_next(ip);
  538         ic2 = (struct icmp *)ip_next(ip);
  539 
  540         if (ip->ip_p == IPPROTO_UDP)
  541                 lnk = FindUdpTcpOut(la, ip->ip_dst, ip->ip_src,
  542                     ud->uh_dport, ud->uh_sport,
  543                     IPPROTO_UDP, 0);
  544         else if (ip->ip_p == IPPROTO_TCP)
  545                 lnk = FindUdpTcpOut(la, ip->ip_dst, ip->ip_src,
  546                     tc->th_dport, tc->th_sport,
  547                     IPPROTO_TCP, 0);
  548         else if (ip->ip_p == IPPROTO_ICMP) {
  549                 if (ic2->icmp_type == ICMP_ECHO || ic2->icmp_type == ICMP_TSTAMP)
  550                         lnk = FindIcmpOut(la, ip->ip_dst, ip->ip_src, ic2->icmp_id, 0);
  551                 else
  552                         lnk = NULL;
  553         } else
  554                 lnk = NULL;
  555 
  556         if (lnk != NULL) {
  557                 if (ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP) {
  558                         int accumulate;
  559                         struct in_addr alias_address;
  560                         u_short alias_port;
  561 
  562                         alias_address = GetAliasAddress(lnk);
  563                         alias_port = GetAliasPort(lnk);
  564 
  565                         /* Adjust ICMP checksum */
  566                         accumulate = twowords(&ip->ip_dst);
  567                         accumulate -= twowords(&alias_address);
  568                         accumulate += ud->uh_dport;
  569                         accumulate -= alias_port;
  570                         ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
  571 
  572                         /*
  573                          * Alias address in IP header if it comes from the host
  574                          * the original TCP/UDP packet was destined for.
  575                          */
  576                         if (pip->ip_src.s_addr == ip->ip_dst.s_addr) {
  577                                 DifferentialChecksum(&pip->ip_sum,
  578                                     &alias_address, &pip->ip_src, 2);
  579                                 pip->ip_src = alias_address;
  580                         }
  581                         /* Alias address and port number of original IP packet
  582                          * fragment contained in ICMP data section */
  583                         ip->ip_dst = alias_address;
  584                         ud->uh_dport = alias_port;
  585                 } else if (ip->ip_p == IPPROTO_ICMP) {
  586                         int accumulate;
  587                         struct in_addr alias_address;
  588                         u_short alias_id;
  589 
  590                         alias_address = GetAliasAddress(lnk);
  591                         alias_id = GetAliasPort(lnk);
  592 
  593                         /* Adjust ICMP checksum */
  594                         accumulate = twowords(&ip->ip_dst);
  595                         accumulate -= twowords(&alias_address);
  596                         accumulate += ic2->icmp_id;
  597                         accumulate -= alias_id;
  598                         ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
  599 
  600                         /*
  601                          * Alias address in IP header if it comes from the host
  602                          * the original ICMP message was destined for.
  603                          */
  604                         if (pip->ip_src.s_addr == ip->ip_dst.s_addr) {
  605                                 DifferentialChecksum(&pip->ip_sum,
  606                                     &alias_address, &pip->ip_src, 2);
  607                                 pip->ip_src = alias_address;
  608                         }
  609                         /* Alias address of original IP packet and
  610                          * sequence number of embedded ICMP datagram */
  611                         ip->ip_dst = alias_address;
  612                         ic2->icmp_id = alias_id;
  613                 }
  614                 return (PKT_ALIAS_OK);
  615         }
  616         return (PKT_ALIAS_IGNORED);
  617 }
  618 
  619 static int
  620 IcmpAliasOut(struct libalias *la, struct ip *pip, int create)
  621 {
  622         int iresult;
  623         struct icmp *ic;
  624 
  625         LIBALIAS_LOCK_ASSERT(la);
  626         (void)create;
  627 
  628         /* Return if proxy-only mode is enabled */
  629         if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
  630                 return (PKT_ALIAS_OK);
  631 
  632         ic = (struct icmp *)ip_next(pip);
  633 
  634         iresult = PKT_ALIAS_IGNORED;
  635         switch (ic->icmp_type) {
  636         case ICMP_ECHO:
  637         case ICMP_TSTAMP:
  638                 if (ic->icmp_code == 0) {
  639                         iresult = IcmpAliasOut1(la, pip, create);
  640                 }
  641                 break;
  642         case ICMP_UNREACH:
  643         case ICMP_SOURCEQUENCH:
  644         case ICMP_TIMXCEED:
  645         case ICMP_PARAMPROB:
  646                 iresult = IcmpAliasOut2(la, pip);
  647                 break;
  648         case ICMP_ECHOREPLY:
  649         case ICMP_TSTAMPREPLY:
  650                 iresult = IcmpAliasOut1(la, pip, create);
  651         }
  652         return (iresult);
  653 }
  654 
  655 /*
  656   Handle incoming IP packets. The
  657   only thing which is done in this case is to alias
  658   the dest IP address of the packet to our inside
  659   machine.
  660 */
  661 static int
  662 ProtoAliasIn(struct libalias *la, struct in_addr ip_src,
  663     struct ip *pip, u_char ip_p, u_short *ip_sum)
  664 {
  665         struct alias_link *lnk;
  666 
  667         LIBALIAS_LOCK_ASSERT(la);
  668         /* Return if proxy-only mode is enabled */
  669         if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
  670                 return (PKT_ALIAS_OK);
  671 
  672         lnk = FindProtoIn(la, ip_src, pip->ip_dst, ip_p);
  673         if (lnk != NULL) {
  674                 struct in_addr original_address;
  675 
  676                 original_address = GetOriginalAddress(lnk);
  677 
  678                 /* Restore original IP address */
  679                 DifferentialChecksum(ip_sum,
  680                     &original_address, &pip->ip_dst, 2);
  681                 pip->ip_dst = original_address;
  682 
  683                 return (PKT_ALIAS_OK);
  684         }
  685         return (PKT_ALIAS_IGNORED);
  686 }
  687 
  688 /*
  689   Handle outgoing IP packets. The
  690   only thing which is done in this case is to alias
  691   the source IP address of the packet.
  692 */
  693 static int
  694 ProtoAliasOut(struct libalias *la, struct ip *pip,
  695     struct in_addr ip_dst, u_char ip_p, u_short *ip_sum, int create)
  696 {
  697         struct alias_link *lnk;
  698 
  699         LIBALIAS_LOCK_ASSERT(la);
  700 
  701         /* Return if proxy-only mode is enabled */
  702         if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
  703                 return (PKT_ALIAS_OK);
  704 
  705         if (!create)
  706                 return (PKT_ALIAS_IGNORED);
  707 
  708         lnk = FindProtoOut(la, pip->ip_src, ip_dst, ip_p);
  709         if (lnk != NULL) {
  710                 struct in_addr alias_address;
  711 
  712                 alias_address = GetAliasAddress(lnk);
  713 
  714                 /* Change source address */
  715                 DifferentialChecksum(ip_sum,
  716                     &alias_address, &pip->ip_src, 2);
  717                 pip->ip_src = alias_address;
  718 
  719                 return (PKT_ALIAS_OK);
  720         }
  721         return (PKT_ALIAS_IGNORED);
  722 }
  723 
  724 #define MF_ISSET(_pip) (ntohs((_pip)->ip_off) & IP_MF)
  725 #define FRAG_NO_HDR(_pip) (ntohs((_pip)->ip_off) & IP_OFFMASK)
  726 
  727 static struct udphdr *
  728 ValidateUdpLength(struct ip *pip)
  729 {
  730         struct udphdr *ud;
  731         size_t dlen;
  732 
  733 #ifdef _KERNEL
  734         KASSERT(!FRAG_NO_HDR(pip), ("header-less fragment isn't expected here"));
  735 #endif
  736         dlen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
  737         if (dlen < sizeof(struct udphdr))
  738                 return (NULL);
  739         ud = (struct udphdr *)ip_next(pip);
  740         if (!MF_ISSET(pip) && dlen < ntohs(ud->uh_ulen))
  741                 return (NULL);
  742         return (ud);
  743 }
  744 
  745 static int
  746 UdpAliasIn(struct libalias *la, struct ip *pip)
  747 {
  748         struct udphdr *ud;
  749         struct alias_link *lnk;
  750 
  751         LIBALIAS_LOCK_ASSERT(la);
  752 
  753         ud = ValidateUdpLength(pip);
  754         if (ud == NULL)
  755                 return (PKT_ALIAS_IGNORED);
  756 
  757         lnk = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst,
  758             ud->uh_sport, ud->uh_dport,
  759             IPPROTO_UDP, !(la->packetAliasMode & PKT_ALIAS_PROXY_ONLY));
  760         if (lnk != NULL) {
  761                 struct in_addr alias_address;
  762                 struct in_addr original_address;
  763                 struct in_addr proxy_address;
  764                 u_short alias_port;
  765                 u_short proxy_port;
  766                 int accumulate;
  767                 int error;
  768                 struct alias_data ad = {
  769                         .lnk = lnk,
  770                         .oaddr = &original_address,
  771                         .aaddr = &alias_address,
  772                         .aport = &alias_port,
  773                         .sport = &ud->uh_sport,
  774                         .dport = &ud->uh_dport,
  775                         .maxpktsize = 0
  776                 };
  777 
  778                 alias_address = GetAliasAddress(lnk);
  779                 original_address = GetOriginalAddress(lnk);
  780                 proxy_address = GetProxyAddress(lnk);
  781                 alias_port = ud->uh_dport;
  782                 ud->uh_dport = GetOriginalPort(lnk);
  783                 proxy_port = GetProxyPort(lnk);
  784 
  785                 /* Walk out chain. */
  786                 error = find_handler(IN, UDP, la, pip, &ad);
  787                 /* If we cannot figure out the packet, ignore it. */
  788                 if (error < 0)
  789                         return (PKT_ALIAS_IGNORED);
  790 
  791                 /* If UDP checksum is not zero, then adjust since
  792                  * destination port is being unaliased and
  793                  * destination address is being altered. */
  794                 if (ud->uh_sum != 0) {
  795                         accumulate = alias_port;
  796                         accumulate -= ud->uh_dport;
  797                         accumulate += twowords(&alias_address);
  798                         accumulate -= twowords(&original_address);
  799 
  800                         /* If this is a proxy packet, modify checksum
  801                          * because of source change.*/
  802                         if (proxy_port != 0) {
  803                                 accumulate += ud->uh_sport;
  804                                 accumulate -= proxy_port;
  805                         }
  806 
  807                         if (proxy_address.s_addr != 0) {
  808                                 accumulate += twowords(&pip->ip_src);
  809                                 accumulate -= twowords(&proxy_address);
  810                         }
  811 
  812                         ADJUST_CHECKSUM(accumulate, ud->uh_sum);
  813                 }
  814 
  815                 /* XXX: Could the two if's below be concatenated to one ? */
  816                 /* Restore source port and/or address in case of proxying*/
  817                 if (proxy_port != 0)
  818                         ud->uh_sport = proxy_port;
  819 
  820                 if (proxy_address.s_addr != 0) {
  821                         DifferentialChecksum(&pip->ip_sum,
  822                             &proxy_address, &pip->ip_src, 2);
  823                         pip->ip_src = proxy_address;
  824                 }
  825 
  826                 /* Restore original IP address */
  827                 DifferentialChecksum(&pip->ip_sum,
  828                     &original_address, &pip->ip_dst, 2);
  829                 pip->ip_dst = original_address;
  830 
  831                 return (PKT_ALIAS_OK);
  832         }
  833         return (PKT_ALIAS_IGNORED);
  834 }
  835 
  836 static int
  837 UdpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create)
  838 {
  839         struct udphdr *ud;
  840         struct alias_link *lnk;
  841         struct in_addr dest_address;
  842         struct in_addr proxy_server_address;
  843         u_short dest_port;
  844         u_short proxy_server_port;
  845         int proxy_type;
  846 
  847         LIBALIAS_LOCK_ASSERT(la);
  848 
  849         ud = ValidateUdpLength(pip);
  850         if (ud == NULL)
  851                 return (PKT_ALIAS_IGNORED);
  852 
  853         /* Return if proxy-only mode is enabled and not proxyrule found.*/
  854         proxy_type = ProxyCheck(la, &proxy_server_address, &proxy_server_port,
  855             pip->ip_src, pip->ip_dst, ud->uh_dport, pip->ip_p);
  856         if (proxy_type == 0 && (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY))
  857                 return (PKT_ALIAS_OK);
  858 
  859         /* If this is a transparent proxy, save original destination,
  860          * then alter the destination and adjust checksums */
  861         dest_port = ud->uh_dport;
  862         dest_address = pip->ip_dst;
  863 
  864         if (proxy_type != 0) {
  865                 int accumulate;
  866 
  867                 accumulate = twowords(&pip->ip_dst);
  868                 accumulate -= twowords(&proxy_server_address);
  869 
  870                 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
  871 
  872                 if (ud->uh_sum != 0) {
  873                         accumulate = twowords(&pip->ip_dst);
  874                         accumulate -= twowords(&proxy_server_address);
  875                         accumulate += ud->uh_dport;
  876                         accumulate -= proxy_server_port;
  877                         ADJUST_CHECKSUM(accumulate, ud->uh_sum);
  878                 }
  879                 pip->ip_dst = proxy_server_address;
  880                 ud->uh_dport = proxy_server_port;
  881         }
  882         lnk = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst,
  883             ud->uh_sport, ud->uh_dport,
  884             IPPROTO_UDP, create);
  885         if (lnk != NULL) {
  886                 u_short alias_port;
  887                 struct in_addr alias_address;
  888                 struct alias_data ad = {
  889                         .lnk = lnk,
  890                         .oaddr = NULL,
  891                         .aaddr = &alias_address,
  892                         .aport = &alias_port,
  893                         .sport = &ud->uh_sport,
  894                         .dport = &ud->uh_dport,
  895                         .maxpktsize = 0
  896                 };
  897 
  898                 /* Save original destination address, if this is a proxy packet.
  899                  * Also modify packet to include destination encoding.  This may
  900                  * change the size of IP header. */
  901                 if (proxy_type != 0) {
  902                         SetProxyPort(lnk, dest_port);
  903                         SetProxyAddress(lnk, dest_address);
  904                         ProxyModify(la, lnk, pip, maxpacketsize, proxy_type);
  905                         ud = (struct udphdr *)ip_next(pip);
  906                 }
  907 
  908                 alias_address = GetAliasAddress(lnk);
  909                 alias_port = GetAliasPort(lnk);
  910 
  911                 /* Walk out chain. */
  912                 find_handler(OUT, UDP, la, pip, &ad);
  913 
  914                 /* If UDP checksum is not zero, adjust since source port is */
  915                 /* being aliased and source address is being altered    */
  916                 if (ud->uh_sum != 0) {
  917                         int accumulate;
  918 
  919                         accumulate = ud->uh_sport;
  920                         accumulate -= alias_port;
  921                         accumulate += twowords(&pip->ip_src);
  922                         accumulate -= twowords(&alias_address);
  923                         ADJUST_CHECKSUM(accumulate, ud->uh_sum);
  924                 }
  925                 /* Put alias port in UDP header */
  926                 ud->uh_sport = alias_port;
  927 
  928                 /* Change source address */
  929                 DifferentialChecksum(&pip->ip_sum,
  930                     &alias_address, &pip->ip_src, 2);
  931                 pip->ip_src = alias_address;
  932 
  933                 return (PKT_ALIAS_OK);
  934         }
  935         return (PKT_ALIAS_IGNORED);
  936 }
  937 
  938 static int
  939 TcpAliasIn(struct libalias *la, struct ip *pip)
  940 {
  941         struct tcphdr *tc;
  942         struct alias_link *lnk;
  943         size_t dlen;
  944 
  945         LIBALIAS_LOCK_ASSERT(la);
  946 
  947         dlen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
  948         if (dlen < sizeof(struct tcphdr))
  949                 return (PKT_ALIAS_IGNORED);
  950         tc = (struct tcphdr *)ip_next(pip);
  951 
  952         lnk = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst,
  953             tc->th_sport, tc->th_dport,
  954             IPPROTO_TCP,
  955             !(la->packetAliasMode & PKT_ALIAS_PROXY_ONLY));
  956         if (lnk != NULL) {
  957                 struct in_addr alias_address;
  958                 struct in_addr original_address;
  959                 struct in_addr proxy_address;
  960                 u_short alias_port;
  961                 u_short proxy_port;
  962                 int accumulate;
  963 
  964                 /*
  965                  * The init of MANY vars is a bit below, but aliashandlepptpin
  966                  * seems to need the destination port that came within the
  967                  * packet and not the original one looks below [*].
  968                  */
  969 
  970                 struct alias_data ad = {
  971                         .lnk = lnk,
  972                         .oaddr = NULL,
  973                         .aaddr = NULL,
  974                         .aport = NULL,
  975                         .sport = &tc->th_sport,
  976                         .dport = &tc->th_dport,
  977                         .maxpktsize = 0
  978                 };
  979 
  980                 /* Walk out chain. */
  981                 find_handler(IN, TCP, la, pip, &ad);
  982 
  983                 alias_address = GetAliasAddress(lnk);
  984                 original_address = GetOriginalAddress(lnk);
  985                 proxy_address = GetProxyAddress(lnk);
  986                 alias_port = tc->th_dport;
  987                 tc->th_dport = GetOriginalPort(lnk);
  988                 proxy_port = GetProxyPort(lnk);
  989 
  990                 /*
  991                  * Look above, if anyone is going to add find_handler AFTER
  992                  * this aliashandlepptpin/point, please redo alias_data too.
  993                  * Uncommenting the piece here below should be enough.
  994                  */
  995 #if 0
  996                                  struct alias_data ad = {
  997                                         .lnk = lnk,
  998                                         .oaddr = &original_address,
  999                                         .aaddr = &alias_address,
 1000                                         .aport = &alias_port,
 1001                                         .sport = &ud->uh_sport,
 1002                                         .dport = &ud->uh_dport,
 1003                                         .maxpktsize = 0
 1004                                 };
 1005 
 1006                                 /* Walk out chain. */
 1007                                 error = find_handler(la, pip, &ad);
 1008                                 if (error == EHDNOF)
 1009                                         printf("Protocol handler not found\n");
 1010 #endif
 1011 
 1012                 /* Adjust TCP checksum since destination port is being
 1013                  * unaliased and destination port is being altered. */
 1014                 accumulate = alias_port;
 1015                 accumulate -= tc->th_dport;
 1016                 accumulate += twowords(&alias_address);
 1017                 accumulate -= twowords(&original_address);
 1018 
 1019                 /* If this is a proxy, then modify the TCP source port
 1020                  * and checksum accumulation */
 1021                 if (proxy_port != 0) {
 1022                         accumulate += tc->th_sport;
 1023                         tc->th_sport = proxy_port;
 1024                         accumulate -= tc->th_sport;
 1025                         accumulate += twowords(&pip->ip_src);
 1026                         accumulate -= twowords(&proxy_address);
 1027                 }
 1028                 /* See if ACK number needs to be modified */
 1029                 if (GetAckModified(lnk) == 1) {
 1030                         int delta;
 1031 
 1032                         tc = (struct tcphdr *)ip_next(pip);
 1033                         delta = GetDeltaAckIn(tc->th_ack, lnk);
 1034                         if (delta != 0) {
 1035                                 accumulate += twowords(&tc->th_ack);
 1036                                 tc->th_ack = htonl(ntohl(tc->th_ack) - delta);
 1037                                 accumulate -= twowords(&tc->th_ack);
 1038                         }
 1039                 }
 1040                 ADJUST_CHECKSUM(accumulate, tc->th_sum);
 1041 
 1042                 /* Restore original IP address */
 1043                 accumulate = twowords(&pip->ip_dst);
 1044                 pip->ip_dst = original_address;
 1045                 accumulate -= twowords(&pip->ip_dst);
 1046 
 1047                 /* If this is a transparent proxy packet,
 1048                  * then modify the source address */
 1049                 if (proxy_address.s_addr != 0) {
 1050                         accumulate += twowords(&pip->ip_src);
 1051                         pip->ip_src = proxy_address;
 1052                         accumulate -= twowords(&pip->ip_src);
 1053                 }
 1054                 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
 1055 
 1056                 /* Monitor TCP connection state */
 1057                 tc = (struct tcphdr *)ip_next(pip);
 1058                 TcpMonitorIn(tc->th_flags, lnk);
 1059 
 1060                 return (PKT_ALIAS_OK);
 1061         }
 1062         return (PKT_ALIAS_IGNORED);
 1063 }
 1064 
 1065 static int
 1066 TcpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create)
 1067 {
 1068         int proxy_type;
 1069         u_short dest_port;
 1070         u_short proxy_server_port;
 1071         size_t dlen;
 1072         struct in_addr dest_address;
 1073         struct in_addr proxy_server_address;
 1074         struct tcphdr *tc;
 1075         struct alias_link *lnk;
 1076 
 1077         LIBALIAS_LOCK_ASSERT(la);
 1078 
 1079         dlen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
 1080         if (dlen < sizeof(struct tcphdr))
 1081                 return (PKT_ALIAS_IGNORED);
 1082         tc = (struct tcphdr *)ip_next(pip);
 1083 
 1084         if (create)
 1085                 proxy_type = ProxyCheck(la, &proxy_server_address,
 1086                     &proxy_server_port, pip->ip_src, pip->ip_dst,
 1087                     tc->th_dport, pip->ip_p);
 1088         else
 1089                 proxy_type = 0;
 1090 
 1091         if (proxy_type == 0 && (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY))
 1092                 return (PKT_ALIAS_OK);
 1093 
 1094         /* If this is a transparent proxy, save original destination,
 1095          * then alter the destination and adjust checksums */
 1096         dest_port = tc->th_dport;
 1097         dest_address = pip->ip_dst;
 1098         if (proxy_type != 0) {
 1099                 int accumulate;
 1100 
 1101                 accumulate = tc->th_dport;
 1102                 tc->th_dport = proxy_server_port;
 1103                 accumulate -= tc->th_dport;
 1104                 accumulate += twowords(&pip->ip_dst);
 1105                 accumulate -= twowords(&proxy_server_address);
 1106                 ADJUST_CHECKSUM(accumulate, tc->th_sum);
 1107 
 1108                 accumulate = twowords(&pip->ip_dst);
 1109                 pip->ip_dst = proxy_server_address;
 1110                 accumulate -= twowords(&pip->ip_dst);
 1111                 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
 1112         }
 1113         lnk = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst,
 1114             tc->th_sport, tc->th_dport,
 1115             IPPROTO_TCP, create);
 1116         if (lnk == NULL)
 1117                 return (PKT_ALIAS_IGNORED);
 1118         if (lnk != NULL) {
 1119                 u_short alias_port;
 1120                 struct in_addr alias_address;
 1121                 int accumulate;
 1122                 struct alias_data ad = {
 1123                         .lnk = lnk,
 1124                         .oaddr = NULL,
 1125                         .aaddr = &alias_address,
 1126                         .aport = &alias_port,
 1127                         .sport = &tc->th_sport,
 1128                         .dport = &tc->th_dport,
 1129                         .maxpktsize = maxpacketsize
 1130                 };
 1131 
 1132                 /* Save original destination address, if this is a proxy packet.
 1133                  * Also modify packet to include destination
 1134                  * encoding.  This may change the size of IP header. */
 1135                 if (proxy_type != 0) {
 1136                         SetProxyPort(lnk, dest_port);
 1137                         SetProxyAddress(lnk, dest_address);
 1138                         ProxyModify(la, lnk, pip, maxpacketsize, proxy_type);
 1139                         tc = (struct tcphdr *)ip_next(pip);
 1140                 }
 1141                 /* Get alias address and port */
 1142                 alias_port = GetAliasPort(lnk);
 1143                 alias_address = GetAliasAddress(lnk);
 1144 
 1145                 /* Monitor TCP connection state */
 1146                 tc = (struct tcphdr *)ip_next(pip);
 1147                 TcpMonitorOut(tc->th_flags, lnk);
 1148 
 1149                 /* Walk out chain. */
 1150                 find_handler(OUT, TCP, la, pip, &ad);
 1151 
 1152                 /* Adjust TCP checksum since source port is being aliased
 1153                  * and source address is being altered */
 1154                 accumulate = tc->th_sport;
 1155                 tc->th_sport = alias_port;
 1156                 accumulate -= tc->th_sport;
 1157                 accumulate += twowords(&pip->ip_src);
 1158                 accumulate -= twowords(&alias_address);
 1159 
 1160                 /* Modify sequence number if necessary */
 1161                 if (GetAckModified(lnk) == 1) {
 1162                         int delta;
 1163 
 1164                         tc = (struct tcphdr *)ip_next(pip);
 1165                         delta = GetDeltaSeqOut(tc->th_seq, lnk);
 1166                         if (delta != 0) {
 1167                                 accumulate += twowords(&tc->th_seq);
 1168                                 tc->th_seq = htonl(ntohl(tc->th_seq) + delta);
 1169                                 accumulate -= twowords(&tc->th_seq);
 1170                         }
 1171                 }
 1172                 ADJUST_CHECKSUM(accumulate, tc->th_sum);
 1173 
 1174                 /* Change source address */
 1175                 accumulate = twowords(&pip->ip_src);
 1176                 pip->ip_src = alias_address;
 1177                 accumulate -= twowords(&pip->ip_src);
 1178                 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
 1179 
 1180                 return (PKT_ALIAS_OK);
 1181         }
 1182         return (PKT_ALIAS_IGNORED);
 1183 }
 1184 
 1185 /* Fragment Handling
 1186 
 1187     FragmentIn()
 1188     FragmentOut()
 1189 
 1190 The packet aliasing module has a limited ability for handling IP
 1191 fragments.  If the ICMP, TCP or UDP header is in the first fragment
 1192 received, then the ID number of the IP packet is saved, and other
 1193 fragments are identified according to their ID number and IP address
 1194 they were sent from.  Pointers to unresolved fragments can also be
 1195 saved and recalled when a header fragment is seen.
 1196 */
 1197 
 1198 /* Local prototypes */
 1199 static int      FragmentIn(struct libalias *la, struct in_addr ip_src,
 1200                     struct ip *pip, u_short ip_id, u_short *ip_sum);
 1201 static int      FragmentOut(struct libalias *, struct ip *pip,
 1202                     u_short *ip_sum);
 1203 
 1204 static int
 1205 FragmentIn(struct libalias *la, struct in_addr ip_src, struct ip *pip,
 1206     u_short ip_id, u_short *ip_sum)
 1207 {
 1208         struct alias_link *lnk;
 1209 
 1210         LIBALIAS_LOCK_ASSERT(la);
 1211         lnk = FindFragmentIn2(la, ip_src, pip->ip_dst, ip_id);
 1212         if (lnk != NULL) {
 1213                 struct in_addr original_address;
 1214 
 1215                 GetFragmentAddr(lnk, &original_address);
 1216                 DifferentialChecksum(ip_sum,
 1217                     &original_address, &pip->ip_dst, 2);
 1218                 pip->ip_dst = original_address;
 1219 
 1220                 return (PKT_ALIAS_OK);
 1221         }
 1222         return (PKT_ALIAS_UNRESOLVED_FRAGMENT);
 1223 }
 1224 
 1225 static int
 1226 FragmentOut(struct libalias *la, struct ip *pip, u_short *ip_sum)
 1227 {
 1228         struct in_addr alias_address;
 1229 
 1230         LIBALIAS_LOCK_ASSERT(la);
 1231         alias_address = FindAliasAddress(la, pip->ip_src);
 1232         DifferentialChecksum(ip_sum,
 1233             &alias_address, &pip->ip_src, 2);
 1234         pip->ip_src = alias_address;
 1235 
 1236         return (PKT_ALIAS_OK);
 1237 }
 1238 
 1239 /* Outside World Access
 1240 
 1241         PacketAliasSaveFragment()
 1242         PacketAliasGetFragment()
 1243         PacketAliasFragmentIn()
 1244         PacketAliasIn()
 1245         PacketAliasOut()
 1246         PacketUnaliasOut()
 1247 
 1248 (prototypes in alias.h)
 1249 */
 1250 
 1251 int
 1252 LibAliasSaveFragment(struct libalias *la, void *ptr)
 1253 {
 1254         int iresult;
 1255         struct alias_link *lnk;
 1256         struct ip *pip;
 1257 
 1258         LIBALIAS_LOCK(la);
 1259         pip = (struct ip *)ptr;
 1260         lnk = AddFragmentPtrLink(la, pip->ip_src, pip->ip_id);
 1261         iresult = PKT_ALIAS_ERROR;
 1262         if (lnk != NULL) {
 1263                 SetFragmentPtr(lnk, ptr);
 1264                 iresult = PKT_ALIAS_OK;
 1265         }
 1266         LIBALIAS_UNLOCK(la);
 1267         return (iresult);
 1268 }
 1269 
 1270 void *
 1271 LibAliasGetFragment(struct libalias *la, void *ptr)
 1272 {
 1273         struct alias_link *lnk;
 1274         void *fptr;
 1275         struct ip *pip;
 1276 
 1277         LIBALIAS_LOCK(la);
 1278         pip = (struct ip *)ptr;
 1279         lnk = FindFragmentPtr(la, pip->ip_src, pip->ip_id);
 1280         if (lnk != NULL) {
 1281                 GetFragmentPtr(lnk, &fptr);
 1282                 SetFragmentPtr(lnk, NULL);
 1283                 SetExpire(lnk, 0);      /* Deletes link */
 1284         } else
 1285                 fptr = NULL;
 1286 
 1287         LIBALIAS_UNLOCK(la);
 1288         return (fptr);
 1289 }
 1290 
 1291 void
 1292 LibAliasFragmentIn(struct libalias *la,
 1293     void *ptr,  /* Points to correctly de-aliased header fragment */
 1294     void *ptr_fragment  /* fragment which must be de-aliased   */
 1295 )
 1296 {
 1297         struct ip *pip;
 1298         struct ip *fpip;
 1299 
 1300         LIBALIAS_LOCK(la);
 1301         (void)la;
 1302         pip = (struct ip *)ptr;
 1303         fpip = (struct ip *)ptr_fragment;
 1304 
 1305         DifferentialChecksum(&fpip->ip_sum,
 1306             &pip->ip_dst, &fpip->ip_dst, 2);
 1307         fpip->ip_dst = pip->ip_dst;
 1308         LIBALIAS_UNLOCK(la);
 1309 }
 1310 
 1311 /* Local prototypes */
 1312 static int
 1313 LibAliasOutLocked(struct libalias *la, struct ip *pip,
 1314     int maxpacketsize, int create);
 1315 static int
 1316 LibAliasInLocked(struct libalias *la, struct ip *pip,
 1317     int maxpacketsize);
 1318 
 1319 int
 1320 LibAliasIn(struct libalias *la, void *ptr, int maxpacketsize)
 1321 {
 1322         int res;
 1323 
 1324         LIBALIAS_LOCK(la);
 1325         res = LibAliasInLocked(la, (struct ip *)ptr, maxpacketsize);
 1326         LIBALIAS_UNLOCK(la);
 1327         return (res);
 1328 }
 1329 
 1330 static int
 1331 LibAliasInLocked(struct libalias *la, struct ip *pip, int maxpacketsize)
 1332 {
 1333         struct in_addr alias_addr;
 1334         int iresult;
 1335 
 1336         if (la->packetAliasMode & PKT_ALIAS_REVERSE) {
 1337                 la->packetAliasMode &= ~PKT_ALIAS_REVERSE;
 1338                 iresult = LibAliasOutLocked(la, pip, maxpacketsize, 1);
 1339                 la->packetAliasMode |= PKT_ALIAS_REVERSE;
 1340                 goto getout;
 1341         }
 1342         HouseKeeping(la);
 1343         alias_addr = pip->ip_dst;
 1344 
 1345         /* Defense against mangled packets */
 1346         if (ntohs(pip->ip_len) > maxpacketsize
 1347             || (pip->ip_hl << 2) > maxpacketsize) {
 1348                 iresult = PKT_ALIAS_IGNORED;
 1349                 goto getout;
 1350         }
 1351 
 1352         if (FRAG_NO_HDR(pip)) {
 1353                 iresult = FragmentIn(la, pip->ip_src, pip, pip->ip_id,
 1354                     &pip->ip_sum);
 1355                 goto getout;
 1356         }
 1357 
 1358         iresult = PKT_ALIAS_IGNORED;
 1359         switch (pip->ip_p) {
 1360         case IPPROTO_ICMP:
 1361                 iresult = IcmpAliasIn(la, pip);
 1362                 break;
 1363         case IPPROTO_UDP:
 1364                 iresult = UdpAliasIn(la, pip);
 1365                 break;
 1366         case IPPROTO_TCP:
 1367                 iresult = TcpAliasIn(la, pip);
 1368                 break;
 1369 #ifdef _KERNEL
 1370         case IPPROTO_SCTP:
 1371                 iresult = SctpAlias(la, pip, SN_TO_LOCAL);
 1372                 break;
 1373 #endif
 1374         case IPPROTO_GRE: {
 1375                 int error;
 1376                 struct alias_data ad = {
 1377                         .lnk = NULL,
 1378                         .oaddr = NULL,
 1379                         .aaddr = NULL,
 1380                         .aport = NULL,
 1381                         .sport = NULL,
 1382                         .dport = NULL,
 1383                         .maxpktsize = 0
 1384                 };
 1385 
 1386                 /* Walk out chain. */
 1387                 error = find_handler(IN, IP, la, pip, &ad);
 1388                 if (error == 0)
 1389                         iresult = PKT_ALIAS_OK;
 1390                 else
 1391                         iresult = ProtoAliasIn(la, pip->ip_src,
 1392                             pip, pip->ip_p, &pip->ip_sum);
 1393                 break;
 1394         }
 1395         default:
 1396                 iresult = ProtoAliasIn(la, pip->ip_src, pip,
 1397                     pip->ip_p, &pip->ip_sum);
 1398                 break;
 1399         }
 1400 
 1401         if (MF_ISSET(pip)) {
 1402                 struct alias_link *lnk;
 1403 
 1404                 lnk = FindFragmentIn1(la, pip->ip_src, alias_addr, pip->ip_id);
 1405                 if (lnk != NULL) {
 1406                         iresult = PKT_ALIAS_FOUND_HEADER_FRAGMENT;
 1407                         SetFragmentAddr(lnk, pip->ip_dst);
 1408                 } else {
 1409                         iresult = PKT_ALIAS_ERROR;
 1410                 }
 1411         }
 1412 
 1413 getout:
 1414         return (iresult);
 1415 }
 1416 
 1417 /* Unregistered address ranges */
 1418 
 1419 /* 10.0.0.0   ->   10.255.255.255 */
 1420 #define UNREG_ADDR_A_LOWER 0x0a000000
 1421 #define UNREG_ADDR_A_UPPER 0x0affffff
 1422 
 1423 /* 172.16.0.0  ->  172.31.255.255 */
 1424 #define UNREG_ADDR_B_LOWER 0xac100000
 1425 #define UNREG_ADDR_B_UPPER 0xac1fffff
 1426 
 1427 /* 192.168.0.0 -> 192.168.255.255 */
 1428 #define UNREG_ADDR_C_LOWER 0xc0a80000
 1429 #define UNREG_ADDR_C_UPPER 0xc0a8ffff
 1430 
 1431 /* 100.64.0.0  -> 100.127.255.255 (RFC 6598 - Carrier Grade NAT) */
 1432 #define UNREG_ADDR_CGN_LOWER 0x64400000
 1433 #define UNREG_ADDR_CGN_UPPER 0x647fffff
 1434 
 1435 int
 1436 LibAliasOut(struct libalias *la, void *ptr, int maxpacketsize)
 1437 {
 1438         int res;
 1439 
 1440         LIBALIAS_LOCK(la);
 1441         res = LibAliasOutLocked(la, (struct ip *)ptr, maxpacketsize, 1);
 1442         LIBALIAS_UNLOCK(la);
 1443         return (res);
 1444 }
 1445 
 1446 int
 1447 LibAliasOutTry(struct libalias *la, void *ptr, int maxpacketsize, int create)
 1448 {
 1449         int res;
 1450 
 1451         LIBALIAS_LOCK(la);
 1452         res = LibAliasOutLocked(la, (struct ip *)ptr, maxpacketsize, create);
 1453         LIBALIAS_UNLOCK(la);
 1454         return (res);
 1455 }
 1456 
 1457 static int
 1458 LibAliasOutLocked(struct libalias *la,
 1459     struct ip *pip,     /* valid IP packet */
 1460     int maxpacketsize,  /* How much the packet data may grow (FTP and IRC inline changes) */
 1461     int create          /* Create new entries ? */
 1462 )
 1463 {
 1464         int iresult;
 1465         struct in_addr addr_save;
 1466 
 1467         if (la->packetAliasMode & PKT_ALIAS_REVERSE) {
 1468                 la->packetAliasMode &= ~PKT_ALIAS_REVERSE;
 1469                 iresult = LibAliasInLocked(la, pip, maxpacketsize);
 1470                 la->packetAliasMode |= PKT_ALIAS_REVERSE;
 1471                 goto getout;
 1472         }
 1473         HouseKeeping(la);
 1474 
 1475         /* Defense against mangled packets */
 1476         if (ntohs(pip->ip_len) > maxpacketsize
 1477             || (pip->ip_hl << 2) > maxpacketsize) {
 1478                 iresult = PKT_ALIAS_IGNORED;
 1479                 goto getout;
 1480         }
 1481 
 1482         addr_save = GetDefaultAliasAddress(la);
 1483         if (la->packetAliasMode & PKT_ALIAS_UNREGISTERED_ONLY ||
 1484             la->packetAliasMode & PKT_ALIAS_UNREGISTERED_CGN) {
 1485                 u_long addr;
 1486                 int iclass;
 1487 
 1488                 iclass = 0;
 1489                 addr = ntohl(pip->ip_src.s_addr);
 1490                 if (addr >= UNREG_ADDR_C_LOWER && addr <= UNREG_ADDR_C_UPPER)
 1491                         iclass = 3;
 1492                 else if (addr >= UNREG_ADDR_B_LOWER && addr <= UNREG_ADDR_B_UPPER)
 1493                         iclass = 2;
 1494                 else if (addr >= UNREG_ADDR_A_LOWER && addr <= UNREG_ADDR_A_UPPER)
 1495                         iclass = 1;
 1496                 else if (addr >= UNREG_ADDR_CGN_LOWER && addr <= UNREG_ADDR_CGN_UPPER &&
 1497                     la->packetAliasMode & PKT_ALIAS_UNREGISTERED_CGN)
 1498                         iclass = 4;
 1499 
 1500                 if (iclass == 0) {
 1501                         SetDefaultAliasAddress(la, pip->ip_src);
 1502                 }
 1503         } else if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY) {
 1504                 SetDefaultAliasAddress(la, pip->ip_src);
 1505         }
 1506 
 1507         if (FRAG_NO_HDR(pip)) {
 1508                 iresult = FragmentOut(la, pip, &pip->ip_sum);
 1509                 goto getout_restore;
 1510         }
 1511 
 1512         iresult = PKT_ALIAS_IGNORED;
 1513         switch (pip->ip_p) {
 1514         case IPPROTO_ICMP:
 1515                 iresult = IcmpAliasOut(la, pip, create);
 1516                 break;
 1517         case IPPROTO_UDP:
 1518                 iresult = UdpAliasOut(la, pip, maxpacketsize, create);
 1519                 break;
 1520         case IPPROTO_TCP:
 1521                 iresult = TcpAliasOut(la, pip, maxpacketsize, create);
 1522                 break;
 1523 #ifdef _KERNEL
 1524         case IPPROTO_SCTP:
 1525                 iresult = SctpAlias(la, pip, SN_TO_GLOBAL);
 1526                 break;
 1527 #endif
 1528         case IPPROTO_GRE: {
 1529                 int error;
 1530                 struct alias_data ad = {
 1531                         .lnk = NULL,
 1532                         .oaddr = NULL,
 1533                         .aaddr = NULL,
 1534                         .aport = NULL,
 1535                         .sport = NULL,
 1536                         .dport = NULL,
 1537                         .maxpktsize = 0
 1538                 };
 1539                 /* Walk out chain. */
 1540                 error = find_handler(OUT, IP, la, pip, &ad);
 1541                 if (error == 0)
 1542                         iresult = PKT_ALIAS_OK;
 1543                 else
 1544                         iresult = ProtoAliasOut(la, pip,
 1545                             pip->ip_dst, pip->ip_p, &pip->ip_sum, create);
 1546                 break;
 1547                 }
 1548         default:
 1549                 iresult = ProtoAliasOut(la, pip,
 1550                     pip->ip_dst, pip->ip_p, &pip->ip_sum, create);
 1551                 break;
 1552         }
 1553 
 1554 getout_restore:
 1555         SetDefaultAliasAddress(la, addr_save);
 1556 getout:
 1557         return (iresult);
 1558 }
 1559 
 1560 int
 1561 LibAliasUnaliasOut(struct libalias *la,
 1562     void *ptr,          /* valid IP packet */
 1563     int maxpacketsize   /* for error checking */
 1564 )
 1565 {
 1566         struct ip *pip;
 1567         struct icmp *ic;
 1568         struct udphdr *ud;
 1569         struct tcphdr *tc;
 1570         struct alias_link *lnk;
 1571         int iresult = PKT_ALIAS_IGNORED;
 1572 
 1573         LIBALIAS_LOCK(la);
 1574         pip = (struct ip *)ptr;
 1575 
 1576         /* Defense against mangled packets */
 1577         if (ntohs(pip->ip_len) > maxpacketsize
 1578             || (pip->ip_hl << 2) > maxpacketsize)
 1579                 goto getout;
 1580 
 1581         ud = (struct udphdr *)ip_next(pip);
 1582         tc = (struct tcphdr *)ip_next(pip);
 1583         ic = (struct icmp *)ip_next(pip);
 1584 
 1585         /* Find a link */
 1586         if (pip->ip_p == IPPROTO_UDP)
 1587                 lnk = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src,
 1588                     ud->uh_dport, ud->uh_sport,
 1589                     IPPROTO_UDP, 0);
 1590         else if (pip->ip_p == IPPROTO_TCP)
 1591                 lnk = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src,
 1592                     tc->th_dport, tc->th_sport,
 1593                     IPPROTO_TCP, 0);
 1594         else if (pip->ip_p == IPPROTO_ICMP)
 1595                 lnk = FindIcmpIn(la, pip->ip_dst, pip->ip_src, ic->icmp_id, 0);
 1596         else
 1597                 lnk = NULL;
 1598 
 1599         /* Change it from an aliased packet to an unaliased packet */
 1600         if (lnk != NULL) {
 1601                 if (pip->ip_p == IPPROTO_UDP || pip->ip_p == IPPROTO_TCP) {
 1602                         int accumulate;
 1603                         struct in_addr original_address;
 1604                         u_short original_port;
 1605 
 1606                         original_address = GetOriginalAddress(lnk);
 1607                         original_port = GetOriginalPort(lnk);
 1608 
 1609                         /* Adjust TCP/UDP checksum */
 1610                         accumulate = twowords(&pip->ip_src);
 1611                         accumulate -= twowords(&original_address);
 1612 
 1613                         if (pip->ip_p == IPPROTO_UDP) {
 1614                                 accumulate += ud->uh_sport;
 1615                                 accumulate -= original_port;
 1616                                 ADJUST_CHECKSUM(accumulate, ud->uh_sum);
 1617                         } else {
 1618                                 accumulate += tc->th_sport;
 1619                                 accumulate -= original_port;
 1620                                 ADJUST_CHECKSUM(accumulate, tc->th_sum);
 1621                         }
 1622 
 1623                         /* Adjust IP checksum */
 1624                         DifferentialChecksum(&pip->ip_sum,
 1625                             &original_address, &pip->ip_src, 2);
 1626 
 1627                         /* Un-alias source address and port number */
 1628                         pip->ip_src = original_address;
 1629                         if (pip->ip_p == IPPROTO_UDP)
 1630                                 ud->uh_sport = original_port;
 1631                         else
 1632                                 tc->th_sport = original_port;
 1633 
 1634                         iresult = PKT_ALIAS_OK;
 1635                 } else if (pip->ip_p == IPPROTO_ICMP) {
 1636                         int accumulate;
 1637                         struct in_addr original_address;
 1638                         u_short original_id;
 1639 
 1640                         original_address = GetOriginalAddress(lnk);
 1641                         original_id = GetOriginalPort(lnk);
 1642 
 1643                         /* Adjust ICMP checksum */
 1644                         accumulate = twowords(&pip->ip_src);
 1645                         accumulate -= twowords(&original_address);
 1646                         accumulate += ic->icmp_id;
 1647                         accumulate -= original_id;
 1648                         ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
 1649 
 1650                         /* Adjust IP checksum */
 1651                         DifferentialChecksum(&pip->ip_sum,
 1652                             &original_address, &pip->ip_src, 2);
 1653 
 1654                         /* Un-alias source address and port number */
 1655                         pip->ip_src = original_address;
 1656                         ic->icmp_id = original_id;
 1657 
 1658                         iresult = PKT_ALIAS_OK;
 1659                 }
 1660         }
 1661 getout:
 1662         LIBALIAS_UNLOCK(la);
 1663         return (iresult);
 1664 }
 1665 
 1666 #ifndef _KERNEL
 1667 
 1668 int
 1669 LibAliasRefreshModules(void)
 1670 {
 1671         char buf[256], conf[] = "/etc/libalias.conf";
 1672         FILE *fd;
 1673         int i, len;
 1674 
 1675         fd = fopen(conf, "r");
 1676         if (fd == NULL)
 1677                 err(1, "fopen(%s)", conf);
 1678 
 1679         LibAliasUnLoadAllModule();
 1680 
 1681         for (;;) {
 1682                 fgets(buf, 256, fd);
 1683                 if (feof(fd))
 1684                         break;
 1685                 len = strlen(buf);
 1686                 if (len > 1) {
 1687                         for (i = 0; i < len; i++)
 1688                                 if (!isspace(buf[i]))
 1689                                         break;
 1690                         if (buf[i] == '#')
 1691                                 continue;
 1692                         buf[len - 1] = '\0';
 1693                         LibAliasLoadModule(buf);
 1694                 }
 1695         }
 1696         fclose(fd);
 1697         return (0);
 1698 }
 1699 
 1700 int
 1701 LibAliasLoadModule(char *path)
 1702 {
 1703         struct dll *t;
 1704         void *handle;
 1705         struct proto_handler *m;
 1706         const char *error;
 1707         moduledata_t *p;
 1708 
 1709         handle = dlopen (path, RTLD_LAZY);
 1710         if (!handle) {
 1711                 fprintf(stderr, "%s\n", dlerror());
 1712                 return (EINVAL);
 1713         }
 1714 
 1715         p = dlsym(handle, "alias_mod");
 1716         if ((error = dlerror()) != NULL)  {
 1717                 fprintf(stderr, "%s\n", dlerror());
 1718                 return (EINVAL);
 1719         }
 1720 
 1721         t = malloc(sizeof(struct dll));
 1722         if (t == NULL)
 1723                 return (ENOMEM);
 1724         strncpy(t->name, p->name, DLL_LEN);
 1725         t->handle = handle;
 1726         if (attach_dll(t) == EEXIST) {
 1727                 free(t);
 1728                 fprintf(stderr, "dll conflict\n");
 1729                 return (EEXIST);
 1730         }
 1731 
 1732         m = dlsym(t->handle, "handlers");
 1733         if ((error = dlerror()) != NULL)  {
 1734                 fprintf(stderr, "%s\n", error);
 1735                 return (EINVAL);
 1736         }
 1737 
 1738         LibAliasAttachHandlers(m);
 1739         return (0);
 1740 }
 1741 
 1742 int
 1743 LibAliasUnLoadAllModule(void)
 1744 {
 1745         struct dll *t;
 1746         struct proto_handler *p;
 1747 
 1748         /* Unload all modules then reload everything. */
 1749         while ((p = first_handler()) != NULL) {
 1750                 LibAliasDetachHandlers(p);
 1751         }
 1752         while ((t = walk_dll_chain()) != NULL) {
 1753                 dlclose(t->handle);
 1754                 free(t);
 1755         }
 1756         return (1);
 1757 }
 1758 
 1759 #endif
 1760 
 1761 #ifdef _KERNEL
 1762 /*
 1763  * m_megapullup() - this function is a big hack.
 1764  * Thankfully, it's only used in ng_nat and ipfw+nat.
 1765  *
 1766  * It allocates an mbuf with cluster and copies the specified part of the chain
 1767  * into cluster, so that it is all contiguous and can be accessed via a plain
 1768  * (char *) pointer. This is required, because libalias doesn't know how to
 1769  * handle mbuf chains.
 1770  *
 1771  * On success, m_megapullup returns an mbuf (possibly with cluster) containing
 1772  * the input packet, on failure NULL. The input packet is always consumed.
 1773  */
 1774 struct mbuf *
 1775 m_megapullup(struct mbuf *m, int len)
 1776 {
 1777         struct mbuf *mcl;
 1778 
 1779         if (len > m->m_pkthdr.len)
 1780                 goto bad;
 1781 
 1782         if (m->m_next == NULL && M_WRITABLE(m))
 1783                 return (m);
 1784 
 1785         if (len <= MJUMPAGESIZE)
 1786                 mcl = m_get2(len, M_NOWAIT, MT_DATA, M_PKTHDR);
 1787         else if (len <= MJUM9BYTES)
 1788                 mcl = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUM9BYTES);
 1789         else if (len <= MJUM16BYTES)
 1790                 mcl = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUM16BYTES);
 1791         else
 1792                 goto bad;
 1793         if (mcl == NULL)
 1794                 goto bad;
 1795         m_align(mcl, len);
 1796         m_move_pkthdr(mcl, m);
 1797         m_copydata(m, 0, len, mtod(mcl, caddr_t));
 1798         mcl->m_len = mcl->m_pkthdr.len = len;
 1799         m_freem(m);
 1800 
 1801         return (mcl);
 1802 bad:
 1803         m_freem(m);
 1804         return (NULL);
 1805 }
 1806 #endif

Cache object: b038986ffb6d00a27d7c0126cb8bddf2


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.