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_db.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 #ifdef _KERNEL
   33 #include <machine/stdarg.h>
   34 #include <sys/param.h>
   35 #include <sys/kernel.h>
   36 #include <sys/systm.h>
   37 #include <sys/lock.h>
   38 #include <sys/module.h>
   39 #include <sys/rwlock.h>
   40 #include <sys/syslog.h>
   41 #else
   42 #include <stdarg.h>
   43 #include <stdlib.h>
   44 #include <stdio.h>
   45 #include <sys/errno.h>
   46 #include <sys/time.h>
   47 #include <unistd.h>
   48 #endif
   49 
   50 #include <sys/socket.h>
   51 #include <netinet/tcp.h>
   52 
   53 #ifdef _KERNEL
   54 #include <netinet/libalias/alias.h>
   55 #include <netinet/libalias/alias_local.h>
   56 #include <netinet/libalias/alias_mod.h>
   57 #include <net/if.h>
   58 #else
   59 #include "alias.h"
   60 #include "alias_local.h"
   61 #include "alias_mod.h"
   62 #endif
   63 
   64 #include "alias_db.h"
   65 
   66 static LIST_HEAD(, libalias) instancehead = LIST_HEAD_INITIALIZER(instancehead);
   67 int LibAliasTime;
   68 
   69 /* Kernel module definition. */
   70 #ifdef _KERNEL
   71 MALLOC_DEFINE(M_ALIAS, "libalias", "packet aliasing");
   72 
   73 MODULE_VERSION(libalias, 1);
   74 
   75 static int
   76 alias_mod_handler(module_t mod, int type, void *data)
   77 {
   78         switch (type) {
   79         case MOD_QUIESCE:
   80         case MOD_UNLOAD:
   81                 finishoff();
   82         case MOD_LOAD:
   83                 return (0);
   84         default:
   85                 return (EINVAL);
   86         }
   87 }
   88 
   89 static moduledata_t alias_mod = {
   90        "alias", alias_mod_handler, NULL
   91 };
   92 
   93 DECLARE_MODULE(alias, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
   94 #endif
   95 
   96 SPLAY_GENERATE(splay_out, alias_link, all.out, cmp_out);
   97 SPLAY_GENERATE(splay_in, group_in, in, cmp_in);
   98 
   99 static struct group_in *
  100 StartPointIn(struct libalias *la,
  101     struct in_addr alias_addr, u_short alias_port, int link_type,
  102     int create)
  103 {
  104         struct group_in *grp;
  105         struct group_in needle = {
  106                 .alias_addr = alias_addr,
  107                 .alias_port = alias_port,
  108                 .link_type = link_type
  109         };
  110 
  111         grp = SPLAY_FIND(splay_in, &la->linkSplayIn, &needle);
  112         if (grp != NULL || !create || (grp = malloc(sizeof(*grp))) == NULL)
  113                 return (grp);
  114         grp->alias_addr = alias_addr;
  115         grp->alias_port = alias_port;
  116         grp->link_type = link_type;
  117         LIST_INIT(&grp->full);
  118         LIST_INIT(&grp->partial);
  119         SPLAY_INSERT(splay_in, &la->linkSplayIn, grp);
  120         return (grp);
  121 }
  122 
  123 static int
  124 SeqDiff(u_long x, u_long y)
  125 {
  126 /* Return the difference between two TCP sequence numbers
  127  * This function is encapsulated in case there are any unusual
  128  * arithmetic conditions that need to be considered.
  129  */
  130         return (ntohl(y) - ntohl(x));
  131 }
  132 
  133 #ifdef _KERNEL
  134 static void
  135 AliasLog(char *str, const char *format, ...)
  136 {
  137         va_list ap;
  138 
  139         va_start(ap, format);
  140         vsnprintf(str, LIBALIAS_BUF_SIZE, format, ap);
  141         va_end(ap);
  142 }
  143 #else
  144 static void
  145 AliasLog(FILE *stream, const char *format, ...)
  146 {
  147         va_list ap;
  148 
  149         va_start(ap, format);
  150         vfprintf(stream, format, ap);
  151         va_end(ap);
  152         fflush(stream);
  153 }
  154 #endif
  155 
  156 static void
  157 ShowAliasStats(struct libalias *la)
  158 {
  159         LIBALIAS_LOCK_ASSERT(la);
  160         /* Used for debugging */
  161         if (la->logDesc) {
  162                 int tot  = la->icmpLinkCount + la->udpLinkCount +
  163                     (la->sctpLinkCount>>1) + /* sctp counts half associations */
  164                     la->tcpLinkCount + la->pptpLinkCount +
  165                     la->protoLinkCount + la->fragmentIdLinkCount +
  166                     la->fragmentPtrLinkCount;
  167 
  168                 AliasLog(la->logDesc,
  169                     "icmp=%u, udp=%u, tcp=%u, sctp=%u, pptp=%u, proto=%u, frag_id=%u frag_ptr=%u / tot=%u",
  170                     la->icmpLinkCount,
  171                     la->udpLinkCount,
  172                     la->tcpLinkCount,
  173                     la->sctpLinkCount>>1, /* sctp counts half associations */
  174                     la->pptpLinkCount,
  175                     la->protoLinkCount,
  176                     la->fragmentIdLinkCount,
  177                     la->fragmentPtrLinkCount,
  178                     tot);
  179 #ifndef _KERNEL
  180                 AliasLog(la->logDesc, " (sock=%u)\n", la->sockCount);
  181 #endif
  182         }
  183 }
  184 
  185 void SctpShowAliasStats(struct libalias *la)
  186 {
  187         ShowAliasStats(la);
  188 }
  189 
  190 /* get random port in network byte order */
  191 static u_short
  192 _RandomPort(struct libalias *la) {
  193         u_short port;
  194 
  195         port = la->aliasPortLower +
  196             arc4random_uniform(la->aliasPortLength);
  197 
  198         return ntohs(port);
  199 }
  200 
  201 /* GetNewPort() allocates port numbers.  Note that if a port number
  202    is already in use, that does not mean that it cannot be used by
  203    another link concurrently.  This is because GetNewPort() looks for
  204    unused triplets: (dest addr, dest port, alias port). */
  205 
  206 static int
  207 GetNewPort(struct libalias *la, struct alias_link *lnk, int alias_port_param)
  208 {
  209         int i;
  210         int max_trials;
  211         u_short port;
  212 
  213         LIBALIAS_LOCK_ASSERT(la);
  214         /*
  215          * Description of alias_port_param for GetNewPort().  When
  216          * this parameter is zero or positive, it precisely specifies
  217          * the port number.  GetNewPort() will return this number
  218          * without check that it is in use.
  219         *
  220          * The aliasing port is automatically selected by one of
  221          * two methods below:
  222          *
  223          * When this parameter is GET_ALIAS_PORT, it indicates to get
  224          * a randomly selected port number.
  225          */
  226         if (alias_port_param >= 0 && alias_port_param < 0x10000) {
  227                 lnk->alias_port = (u_short) alias_port_param;
  228                 return (0);
  229         }
  230         if (alias_port_param != GET_ALIAS_PORT) {
  231 #ifdef LIBALIAS_DEBUG
  232                 fprintf(stderr, "PacketAlias/GetNewPort(): ");
  233                 fprintf(stderr, "input parameter error\n");
  234 #endif
  235                 return (-1);
  236         }
  237 
  238         max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
  239 
  240         /*
  241          * When the PKT_ALIAS_SAME_PORTS option is chosen,
  242          * the first try will be the actual source port. If
  243          * this is already in use, the remainder of the
  244          * trials will be random.
  245          */
  246         port = (la->packetAliasMode & PKT_ALIAS_SAME_PORTS)
  247             ? lnk->src_port
  248             : _RandomPort(la);
  249 
  250         /* Port number search */
  251         for (i = 0; i < max_trials; i++, port = _RandomPort(la)) {
  252                 struct group_in *grp;
  253                 struct alias_link *search_result;
  254 
  255                 grp = StartPointIn(la, lnk->alias_addr, port, lnk->link_type, 0);
  256                 if (grp == NULL)
  257                         break;
  258 
  259                 LIST_FOREACH(search_result, &grp->full, all.in) {
  260                         if (lnk->dst_addr.s_addr == search_result->dst_addr.s_addr &&
  261                             lnk->dst_port == search_result->dst_port)
  262                             break;     /* found match */
  263                 }
  264                 if (search_result == NULL)
  265                         break;
  266         }
  267 
  268         if (i >= max_trials) {
  269 #ifdef LIBALIAS_DEBUG
  270                 fprintf(stderr, "PacketAlias/GetNewPort(): ");
  271                 fprintf(stderr, "could not find free port\n");
  272 #endif
  273                 return (-1);
  274         }
  275 
  276 #ifndef NO_USE_SOCKETS
  277         if ((la->packetAliasMode & PKT_ALIAS_USE_SOCKETS) &&
  278             (lnk->flags & LINK_PARTIALLY_SPECIFIED) &&
  279             ((lnk->link_type == LINK_TCP) ||
  280              (lnk->link_type == LINK_UDP))) {
  281                 if (!GetSocket(la, port, &lnk->sockfd, lnk->link_type)) {
  282                         return (-1);
  283                 }
  284         }
  285 #endif
  286         lnk->alias_port = port;
  287 
  288         return (0);
  289 }
  290 
  291 #ifndef NO_USE_SOCKETS
  292 static          u_short
  293 GetSocket(struct libalias *la, u_short port_net, int *sockfd, int link_type)
  294 {
  295         int err;
  296         int sock;
  297         struct sockaddr_in sock_addr;
  298 
  299         LIBALIAS_LOCK_ASSERT(la);
  300         if (link_type == LINK_TCP)
  301                 sock = socket(AF_INET, SOCK_STREAM, 0);
  302         else if (link_type == LINK_UDP)
  303                 sock = socket(AF_INET, SOCK_DGRAM, 0);
  304         else {
  305 #ifdef LIBALIAS_DEBUG
  306                 fprintf(stderr, "PacketAlias/GetSocket(): ");
  307                 fprintf(stderr, "incorrect link type\n");
  308 #endif
  309                 return (0);
  310         }
  311 
  312         if (sock < 0) {
  313 #ifdef LIBALIAS_DEBUG
  314                 fprintf(stderr, "PacketAlias/GetSocket(): ");
  315                 fprintf(stderr, "socket() error %d\n", *sockfd);
  316 #endif
  317                 return (0);
  318         }
  319         sock_addr.sin_family = AF_INET;
  320         sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  321         sock_addr.sin_port = port_net;
  322 
  323         err = bind(sock,
  324             (struct sockaddr *)&sock_addr,
  325             sizeof(sock_addr));
  326         if (err == 0) {
  327                 la->sockCount++;
  328                 *sockfd = sock;
  329                 return (1);
  330         } else {
  331                 close(sock);
  332                 return (0);
  333         }
  334 }
  335 #endif
  336 
  337 /* FindNewPortGroup() returns a base port number for an available
  338    range of contiguous port numbers. Note that if a port number
  339    is already in use, that does not mean that it cannot be used by
  340    another link concurrently.  This is because FindNewPortGroup()
  341    looks for unused triplets: (dest addr, dest port, alias port). */
  342 
  343 int
  344 FindNewPortGroup(struct libalias *la,
  345     struct in_addr dst_addr,
  346     struct in_addr alias_addr,
  347     u_short src_port,
  348     u_short dst_port,
  349     u_short port_count,
  350     u_char proto,
  351     u_char align)
  352 {
  353         int i, j;
  354         int max_trials;
  355         u_short port;
  356         int link_type;
  357 
  358         LIBALIAS_LOCK_ASSERT(la);
  359         /*
  360          * Get link_type from protocol
  361          */
  362 
  363         switch (proto) {
  364         case IPPROTO_UDP:
  365                 link_type = LINK_UDP;
  366                 break;
  367         case IPPROTO_TCP:
  368                 link_type = LINK_TCP;
  369                 break;
  370         default:
  371                 return (0);
  372                 break;
  373         }
  374 
  375         /*
  376          * The aliasing port is automatically selected by one of two
  377          * methods below:
  378          */
  379         max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
  380 
  381         if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) {
  382                 /*
  383                  * When the ALIAS_SAME_PORTS option is chosen, the first
  384                  * try will be the actual source port. If this is already
  385                  * in use, the remainder of the trials will be random.
  386                  */
  387                 port = src_port;
  388 
  389         } else {
  390                 port = _RandomPort(la);
  391         }
  392 
  393         /* Port number search */
  394         for (i = 0; i < max_trials; i++, port = _RandomPort(la)) {
  395                 struct alias_link *search_result;
  396 
  397                 if (align)
  398                         port &= htons(0xfffe);
  399 
  400                 for (j = 0; j < port_count; j++) {
  401                         u_short port_j = ntohs(port) + j;
  402 
  403                         if ((search_result = FindLinkIn(la, dst_addr,
  404                             alias_addr, dst_port, htons(port_j),
  405                             link_type, 0)) != NULL)
  406                                 break;
  407                 }
  408 
  409                 /* Found a good range, return base */
  410                 if (j == port_count)
  411                         return (port);
  412         }
  413 
  414 #ifdef LIBALIAS_DEBUG
  415         fprintf(stderr, "PacketAlias/FindNewPortGroup(): ");
  416         fprintf(stderr, "could not find free port(s)\n");
  417 #endif
  418 
  419         return (0);
  420 }
  421 
  422 static void
  423 CleanupAliasData(struct libalias *la, int deletePermanent)
  424 {
  425         struct alias_link *lnk, *lnk_tmp;
  426 
  427         LIBALIAS_LOCK_ASSERT(la);
  428 
  429         /* permanent entries may stay */
  430         TAILQ_FOREACH_SAFE(lnk, &la->checkExpire, expire.list, lnk_tmp)
  431                 DeleteLink(&lnk, deletePermanent);
  432 }
  433 static void
  434 CleanupLink(struct libalias *la, struct alias_link **lnk, int deletePermanent)
  435 {
  436         LIBALIAS_LOCK_ASSERT(la);
  437 
  438         if (lnk == NULL || *lnk == NULL)
  439                 return;
  440 
  441         if (LibAliasTime - (*lnk)->timestamp > (*lnk)->expire.time) {
  442                 DeleteLink(lnk, deletePermanent);
  443                 if ((*lnk) == NULL)
  444                         return;
  445         }
  446 
  447         /* move to end, swap may fail on a single entry list */
  448         TAILQ_REMOVE(&la->checkExpire, (*lnk), expire.list);
  449         TAILQ_INSERT_TAIL(&la->checkExpire, (*lnk), expire.list);
  450 }
  451 
  452 static struct alias_link *
  453 UseLink(struct libalias *la, struct alias_link *lnk)
  454 {
  455         CleanupLink(la, &lnk, 0);
  456         if (lnk != NULL)
  457                 lnk->timestamp = LibAliasTime;
  458         return (lnk);
  459 }
  460 
  461 static void
  462 DeleteLink(struct alias_link **plnk, int deletePermanent)
  463 {
  464         struct alias_link *lnk = *plnk;
  465         struct libalias *la = lnk->la;
  466 
  467         LIBALIAS_LOCK_ASSERT(la);
  468         /* Don't do anything if the link is marked permanent */
  469         if (!deletePermanent && (lnk->flags & LINK_PERMANENT))
  470                 return;
  471 
  472 #ifndef NO_FW_PUNCH
  473         /* Delete associated firewall hole, if any */
  474         ClearFWHole(lnk);
  475 #endif
  476 
  477         switch (lnk->link_type) {
  478         case LINK_PPTP:
  479                 LIST_REMOVE(lnk, pptp.list);
  480                 break;
  481         default: {
  482                 struct group_in *grp;
  483 
  484                 /* Free memory allocated for LSNAT server pool */
  485                 if (lnk->server != NULL) {
  486                         struct server *head, *curr, *next;
  487 
  488                         head = curr = lnk->server;
  489                         do {
  490                                 next = curr->next;
  491                                 free(curr);
  492                         } while ((curr = next) != head);
  493                 } else {
  494                         /* Adjust output table pointers */
  495                         SPLAY_REMOVE(splay_out, &la->linkSplayOut, lnk);
  496                 }
  497 
  498                 /* Adjust input table pointers */
  499                 LIST_REMOVE(lnk, all.in);
  500 
  501                 /* Remove intermediate node, if empty */
  502                 grp = StartPointIn(la, lnk->alias_addr, lnk->alias_port, lnk->link_type, 0);
  503                 if (grp != NULL &&
  504                     LIST_EMPTY(&grp->full) &&
  505                     LIST_EMPTY(&grp->partial)) {
  506                         SPLAY_REMOVE(splay_in, &la->linkSplayIn, grp);
  507                         free(grp);
  508                 }
  509         }
  510                 break;
  511         }
  512 
  513         /* remove from housekeeping */
  514         TAILQ_REMOVE(&la->checkExpire, lnk, expire.list);
  515 
  516 #ifndef NO_USE_SOCKETS
  517         /* Close socket, if one has been allocated */
  518         if (lnk->sockfd != -1) {
  519                 la->sockCount--;
  520                 close(lnk->sockfd);
  521         }
  522 #endif
  523         /* Link-type dependent cleanup */
  524         switch (lnk->link_type) {
  525         case LINK_ICMP:
  526                 la->icmpLinkCount--;
  527                 break;
  528         case LINK_UDP:
  529                 la->udpLinkCount--;
  530                 break;
  531         case LINK_TCP:
  532                 la->tcpLinkCount--;
  533                 free(lnk->data.tcp);
  534                 break;
  535         case LINK_PPTP:
  536                 la->pptpLinkCount--;
  537                 break;
  538         case LINK_FRAGMENT_ID:
  539                 la->fragmentIdLinkCount--;
  540                 break;
  541         case LINK_FRAGMENT_PTR:
  542                 la->fragmentPtrLinkCount--;
  543                 if (lnk->data.frag_ptr != NULL)
  544                         free(lnk->data.frag_ptr);
  545                 break;
  546         case LINK_ADDR:
  547                 break;
  548         default:
  549                 la->protoLinkCount--;
  550                 break;
  551         }
  552 
  553         /* Free memory */
  554         free(lnk);
  555         *plnk = NULL;
  556 
  557         /* Write statistics, if logging enabled */
  558         if (la->packetAliasMode & PKT_ALIAS_LOG) {
  559                 ShowAliasStats(la);
  560         }
  561 }
  562 
  563 struct alias_link *
  564 AddLink(struct libalias *la, struct in_addr src_addr, struct in_addr dst_addr,
  565     struct in_addr alias_addr, u_short src_port, u_short dst_port,
  566     int alias_port_param, int link_type)
  567 {
  568         struct alias_link *lnk;
  569 
  570         LIBALIAS_LOCK_ASSERT(la);
  571 
  572         lnk = malloc(sizeof(struct alias_link));
  573         if (lnk == NULL) {
  574 #ifdef LIBALIAS_DEBUG
  575                 fprintf(stderr, "PacketAlias/AddLink(): ");
  576                 fprintf(stderr, "malloc() call failed.\n");
  577 #endif
  578                 return (NULL);
  579         }
  580         /* Basic initialization */
  581         lnk->la = la;
  582         lnk->src_addr = src_addr;
  583         lnk->dst_addr = dst_addr;
  584         lnk->alias_addr = alias_addr;
  585         lnk->proxy_addr.s_addr = INADDR_ANY;
  586         lnk->src_port = src_port;
  587         lnk->dst_port = dst_port;
  588         lnk->proxy_port = 0;
  589         lnk->server = NULL;
  590         lnk->link_type = link_type;
  591 #ifndef NO_USE_SOCKETS
  592         lnk->sockfd = -1;
  593 #endif
  594         lnk->flags = 0;
  595         lnk->pflags = 0;
  596         lnk->timestamp = LibAliasTime;
  597 
  598         /* Expiration time */
  599         switch (link_type) {
  600         case LINK_ICMP:
  601                 lnk->expire.time = ICMP_EXPIRE_TIME;
  602                 break;
  603         case LINK_UDP:
  604                 lnk->expire.time = UDP_EXPIRE_TIME;
  605                 break;
  606         case LINK_TCP:
  607                 lnk->expire.time = TCP_EXPIRE_INITIAL;
  608                 break;
  609         case LINK_FRAGMENT_ID:
  610                 lnk->expire.time = FRAGMENT_ID_EXPIRE_TIME;
  611                 break;
  612         case LINK_FRAGMENT_PTR:
  613                 lnk->expire.time = FRAGMENT_PTR_EXPIRE_TIME;
  614                 break;
  615         default:
  616                 lnk->expire.time = PROTO_EXPIRE_TIME;
  617                 break;
  618         }
  619 
  620         /* Determine alias flags */
  621         if (dst_addr.s_addr == INADDR_ANY)
  622                 lnk->flags |= LINK_UNKNOWN_DEST_ADDR;
  623         if (dst_port == 0)
  624                 lnk->flags |= LINK_UNKNOWN_DEST_PORT;
  625 
  626         /* Determine alias port */
  627         if (GetNewPort(la, lnk, alias_port_param) != 0) {
  628                 free(lnk);
  629                 return (NULL);
  630         }
  631         /* Link-type dependent initialization */
  632         switch (link_type) {
  633         case LINK_ICMP:
  634                 la->icmpLinkCount++;
  635                 break;
  636         case LINK_UDP:
  637                 la->udpLinkCount++;
  638                 break;
  639         case LINK_TCP: {
  640                 struct tcp_dat *aux_tcp;
  641                 int i;
  642 
  643                 aux_tcp = malloc(sizeof(struct tcp_dat));
  644                 if (aux_tcp == NULL) {
  645 #ifdef LIBALIAS_DEBUG
  646                         fprintf(stderr, "PacketAlias/AddLink: ");
  647                         fprintf(stderr, " cannot allocate auxiliary TCP data\n");
  648 #endif
  649                         free(lnk);
  650                         return (NULL);
  651                 }
  652 
  653                 la->tcpLinkCount++;
  654                 aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED;
  655                 aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED;
  656                 aux_tcp->state.index = 0;
  657                 aux_tcp->state.ack_modified = 0;
  658                 for (i = 0; i < N_LINK_TCP_DATA; i++)
  659                         aux_tcp->ack[i].active = 0;
  660                 aux_tcp->fwhole = -1;
  661                 lnk->data.tcp = aux_tcp;
  662         }
  663                 break;
  664         case LINK_PPTP:
  665                 la->pptpLinkCount++;
  666                 break;
  667         case LINK_FRAGMENT_ID:
  668                 la->fragmentIdLinkCount++;
  669                 break;
  670         case LINK_FRAGMENT_PTR:
  671                 la->fragmentPtrLinkCount++;
  672                 break;
  673         case LINK_ADDR:
  674                 break;
  675         default:
  676                 la->protoLinkCount++;
  677                 break;
  678         }
  679 
  680         switch (link_type) {
  681         case LINK_PPTP:
  682                 LIST_INSERT_HEAD(&la->pptpList, lnk, pptp.list);
  683                 break;
  684         default: {
  685                 struct group_in *grp;
  686 
  687                 grp = StartPointIn(la, alias_addr, lnk->alias_port, link_type, 1);
  688                 if (grp == NULL) {
  689                         free(lnk);
  690                         return (NULL);
  691                 }
  692 
  693                 /* Set up pointers for output lookup table */
  694                 SPLAY_INSERT(splay_out, &la->linkSplayOut, lnk);
  695 
  696                 /* Set up pointers for input lookup table */
  697                 if (lnk->flags & LINK_PARTIALLY_SPECIFIED)
  698                         LIST_INSERT_HEAD(&grp->partial, lnk, all.in);
  699                 else
  700                         LIST_INSERT_HEAD(&grp->full, lnk, all.in);
  701         }
  702                 break;
  703         }
  704 
  705         /* Include the element into the housekeeping list */
  706         TAILQ_INSERT_TAIL(&la->checkExpire, lnk, expire.list);
  707 
  708         if (la->packetAliasMode & PKT_ALIAS_LOG)
  709                 ShowAliasStats(la);
  710 
  711         return (lnk);
  712 }
  713 
  714 /*
  715  * If alias_port_param is less than zero, alias port will be automatically
  716  * chosen. If greater than zero, equal to alias port
  717  */
  718 static struct alias_link *
  719 ReLink(struct alias_link *old_lnk,
  720     struct in_addr src_addr,
  721     struct in_addr dst_addr,
  722     struct in_addr alias_addr,
  723     u_short src_port,
  724     u_short dst_port,
  725     int alias_port_param,
  726     int link_type,
  727     int deletePermanent)
  728 {
  729         struct alias_link *new_lnk;
  730         struct libalias *la = old_lnk->la;
  731 
  732         LIBALIAS_LOCK_ASSERT(la);
  733         new_lnk = AddLink(la, src_addr, dst_addr, alias_addr,
  734             src_port, dst_port, alias_port_param,
  735             link_type);
  736 #ifndef NO_FW_PUNCH
  737         if (new_lnk != NULL &&
  738             old_lnk->link_type == LINK_TCP &&
  739             old_lnk->data.tcp->fwhole > 0) {
  740                 PunchFWHole(new_lnk);
  741         }
  742 #endif
  743         DeleteLink(&old_lnk, deletePermanent);
  744         return (new_lnk);
  745 }
  746 
  747 static struct alias_link *
  748 _SearchLinkOut(struct libalias *la, struct in_addr src_addr,
  749     struct in_addr dst_addr,
  750     u_short src_port,
  751     u_short dst_port,
  752     int link_type) {
  753         struct alias_link *lnk;
  754         struct alias_link needle = {
  755                 .src_addr = src_addr,
  756                 .dst_addr = dst_addr,
  757                 .src_port = src_port,
  758                 .dst_port = dst_port,
  759                 .link_type = link_type
  760         };
  761 
  762         lnk = SPLAY_FIND(splay_out, &la->linkSplayOut, &needle);
  763         return (UseLink(la, lnk));
  764 }
  765 
  766 static struct alias_link *
  767 _FindLinkOut(struct libalias *la, struct in_addr src_addr,
  768     struct in_addr dst_addr,
  769     u_short src_port,
  770     u_short dst_port,
  771     int link_type,
  772     int replace_partial_links)
  773 {
  774         struct alias_link *lnk;
  775 
  776         LIBALIAS_LOCK_ASSERT(la);
  777         lnk = _SearchLinkOut(la, src_addr, dst_addr, src_port, dst_port, link_type);
  778         if (lnk != NULL || !replace_partial_links)
  779                 return (lnk);
  780 
  781         /* Search for partially specified links. */
  782         if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY) {
  783                 lnk = _SearchLinkOut(la, src_addr, dst_addr, src_port, 0,
  784                     link_type);
  785                 if (lnk == NULL)
  786                         lnk = _SearchLinkOut(la, src_addr, ANY_ADDR, src_port,
  787                             dst_port, link_type);
  788         }
  789         if (lnk == NULL &&
  790             (dst_port != 0 || dst_addr.s_addr != INADDR_ANY)) {
  791                 lnk = _SearchLinkOut(la, src_addr, ANY_ADDR, src_port, 0,
  792                     link_type);
  793         }
  794         if (lnk != NULL) {
  795                 lnk = ReLink(lnk,
  796                     src_addr, dst_addr, lnk->alias_addr,
  797                     src_port, dst_port, lnk->alias_port,
  798                     link_type, 0);
  799         }
  800         return (lnk);
  801 }
  802 
  803 static struct alias_link *
  804 FindLinkOut(struct libalias *la, struct in_addr src_addr,
  805     struct in_addr dst_addr,
  806     u_short src_port,
  807     u_short dst_port,
  808     int link_type,
  809     int replace_partial_links)
  810 {
  811         struct alias_link *lnk;
  812 
  813         LIBALIAS_LOCK_ASSERT(la);
  814         lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, dst_port,
  815             link_type, replace_partial_links);
  816 
  817         if (lnk == NULL) {
  818                 /*
  819                  * The following allows permanent links to be specified as
  820                  * using the default source address (i.e. device interface
  821                  * address) without knowing in advance what that address
  822                  * is.
  823                  */
  824                 if (la->aliasAddress.s_addr != INADDR_ANY &&
  825                     src_addr.s_addr == la->aliasAddress.s_addr) {
  826                         lnk = _FindLinkOut(la, ANY_ADDR, dst_addr, src_port, dst_port,
  827                             link_type, replace_partial_links);
  828                 }
  829         }
  830         return (lnk);
  831 }
  832 
  833 static struct alias_link *
  834 _FindLinkIn(struct libalias *la, struct in_addr dst_addr,
  835     struct in_addr alias_addr,
  836     u_short dst_port,
  837     u_short alias_port,
  838     int link_type,
  839     int replace_partial_links)
  840 {
  841         int flags_in;
  842         struct group_in *grp;
  843         struct alias_link *lnk;
  844         struct alias_link *lnk_unknown_all;
  845         struct alias_link *lnk_unknown_dst_addr;
  846         struct alias_link *lnk_unknown_dst_port;
  847         struct in_addr src_addr;
  848         u_short src_port;
  849 
  850         LIBALIAS_LOCK_ASSERT(la);
  851         /* Initialize pointers */
  852         lnk_unknown_all = NULL;
  853         lnk_unknown_dst_addr = NULL;
  854         lnk_unknown_dst_port = NULL;
  855 
  856         /* If either the dest addr or port is unknown, the search
  857          * loop will have to know about this. */
  858         flags_in = 0;
  859         if (dst_addr.s_addr == INADDR_ANY)
  860                 flags_in |= LINK_UNKNOWN_DEST_ADDR;
  861         if (dst_port == 0)
  862                 flags_in |= LINK_UNKNOWN_DEST_PORT;
  863 
  864         /* Search loop */
  865         grp = StartPointIn(la, alias_addr, alias_port, link_type, 0);
  866         if (grp == NULL)
  867                 return (NULL);
  868 
  869         switch (flags_in) {
  870         case 0:
  871                 LIST_FOREACH(lnk, &grp->full, all.in) {
  872                         if (lnk->dst_addr.s_addr == dst_addr.s_addr &&
  873                             lnk->dst_port == dst_port)
  874                                 return (UseLink(la, lnk));
  875                 }
  876                 break;
  877         case LINK_UNKNOWN_DEST_PORT:
  878                 LIST_FOREACH(lnk, &grp->full, all.in) {
  879                         if(lnk->dst_addr.s_addr == dst_addr.s_addr) {
  880                                 lnk_unknown_dst_port = lnk;
  881                                 break;
  882                         }
  883                 }
  884                 break;
  885         case LINK_UNKNOWN_DEST_ADDR:
  886                 LIST_FOREACH(lnk, &grp->full, all.in) {
  887                         if(lnk->dst_port == dst_port) {
  888                                 lnk_unknown_dst_addr = lnk;
  889                                 break;
  890                         }
  891                 }
  892                 break;
  893         case LINK_PARTIALLY_SPECIFIED:
  894                 lnk_unknown_all = LIST_FIRST(&grp->full);
  895                 break;
  896         }
  897 
  898         if (lnk_unknown_dst_port == NULL) {
  899                 LIST_FOREACH(lnk, &grp->partial, all.in) {
  900                         int flags = (flags_in | lnk->flags) & LINK_PARTIALLY_SPECIFIED;
  901 
  902                         if (flags == LINK_PARTIALLY_SPECIFIED &&
  903                             lnk_unknown_all == NULL)
  904                                 lnk_unknown_all = lnk;
  905                         if (flags == LINK_UNKNOWN_DEST_ADDR &&
  906                             lnk->dst_port == dst_port &&
  907                             lnk_unknown_dst_addr == NULL)
  908                                 lnk_unknown_dst_addr = lnk;
  909                         if (flags == LINK_UNKNOWN_DEST_PORT &&
  910                             lnk->dst_addr.s_addr == dst_addr.s_addr) {
  911                                 lnk_unknown_dst_port = lnk;
  912                                 break;
  913                         }
  914                 }
  915         }
  916 
  917         lnk = (lnk_unknown_dst_port != NULL) ? lnk_unknown_dst_port
  918             : (lnk_unknown_dst_addr != NULL) ? lnk_unknown_dst_addr
  919             : lnk_unknown_all;
  920 
  921         if (lnk == NULL || !replace_partial_links)
  922                 return (lnk);
  923 
  924         if (lnk->server != NULL) {      /* LSNAT link */
  925                 src_addr = lnk->server->addr;
  926                 src_port = lnk->server->port;
  927                 lnk->server = lnk->server->next;
  928         } else {
  929                 src_addr = lnk->src_addr;
  930                 src_port = lnk->src_port;
  931         }
  932 
  933         if (link_type == LINK_SCTP) {
  934                 lnk->src_addr = src_addr;
  935                 lnk->src_port = src_port;
  936         } else {
  937                 lnk = ReLink(lnk,
  938                     src_addr, dst_addr, alias_addr,
  939                     src_port, dst_port, alias_port,
  940                     link_type, 0);
  941         }
  942         return (lnk);
  943 }
  944 
  945 static struct alias_link *
  946 FindLinkIn(struct libalias *la, struct in_addr dst_addr,
  947     struct in_addr alias_addr,
  948     u_short dst_port,
  949     u_short alias_port,
  950     int link_type,
  951     int replace_partial_links)
  952 {
  953         struct alias_link *lnk;
  954 
  955         LIBALIAS_LOCK_ASSERT(la);
  956         lnk = _FindLinkIn(la, dst_addr, alias_addr, dst_port, alias_port,
  957             link_type, replace_partial_links);
  958 
  959         if (lnk == NULL) {
  960                 /*
  961                  * The following allows permanent links to be specified as
  962                  * using the default aliasing address (i.e. device
  963                  * interface address) without knowing in advance what that
  964                  * address is.
  965                  */
  966                 if (la->aliasAddress.s_addr != INADDR_ANY &&
  967                     alias_addr.s_addr == la->aliasAddress.s_addr) {
  968                         lnk = _FindLinkIn(la, dst_addr, ANY_ADDR, dst_port, alias_port,
  969                             link_type, replace_partial_links);
  970                 }
  971         }
  972         return (lnk);
  973 }
  974 
  975 /* External routines for finding/adding links
  976 
  977 -- "external" means outside alias_db.c, but within alias*.c --
  978 
  979     FindIcmpIn(), FindIcmpOut()
  980     FindFragmentIn1(), FindFragmentIn2()
  981     AddFragmentPtrLink(), FindFragmentPtr()
  982     FindProtoIn(), FindProtoOut()
  983     FindUdpTcpIn(), FindUdpTcpOut()
  984     AddPptp(), FindPptpOutByCallId(), FindPptpInByCallId(),
  985     FindPptpOutByPeerCallId(), FindPptpInByPeerCallId()
  986     FindOriginalAddress(), FindAliasAddress()
  987 
  988 (prototypes in alias_local.h)
  989 */
  990 
  991 struct alias_link *
  992 FindIcmpIn(struct libalias *la, struct in_addr dst_addr,
  993     struct in_addr alias_addr,
  994     u_short id_alias,
  995     int create)
  996 {
  997         struct alias_link *lnk;
  998 
  999         LIBALIAS_LOCK_ASSERT(la);
 1000         lnk = FindLinkIn(la, dst_addr, alias_addr,
 1001             NO_DEST_PORT, id_alias,
 1002             LINK_ICMP, 0);
 1003         if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
 1004                 struct in_addr target_addr;
 1005 
 1006                 target_addr = FindOriginalAddress(la, alias_addr);
 1007                 lnk = AddLink(la, target_addr, dst_addr, alias_addr,
 1008                     id_alias, NO_DEST_PORT, id_alias,
 1009                     LINK_ICMP);
 1010         }
 1011         return (lnk);
 1012 }
 1013 
 1014 struct alias_link *
 1015 FindIcmpOut(struct libalias *la, struct in_addr src_addr,
 1016     struct in_addr dst_addr,
 1017     u_short id,
 1018     int create)
 1019 {
 1020         struct alias_link *lnk;
 1021 
 1022         LIBALIAS_LOCK_ASSERT(la);
 1023         lnk = FindLinkOut(la, src_addr, dst_addr,
 1024             id, NO_DEST_PORT,
 1025             LINK_ICMP, 0);
 1026         if (lnk == NULL && create) {
 1027                 struct in_addr alias_addr;
 1028 
 1029                 alias_addr = FindAliasAddress(la, src_addr);
 1030                 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
 1031                     id, NO_DEST_PORT, GET_ALIAS_ID,
 1032                     LINK_ICMP);
 1033         }
 1034         return (lnk);
 1035 }
 1036 
 1037 struct alias_link *
 1038 FindFragmentIn1(struct libalias *la, struct in_addr dst_addr,
 1039     struct in_addr alias_addr,
 1040     u_short ip_id)
 1041 {
 1042         struct alias_link *lnk;
 1043 
 1044         LIBALIAS_LOCK_ASSERT(la);
 1045         lnk = FindLinkIn(la, dst_addr, alias_addr,
 1046             NO_DEST_PORT, ip_id,
 1047             LINK_FRAGMENT_ID, 0);
 1048 
 1049         if (lnk == NULL) {
 1050                 lnk = AddLink(la, ANY_ADDR, dst_addr, alias_addr,
 1051                     NO_SRC_PORT, NO_DEST_PORT, ip_id,
 1052                     LINK_FRAGMENT_ID);
 1053         }
 1054         return (lnk);
 1055 }
 1056 
 1057 /* Doesn't add a link if one is not found. */
 1058 struct alias_link *
 1059 FindFragmentIn2(struct libalias *la, struct in_addr dst_addr,
 1060     struct in_addr alias_addr, u_short ip_id)
 1061 {
 1062         LIBALIAS_LOCK_ASSERT(la);
 1063         return FindLinkIn(la, dst_addr, alias_addr,
 1064             NO_DEST_PORT, ip_id,
 1065             LINK_FRAGMENT_ID, 0);
 1066 }
 1067 
 1068 struct alias_link *
 1069 AddFragmentPtrLink(struct libalias *la, struct in_addr dst_addr,
 1070     u_short ip_id)
 1071 {
 1072         LIBALIAS_LOCK_ASSERT(la);
 1073         return AddLink(la, ANY_ADDR, dst_addr, ANY_ADDR,
 1074             NO_SRC_PORT, NO_DEST_PORT, ip_id,
 1075             LINK_FRAGMENT_PTR);
 1076 }
 1077 
 1078 struct alias_link *
 1079 FindFragmentPtr(struct libalias *la, struct in_addr dst_addr,
 1080     u_short ip_id)
 1081 {
 1082         LIBALIAS_LOCK_ASSERT(la);
 1083         return FindLinkIn(la, dst_addr, ANY_ADDR,
 1084             NO_DEST_PORT, ip_id,
 1085             LINK_FRAGMENT_PTR, 0);
 1086 }
 1087 
 1088 struct alias_link *
 1089 FindProtoIn(struct libalias *la, struct in_addr dst_addr,
 1090     struct in_addr alias_addr,
 1091     u_char proto)
 1092 {
 1093         struct alias_link *lnk;
 1094 
 1095         LIBALIAS_LOCK_ASSERT(la);
 1096         lnk = FindLinkIn(la, dst_addr, alias_addr,
 1097             NO_DEST_PORT, 0,
 1098             proto, 1);
 1099 
 1100         if (lnk == NULL && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
 1101                 struct in_addr target_addr;
 1102 
 1103                 target_addr = FindOriginalAddress(la, alias_addr);
 1104                 lnk = AddLink(la, target_addr, dst_addr, alias_addr,
 1105                     NO_SRC_PORT, NO_DEST_PORT, 0,
 1106                     proto);
 1107         }
 1108         return (lnk);
 1109 }
 1110 
 1111 struct alias_link *
 1112 FindProtoOut(struct libalias *la, struct in_addr src_addr,
 1113     struct in_addr dst_addr,
 1114     u_char proto)
 1115 {
 1116         struct alias_link *lnk;
 1117 
 1118         LIBALIAS_LOCK_ASSERT(la);
 1119         lnk = FindLinkOut(la, src_addr, dst_addr,
 1120             NO_SRC_PORT, NO_DEST_PORT,
 1121             proto, 1);
 1122 
 1123         if (lnk == NULL) {
 1124                 struct in_addr alias_addr;
 1125 
 1126                 alias_addr = FindAliasAddress(la, src_addr);
 1127                 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
 1128                     NO_SRC_PORT, NO_DEST_PORT, 0,
 1129                     proto);
 1130         }
 1131         return (lnk);
 1132 }
 1133 
 1134 struct alias_link *
 1135 FindUdpTcpIn(struct libalias *la, struct in_addr dst_addr,
 1136     struct in_addr alias_addr,
 1137     u_short dst_port,
 1138     u_short alias_port,
 1139     u_char proto,
 1140     int create)
 1141 {
 1142         int link_type;
 1143         struct alias_link *lnk;
 1144 
 1145         LIBALIAS_LOCK_ASSERT(la);
 1146         switch (proto) {
 1147         case IPPROTO_UDP:
 1148                 link_type = LINK_UDP;
 1149                 break;
 1150         case IPPROTO_TCP:
 1151                 link_type = LINK_TCP;
 1152                 break;
 1153         default:
 1154                 return (NULL);
 1155                 break;
 1156         }
 1157 
 1158         lnk = FindLinkIn(la, dst_addr, alias_addr,
 1159             dst_port, alias_port,
 1160             link_type, create);
 1161 
 1162         if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
 1163                 struct in_addr target_addr;
 1164 
 1165                 target_addr = FindOriginalAddress(la, alias_addr);
 1166                 lnk = AddLink(la, target_addr, dst_addr, alias_addr,
 1167                     alias_port, dst_port, alias_port,
 1168                     link_type);
 1169         }
 1170         return (lnk);
 1171 }
 1172 
 1173 struct alias_link *
 1174 FindUdpTcpOut(struct libalias *la, struct in_addr src_addr,
 1175     struct in_addr dst_addr,
 1176     u_short src_port,
 1177     u_short dst_port,
 1178     u_char proto,
 1179     int create)
 1180 {
 1181         int link_type;
 1182         struct alias_link *lnk;
 1183 
 1184         LIBALIAS_LOCK_ASSERT(la);
 1185         switch (proto) {
 1186         case IPPROTO_UDP:
 1187                 link_type = LINK_UDP;
 1188                 break;
 1189         case IPPROTO_TCP:
 1190                 link_type = LINK_TCP;
 1191                 break;
 1192         default:
 1193                 return (NULL);
 1194                 break;
 1195         }
 1196 
 1197         lnk = FindLinkOut(la, src_addr, dst_addr, src_port, dst_port, link_type, create);
 1198 
 1199         if (lnk == NULL && create) {
 1200                 struct in_addr alias_addr;
 1201 
 1202                 alias_addr = FindAliasAddress(la, src_addr);
 1203                 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
 1204                     src_port, dst_port, GET_ALIAS_PORT,
 1205                     link_type);
 1206         }
 1207         return (lnk);
 1208 }
 1209 
 1210 struct alias_link *
 1211 AddPptp(struct libalias *la, struct in_addr src_addr,
 1212     struct in_addr dst_addr,
 1213     struct in_addr alias_addr,
 1214     u_int16_t src_call_id)
 1215 {
 1216         struct alias_link *lnk;
 1217 
 1218         LIBALIAS_LOCK_ASSERT(la);
 1219         lnk = AddLink(la, src_addr, dst_addr, alias_addr,
 1220             src_call_id, 0, GET_ALIAS_PORT,
 1221             LINK_PPTP);
 1222 
 1223         return (lnk);
 1224 }
 1225 
 1226 struct alias_link *
 1227 FindPptpOutByCallId(struct libalias *la, struct in_addr src_addr,
 1228     struct in_addr dst_addr,
 1229     u_int16_t src_call_id)
 1230 {
 1231         struct alias_link *lnk;
 1232 
 1233         LIBALIAS_LOCK_ASSERT(la);
 1234         LIST_FOREACH(lnk, &la->pptpList, pptp.list)
 1235                 if (lnk->src_addr.s_addr == src_addr.s_addr &&
 1236                     lnk->dst_addr.s_addr == dst_addr.s_addr &&
 1237                     lnk->src_port == src_call_id)
 1238                         break;
 1239 
 1240         return (UseLink(la, lnk));
 1241 }
 1242 
 1243 struct alias_link *
 1244 FindPptpOutByPeerCallId(struct libalias *la, struct in_addr src_addr,
 1245     struct in_addr dst_addr,
 1246     u_int16_t dst_call_id)
 1247 {
 1248         struct alias_link *lnk;
 1249 
 1250         LIBALIAS_LOCK_ASSERT(la);
 1251         LIST_FOREACH(lnk, &la->pptpList, pptp.list)
 1252                 if (lnk->src_addr.s_addr == src_addr.s_addr &&
 1253                     lnk->dst_addr.s_addr == dst_addr.s_addr &&
 1254                     lnk->dst_port == dst_call_id)
 1255                         break;
 1256 
 1257         return (UseLink(la, lnk));
 1258 }
 1259 
 1260 struct alias_link *
 1261 FindPptpInByCallId(struct libalias *la, struct in_addr dst_addr,
 1262     struct in_addr alias_addr,
 1263     u_int16_t dst_call_id)
 1264 {
 1265         struct alias_link *lnk;
 1266 
 1267         LIBALIAS_LOCK_ASSERT(la);
 1268 
 1269         LIST_FOREACH(lnk, &la->pptpList, pptp.list)
 1270                 if (lnk->dst_port == dst_call_id &&
 1271                     lnk->dst_addr.s_addr == dst_addr.s_addr &&
 1272                     lnk->alias_addr.s_addr == alias_addr.s_addr)
 1273                         break;
 1274 
 1275         return (UseLink(la, lnk));
 1276 }
 1277 
 1278 struct alias_link *
 1279 FindPptpInByPeerCallId(struct libalias *la, struct in_addr dst_addr,
 1280     struct in_addr alias_addr,
 1281     u_int16_t alias_call_id)
 1282 {
 1283         struct alias_link *lnk;
 1284 
 1285         LIBALIAS_LOCK_ASSERT(la);
 1286         LIST_FOREACH(lnk, &la->pptpList, pptp.list)
 1287                 if (lnk->alias_port == alias_call_id &&
 1288                     lnk->dst_addr.s_addr == dst_addr.s_addr &&
 1289                     lnk->alias_addr.s_addr == alias_addr.s_addr)
 1290                         break;
 1291 
 1292         return (lnk);
 1293 }
 1294 
 1295 struct alias_link *
 1296 FindRtspOut(struct libalias *la, struct in_addr src_addr,
 1297     struct in_addr dst_addr,
 1298     u_short src_port,
 1299     u_short alias_port,
 1300     u_char proto)
 1301 {
 1302         int link_type;
 1303         struct alias_link *lnk;
 1304 
 1305         LIBALIAS_LOCK_ASSERT(la);
 1306         switch (proto) {
 1307         case IPPROTO_UDP:
 1308                 link_type = LINK_UDP;
 1309                 break;
 1310         case IPPROTO_TCP:
 1311                 link_type = LINK_TCP;
 1312                 break;
 1313         default:
 1314                 return (NULL);
 1315                 break;
 1316         }
 1317 
 1318         lnk = FindLinkOut(la, src_addr, dst_addr, src_port, 0, link_type, 1);
 1319 
 1320         if (lnk == NULL) {
 1321                 struct in_addr alias_addr;
 1322 
 1323                 alias_addr = FindAliasAddress(la, src_addr);
 1324                 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
 1325                     src_port, 0, alias_port,
 1326                     link_type);
 1327         }
 1328         return (lnk);
 1329 }
 1330 
 1331 struct in_addr
 1332 FindOriginalAddress(struct libalias *la, struct in_addr alias_addr)
 1333 {
 1334         struct alias_link *lnk;
 1335 
 1336         LIBALIAS_LOCK_ASSERT(la);
 1337         lnk = FindLinkIn(la, ANY_ADDR, alias_addr,
 1338             0, 0, LINK_ADDR, 0);
 1339         if (lnk == NULL) {
 1340                 if (la->targetAddress.s_addr == INADDR_ANY)
 1341                         return (alias_addr);
 1342                 else if (la->targetAddress.s_addr == INADDR_NONE)
 1343                         return (la->aliasAddress.s_addr != INADDR_ANY) ?
 1344                             la->aliasAddress : alias_addr;
 1345                 else
 1346                         return (la->targetAddress);
 1347         } else {
 1348                 if (lnk->server != NULL) {      /* LSNAT link */
 1349                         struct in_addr src_addr;
 1350 
 1351                         src_addr = lnk->server->addr;
 1352                         lnk->server = lnk->server->next;
 1353                         return (src_addr);
 1354                 } else if (lnk->src_addr.s_addr == INADDR_ANY)
 1355                         return (la->aliasAddress.s_addr != INADDR_ANY) ?
 1356                             la->aliasAddress : alias_addr;
 1357                 else
 1358                         return (lnk->src_addr);
 1359         }
 1360 }
 1361 
 1362 struct in_addr
 1363 FindAliasAddress(struct libalias *la, struct in_addr original_addr)
 1364 {
 1365         struct alias_link *lnk;
 1366 
 1367         LIBALIAS_LOCK_ASSERT(la);
 1368         lnk = FindLinkOut(la, original_addr, ANY_ADDR,
 1369             0, 0, LINK_ADDR, 0);
 1370         if (lnk == NULL) {
 1371                 return (la->aliasAddress.s_addr != INADDR_ANY) ?
 1372                     la->aliasAddress : original_addr;
 1373         } else {
 1374                 if (lnk->alias_addr.s_addr == INADDR_ANY)
 1375                         return (la->aliasAddress.s_addr != INADDR_ANY) ?
 1376                             la->aliasAddress : original_addr;
 1377                 else
 1378                         return (lnk->alias_addr);
 1379         }
 1380 }
 1381 
 1382 /* External routines for getting or changing link data
 1383    (external to alias_db.c, but internal to alias*.c)
 1384 
 1385     SetFragmentData(), GetFragmentData()
 1386     SetFragmentPtr(), GetFragmentPtr()
 1387     SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut()
 1388     GetOriginalAddress(), GetDestAddress(), GetAliasAddress()
 1389     GetOriginalPort(), GetAliasPort()
 1390     SetAckModified(), GetAckModified()
 1391     GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq()
 1392     SetProtocolFlags(), GetProtocolFlags()
 1393     SetDestCallId()
 1394 */
 1395 
 1396 void
 1397 SetFragmentAddr(struct alias_link *lnk, struct in_addr src_addr)
 1398 {
 1399         lnk->data.frag_addr = src_addr;
 1400 }
 1401 
 1402 void
 1403 GetFragmentAddr(struct alias_link *lnk, struct in_addr *src_addr)
 1404 {
 1405         *src_addr = lnk->data.frag_addr;
 1406 }
 1407 
 1408 void
 1409 SetFragmentPtr(struct alias_link *lnk, void *fptr)
 1410 {
 1411         lnk->data.frag_ptr = fptr;
 1412 }
 1413 
 1414 void
 1415 GetFragmentPtr(struct alias_link *lnk, void **fptr)
 1416 {
 1417         *fptr = lnk->data.frag_ptr;
 1418 }
 1419 
 1420 void
 1421 SetStateIn(struct alias_link *lnk, int state)
 1422 {
 1423         /* TCP input state */
 1424         switch (state) {
 1425                 case ALIAS_TCP_STATE_DISCONNECTED:
 1426                 if (lnk->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED)
 1427                         lnk->expire.time = TCP_EXPIRE_DEAD;
 1428                 else
 1429                         lnk->expire.time = TCP_EXPIRE_SINGLEDEAD;
 1430                 break;
 1431         case ALIAS_TCP_STATE_CONNECTED:
 1432                 if (lnk->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED)
 1433                         lnk->expire.time = TCP_EXPIRE_CONNECTED;
 1434                 break;
 1435         default:
 1436 #ifdef _KERNEL
 1437                 panic("libalias:SetStateIn() unknown state");
 1438 #else
 1439                 abort();
 1440 #endif
 1441         }
 1442         lnk->data.tcp->state.in = state;
 1443 }
 1444 
 1445 void
 1446 SetStateOut(struct alias_link *lnk, int state)
 1447 {
 1448         /* TCP output state */
 1449         switch (state) {
 1450                 case ALIAS_TCP_STATE_DISCONNECTED:
 1451                 if (lnk->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED)
 1452                         lnk->expire.time = TCP_EXPIRE_DEAD;
 1453                 else
 1454                         lnk->expire.time = TCP_EXPIRE_SINGLEDEAD;
 1455                 break;
 1456         case ALIAS_TCP_STATE_CONNECTED:
 1457                 if (lnk->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED)
 1458                         lnk->expire.time = TCP_EXPIRE_CONNECTED;
 1459                 break;
 1460         default:
 1461 #ifdef _KERNEL
 1462                 panic("libalias:SetStateOut() unknown state");
 1463 #else
 1464                 abort();
 1465 #endif
 1466         }
 1467         lnk->data.tcp->state.out = state;
 1468 }
 1469 
 1470 int
 1471 GetStateIn(struct alias_link *lnk)
 1472 {
 1473         /* TCP input state */
 1474         return (lnk->data.tcp->state.in);
 1475 }
 1476 
 1477 int
 1478 GetStateOut(struct alias_link *lnk)
 1479 {
 1480         /* TCP output state */
 1481         return (lnk->data.tcp->state.out);
 1482 }
 1483 
 1484 struct in_addr
 1485 GetOriginalAddress(struct alias_link *lnk)
 1486 {
 1487         if (lnk->src_addr.s_addr == INADDR_ANY)
 1488                 return (lnk->la->aliasAddress);
 1489         else
 1490                 return (lnk->src_addr);
 1491 }
 1492 
 1493 struct in_addr
 1494 GetDestAddress(struct alias_link *lnk)
 1495 {
 1496         return (lnk->dst_addr);
 1497 }
 1498 
 1499 struct in_addr
 1500 GetAliasAddress(struct alias_link *lnk)
 1501 {
 1502         if (lnk->alias_addr.s_addr == INADDR_ANY)
 1503                 return (lnk->la->aliasAddress);
 1504         else
 1505                 return (lnk->alias_addr);
 1506 }
 1507 
 1508 struct in_addr
 1509 GetDefaultAliasAddress(struct libalias *la)
 1510 {
 1511         LIBALIAS_LOCK_ASSERT(la);
 1512         return (la->aliasAddress);
 1513 }
 1514 
 1515 void
 1516 SetDefaultAliasAddress(struct libalias *la, struct in_addr alias_addr)
 1517 {
 1518         LIBALIAS_LOCK_ASSERT(la);
 1519         la->aliasAddress = alias_addr;
 1520 }
 1521 
 1522 u_short
 1523 GetOriginalPort(struct alias_link *lnk)
 1524 {
 1525         return (lnk->src_port);
 1526 }
 1527 
 1528 u_short
 1529 GetAliasPort(struct alias_link *lnk)
 1530 {
 1531         return (lnk->alias_port);
 1532 }
 1533 
 1534 #ifndef NO_FW_PUNCH
 1535 static u_short
 1536 GetDestPort(struct alias_link *lnk)
 1537 {
 1538         return (lnk->dst_port);
 1539 }
 1540 
 1541 #endif
 1542 
 1543 /* Indicate that ACK numbers have been modified in a TCP connection */
 1544 void
 1545 SetAckModified(struct alias_link *lnk)
 1546 {
 1547         lnk->data.tcp->state.ack_modified = 1;
 1548 }
 1549 
 1550 struct in_addr
 1551 GetProxyAddress(struct alias_link *lnk)
 1552 {
 1553         return (lnk->proxy_addr);
 1554 }
 1555 
 1556 void
 1557 SetProxyAddress(struct alias_link *lnk, struct in_addr addr)
 1558 {
 1559         lnk->proxy_addr = addr;
 1560 }
 1561 
 1562 u_short
 1563 GetProxyPort(struct alias_link *lnk)
 1564 {
 1565         return (lnk->proxy_port);
 1566 }
 1567 
 1568 void
 1569 SetProxyPort(struct alias_link *lnk, u_short port)
 1570 {
 1571         lnk->proxy_port = port;
 1572 }
 1573 
 1574 /* See if ACK numbers have been modified */
 1575 int
 1576 GetAckModified(struct alias_link *lnk)
 1577 {
 1578         return (lnk->data.tcp->state.ack_modified);
 1579 }
 1580 
 1581 /*
 1582  * Find out how much the ACK number has been altered for an
 1583  * incoming TCP packet.  To do this, a circular list of ACK
 1584  * numbers where the TCP packet size was altered is searched.
 1585  */
 1586 // XXX ip free
 1587 int
 1588 GetDeltaAckIn(u_long ack, struct alias_link *lnk)
 1589 {
 1590         int i, j;
 1591         int delta, ack_diff_min;
 1592 
 1593         delta = 0;
 1594         ack_diff_min = -1;
 1595         i = lnk->data.tcp->state.index;
 1596         for (j = 0; j < N_LINK_TCP_DATA; j++) {
 1597                 struct ack_data_record x;
 1598 
 1599                 if (i == 0)
 1600                         i = N_LINK_TCP_DATA;
 1601                 i--;
 1602                 x = lnk->data.tcp->ack[i];
 1603                 if (x.active == 1) {
 1604                         int ack_diff;
 1605 
 1606                         ack_diff = SeqDiff(x.ack_new, ack);
 1607                         if (ack_diff >= 0) {
 1608                                 if (ack_diff_min >= 0) {
 1609                                         if (ack_diff < ack_diff_min) {
 1610                                                 delta = x.delta;
 1611                                                 ack_diff_min = ack_diff;
 1612                                         }
 1613                                 } else {
 1614                                         delta = x.delta;
 1615                                         ack_diff_min = ack_diff;
 1616                                 }
 1617                         }
 1618                 }
 1619         }
 1620         return (delta);
 1621 }
 1622 
 1623 /*
 1624  * Find out how much the sequence number has been altered for an
 1625  * outgoing TCP packet.  To do this, a circular list of ACK numbers
 1626  * where the TCP packet size was altered is searched.
 1627  */
 1628 // XXX ip free
 1629 int
 1630 GetDeltaSeqOut(u_long seq, struct alias_link *lnk)
 1631 {
 1632         int i, j;
 1633         int delta, seq_diff_min;
 1634 
 1635         delta = 0;
 1636         seq_diff_min = -1;
 1637         i = lnk->data.tcp->state.index;
 1638         for (j = 0; j < N_LINK_TCP_DATA; j++) {
 1639                 struct ack_data_record x;
 1640 
 1641                 if (i == 0)
 1642                         i = N_LINK_TCP_DATA;
 1643                 i--;
 1644                 x = lnk->data.tcp->ack[i];
 1645                 if (x.active == 1) {
 1646                         int seq_diff;
 1647 
 1648                         seq_diff = SeqDiff(x.ack_old, seq);
 1649                         if (seq_diff >= 0) {
 1650                                 if (seq_diff_min >= 0) {
 1651                                         if (seq_diff < seq_diff_min) {
 1652                                                 delta = x.delta;
 1653                                                 seq_diff_min = seq_diff;
 1654                                         }
 1655                                 } else {
 1656                                         delta = x.delta;
 1657                                         seq_diff_min = seq_diff;
 1658                                 }
 1659                         }
 1660                 }
 1661         }
 1662         return (delta);
 1663 }
 1664 
 1665 /*
 1666  * When a TCP packet has been altered in length, save this
 1667  * information in a circular list.  If enough packets have been
 1668  * altered, then this list will begin to overwrite itself.
 1669  */
 1670 // XXX ip free
 1671 void
 1672 AddSeq(struct alias_link *lnk, int delta, u_int ip_hl, u_short ip_len,
 1673     u_long th_seq, u_int th_off)
 1674 {
 1675         struct ack_data_record x;
 1676         int hlen, tlen, dlen;
 1677         int i;
 1678 
 1679         hlen = (ip_hl + th_off) << 2;
 1680         tlen = ntohs(ip_len);
 1681         dlen = tlen - hlen;
 1682 
 1683         x.ack_old = htonl(ntohl(th_seq) + dlen);
 1684         x.ack_new = htonl(ntohl(th_seq) + dlen + delta);
 1685         x.delta = delta;
 1686         x.active = 1;
 1687 
 1688         i = lnk->data.tcp->state.index;
 1689         lnk->data.tcp->ack[i] = x;
 1690 
 1691         i++;
 1692         if (i == N_LINK_TCP_DATA)
 1693                 lnk->data.tcp->state.index = 0;
 1694         else
 1695                 lnk->data.tcp->state.index = i;
 1696 }
 1697 
 1698 void
 1699 SetExpire(struct alias_link *lnk, int expire)
 1700 {
 1701         if (expire == 0) {
 1702                 lnk->flags &= ~LINK_PERMANENT;
 1703                 DeleteLink(&lnk, 0);
 1704         } else if (expire == -1) {
 1705                 lnk->flags |= LINK_PERMANENT;
 1706         } else if (expire > 0) {
 1707                 lnk->expire.time = expire;
 1708         } else {
 1709 #ifdef LIBALIAS_DEBUG
 1710                 fprintf(stderr, "PacketAlias/SetExpire(): ");
 1711                 fprintf(stderr, "error in expire parameter\n");
 1712 #endif
 1713         }
 1714 }
 1715 
 1716 void
 1717 SetProtocolFlags(struct alias_link *lnk, int pflags)
 1718 {
 1719         lnk->pflags = pflags;
 1720 }
 1721 
 1722 int
 1723 GetProtocolFlags(struct alias_link *lnk)
 1724 {
 1725         return (lnk->pflags);
 1726 }
 1727 
 1728 void
 1729 SetDestCallId(struct alias_link *lnk, u_int16_t cid)
 1730 {
 1731         LIBALIAS_LOCK_ASSERT(lnk->la);
 1732         ReLink(lnk, lnk->src_addr, lnk->dst_addr, lnk->alias_addr,
 1733             lnk->src_port, cid, lnk->alias_port, lnk->link_type, 1);
 1734 }
 1735 
 1736 /* Miscellaneous Functions
 1737 
 1738     HouseKeeping()
 1739     InitPacketAliasLog()
 1740     UninitPacketAliasLog()
 1741 */
 1742 
 1743 /*
 1744     Whenever an outgoing or incoming packet is handled, HouseKeeping()
 1745     is called to find and remove timed-out aliasing links.  Logic exists
 1746     to sweep through the entire table and linked list structure
 1747     every 60 seconds.
 1748 
 1749     (prototype in alias_local.h)
 1750 */
 1751 
 1752 void
 1753 HouseKeeping(struct libalias *la)
 1754 {
 1755         static unsigned int packets = 0;
 1756         static unsigned int packet_limit = 1000;
 1757 
 1758         LIBALIAS_LOCK_ASSERT(la);
 1759         packets++;
 1760 
 1761         /*
 1762          * User space time/gettimeofday/... is very expensive.
 1763          * Kernel space cache trashing is unnecessary.
 1764          *
 1765          * Save system time (seconds) in global variable LibAliasTime
 1766          * for use by other functions. This is done so as not to
 1767          * unnecessarily waste timeline by making system calls.
 1768          *
 1769          * Reduce the amount of house keeping work substantially by
 1770          * sampling over the packets.
 1771          */
 1772         if (packet_limit <= 1 || packets % packet_limit == 0) {
 1773                 time_t now;
 1774 
 1775 #ifdef _KERNEL
 1776                 now = time_uptime;
 1777 #else
 1778                 now = time(NULL);
 1779 #endif
 1780                 if (now != LibAliasTime) {
 1781                         /* retry three times a second */
 1782                         packet_limit = packets / 3;
 1783                         packets = 0;
 1784                         LibAliasTime = now;
 1785                 }
 1786 
 1787         }
 1788         /* Do a cleanup for the first packets of the new second only */
 1789         if (packets < (la->udpLinkCount + la->tcpLinkCount)) {
 1790                 struct alias_link * lnk = TAILQ_FIRST(&la->checkExpire);
 1791 
 1792                 CleanupLink(la, &lnk, 0);
 1793         }
 1794 }
 1795 
 1796 /* Init the log file and enable logging */
 1797 static int
 1798 InitPacketAliasLog(struct libalias *la)
 1799 {
 1800         LIBALIAS_LOCK_ASSERT(la);
 1801         if (~la->packetAliasMode & PKT_ALIAS_LOG) {
 1802 #ifdef _KERNEL
 1803                 if ((la->logDesc = malloc(LIBALIAS_BUF_SIZE)))
 1804                         ;
 1805 #else
 1806                 if ((la->logDesc = fopen("/var/log/alias.log", "w")))
 1807                         fprintf(la->logDesc, "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");
 1808 #endif
 1809                 else
 1810                         return (ENOMEM); /* log initialization failed */
 1811                 la->packetAliasMode |= PKT_ALIAS_LOG;
 1812         }
 1813 
 1814         return (1);
 1815 }
 1816 
 1817 /* Close the log-file and disable logging. */
 1818 static void
 1819 UninitPacketAliasLog(struct libalias *la)
 1820 {
 1821         LIBALIAS_LOCK_ASSERT(la);
 1822         if (la->logDesc) {
 1823 #ifdef _KERNEL
 1824                 free(la->logDesc);
 1825 #else
 1826                 fclose(la->logDesc);
 1827 #endif
 1828                 la->logDesc = NULL;
 1829         }
 1830         la->packetAliasMode &= ~PKT_ALIAS_LOG;
 1831 }
 1832 
 1833 /* Outside world interfaces
 1834 
 1835 -- "outside world" means other than alias*.c routines --
 1836 
 1837     PacketAliasRedirectPort()
 1838     PacketAliasAddServer()
 1839     PacketAliasRedirectProto()
 1840     PacketAliasRedirectAddr()
 1841     PacketAliasRedirectDynamic()
 1842     PacketAliasRedirectDelete()
 1843     PacketAliasSetAddress()
 1844     PacketAliasInit()
 1845     PacketAliasUninit()
 1846     PacketAliasSetMode()
 1847 
 1848 (prototypes in alias.h)
 1849 */
 1850 
 1851 /* Redirection from a specific public addr:port to a
 1852    private addr:port */
 1853 struct alias_link *
 1854 LibAliasRedirectPort(struct libalias *la, struct in_addr src_addr, u_short src_port,
 1855     struct in_addr dst_addr, u_short dst_port,
 1856     struct in_addr alias_addr, u_short alias_port,
 1857     u_char proto)
 1858 {
 1859         int link_type;
 1860         struct alias_link *lnk;
 1861 
 1862         LIBALIAS_LOCK(la);
 1863         switch (proto) {
 1864         case IPPROTO_UDP:
 1865                 link_type = LINK_UDP;
 1866                 break;
 1867         case IPPROTO_TCP:
 1868                 link_type = LINK_TCP;
 1869                 break;
 1870         case IPPROTO_SCTP:
 1871                 link_type = LINK_SCTP;
 1872                 break;
 1873         default:
 1874 #ifdef LIBALIAS_DEBUG
 1875                 fprintf(stderr, "PacketAliasRedirectPort(): ");
 1876                 fprintf(stderr, "only SCTP, TCP and UDP protocols allowed\n");
 1877 #endif
 1878                 lnk = NULL;
 1879                 goto getout;
 1880         }
 1881 
 1882         lnk = AddLink(la, src_addr, dst_addr, alias_addr,
 1883             src_port, dst_port, alias_port,
 1884             link_type);
 1885 
 1886         if (lnk != NULL) {
 1887                 lnk->flags |= LINK_PERMANENT;
 1888         }
 1889 #ifdef LIBALIAS_DEBUG
 1890         else {
 1891                 fprintf(stderr, "PacketAliasRedirectPort(): "
 1892                     "call to AddLink() failed\n");
 1893         }
 1894 #endif
 1895 
 1896 getout:
 1897         LIBALIAS_UNLOCK(la);
 1898         return (lnk);
 1899 }
 1900 
 1901 /* Add server to the pool of servers */
 1902 int
 1903 LibAliasAddServer(struct libalias *la, struct alias_link *lnk, struct in_addr addr, u_short port)
 1904 {
 1905         struct server *server;
 1906         int res;
 1907 
 1908         LIBALIAS_LOCK(la);
 1909         (void)la;
 1910 
 1911         switch (lnk->link_type) {
 1912         case LINK_PPTP:
 1913                 server = NULL;
 1914                 break;
 1915         default:
 1916                 server = malloc(sizeof(struct server));
 1917                 break;
 1918         }
 1919 
 1920         if (server != NULL) {
 1921                 struct server *head;
 1922 
 1923                 server->addr = addr;
 1924                 server->port = port;
 1925 
 1926                 head = lnk->server;
 1927                 if (head == NULL) {
 1928                         server->next = server;
 1929                         /* not usable for outgoing connections */
 1930                         SPLAY_REMOVE(splay_out, &la->linkSplayOut, lnk);
 1931                 } else {
 1932                         struct server *s;
 1933 
 1934                         for (s = head; s->next != head; s = s->next)
 1935                                 ;
 1936                         s->next = server;
 1937                         server->next = head;
 1938                 }
 1939                 lnk->server = server;
 1940                 res = 0;
 1941         } else
 1942                 res = -1;
 1943 
 1944         LIBALIAS_UNLOCK(la);
 1945         return (res);
 1946 }
 1947 
 1948 /* Redirect packets of a given IP protocol from a specific
 1949    public address to a private address */
 1950 struct alias_link *
 1951 LibAliasRedirectProto(struct libalias *la, struct in_addr src_addr,
 1952     struct in_addr dst_addr,
 1953     struct in_addr alias_addr,
 1954     u_char proto)
 1955 {
 1956         struct alias_link *lnk;
 1957 
 1958         LIBALIAS_LOCK(la);
 1959         lnk = AddLink(la, src_addr, dst_addr, alias_addr,
 1960             NO_SRC_PORT, NO_DEST_PORT, 0,
 1961             proto);
 1962 
 1963         if (lnk != NULL) {
 1964                 lnk->flags |= LINK_PERMANENT;
 1965         }
 1966 #ifdef LIBALIAS_DEBUG
 1967         else {
 1968                 fprintf(stderr, "PacketAliasRedirectProto(): "
 1969                     "call to AddLink() failed\n");
 1970         }
 1971 #endif
 1972 
 1973         LIBALIAS_UNLOCK(la);
 1974         return (lnk);
 1975 }
 1976 
 1977 /* Static address translation */
 1978 struct alias_link *
 1979 LibAliasRedirectAddr(struct libalias *la, struct in_addr src_addr,
 1980     struct in_addr alias_addr)
 1981 {
 1982         struct alias_link *lnk;
 1983 
 1984         LIBALIAS_LOCK(la);
 1985         lnk = AddLink(la, src_addr, ANY_ADDR, alias_addr,
 1986             0, 0, 0,
 1987             LINK_ADDR);
 1988 
 1989         if (lnk != NULL) {
 1990                 lnk->flags |= LINK_PERMANENT;
 1991         }
 1992 #ifdef LIBALIAS_DEBUG
 1993         else {
 1994                 fprintf(stderr, "PacketAliasRedirectAddr(): "
 1995                     "call to AddLink() failed\n");
 1996         }
 1997 #endif
 1998 
 1999         LIBALIAS_UNLOCK(la);
 2000         return (lnk);
 2001 }
 2002 
 2003 /* Mark the aliasing link dynamic */
 2004 int
 2005 LibAliasRedirectDynamic(struct libalias *la, struct alias_link *lnk)
 2006 {
 2007         int res;
 2008 
 2009         LIBALIAS_LOCK(la);
 2010         (void)la;
 2011 
 2012         if (lnk->flags & LINK_PARTIALLY_SPECIFIED)
 2013                 res = -1;
 2014         else {
 2015                 lnk->flags &= ~LINK_PERMANENT;
 2016                 res = 0;
 2017         }
 2018         LIBALIAS_UNLOCK(la);
 2019         return (res);
 2020 }
 2021 
 2022 /* This is a dangerous function to put in the API,
 2023    because an invalid pointer can crash the program. */
 2024 void
 2025 LibAliasRedirectDelete(struct libalias *la, struct alias_link *lnk)
 2026 {
 2027         LIBALIAS_LOCK(la);
 2028         (void)la;
 2029         DeleteLink(&lnk, 1);
 2030         LIBALIAS_UNLOCK(la);
 2031 }
 2032 
 2033 void
 2034 LibAliasSetAddress(struct libalias *la, struct in_addr addr)
 2035 {
 2036         LIBALIAS_LOCK(la);
 2037         if (la->packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE
 2038             && la->aliasAddress.s_addr != addr.s_addr)
 2039                 CleanupAliasData(la, 0);
 2040 
 2041         la->aliasAddress = addr;
 2042         LIBALIAS_UNLOCK(la);
 2043 }
 2044 
 2045 void
 2046 LibAliasSetAliasPortRange(struct libalias *la, u_short port_low,
 2047     u_short port_high)
 2048 {
 2049         LIBALIAS_LOCK(la);
 2050         if (port_low) {
 2051                 la->aliasPortLower = port_low;
 2052                 /* Add 1 to the aliasPortLength as modulo has range of 1 to n-1 */
 2053                 la->aliasPortLength = port_high - port_low + 1;
 2054         } else {
 2055                 /* Set default values */
 2056                 la->aliasPortLower = 0x8000;
 2057                 la->aliasPortLength = 0x8000;
 2058         }
 2059         LIBALIAS_UNLOCK(la);
 2060 }
 2061 
 2062 void
 2063 LibAliasSetTarget(struct libalias *la, struct in_addr target_addr)
 2064 {
 2065         LIBALIAS_LOCK(la);
 2066         la->targetAddress = target_addr;
 2067         LIBALIAS_UNLOCK(la);
 2068 }
 2069 
 2070 static void
 2071 finishoff(void)
 2072 {
 2073         while (!LIST_EMPTY(&instancehead))
 2074                 LibAliasUninit(LIST_FIRST(&instancehead));
 2075 }
 2076 
 2077 struct libalias *
 2078 LibAliasInit(struct libalias *la)
 2079 {
 2080         if (la == NULL) {
 2081 #ifdef _KERNEL
 2082 #undef malloc   /* XXX: ugly */
 2083                 la = malloc(sizeof *la, M_ALIAS, M_WAITOK | M_ZERO);
 2084 #else
 2085                 la = calloc(sizeof *la, 1);
 2086                 if (la == NULL)
 2087                         return (la);
 2088 #endif
 2089 
 2090 #ifndef _KERNEL
 2091                 /* kernel cleans up on module unload */
 2092                 if (LIST_EMPTY(&instancehead))
 2093                         atexit(finishoff);
 2094 #endif
 2095                 LIST_INSERT_HEAD(&instancehead, la, instancelist);
 2096 
 2097 #ifdef _KERNEL
 2098                 LibAliasTime = time_uptime;
 2099 #else
 2100                 LibAliasTime = time(NULL);
 2101 #endif
 2102 
 2103                 SPLAY_INIT(&la->linkSplayIn);
 2104                 SPLAY_INIT(&la->linkSplayOut);
 2105                 LIST_INIT(&la->pptpList);
 2106                 TAILQ_INIT(&la->checkExpire);
 2107 #ifdef _KERNEL
 2108                 AliasSctpInit(la);
 2109 #endif
 2110                 LIBALIAS_LOCK_INIT(la);
 2111                 LIBALIAS_LOCK(la);
 2112         } else {
 2113                 LIBALIAS_LOCK(la);
 2114                 CleanupAliasData(la, 1);
 2115 #ifdef _KERNEL
 2116                 AliasSctpTerm(la);
 2117                 AliasSctpInit(la);
 2118 #endif
 2119         }
 2120 
 2121         la->aliasAddress.s_addr = INADDR_ANY;
 2122         la->targetAddress.s_addr = INADDR_ANY;
 2123         la->aliasPortLower = 0x8000;
 2124         la->aliasPortLength = 0x8000;
 2125 
 2126         la->icmpLinkCount = 0;
 2127         la->udpLinkCount = 0;
 2128         la->tcpLinkCount = 0;
 2129         la->sctpLinkCount = 0;
 2130         la->pptpLinkCount = 0;
 2131         la->protoLinkCount = 0;
 2132         la->fragmentIdLinkCount = 0;
 2133         la->fragmentPtrLinkCount = 0;
 2134         la->sockCount = 0;
 2135 
 2136         la->packetAliasMode = PKT_ALIAS_SAME_PORTS
 2137 #ifndef NO_USE_SOCKETS
 2138             | PKT_ALIAS_USE_SOCKETS
 2139 #endif
 2140             | PKT_ALIAS_RESET_ON_ADDR_CHANGE;
 2141 #ifndef NO_FW_PUNCH
 2142         la->fireWallFD = -1;
 2143 #endif
 2144 #ifndef _KERNEL
 2145         LibAliasRefreshModules();
 2146 #endif
 2147         LIBALIAS_UNLOCK(la);
 2148         return (la);
 2149 }
 2150 
 2151 void
 2152 LibAliasUninit(struct libalias *la)
 2153 {
 2154         LIBALIAS_LOCK(la);
 2155 #ifdef _KERNEL
 2156         AliasSctpTerm(la);
 2157 #endif
 2158         CleanupAliasData(la, 1);
 2159         UninitPacketAliasLog(la);
 2160 #ifndef NO_FW_PUNCH
 2161         UninitPunchFW(la);
 2162 #endif
 2163         LIST_REMOVE(la, instancelist);
 2164         LIBALIAS_UNLOCK(la);
 2165         LIBALIAS_LOCK_DESTROY(la);
 2166         free(la);
 2167 }
 2168 
 2169 /* Change mode for some operations */
 2170 unsigned int
 2171 LibAliasSetMode(
 2172     struct libalias *la,
 2173     unsigned int flags,         /* Which state to bring flags to */
 2174     unsigned int mask           /* Mask of which flags to affect (use 0 to
 2175                                  * do a probe for flag values) */
 2176 )
 2177 {
 2178         int res = -1;
 2179 
 2180         LIBALIAS_LOCK(la);
 2181         if (flags & mask & PKT_ALIAS_LOG) {
 2182                 /* Enable logging */
 2183                 if (InitPacketAliasLog(la) == ENOMEM)
 2184                         goto getout;
 2185         } else if (~flags & mask & PKT_ALIAS_LOG)
 2186                 /* _Disable_ logging */
 2187                 UninitPacketAliasLog(la);
 2188 
 2189 #ifndef NO_FW_PUNCH
 2190         if (flags & mask & PKT_ALIAS_PUNCH_FW)
 2191                 /* Start punching holes in the firewall? */
 2192                 InitPunchFW(la);
 2193         else if (~flags & mask & PKT_ALIAS_PUNCH_FW)
 2194                 /* Stop punching holes in the firewall? */
 2195                 UninitPunchFW(la);
 2196 #endif
 2197 
 2198         /* Other flags can be set/cleared without special action */
 2199         la->packetAliasMode = (flags & mask) | (la->packetAliasMode & ~mask);
 2200         res = la->packetAliasMode;
 2201 getout:
 2202         LIBALIAS_UNLOCK(la);
 2203         return (res);
 2204 }
 2205 
 2206 #ifndef NO_FW_PUNCH
 2207 
 2208 /*****************
 2209   Code to support firewall punching.  This shouldn't really be in this
 2210   file, but making variables global is evil too.
 2211   ****************/
 2212 
 2213 /* Firewall include files */
 2214 #include <net/if.h>
 2215 #include <netinet/ip_fw.h>
 2216 #include <string.h>
 2217 #include <err.h>
 2218 
 2219 /*
 2220  * helper function, updates the pointer to cmd with the length
 2221  * of the current command, and also cleans up the first word of
 2222  * the new command in case it has been clobbered before.
 2223  */
 2224 static ipfw_insn *
 2225 next_cmd(ipfw_insn * cmd)
 2226 {
 2227         cmd += F_LEN(cmd);
 2228         bzero(cmd, sizeof(*cmd));
 2229         return (cmd);
 2230 }
 2231 
 2232 /*
 2233  * A function to fill simple commands of size 1.
 2234  * Existing flags are preserved.
 2235  */
 2236 static ipfw_insn *
 2237 fill_cmd(ipfw_insn * cmd, enum ipfw_opcodes opcode, int size,
 2238     int flags, u_int16_t arg)
 2239 {
 2240         cmd->opcode = opcode;
 2241         cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | (size & F_LEN_MASK);
 2242         cmd->arg1 = arg;
 2243         return next_cmd(cmd);
 2244 }
 2245 
 2246 static ipfw_insn *
 2247 fill_ip(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int32_t addr)
 2248 {
 2249         ipfw_insn_ip *cmd = (ipfw_insn_ip *)cmd1;
 2250 
 2251         cmd->addr.s_addr = addr;
 2252         return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u32), 0, 0);
 2253 }
 2254 
 2255 static ipfw_insn *
 2256 fill_one_port(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int16_t port)
 2257 {
 2258         ipfw_insn_u16 *cmd = (ipfw_insn_u16 *)cmd1;
 2259 
 2260         cmd->ports[0] = cmd->ports[1] = port;
 2261         return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u16), 0, 0);
 2262 }
 2263 
 2264 static int
 2265 fill_rule(void *buf, int bufsize, int rulenum,
 2266     enum ipfw_opcodes action, int proto,
 2267     struct in_addr sa, u_int16_t sp, struct in_addr da, u_int16_t dp)
 2268 {
 2269         struct ip_fw *rule = (struct ip_fw *)buf;
 2270         ipfw_insn *cmd = (ipfw_insn *)rule->cmd;
 2271 
 2272         bzero(buf, bufsize);
 2273         rule->rulenum = rulenum;
 2274 
 2275         cmd = fill_cmd(cmd, O_PROTO, F_INSN_SIZE(ipfw_insn), 0, proto);
 2276         cmd = fill_ip(cmd, O_IP_SRC, sa.s_addr);
 2277         cmd = fill_one_port(cmd, O_IP_SRCPORT, sp);
 2278         cmd = fill_ip(cmd, O_IP_DST, da.s_addr);
 2279         cmd = fill_one_port(cmd, O_IP_DSTPORT, dp);
 2280 
 2281         rule->act_ofs = (u_int32_t *)cmd - (u_int32_t *)rule->cmd;
 2282         cmd = fill_cmd(cmd, action, F_INSN_SIZE(ipfw_insn), 0, 0);
 2283 
 2284         rule->cmd_len = (u_int32_t *)cmd - (u_int32_t *)rule->cmd;
 2285 
 2286         return ((char *)cmd - (char *)buf);
 2287 }
 2288 
 2289 static void
 2290 InitPunchFW(struct libalias *la)
 2291 {
 2292         la->fireWallField = malloc(la->fireWallNumNums);
 2293         if (la->fireWallField) {
 2294                 memset(la->fireWallField, 0, la->fireWallNumNums);
 2295                 if (la->fireWallFD < 0) {
 2296                         la->fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
 2297                 }
 2298                 ClearAllFWHoles(la);
 2299                 la->fireWallActiveNum = la->fireWallBaseNum;
 2300         }
 2301 }
 2302 
 2303 static void
 2304 UninitPunchFW(struct libalias *la)
 2305 {
 2306         ClearAllFWHoles(la);
 2307         if (la->fireWallFD >= 0)
 2308                 close(la->fireWallFD);
 2309         la->fireWallFD = -1;
 2310         if (la->fireWallField)
 2311                 free(la->fireWallField);
 2312         la->fireWallField = NULL;
 2313         la->packetAliasMode &= ~PKT_ALIAS_PUNCH_FW;
 2314 }
 2315 
 2316 /* Make a certain link go through the firewall */
 2317 void
 2318 PunchFWHole(struct alias_link *lnk)
 2319 {
 2320         struct libalias *la;
 2321         int r;                  /* Result code */
 2322         struct ip_fw rule;      /* On-the-fly built rule */
 2323         int fwhole;             /* Where to punch hole */
 2324 
 2325         la = lnk->la;
 2326 
 2327         /* Don't do anything unless we are asked to */
 2328         if (!(la->packetAliasMode & PKT_ALIAS_PUNCH_FW) ||
 2329             la->fireWallFD < 0 ||
 2330             lnk->link_type != LINK_TCP)
 2331                 return;
 2332 
 2333         memset(&rule, 0, sizeof rule);
 2334 
 2335         /** Build rule **/
 2336 
 2337         /* Find empty slot */
 2338         for (fwhole = la->fireWallActiveNum;
 2339             fwhole < la->fireWallBaseNum + la->fireWallNumNums &&
 2340             fw_tstfield(la, la->fireWallField, fwhole);
 2341             fwhole++);
 2342         if (fwhole == la->fireWallBaseNum + la->fireWallNumNums) {
 2343                 for (fwhole = la->fireWallBaseNum;
 2344                     fwhole < la->fireWallActiveNum &&
 2345                     fw_tstfield(la, la->fireWallField, fwhole);
 2346                     fwhole++);
 2347                 if (fwhole == la->fireWallActiveNum) {
 2348                         /* No rule point empty - we can't punch more holes. */
 2349                         la->fireWallActiveNum = la->fireWallBaseNum;
 2350 #ifdef LIBALIAS_DEBUG
 2351                         fprintf(stderr, "libalias: Unable to create firewall hole!\n");
 2352 #endif
 2353                         return;
 2354                 }
 2355         }
 2356         /* Start next search at next position */
 2357         la->fireWallActiveNum = fwhole + 1;
 2358 
 2359         /*
 2360          * generate two rules of the form
 2361          *
 2362          * add fwhole accept tcp from OAddr OPort to DAddr DPort add fwhole
 2363          * accept tcp from DAddr DPort to OAddr OPort
 2364          */
 2365         if (GetOriginalPort(lnk) != 0 && GetDestPort(lnk) != 0) {
 2366                 u_int32_t rulebuf[255];
 2367                 int i;
 2368 
 2369                 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
 2370                     O_ACCEPT, IPPROTO_TCP,
 2371                     GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)),
 2372                     GetDestAddress(lnk), ntohs(GetDestPort(lnk)));
 2373                 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
 2374                 if (r)
 2375                         err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
 2376 
 2377                 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
 2378                     O_ACCEPT, IPPROTO_TCP,
 2379                     GetDestAddress(lnk), ntohs(GetDestPort(lnk)),
 2380                     GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)));
 2381                 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
 2382                 if (r)
 2383                         err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
 2384         }
 2385 
 2386         /* Indicate hole applied */
 2387         lnk->data.tcp->fwhole = fwhole;
 2388         fw_setfield(la, la->fireWallField, fwhole);
 2389 }
 2390 
 2391 /* Remove a hole in a firewall associated with a particular alias
 2392    lnk.  Calling this too often is harmless. */
 2393 static void
 2394 ClearFWHole(struct alias_link *lnk)
 2395 {
 2396         struct libalias *la;
 2397 
 2398         la = lnk->la;
 2399         if (lnk->link_type == LINK_TCP) {
 2400                 int fwhole = lnk->data.tcp->fwhole;  /* Where is the firewall hole? */
 2401                 struct ip_fw rule;
 2402 
 2403                 if (fwhole < 0)
 2404                         return;
 2405 
 2406                 memset(&rule, 0, sizeof rule);  /* useless for ipfw2 */
 2407                 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL,
 2408                     &fwhole, sizeof fwhole));
 2409                 fw_clrfield(la, la->fireWallField, fwhole);
 2410                 lnk->data.tcp->fwhole = -1;
 2411         }
 2412 }
 2413 
 2414 /* Clear out the entire range dedicated to firewall holes. */
 2415 static void
 2416 ClearAllFWHoles(struct libalias *la)
 2417 {
 2418         struct ip_fw rule;      /* On-the-fly built rule */
 2419         int i;
 2420 
 2421         if (la->fireWallFD < 0)
 2422                 return;
 2423 
 2424         memset(&rule, 0, sizeof rule);
 2425         for (i = la->fireWallBaseNum; i < la->fireWallBaseNum + la->fireWallNumNums; i++) {
 2426                 int r = i;
 2427 
 2428                 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, &r, sizeof r));
 2429         }
 2430         /* XXX: third arg correct here ? /phk */
 2431         memset(la->fireWallField, 0, la->fireWallNumNums);
 2432 }
 2433 
 2434 #endif /* !NO_FW_PUNCH */
 2435 
 2436 void
 2437 LibAliasSetFWBase(struct libalias *la, unsigned int base, unsigned int num)
 2438 {
 2439         LIBALIAS_LOCK(la);
 2440 #ifndef NO_FW_PUNCH
 2441         la->fireWallBaseNum = base;
 2442         la->fireWallNumNums = num;
 2443 #endif
 2444         LIBALIAS_UNLOCK(la);
 2445 }
 2446 
 2447 void
 2448 LibAliasSetSkinnyPort(struct libalias *la, unsigned int port)
 2449 {
 2450         LIBALIAS_LOCK(la);
 2451         la->skinnyPort = port;
 2452         LIBALIAS_UNLOCK(la);
 2453 }
 2454 
 2455 /*
 2456  * Find the address to redirect incoming packets
 2457  */
 2458 struct in_addr
 2459 FindSctpRedirectAddress(struct libalias *la,  struct sctp_nat_msg *sm)
 2460 {
 2461         struct alias_link *lnk;
 2462         struct in_addr redir;
 2463 
 2464         LIBALIAS_LOCK_ASSERT(la);
 2465         lnk = FindLinkIn(la, sm->ip_hdr->ip_src, sm->ip_hdr->ip_dst,
 2466             sm->sctp_hdr->dest_port,sm->sctp_hdr->dest_port, LINK_SCTP, 1);
 2467         if (lnk != NULL) {
 2468                 /* port redirect */
 2469                 return (lnk->src_addr);
 2470         } else {
 2471                 redir = FindOriginalAddress(la,sm->ip_hdr->ip_dst);
 2472                 if (redir.s_addr == la->aliasAddress.s_addr ||
 2473                     redir.s_addr == la->targetAddress.s_addr) {
 2474                         /* No address found */
 2475                         lnk = FindLinkIn(la, sm->ip_hdr->ip_src, sm->ip_hdr->ip_dst,
 2476                             NO_DEST_PORT, 0, LINK_SCTP, 1);
 2477                         if (lnk != NULL)
 2478                                 /* redirect proto */
 2479                                 return (lnk->src_addr);
 2480                 }
 2481                 return (redir); /* address redirect */
 2482         }
 2483 }

Cache object: b07112c06f485ac61289eff708540f54


[ 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.