]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netinet/libalias/alias_db.c
This commit was generated by cvs2svn to compensate for changes in r164219,
[FreeBSD/FreeBSD.git] / sys / netinet / libalias / alias_db.c
1 /*-
2  * Copyright (c) 2001 Charles Mott <cm@linktel.net>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 /*
31     Alias_db.c encapsulates all data structures used for storing
32     packet aliasing data.  Other parts of the aliasing software
33     access data through functions provided in this file.
34
35     Data storage is based on the notion of a "link", which is
36     established for ICMP echo/reply packets, UDP datagrams and
37     TCP stream connections.  A link stores the original source
38     and destination addresses.  For UDP and TCP, it also stores
39     source and destination port numbers, as well as an alias
40     port number.  Links are also used to store information about
41     fragments.
42
43     There is a facility for sweeping through and deleting old
44     links as new packets are sent through.  A simple timeout is
45     used for ICMP and UDP links.  TCP links are left alone unless
46     there is an incomplete connection, in which case the link
47     can be deleted after a certain amount of time.
48
49
50     Initial version: August, 1996  (cjm)
51
52     Version 1.4: September 16, 1996 (cjm)
53         Facility for handling incoming links added.
54
55     Version 1.6: September 18, 1996 (cjm)
56         ICMP data handling simplified.
57
58     Version 1.7: January 9, 1997 (cjm)
59         Fragment handling simplified.
60         Saves pointers for unresolved fragments.
61         Permits links for unspecified remote ports
62           or unspecified remote addresses.
63         Fixed bug which did not properly zero port
64           table entries after a link was deleted.
65         Cleaned up some obsolete comments.
66
67     Version 1.8: January 14, 1997 (cjm)
68         Fixed data type error in StartPoint().
69         (This error did not exist prior to v1.7
70         and was discovered and fixed by Ari Suutari)
71
72     Version 1.9: February 1, 1997
73         Optionally, connections initiated from packet aliasing host
74         machine will will not have their port number aliased unless it
75         conflicts with an aliasing port already being used. (cjm)
76
77         All options earlier being #ifdef'ed are now available through
78         a new interface, SetPacketAliasMode().  This allows run time
79         control (which is now available in PPP+pktAlias through the
80         'alias' keyword). (ee)
81
82         Added ability to create an alias port without
83         either destination address or port specified.
84         port type = ALIAS_PORT_UNKNOWN_DEST_ALL (ee)
85
86         Removed K&R style function headers
87         and general cleanup. (ee)
88
89         Added packetAliasMode to replace compiler #defines's (ee)
90
91         Allocates sockets for partially specified
92         ports if ALIAS_USE_SOCKETS defined. (cjm)
93
94     Version 2.0: March, 1997
95         SetAliasAddress() will now clean up alias links
96         if the aliasing address is changed. (cjm)
97
98         PacketAliasPermanentLink() function added to support permanent
99         links.  (J. Fortes suggested the need for this.)
100         Examples:
101
102         (192.168.0.1, port 23)  <-> alias port 6002, unknown dest addr/port
103
104         (192.168.0.2, port 21)  <-> alias port 3604, known dest addr
105                                                      unknown dest port
106
107         These permanent links allow for incoming connections to
108         machines on the local network.  They can be given with a
109         user-chosen amount of specificity, with increasing specificity
110         meaning more security. (cjm)
111
112         Quite a bit of rework to the basic engine.  The portTable[]
113         array, which kept track of which ports were in use was replaced
114         by a table/linked list structure. (cjm)
115
116         SetExpire() function added. (cjm)
117
118         DeleteLink() no longer frees memory association with a pointer
119         to a fragment (this bug was first recognized by E. Eklund in
120         v1.9).
121
122     Version 2.1: May, 1997 (cjm)
123         Packet aliasing engine reworked so that it can handle
124         multiple external addresses rather than just a single
125         host address.
126
127         PacketAliasRedirectPort() and PacketAliasRedirectAddr()
128         added to the API.  The first function is a more generalized
129         version of PacketAliasPermanentLink().  The second function
130         implements static network address translation.
131
132     Version 3.2: July, 2000 (salander and satoh)
133         Added FindNewPortGroup to get contiguous range of port values.
134
135         Added QueryUdpTcpIn and QueryUdpTcpOut to look for an aliasing
136         link but not actually add one.
137
138         Added FindRtspOut, which is closely derived from FindUdpTcpOut,
139         except that the alias port (from FindNewPortGroup) is provided
140         as input.
141
142     See HISTORY file for additional revisions.
143 */
144
145 #ifdef _KERNEL
146 #include <machine/stdarg.h>
147 #include <sys/param.h>
148 #include <sys/kernel.h>
149 #include <sys/module.h>
150 #include <sys/syslog.h>
151 #else
152 #include <stdarg.h>
153 #include <stdlib.h>
154 #include <stdio.h>
155 #include <sys/errno.h>
156 #include <sys/time.h>
157 #include <unistd.h> 
158 #endif
159
160 #include <sys/socket.h>
161 #include <netinet/tcp.h>
162
163 #ifdef _KERNEL  
164 #include <netinet/libalias/alias.h>
165 #include <netinet/libalias/alias_local.h>
166 #include <netinet/libalias/alias_mod.h>
167 #include <net/if.h>
168 #else
169 #include "alias.h"
170 #include "alias_local.h"
171 #include "alias_mod.h"
172 #endif
173
174 static          LIST_HEAD(, libalias) instancehead = LIST_HEAD_INITIALIZER(instancehead);
175
176
177 /*
178    Constants (note: constants are also defined
179               near relevant functions or structs)
180 */
181
182 /* Parameters used for cleanup of expired links */
183 #define ALIAS_CLEANUP_INTERVAL_SECS  60
184 #define ALIAS_CLEANUP_MAX_SPOKES     30
185
186 /* Timeouts (in seconds) for different link types */
187 #define ICMP_EXPIRE_TIME             60
188 #define UDP_EXPIRE_TIME              60
189 #define PROTO_EXPIRE_TIME            60
190 #define FRAGMENT_ID_EXPIRE_TIME      10
191 #define FRAGMENT_PTR_EXPIRE_TIME     30
192
193 /* TCP link expire time for different cases */
194 /* When the link has been used and closed - minimal grace time to
195    allow ACKs and potential re-connect in FTP (XXX - is this allowed?)  */
196 #ifndef TCP_EXPIRE_DEAD
197 #define TCP_EXPIRE_DEAD           10
198 #endif
199
200 /* When the link has been used and closed on one side - the other side
201    is allowed to still send data */
202 #ifndef TCP_EXPIRE_SINGLEDEAD
203 #define TCP_EXPIRE_SINGLEDEAD     90
204 #endif
205
206 /* When the link isn't yet up */
207 #ifndef TCP_EXPIRE_INITIAL
208 #define TCP_EXPIRE_INITIAL       300
209 #endif
210
211 /* When the link is up */
212 #ifndef TCP_EXPIRE_CONNECTED
213 #define TCP_EXPIRE_CONNECTED   86400
214 #endif
215
216
217 /* Dummy port number codes used for FindLinkIn/Out() and AddLink().
218    These constants can be anything except zero, which indicates an
219    unknown port number. */
220
221 #define NO_DEST_PORT     1
222 #define NO_SRC_PORT      1
223
224
225
226 /* Data Structures
227
228     The fundamental data structure used in this program is
229     "struct alias_link".  Whenever a TCP connection is made,
230     a UDP datagram is sent out, or an ICMP echo request is made,
231     a link record is made (if it has not already been created).
232     The link record is identified by the source address/port
233     and the destination address/port. In the case of an ICMP
234     echo request, the source port is treated as being equivalent
235     with the 16-bit ID number of the ICMP packet.
236
237     The link record also can store some auxiliary data.  For
238     TCP connections that have had sequence and acknowledgment
239     modifications, data space is available to track these changes.
240     A state field is used to keep track in changes to the TCP
241     connection state.  ID numbers of fragments can also be
242     stored in the auxiliary space.  Pointers to unresolved
243     fragments can also be stored.
244
245     The link records support two independent chainings.  Lookup
246     tables for input and out tables hold the initial pointers
247     the link chains.  On input, the lookup table indexes on alias
248     port and link type.  On output, the lookup table indexes on
249     source address, destination address, source port, destination
250     port and link type.
251 */
252
253 struct ack_data_record {        /* used to save changes to ACK/sequence
254                                  * numbers */
255         u_long          ack_old;
256         u_long          ack_new;
257         int             delta;
258         int             active;
259 };
260
261 struct tcp_state {              /* Information about TCP connection        */
262         int             in;     /* State for outside -> inside             */
263         int             out;    /* State for inside  -> outside            */
264         int             index;  /* Index to ACK data array                 */
265         int             ack_modified;   /* Indicates whether ACK and
266                                          * sequence numbers */
267         /* been modified                           */
268 };
269
270 #define N_LINK_TCP_DATA   3     /* Number of distinct ACK number changes
271                                  * saved for a modified TCP stream */
272 struct tcp_dat {
273         struct tcp_state state;
274         struct ack_data_record ack[N_LINK_TCP_DATA];
275         int             fwhole; /* Which firewall record is used for this
276                                  * hole? */
277 };
278
279 struct server {                 /* LSNAT server pool (circular list) */
280         struct in_addr  addr;
281         u_short         port;
282         struct server  *next;
283 };
284
285 struct alias_link {             /* Main data structure */
286         struct libalias *la;
287         struct in_addr  src_addr;       /* Address and port information        */
288         struct in_addr  dst_addr;
289         struct in_addr  alias_addr;
290         struct in_addr  proxy_addr;
291         u_short         src_port;
292         u_short         dst_port;
293         u_short         alias_port;
294         u_short         proxy_port;
295         struct server  *server;
296
297         int             link_type;      /* Type of link: TCP, UDP, ICMP,
298                                          * proto, frag */
299
300 /* values for link_type */
301 #define LINK_ICMP                     IPPROTO_ICMP
302 #define LINK_UDP                      IPPROTO_UDP
303 #define LINK_TCP                      IPPROTO_TCP
304 #define LINK_FRAGMENT_ID              (IPPROTO_MAX + 1)
305 #define LINK_FRAGMENT_PTR             (IPPROTO_MAX + 2)
306 #define LINK_ADDR                     (IPPROTO_MAX + 3)
307 #define LINK_PPTP                     (IPPROTO_MAX + 4)
308
309         int             flags;  /* indicates special characteristics   */
310         int             pflags; /* protocol-specific flags */
311
312 /* flag bits */
313 #define LINK_UNKNOWN_DEST_PORT     0x01
314 #define LINK_UNKNOWN_DEST_ADDR     0x02
315 #define LINK_PERMANENT             0x04
316 #define LINK_PARTIALLY_SPECIFIED   0x03 /* logical-or of first two bits */
317 #define LINK_UNFIREWALLED          0x08
318
319         int             timestamp;      /* Time link was last accessed         */
320         int             expire_time;    /* Expire time for link                */
321 #ifndef NO_USE_SOCKETS
322         int             sockfd; /* socket descriptor                   */
323 #endif
324                         LIST_ENTRY    (alias_link) list_out;    /* Linked list of
325                                                                  * pointers for     */
326                         LIST_ENTRY    (alias_link) list_in;     /* input and output
327                                                                  * lookup tables  */
328
329         union {                 /* Auxiliary data                      */
330                 char           *frag_ptr;
331                 struct in_addr  frag_addr;
332                 struct tcp_dat *tcp;
333         }               data;
334 };
335
336 /* Clean up procedure. */
337 static void finishoff(void);
338
339 /* Kernel module definition. */
340 #ifdef  _KERNEL
341 MALLOC_DEFINE(M_ALIAS, "libalias", "packet aliasing");
342
343 MODULE_VERSION(libalias, 1);
344
345 static int
346 alias_mod_handler(module_t mod, int type, void *data)
347 {
348         int error;
349
350         switch (type) {
351         case MOD_LOAD:
352                 error = 0;
353                 handler_chain_init();
354                 break;
355         case MOD_QUIESCE:
356         case MOD_UNLOAD:
357                 handler_chain_destroy();
358                 finishoff();
359                 error = 0;
360                 break;
361         default:
362                 error = EINVAL;
363         }
364
365         return (error);
366 }
367
368 static moduledata_t alias_mod = {
369        "alias", alias_mod_handler, NULL
370 };
371
372 DECLARE_MODULE(alias, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
373 #endif
374
375 /* Internal utility routines (used only in alias_db.c)
376
377 Lookup table starting points:
378     StartPointIn()           -- link table initial search point for
379                                 incoming packets
380     StartPointOut()          -- link table initial search point for
381                                 outgoing packets
382
383 Miscellaneous:
384     SeqDiff()                -- difference between two TCP sequences
385     ShowAliasStats()         -- send alias statistics to a monitor file
386 */
387
388
389 /* Local prototypes */
390 static u_int    StartPointIn(struct in_addr, u_short, int);
391
392 static          u_int
393 StartPointOut(struct in_addr, struct in_addr,
394     u_short, u_short, int);
395
396 static int      SeqDiff(u_long, u_long);
397
398 #ifndef NO_FW_PUNCH
399 /* Firewall control */
400 static void     InitPunchFW(struct libalias *);
401 static void     UninitPunchFW(struct libalias *);
402 static void     ClearFWHole(struct alias_link *);
403
404 #endif
405
406 /* Log file control */
407 static void     ShowAliasStats(struct libalias *);
408 static int      InitPacketAliasLog(struct libalias *);
409 static void     UninitPacketAliasLog(struct libalias *);
410
411 static          u_int
412 StartPointIn(struct in_addr alias_addr,
413     u_short alias_port,
414     int link_type)
415 {
416         u_int n;
417
418         n = alias_addr.s_addr;
419         if (link_type != LINK_PPTP)
420                 n += alias_port;
421         n += link_type;
422         return (n % LINK_TABLE_IN_SIZE);
423 }
424
425
426 static          u_int
427 StartPointOut(struct in_addr src_addr, struct in_addr dst_addr,
428     u_short src_port, u_short dst_port, int link_type)
429 {
430         u_int n;
431
432         n = src_addr.s_addr;
433         n += dst_addr.s_addr;
434         if (link_type != LINK_PPTP) {
435                 n += src_port;
436                 n += dst_port;
437         }
438         n += link_type;
439
440         return (n % LINK_TABLE_OUT_SIZE);
441 }
442
443
444 static int
445 SeqDiff(u_long x, u_long y)
446 {
447 /* Return the difference between two TCP sequence numbers */
448
449 /*
450     This function is encapsulated in case there are any unusual
451     arithmetic conditions that need to be considered.
452 */
453
454         return (ntohl(y) - ntohl(x));
455 }
456
457 #ifdef _KERNEL
458
459 static void
460 AliasLog(char *str, const char *format, ...)
461 {               
462         va_list ap;
463         
464         va_start(ap, format);
465         vsnprintf(str, LIBALIAS_BUF_SIZE, format, ap);
466         log(LOG_SECURITY | LOG_INFO, "%s\n", str);
467         va_end(ap);
468 }
469 #else
470 static void
471 AliasLog(FILE *stream, const char *format, ...)
472 {
473         va_list ap;
474         
475         va_start(ap, format);
476         vfprintf(stream, format, ap);
477         va_end(ap);
478         fflush(stream);
479 }
480 #endif
481
482 static void
483 ShowAliasStats(struct libalias *la)
484 {
485 /* Used for debugging */
486         if (la->logDesc) {
487                 int tot  = la->icmpLinkCount + la->udpLinkCount + 
488                         la->tcpLinkCount + la->pptpLinkCount +
489                         la->protoLinkCount + la->fragmentIdLinkCount +
490                         la->fragmentPtrLinkCount;
491                 
492                 AliasLog(la->logDesc,
493                          "icmp=%u, udp=%u, tcp=%u, pptp=%u, proto=%u, frag_id=%u frag_ptr=%u / tot=%u",
494                          la->icmpLinkCount,
495                          la->udpLinkCount,
496                          la->tcpLinkCount,
497                          la->pptpLinkCount,
498                          la->protoLinkCount,
499                          la->fragmentIdLinkCount,
500                          la->fragmentPtrLinkCount, tot);
501 #ifndef _KERNEL
502                 AliasLog(la->logDesc, " (sock=%u)\n", la->sockCount); 
503 #endif
504         }
505 }
506
507 /* Internal routines for finding, deleting and adding links
508
509 Port Allocation:
510     GetNewPort()             -- find and reserve new alias port number
511     GetSocket()              -- try to allocate a socket for a given port
512
513 Link creation and deletion:
514     CleanupAliasData()      - remove all link chains from lookup table
515     IncrementalCleanup()    - look for stale links in a single chain
516     DeleteLink()            - remove link
517     AddLink()               - add link
518     ReLink()                - change link
519
520 Link search:
521     FindLinkOut()           - find link for outgoing packets
522     FindLinkIn()            - find link for incoming packets
523
524 Port search:
525     FindNewPortGroup()      - find an available group of ports
526 */
527
528 /* Local prototypes */
529 static int      GetNewPort(struct libalias *, struct alias_link *, int);
530 #ifndef NO_USE_SOCKETS
531 static u_short  GetSocket(struct libalias *, u_short, int *, int);
532 #endif
533 static void     CleanupAliasData(struct libalias *);
534
535 static void     IncrementalCleanup(struct libalias *);
536
537 static void     DeleteLink(struct alias_link *);
538
539 static struct alias_link *
540 AddLink(struct libalias *, struct in_addr, struct in_addr, struct in_addr,
541     u_short, u_short, int, int);
542
543 static struct alias_link *
544 ReLink(struct alias_link *,
545     struct in_addr, struct in_addr, struct in_addr,
546     u_short, u_short, int, int);
547
548 static struct alias_link *
549                 FindLinkOut   (struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int);
550
551 static struct alias_link *
552                 FindLinkIn    (struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int);
553
554
555 #define ALIAS_PORT_BASE            0x08000
556 #define ALIAS_PORT_MASK            0x07fff
557 #define ALIAS_PORT_MASK_EVEN       0x07ffe
558 #define GET_NEW_PORT_MAX_ATTEMPTS       20
559
560 #define GET_ALIAS_PORT                  -1
561 #define GET_ALIAS_ID        GET_ALIAS_PORT
562
563 #define FIND_EVEN_ALIAS_BASE             1
564
565 /* GetNewPort() allocates port numbers.  Note that if a port number
566    is already in use, that does not mean that it cannot be used by
567    another link concurrently.  This is because GetNewPort() looks for
568    unused triplets: (dest addr, dest port, alias port). */
569
570 static int
571 GetNewPort(struct libalias *la, struct alias_link *lnk, int alias_port_param)
572 {
573         int i;
574         int max_trials;
575         u_short port_sys;
576         u_short port_net;
577
578 /*
579    Description of alias_port_param for GetNewPort().  When
580    this parameter is zero or positive, it precisely specifies
581    the port number.  GetNewPort() will return this number
582    without check that it is in use.
583
584    When this parameter is GET_ALIAS_PORT, it indicates to get a randomly
585    selected port number.
586 */
587
588         if (alias_port_param == GET_ALIAS_PORT) {
589                 /*
590                  * The aliasing port is automatically selected by one of
591                  * two methods below:
592                  */
593                 max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
594
595                 if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) {
596                         /*
597                          * When the PKT_ALIAS_SAME_PORTS option is chosen,
598                          * the first try will be the actual source port. If
599                          * this is already in use, the remainder of the
600                          * trials will be random.
601                          */
602                         port_net = lnk->src_port;
603                         port_sys = ntohs(port_net);
604                 } else {
605                         /* First trial and all subsequent are random. */
606                         port_sys = random() & ALIAS_PORT_MASK;
607                         port_sys += ALIAS_PORT_BASE;
608                         port_net = htons(port_sys);
609                 }
610         } else if (alias_port_param >= 0 && alias_port_param < 0x10000) {
611                 lnk->alias_port = (u_short) alias_port_param;
612                 return (0);
613         } else {
614 #ifdef LIBALIAS_DEBUG
615                 fprintf(stderr, "PacketAlias/GetNewPort(): ");
616                 fprintf(stderr, "input parameter error\n");
617 #endif
618                 return (-1);
619         }
620
621
622 /* Port number search */
623         for (i = 0; i < max_trials; i++) {
624                 int go_ahead;
625                 struct alias_link *search_result;
626
627                 search_result = FindLinkIn(la, lnk->dst_addr, lnk->alias_addr,
628                     lnk->dst_port, port_net,
629                     lnk->link_type, 0);
630
631                 if (search_result == NULL)
632                         go_ahead = 1;
633                 else if (!(lnk->flags & LINK_PARTIALLY_SPECIFIED)
634                     && (search_result->flags & LINK_PARTIALLY_SPECIFIED))
635                         go_ahead = 1;
636                 else
637                         go_ahead = 0;
638
639                 if (go_ahead) {
640 #ifndef NO_USE_SOCKETS
641                         if ((la->packetAliasMode & PKT_ALIAS_USE_SOCKETS)
642                             && (lnk->flags & LINK_PARTIALLY_SPECIFIED)
643                             && ((lnk->link_type == LINK_TCP) ||
644                             (lnk->link_type == LINK_UDP))) {
645                                 if (GetSocket(la, port_net, &lnk->sockfd, lnk->link_type)) {
646                                         lnk->alias_port = port_net;
647                                         return (0);
648                                 }
649                         } else {
650 #endif
651                                 lnk->alias_port = port_net;
652                                 return (0);
653 #ifndef NO_USE_SOCKETS
654                         }
655 #endif
656                 }
657                 port_sys = random() & ALIAS_PORT_MASK;
658                 port_sys += ALIAS_PORT_BASE;
659                 port_net = htons(port_sys);
660         }
661
662 #ifdef LIBALIAS_DEBUG
663         fprintf(stderr, "PacketAlias/GetnewPort(): ");
664         fprintf(stderr, "could not find free port\n");
665 #endif
666
667         return (-1);
668 }
669
670 #ifndef NO_USE_SOCKETS
671 static          u_short
672 GetSocket(struct libalias *la, u_short port_net, int *sockfd, int link_type)
673 {
674         int err;
675         int sock;
676         struct sockaddr_in sock_addr;
677
678         if (link_type == LINK_TCP)
679                 sock = socket(AF_INET, SOCK_STREAM, 0);
680         else if (link_type == LINK_UDP)
681                 sock = socket(AF_INET, SOCK_DGRAM, 0);
682         else {
683 #ifdef LIBALIAS_DEBUG
684                 fprintf(stderr, "PacketAlias/GetSocket(): ");
685                 fprintf(stderr, "incorrect link type\n");
686 #endif
687                 return (0);
688         }
689
690         if (sock < 0) {
691 #ifdef LIBALIAS_DEBUG
692                 fprintf(stderr, "PacketAlias/GetSocket(): ");
693                 fprintf(stderr, "socket() error %d\n", *sockfd);
694 #endif
695                 return (0);
696         }
697         sock_addr.sin_family = AF_INET;
698         sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
699         sock_addr.sin_port = port_net;
700
701         err = bind(sock,
702             (struct sockaddr *)&sock_addr,
703             sizeof(sock_addr));
704         if (err == 0) {
705                 la->sockCount++;
706                 *sockfd = sock;
707                 return (1);
708         } else {
709                 close(sock);
710                 return (0);
711         }
712 }
713 #endif
714
715 /* FindNewPortGroup() returns a base port number for an available
716    range of contiguous port numbers. Note that if a port number
717    is already in use, that does not mean that it cannot be used by
718    another link concurrently.  This is because FindNewPortGroup()
719    looks for unused triplets: (dest addr, dest port, alias port). */
720
721 int
722 FindNewPortGroup(struct libalias *la,
723     struct in_addr dst_addr,
724     struct in_addr alias_addr,
725     u_short src_port,
726     u_short dst_port,
727     u_short port_count,
728     u_char proto,
729     u_char align)
730 {
731         int i, j;
732         int max_trials;
733         u_short port_sys;
734         int link_type;
735
736         /*
737          * Get link_type from protocol
738          */
739
740         switch (proto) {
741         case IPPROTO_UDP:
742                 link_type = LINK_UDP;
743                 break;
744         case IPPROTO_TCP:
745                 link_type = LINK_TCP;
746                 break;
747         default:
748                 return (0);
749                 break;
750         }
751
752         /*
753          * The aliasing port is automatically selected by one of two
754          * methods below:
755          */
756         max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
757
758         if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) {
759                 /*
760                  * When the ALIAS_SAME_PORTS option is chosen, the first
761                  * try will be the actual source port. If this is already
762                  * in use, the remainder of the trials will be random.
763                  */
764                 port_sys = ntohs(src_port);
765
766         } else {
767
768                 /* First trial and all subsequent are random. */
769                 if (align == FIND_EVEN_ALIAS_BASE)
770                         port_sys = random() & ALIAS_PORT_MASK_EVEN;
771                 else
772                         port_sys = random() & ALIAS_PORT_MASK;
773
774                 port_sys += ALIAS_PORT_BASE;
775         }
776
777 /* Port number search */
778         for (i = 0; i < max_trials; i++) {
779
780                 struct alias_link *search_result;
781
782                 for (j = 0; j < port_count; j++)
783                         if (0 != (search_result = FindLinkIn(la, dst_addr, alias_addr,
784                             dst_port, htons(port_sys + j),
785                             link_type, 0)))
786                                 break;
787
788                 /* Found a good range, return base */
789                 if (j == port_count)
790                         return (htons(port_sys));
791
792                 /* Find a new base to try */
793                 if (align == FIND_EVEN_ALIAS_BASE)
794                         port_sys = random() & ALIAS_PORT_MASK_EVEN;
795                 else
796                         port_sys = random() & ALIAS_PORT_MASK;
797
798                 port_sys += ALIAS_PORT_BASE;
799         }
800
801 #ifdef LIBALIAS_DEBUG
802         fprintf(stderr, "PacketAlias/FindNewPortGroup(): ");
803         fprintf(stderr, "could not find free port(s)\n");
804 #endif
805
806         return (0);
807 }
808
809 static void
810 CleanupAliasData(struct libalias *la)
811 {
812         struct alias_link *lnk;
813         int i, icount;
814
815         icount = 0;
816         for (i = 0; i < LINK_TABLE_OUT_SIZE; i++) {
817                 lnk = LIST_FIRST(&la->linkTableOut[i]);
818                 while (lnk != NULL) {
819                         struct alias_link *link_next;
820
821                         link_next = LIST_NEXT(lnk, list_out);
822                         icount++;
823                         DeleteLink(lnk);
824                         lnk = link_next;
825                 }
826         }
827
828         la->cleanupIndex = 0;
829 }
830
831
832 static void
833 IncrementalCleanup(struct libalias *la)
834 {
835         int icount;
836         struct alias_link *lnk;
837
838         icount = 0;
839         lnk = LIST_FIRST(&la->linkTableOut[la->cleanupIndex++]);
840         while (lnk != NULL) {
841                 int idelta;
842                 struct alias_link *link_next;
843
844                 link_next = LIST_NEXT(lnk, list_out);
845                 idelta = la->timeStamp - lnk->timestamp;
846                 switch (lnk->link_type) {
847                 case LINK_TCP:
848                         if (idelta > lnk->expire_time) {
849                                 struct tcp_dat *tcp_aux;
850
851                                 tcp_aux = lnk->data.tcp;
852                                 if (tcp_aux->state.in != ALIAS_TCP_STATE_CONNECTED
853                                     || tcp_aux->state.out != ALIAS_TCP_STATE_CONNECTED) {
854                                         DeleteLink(lnk);
855                                         icount++;
856                                 }
857                         }
858                         break;
859                 default:
860                         if (idelta > lnk->expire_time) {
861                                 DeleteLink(lnk);
862                                 icount++;
863                         }
864                         break;
865                 }
866                 lnk = link_next;
867         }
868
869         if (la->cleanupIndex == LINK_TABLE_OUT_SIZE)
870                 la->cleanupIndex = 0;
871 }
872
873 static void
874 DeleteLink(struct alias_link *lnk)
875 {
876         struct libalias *la = lnk->la;
877
878 /* Don't do anything if the link is marked permanent */
879         if (la->deleteAllLinks == 0 && lnk->flags & LINK_PERMANENT)
880                 return;
881
882 #ifndef NO_FW_PUNCH
883 /* Delete associated firewall hole, if any */
884         ClearFWHole(lnk);
885 #endif
886
887 /* Free memory allocated for LSNAT server pool */
888         if (lnk->server != NULL) {
889                 struct server *head, *curr, *next;
890
891                 head = curr = lnk->server;
892                 do {
893                         next = curr->next;
894                         free(curr);
895                 } while ((curr = next) != head);
896         }
897 /* Adjust output table pointers */
898         LIST_REMOVE(lnk, list_out);
899
900 /* Adjust input table pointers */
901         LIST_REMOVE(lnk, list_in);
902 #ifndef NO_USE_SOCKETS
903 /* Close socket, if one has been allocated */
904         if (lnk->sockfd != -1) {
905                 la->sockCount--;
906                 close(lnk->sockfd);
907         }
908 #endif
909 /* Link-type dependent cleanup */
910         switch (lnk->link_type) {
911         case LINK_ICMP:
912                 la->icmpLinkCount--;
913                 break;
914         case LINK_UDP:
915                 la->udpLinkCount--;
916                 break;
917         case LINK_TCP:
918                 la->tcpLinkCount--;
919                 free(lnk->data.tcp);
920                 break;
921         case LINK_PPTP:
922                 la->pptpLinkCount--;
923                 break;
924         case LINK_FRAGMENT_ID:
925                 la->fragmentIdLinkCount--;
926                 break;
927         case LINK_FRAGMENT_PTR:
928                 la->fragmentPtrLinkCount--;
929                 if (lnk->data.frag_ptr != NULL)
930                         free(lnk->data.frag_ptr);
931                 break;
932         case LINK_ADDR:
933                 break;
934         default:
935                 la->protoLinkCount--;
936                 break;
937         }
938
939 /* Free memory */
940         free(lnk);
941
942 /* Write statistics, if logging enabled */
943         if (la->packetAliasMode & PKT_ALIAS_LOG) {
944                 ShowAliasStats(la);
945         }
946 }
947
948
949 static struct alias_link *
950 AddLink(struct libalias *la, struct in_addr src_addr,
951     struct in_addr dst_addr,
952     struct in_addr alias_addr,
953     u_short src_port,
954     u_short dst_port,
955     int alias_port_param,       /* if less than zero, alias   */
956     int link_type)
957 {                               /* port will be automatically *//* chosen.
958                                  * If greater than    */
959         u_int start_point;      /* zero, equal to alias port  */
960         struct alias_link *lnk;
961
962         lnk = malloc(sizeof(struct alias_link));
963         if (lnk != NULL) {
964                 /* Basic initialization */
965                 lnk->la = la;
966                 lnk->src_addr = src_addr;
967                 lnk->dst_addr = dst_addr;
968                 lnk->alias_addr = alias_addr;
969                 lnk->proxy_addr.s_addr = INADDR_ANY;
970                 lnk->src_port = src_port;
971                 lnk->dst_port = dst_port;
972                 lnk->proxy_port = 0;
973                 lnk->server = NULL;
974                 lnk->link_type = link_type;
975 #ifndef NO_USE_SOCKETS
976                 lnk->sockfd = -1;
977 #endif
978                 lnk->flags = 0;
979                 lnk->pflags = 0;
980                 lnk->timestamp = la->timeStamp;
981
982                 /* Expiration time */
983                 switch (link_type) {
984                 case LINK_ICMP:
985                         lnk->expire_time = ICMP_EXPIRE_TIME;
986                         break;
987                 case LINK_UDP:
988                         lnk->expire_time = UDP_EXPIRE_TIME;
989                         break;
990                 case LINK_TCP:
991                         lnk->expire_time = TCP_EXPIRE_INITIAL;
992                         break;
993                 case LINK_PPTP:
994                         lnk->flags |= LINK_PERMANENT;   /* no timeout. */
995                         break;
996                 case LINK_FRAGMENT_ID:
997                         lnk->expire_time = FRAGMENT_ID_EXPIRE_TIME;
998                         break;
999                 case LINK_FRAGMENT_PTR:
1000                         lnk->expire_time = FRAGMENT_PTR_EXPIRE_TIME;
1001                         break;
1002                 case LINK_ADDR:
1003                         break;
1004                 default:
1005                         lnk->expire_time = PROTO_EXPIRE_TIME;
1006                         break;
1007                 }
1008
1009                 /* Determine alias flags */
1010                 if (dst_addr.s_addr == INADDR_ANY)
1011                         lnk->flags |= LINK_UNKNOWN_DEST_ADDR;
1012                 if (dst_port == 0)
1013                         lnk->flags |= LINK_UNKNOWN_DEST_PORT;
1014
1015                 /* Determine alias port */
1016                 if (GetNewPort(la, lnk, alias_port_param) != 0) {
1017                         free(lnk);
1018                         return (NULL);
1019                 }
1020                 /* Link-type dependent initialization */
1021                 switch (link_type) {
1022                         struct tcp_dat *aux_tcp;
1023
1024                 case LINK_ICMP:
1025                         la->icmpLinkCount++;
1026                         break;
1027                 case LINK_UDP:
1028                         la->udpLinkCount++;
1029                         break;
1030                 case LINK_TCP:
1031                         aux_tcp = malloc(sizeof(struct tcp_dat));
1032                         if (aux_tcp != NULL) {
1033                                 int i;
1034
1035                                 la->tcpLinkCount++;
1036                                 aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED;
1037                                 aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED;
1038                                 aux_tcp->state.index = 0;
1039                                 aux_tcp->state.ack_modified = 0;
1040                                 for (i = 0; i < N_LINK_TCP_DATA; i++)
1041                                         aux_tcp->ack[i].active = 0;
1042                                 aux_tcp->fwhole = -1;
1043                                 lnk->data.tcp = aux_tcp;
1044                         } else {
1045 #ifdef LIBALIAS_DEBUG
1046                                 fprintf(stderr, "PacketAlias/AddLink: ");
1047                                 fprintf(stderr, " cannot allocate auxiliary TCP data\n");
1048 #endif
1049                                 free(lnk);
1050                                 return (NULL);
1051                         }
1052                         break;
1053                 case LINK_PPTP:
1054                         la->pptpLinkCount++;
1055                         break;
1056                 case LINK_FRAGMENT_ID:
1057                         la->fragmentIdLinkCount++;
1058                         break;
1059                 case LINK_FRAGMENT_PTR:
1060                         la->fragmentPtrLinkCount++;
1061                         break;
1062                 case LINK_ADDR:
1063                         break;
1064                 default:
1065                         la->protoLinkCount++;
1066                         break;
1067                 }
1068
1069                 /* Set up pointers for output lookup table */
1070                 start_point = StartPointOut(src_addr, dst_addr,
1071                     src_port, dst_port, link_type);
1072                 LIST_INSERT_HEAD(&la->linkTableOut[start_point], lnk, list_out);
1073
1074                 /* Set up pointers for input lookup table */
1075                 start_point = StartPointIn(alias_addr, lnk->alias_port, link_type);
1076                 LIST_INSERT_HEAD(&la->linkTableIn[start_point], lnk, list_in);
1077         } else {
1078 #ifdef LIBALIAS_DEBUG
1079                 fprintf(stderr, "PacketAlias/AddLink(): ");
1080                 fprintf(stderr, "malloc() call failed.\n");
1081 #endif
1082         }
1083         if (la->packetAliasMode & PKT_ALIAS_LOG) {
1084                 ShowAliasStats(la);
1085         }
1086         return (lnk);
1087 }
1088
1089 static struct alias_link *
1090 ReLink(struct alias_link *old_lnk,
1091     struct in_addr src_addr,
1092     struct in_addr dst_addr,
1093     struct in_addr alias_addr,
1094     u_short src_port,
1095     u_short dst_port,
1096     int alias_port_param,       /* if less than zero, alias   */
1097     int link_type)
1098 {                               /* port will be automatically *//* chosen.
1099                                  * If greater than    */
1100         struct alias_link *new_lnk;     /* zero, equal to alias port  */
1101         struct libalias *la = old_lnk->la;
1102
1103         new_lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1104             src_port, dst_port, alias_port_param,
1105             link_type);
1106 #ifndef NO_FW_PUNCH
1107         if (new_lnk != NULL &&
1108             old_lnk->link_type == LINK_TCP &&
1109             old_lnk->data.tcp->fwhole > 0) {
1110                 PunchFWHole(new_lnk);
1111         }
1112 #endif
1113         DeleteLink(old_lnk);
1114         return (new_lnk);
1115 }
1116
1117 static struct alias_link *
1118 _FindLinkOut(struct libalias *la, struct in_addr src_addr,
1119     struct in_addr dst_addr,
1120     u_short src_port,
1121     u_short dst_port,
1122     int link_type,
1123     int replace_partial_links)
1124 {
1125         u_int i;
1126         struct alias_link *lnk;
1127
1128         i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type);
1129         LIST_FOREACH(lnk, &la->linkTableOut[i], list_out) {
1130                 if (lnk->src_addr.s_addr == src_addr.s_addr
1131                     && lnk->server == NULL
1132                     && lnk->dst_addr.s_addr == dst_addr.s_addr
1133                     && lnk->dst_port == dst_port
1134                     && lnk->src_port == src_port
1135                     && lnk->link_type == link_type) {
1136                         lnk->timestamp = la->timeStamp;
1137                         break;
1138                 }
1139         }
1140
1141 /* Search for partially specified links. */
1142         if (lnk == NULL && replace_partial_links) {
1143                 if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY) {
1144                         lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, 0,
1145                             link_type, 0);
1146                         if (lnk == NULL)
1147                                 lnk = _FindLinkOut(la, src_addr, la->nullAddress, src_port,
1148                                     dst_port, link_type, 0);
1149                 }
1150                 if (lnk == NULL &&
1151                     (dst_port != 0 || dst_addr.s_addr != INADDR_ANY)) {
1152                         lnk = _FindLinkOut(la, src_addr, la->nullAddress, src_port, 0,
1153                             link_type, 0);
1154                 }
1155                 if (lnk != NULL) {
1156                         lnk = ReLink(lnk,
1157                             src_addr, dst_addr, lnk->alias_addr,
1158                             src_port, dst_port, lnk->alias_port,
1159                             link_type);
1160                 }
1161         }
1162         return (lnk);
1163 }
1164
1165 static struct alias_link *
1166 FindLinkOut(struct libalias *la, struct in_addr src_addr,
1167     struct in_addr dst_addr,
1168     u_short src_port,
1169     u_short dst_port,
1170     int link_type,
1171     int replace_partial_links)
1172 {
1173         struct alias_link *lnk;
1174
1175         lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, dst_port,
1176             link_type, replace_partial_links);
1177
1178         if (lnk == NULL) {
1179                 /*
1180                  * The following allows permanent links to be specified as
1181                  * using the default source address (i.e. device interface
1182                  * address) without knowing in advance what that address
1183                  * is.
1184                  */
1185                 if (la->aliasAddress.s_addr != INADDR_ANY &&
1186                     src_addr.s_addr == la->aliasAddress.s_addr) {
1187                         lnk = _FindLinkOut(la, la->nullAddress, dst_addr, src_port, dst_port,
1188                             link_type, replace_partial_links);
1189                 }
1190         }
1191         return (lnk);
1192 }
1193
1194
1195 static struct alias_link *
1196 _FindLinkIn(struct libalias *la, struct in_addr dst_addr,
1197     struct in_addr alias_addr,
1198     u_short dst_port,
1199     u_short alias_port,
1200     int link_type,
1201     int replace_partial_links)
1202 {
1203         int flags_in;
1204         u_int start_point;
1205         struct alias_link *lnk;
1206         struct alias_link *lnk_fully_specified;
1207         struct alias_link *lnk_unknown_all;
1208         struct alias_link *lnk_unknown_dst_addr;
1209         struct alias_link *lnk_unknown_dst_port;
1210
1211 /* Initialize pointers */
1212         lnk_fully_specified = NULL;
1213         lnk_unknown_all = NULL;
1214         lnk_unknown_dst_addr = NULL;
1215         lnk_unknown_dst_port = NULL;
1216
1217 /* If either the dest addr or port is unknown, the search
1218    loop will have to know about this. */
1219
1220         flags_in = 0;
1221         if (dst_addr.s_addr == INADDR_ANY)
1222                 flags_in |= LINK_UNKNOWN_DEST_ADDR;
1223         if (dst_port == 0)
1224                 flags_in |= LINK_UNKNOWN_DEST_PORT;
1225
1226 /* Search loop */
1227         start_point = StartPointIn(alias_addr, alias_port, link_type);
1228         LIST_FOREACH(lnk, &la->linkTableIn[start_point], list_in) {
1229                 int flags;
1230
1231                 flags = flags_in | lnk->flags;
1232                 if (!(flags & LINK_PARTIALLY_SPECIFIED)) {
1233                         if (lnk->alias_addr.s_addr == alias_addr.s_addr
1234                             && lnk->alias_port == alias_port
1235                             && lnk->dst_addr.s_addr == dst_addr.s_addr
1236                             && lnk->dst_port == dst_port
1237                             && lnk->link_type == link_type) {
1238                                 lnk_fully_specified = lnk;
1239                                 break;
1240                         }
1241                 } else if ((flags & LINK_UNKNOWN_DEST_ADDR)
1242                     && (flags & LINK_UNKNOWN_DEST_PORT)) {
1243                         if (lnk->alias_addr.s_addr == alias_addr.s_addr
1244                             && lnk->alias_port == alias_port
1245                             && lnk->link_type == link_type) {
1246                                 if (lnk_unknown_all == NULL)
1247                                         lnk_unknown_all = lnk;
1248                         }
1249                 } else if (flags & LINK_UNKNOWN_DEST_ADDR) {
1250                         if (lnk->alias_addr.s_addr == alias_addr.s_addr
1251                             && lnk->alias_port == alias_port
1252                             && lnk->link_type == link_type
1253                             && lnk->dst_port == dst_port) {
1254                                 if (lnk_unknown_dst_addr == NULL)
1255                                         lnk_unknown_dst_addr = lnk;
1256                         }
1257                 } else if (flags & LINK_UNKNOWN_DEST_PORT) {
1258                         if (lnk->alias_addr.s_addr == alias_addr.s_addr
1259                             && lnk->alias_port == alias_port
1260                             && lnk->link_type == link_type
1261                             && lnk->dst_addr.s_addr == dst_addr.s_addr) {
1262                                 if (lnk_unknown_dst_port == NULL)
1263                                         lnk_unknown_dst_port = lnk;
1264                         }
1265                 }
1266         }
1267
1268
1269
1270         if (lnk_fully_specified != NULL) {
1271                 lnk_fully_specified->timestamp = la->timeStamp;
1272                 lnk = lnk_fully_specified;
1273         } else if (lnk_unknown_dst_port != NULL)
1274                 lnk = lnk_unknown_dst_port;
1275         else if (lnk_unknown_dst_addr != NULL)
1276                 lnk = lnk_unknown_dst_addr;
1277         else if (lnk_unknown_all != NULL)
1278                 lnk = lnk_unknown_all;
1279         else
1280                 return (NULL);
1281
1282         if (replace_partial_links &&
1283             (lnk->flags & LINK_PARTIALLY_SPECIFIED || lnk->server != NULL)) {
1284                 struct in_addr src_addr;
1285                 u_short src_port;
1286
1287                 if (lnk->server != NULL) {      /* LSNAT link */
1288                         src_addr = lnk->server->addr;
1289                         src_port = lnk->server->port;
1290                         lnk->server = lnk->server->next;
1291                 } else {
1292                         src_addr = lnk->src_addr;
1293                         src_port = lnk->src_port;
1294                 }
1295
1296                 lnk = ReLink(lnk,
1297                     src_addr, dst_addr, alias_addr,
1298                     src_port, dst_port, alias_port,
1299                     link_type);
1300         }
1301         return (lnk);
1302 }
1303
1304 static struct alias_link *
1305 FindLinkIn(struct libalias *la, struct in_addr dst_addr,
1306     struct in_addr alias_addr,
1307     u_short dst_port,
1308     u_short alias_port,
1309     int link_type,
1310     int replace_partial_links)
1311 {
1312         struct alias_link *lnk;
1313
1314         lnk = _FindLinkIn(la, dst_addr, alias_addr, dst_port, alias_port,
1315             link_type, replace_partial_links);
1316
1317         if (lnk == NULL) {
1318                 /*
1319                  * The following allows permanent links to be specified as
1320                  * using the default aliasing address (i.e. device
1321                  * interface address) without knowing in advance what that
1322                  * address is.
1323                  */
1324                 if (la->aliasAddress.s_addr != INADDR_ANY &&
1325                     alias_addr.s_addr == la->aliasAddress.s_addr) {
1326                         lnk = _FindLinkIn(la, dst_addr, la->nullAddress, dst_port, alias_port,
1327                             link_type, replace_partial_links);
1328                 }
1329         }
1330         return (lnk);
1331 }
1332
1333
1334
1335
1336 /* External routines for finding/adding links
1337
1338 -- "external" means outside alias_db.c, but within alias*.c --
1339
1340     FindIcmpIn(), FindIcmpOut()
1341     FindFragmentIn1(), FindFragmentIn2()
1342     AddFragmentPtrLink(), FindFragmentPtr()
1343     FindProtoIn(), FindProtoOut()
1344     FindUdpTcpIn(), FindUdpTcpOut()
1345     AddPptp(), FindPptpOutByCallId(), FindPptpInByCallId(),
1346     FindPptpOutByPeerCallId(), FindPptpInByPeerCallId()
1347     FindOriginalAddress(), FindAliasAddress()
1348
1349 (prototypes in alias_local.h)
1350 */
1351
1352
1353 struct alias_link *
1354 FindIcmpIn(struct libalias *la, struct in_addr dst_addr,
1355     struct in_addr alias_addr,
1356     u_short id_alias,
1357     int create)
1358 {
1359         struct alias_link *lnk;
1360
1361         lnk = FindLinkIn(la, dst_addr, alias_addr,
1362             NO_DEST_PORT, id_alias,
1363             LINK_ICMP, 0);
1364         if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1365                 struct in_addr target_addr;
1366
1367                 target_addr = FindOriginalAddress(la, alias_addr);
1368                 lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1369                     id_alias, NO_DEST_PORT, id_alias,
1370                     LINK_ICMP);
1371         }
1372         return (lnk);
1373 }
1374
1375
1376 struct alias_link *
1377 FindIcmpOut(struct libalias *la, struct in_addr src_addr,
1378     struct in_addr dst_addr,
1379     u_short id,
1380     int create)
1381 {
1382         struct alias_link *lnk;
1383
1384         lnk = FindLinkOut(la, src_addr, dst_addr,
1385             id, NO_DEST_PORT,
1386             LINK_ICMP, 0);
1387         if (lnk == NULL && create) {
1388                 struct in_addr alias_addr;
1389
1390                 alias_addr = FindAliasAddress(la, src_addr);
1391                 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1392                     id, NO_DEST_PORT, GET_ALIAS_ID,
1393                     LINK_ICMP);
1394         }
1395         return (lnk);
1396 }
1397
1398
1399 struct alias_link *
1400 FindFragmentIn1(struct libalias *la, struct in_addr dst_addr,
1401     struct in_addr alias_addr,
1402     u_short ip_id)
1403 {
1404         struct alias_link *lnk;
1405
1406         lnk = FindLinkIn(la, dst_addr, alias_addr,
1407             NO_DEST_PORT, ip_id,
1408             LINK_FRAGMENT_ID, 0);
1409
1410         if (lnk == NULL) {
1411                 lnk = AddLink(la, la->nullAddress, dst_addr, alias_addr,
1412                     NO_SRC_PORT, NO_DEST_PORT, ip_id,
1413                     LINK_FRAGMENT_ID);
1414         }
1415         return (lnk);
1416 }
1417
1418
1419 struct alias_link *
1420 FindFragmentIn2(struct libalias *la, struct in_addr dst_addr,   /* Doesn't add a link if
1421                                                                  * one */
1422     struct in_addr alias_addr,  /* is not found.           */
1423     u_short ip_id)
1424 {
1425         return FindLinkIn(la, dst_addr, alias_addr,
1426             NO_DEST_PORT, ip_id,
1427             LINK_FRAGMENT_ID, 0);
1428 }
1429
1430
1431 struct alias_link *
1432 AddFragmentPtrLink(struct libalias *la, struct in_addr dst_addr,
1433     u_short ip_id)
1434 {
1435         return AddLink(la, la->nullAddress, dst_addr, la->nullAddress,
1436             NO_SRC_PORT, NO_DEST_PORT, ip_id,
1437             LINK_FRAGMENT_PTR);
1438 }
1439
1440
1441 struct alias_link *
1442 FindFragmentPtr(struct libalias *la, struct in_addr dst_addr,
1443     u_short ip_id)
1444 {
1445         return FindLinkIn(la, dst_addr, la->nullAddress,
1446             NO_DEST_PORT, ip_id,
1447             LINK_FRAGMENT_PTR, 0);
1448 }
1449
1450
1451 struct alias_link *
1452 FindProtoIn(struct libalias *la, struct in_addr dst_addr,
1453     struct in_addr alias_addr,
1454     u_char proto)
1455 {
1456         struct alias_link *lnk;
1457
1458         lnk = FindLinkIn(la, dst_addr, alias_addr,
1459             NO_DEST_PORT, 0,
1460             proto, 1);
1461
1462         if (lnk == NULL && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1463                 struct in_addr target_addr;
1464
1465                 target_addr = FindOriginalAddress(la, alias_addr);
1466                 lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1467                     NO_SRC_PORT, NO_DEST_PORT, 0,
1468                     proto);
1469         }
1470         return (lnk);
1471 }
1472
1473
1474 struct alias_link *
1475 FindProtoOut(struct libalias *la, struct in_addr src_addr,
1476     struct in_addr dst_addr,
1477     u_char proto)
1478 {
1479         struct alias_link *lnk;
1480
1481         lnk = FindLinkOut(la, src_addr, dst_addr,
1482             NO_SRC_PORT, NO_DEST_PORT,
1483             proto, 1);
1484
1485         if (lnk == NULL) {
1486                 struct in_addr alias_addr;
1487
1488                 alias_addr = FindAliasAddress(la, src_addr);
1489                 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1490                     NO_SRC_PORT, NO_DEST_PORT, 0,
1491                     proto);
1492         }
1493         return (lnk);
1494 }
1495
1496
1497 struct alias_link *
1498 FindUdpTcpIn(struct libalias *la, struct in_addr dst_addr,
1499     struct in_addr alias_addr,
1500     u_short dst_port,
1501     u_short alias_port,
1502     u_char proto,
1503     int create)
1504 {
1505         int link_type;
1506         struct alias_link *lnk;
1507
1508         switch (proto) {
1509         case IPPROTO_UDP:
1510                 link_type = LINK_UDP;
1511                 break;
1512         case IPPROTO_TCP:
1513                 link_type = LINK_TCP;
1514                 break;
1515         default:
1516                 return (NULL);
1517                 break;
1518         }
1519
1520         lnk = FindLinkIn(la, dst_addr, alias_addr,
1521             dst_port, alias_port,
1522             link_type, create);
1523
1524         if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1525                 struct in_addr target_addr;
1526
1527                 target_addr = FindOriginalAddress(la, alias_addr);
1528                 lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1529                     alias_port, dst_port, alias_port,
1530                     link_type);
1531         }
1532         return (lnk);
1533 }
1534
1535
1536 struct alias_link *
1537 FindUdpTcpOut(struct libalias *la, struct in_addr src_addr,
1538     struct in_addr dst_addr,
1539     u_short src_port,
1540     u_short dst_port,
1541     u_char proto,
1542     int create)
1543 {
1544         int link_type;
1545         struct alias_link *lnk;
1546
1547         switch (proto) {
1548         case IPPROTO_UDP:
1549                 link_type = LINK_UDP;
1550                 break;
1551         case IPPROTO_TCP:
1552                 link_type = LINK_TCP;
1553                 break;
1554         default:
1555                 return (NULL);
1556                 break;
1557         }
1558
1559         lnk = FindLinkOut(la, src_addr, dst_addr, src_port, dst_port, link_type, create);
1560
1561         if (lnk == NULL && create) {
1562                 struct in_addr alias_addr;
1563
1564                 alias_addr = FindAliasAddress(la, src_addr);
1565                 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1566                     src_port, dst_port, GET_ALIAS_PORT,
1567                     link_type);
1568         }
1569         return (lnk);
1570 }
1571
1572
1573 struct alias_link *
1574 AddPptp(struct libalias *la, struct in_addr src_addr,
1575     struct in_addr dst_addr,
1576     struct in_addr alias_addr,
1577     u_int16_t src_call_id)
1578 {
1579         struct alias_link *lnk;
1580
1581         lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1582             src_call_id, 0, GET_ALIAS_PORT,
1583             LINK_PPTP);
1584
1585         return (lnk);
1586 }
1587
1588
1589 struct alias_link *
1590 FindPptpOutByCallId(struct libalias *la, struct in_addr src_addr,
1591     struct in_addr dst_addr,
1592     u_int16_t src_call_id)
1593 {
1594         u_int i;
1595         struct alias_link *lnk;
1596
1597         i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1598         LIST_FOREACH(lnk, &la->linkTableOut[i], list_out)
1599             if (lnk->link_type == LINK_PPTP &&
1600             lnk->src_addr.s_addr == src_addr.s_addr &&
1601             lnk->dst_addr.s_addr == dst_addr.s_addr &&
1602             lnk->src_port == src_call_id)
1603                 break;
1604
1605         return (lnk);
1606 }
1607
1608
1609 struct alias_link *
1610 FindPptpOutByPeerCallId(struct libalias *la, struct in_addr src_addr,
1611     struct in_addr dst_addr,
1612     u_int16_t dst_call_id)
1613 {
1614         u_int i;
1615         struct alias_link *lnk;
1616
1617         i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1618         LIST_FOREACH(lnk, &la->linkTableOut[i], list_out)
1619             if (lnk->link_type == LINK_PPTP &&
1620             lnk->src_addr.s_addr == src_addr.s_addr &&
1621             lnk->dst_addr.s_addr == dst_addr.s_addr &&
1622             lnk->dst_port == dst_call_id)
1623                 break;
1624
1625         return (lnk);
1626 }
1627
1628
1629 struct alias_link *
1630 FindPptpInByCallId(struct libalias *la, struct in_addr dst_addr,
1631     struct in_addr alias_addr,
1632     u_int16_t dst_call_id)
1633 {
1634         u_int i;
1635         struct alias_link *lnk;
1636
1637         i = StartPointIn(alias_addr, 0, LINK_PPTP);
1638         LIST_FOREACH(lnk, &la->linkTableIn[i], list_in)
1639             if (lnk->link_type == LINK_PPTP &&
1640             lnk->dst_addr.s_addr == dst_addr.s_addr &&
1641             lnk->alias_addr.s_addr == alias_addr.s_addr &&
1642             lnk->dst_port == dst_call_id)
1643                 break;
1644
1645         return (lnk);
1646 }
1647
1648
1649 struct alias_link *
1650 FindPptpInByPeerCallId(struct libalias *la, struct in_addr dst_addr,
1651     struct in_addr alias_addr,
1652     u_int16_t alias_call_id)
1653 {
1654         struct alias_link *lnk;
1655
1656         lnk = FindLinkIn(la, dst_addr, alias_addr,
1657             0 /* any */ , alias_call_id,
1658             LINK_PPTP, 0);
1659
1660
1661         return (lnk);
1662 }
1663
1664
1665 struct alias_link *
1666 FindRtspOut(struct libalias *la, struct in_addr src_addr,
1667     struct in_addr dst_addr,
1668     u_short src_port,
1669     u_short alias_port,
1670     u_char proto)
1671 {
1672         int link_type;
1673         struct alias_link *lnk;
1674
1675         switch (proto) {
1676         case IPPROTO_UDP:
1677                 link_type = LINK_UDP;
1678                 break;
1679         case IPPROTO_TCP:
1680                 link_type = LINK_TCP;
1681                 break;
1682         default:
1683                 return (NULL);
1684                 break;
1685         }
1686
1687         lnk = FindLinkOut(la, src_addr, dst_addr, src_port, 0, link_type, 1);
1688
1689         if (lnk == NULL) {
1690                 struct in_addr alias_addr;
1691
1692                 alias_addr = FindAliasAddress(la, src_addr);
1693                 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1694                     src_port, 0, alias_port,
1695                     link_type);
1696         }
1697         return (lnk);
1698 }
1699
1700
1701 struct in_addr
1702 FindOriginalAddress(struct libalias *la, struct in_addr alias_addr)
1703 {
1704         struct alias_link *lnk;
1705
1706         lnk = FindLinkIn(la, la->nullAddress, alias_addr,
1707             0, 0, LINK_ADDR, 0);
1708         if (lnk == NULL) {
1709                 la->newDefaultLink = 1;
1710                 if (la->targetAddress.s_addr == INADDR_ANY)
1711                         return (alias_addr);
1712                 else if (la->targetAddress.s_addr == INADDR_NONE)
1713                         return (la->aliasAddress.s_addr != INADDR_ANY) ?
1714                             la->aliasAddress : alias_addr;
1715                 else
1716                         return (la->targetAddress);
1717         } else {
1718                 if (lnk->server != NULL) {      /* LSNAT link */
1719                         struct in_addr src_addr;
1720
1721                         src_addr = lnk->server->addr;
1722                         lnk->server = lnk->server->next;
1723                         return (src_addr);
1724                 } else if (lnk->src_addr.s_addr == INADDR_ANY)
1725                         return (la->aliasAddress.s_addr != INADDR_ANY) ?
1726                             la->aliasAddress : alias_addr;
1727                 else
1728                         return (lnk->src_addr);
1729         }
1730 }
1731
1732
1733 struct in_addr
1734 FindAliasAddress(struct libalias *la, struct in_addr original_addr)
1735 {
1736         struct alias_link *lnk;
1737
1738         lnk = FindLinkOut(la, original_addr, la->nullAddress,
1739             0, 0, LINK_ADDR, 0);
1740         if (lnk == NULL) {
1741                 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1742                     la->aliasAddress : original_addr;
1743         } else {
1744                 if (lnk->alias_addr.s_addr == INADDR_ANY)
1745                         return (la->aliasAddress.s_addr != INADDR_ANY) ?
1746                             la->aliasAddress : original_addr;
1747                 else
1748                         return (lnk->alias_addr);
1749         }
1750 }
1751
1752
1753 /* External routines for getting or changing link data
1754    (external to alias_db.c, but internal to alias*.c)
1755
1756     SetFragmentData(), GetFragmentData()
1757     SetFragmentPtr(), GetFragmentPtr()
1758     SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut()
1759     GetOriginalAddress(), GetDestAddress(), GetAliasAddress()
1760     GetOriginalPort(), GetAliasPort()
1761     SetAckModified(), GetAckModified()
1762     GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq()
1763     SetProtocolFlags(), GetProtocolFlags()
1764     SetDestCallId()
1765 */
1766
1767
1768 void
1769 SetFragmentAddr(struct alias_link *lnk, struct in_addr src_addr)
1770 {
1771         lnk->data.frag_addr = src_addr;
1772 }
1773
1774
1775 void
1776 GetFragmentAddr(struct alias_link *lnk, struct in_addr *src_addr)
1777 {
1778         *src_addr = lnk->data.frag_addr;
1779 }
1780
1781
1782 void
1783 SetFragmentPtr(struct alias_link *lnk, char *fptr)
1784 {
1785         lnk->data.frag_ptr = fptr;
1786 }
1787
1788
1789 void
1790 GetFragmentPtr(struct alias_link *lnk, char **fptr)
1791 {
1792         *fptr = lnk->data.frag_ptr;
1793 }
1794
1795
1796 void
1797 SetStateIn(struct alias_link *lnk, int state)
1798 {
1799         /* TCP input state */
1800         switch (state) {
1801                 case ALIAS_TCP_STATE_DISCONNECTED:
1802                 if (lnk->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED)
1803                         lnk->expire_time = TCP_EXPIRE_DEAD;
1804                 else
1805                         lnk->expire_time = TCP_EXPIRE_SINGLEDEAD;
1806                 break;
1807         case ALIAS_TCP_STATE_CONNECTED:
1808                 if (lnk->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED)
1809                         lnk->expire_time = TCP_EXPIRE_CONNECTED;
1810                 break;
1811         default:
1812 #ifdef  _KERNEL
1813                 panic("libalias:SetStateIn() unknown state");
1814 #else
1815                 abort();
1816 #endif
1817         }
1818         lnk->data.tcp->state.in = state;
1819 }
1820
1821
1822 void
1823 SetStateOut(struct alias_link *lnk, int state)
1824 {
1825         /* TCP output state */
1826         switch (state) {
1827                 case ALIAS_TCP_STATE_DISCONNECTED:
1828                 if (lnk->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED)
1829                         lnk->expire_time = TCP_EXPIRE_DEAD;
1830                 else
1831                         lnk->expire_time = TCP_EXPIRE_SINGLEDEAD;
1832                 break;
1833         case ALIAS_TCP_STATE_CONNECTED:
1834                 if (lnk->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED)
1835                         lnk->expire_time = TCP_EXPIRE_CONNECTED;
1836                 break;
1837         default:
1838 #ifdef  _KERNEL
1839                 panic("libalias:SetStateOut() unknown state");
1840 #else
1841                 abort();
1842 #endif
1843         }
1844         lnk->data.tcp->state.out = state;
1845 }
1846
1847
1848 int
1849 GetStateIn(struct alias_link *lnk)
1850 {
1851         /* TCP input state */
1852         return (lnk->data.tcp->state.in);
1853 }
1854
1855
1856 int
1857 GetStateOut(struct alias_link *lnk)
1858 {
1859         /* TCP output state */
1860         return (lnk->data.tcp->state.out);
1861 }
1862
1863
1864 struct in_addr
1865 GetOriginalAddress(struct alias_link *lnk)
1866 {
1867         if (lnk->src_addr.s_addr == INADDR_ANY)
1868                 return (lnk->la->aliasAddress);
1869         else
1870                 return (lnk->src_addr);
1871 }
1872
1873
1874 struct in_addr
1875 GetDestAddress(struct alias_link *lnk)
1876 {
1877         return (lnk->dst_addr);
1878 }
1879
1880
1881 struct in_addr
1882 GetAliasAddress(struct alias_link *lnk)
1883 {
1884         if (lnk->alias_addr.s_addr == INADDR_ANY)
1885                 return (lnk->la->aliasAddress);
1886         else
1887                 return (lnk->alias_addr);
1888 }
1889
1890
1891 struct in_addr
1892 GetDefaultAliasAddress(struct libalias *la)
1893 {
1894         return (la->aliasAddress);
1895 }
1896
1897
1898 void
1899 SetDefaultAliasAddress(struct libalias *la, struct in_addr alias_addr)
1900 {
1901         la->aliasAddress = alias_addr;
1902 }
1903
1904
1905 u_short
1906 GetOriginalPort(struct alias_link *lnk)
1907 {
1908         return (lnk->src_port);
1909 }
1910
1911
1912 u_short
1913 GetAliasPort(struct alias_link *lnk)
1914 {
1915         return (lnk->alias_port);
1916 }
1917
1918 #ifndef NO_FW_PUNCH
1919 static          u_short
1920 GetDestPort(struct alias_link *lnk)
1921 {
1922         return (lnk->dst_port);
1923 }
1924
1925 #endif
1926
1927 void
1928 SetAckModified(struct alias_link *lnk)
1929 {
1930 /* Indicate that ACK numbers have been modified in a TCP connection */
1931         lnk->data.tcp->state.ack_modified = 1;
1932 }
1933
1934
1935 struct in_addr
1936 GetProxyAddress(struct alias_link *lnk)
1937 {
1938         return (lnk->proxy_addr);
1939 }
1940
1941
1942 void
1943 SetProxyAddress(struct alias_link *lnk, struct in_addr addr)
1944 {
1945         lnk->proxy_addr = addr;
1946 }
1947
1948
1949 u_short
1950 GetProxyPort(struct alias_link *lnk)
1951 {
1952         return (lnk->proxy_port);
1953 }
1954
1955
1956 void
1957 SetProxyPort(struct alias_link *lnk, u_short port)
1958 {
1959         lnk->proxy_port = port;
1960 }
1961
1962
1963 int
1964 GetAckModified(struct alias_link *lnk)
1965 {
1966 /* See if ACK numbers have been modified */
1967         return (lnk->data.tcp->state.ack_modified);
1968 }
1969
1970
1971 int
1972 GetDeltaAckIn(struct ip *pip, struct alias_link *lnk)
1973 {
1974 /*
1975 Find out how much the ACK number has been altered for an incoming
1976 TCP packet.  To do this, a circular list of ACK numbers where the TCP
1977 packet size was altered is searched.
1978 */
1979
1980         int i;
1981         struct tcphdr *tc;
1982         int delta, ack_diff_min;
1983         u_long ack;
1984
1985         tc = ip_next(pip);
1986         ack = tc->th_ack;
1987
1988         delta = 0;
1989         ack_diff_min = -1;
1990         for (i = 0; i < N_LINK_TCP_DATA; i++) {
1991                 struct ack_data_record x;
1992
1993                 x = lnk->data.tcp->ack[i];
1994                 if (x.active == 1) {
1995                         int ack_diff;
1996
1997                         ack_diff = SeqDiff(x.ack_new, ack);
1998                         if (ack_diff >= 0) {
1999                                 if (ack_diff_min >= 0) {
2000                                         if (ack_diff < ack_diff_min) {
2001                                                 delta = x.delta;
2002                                                 ack_diff_min = ack_diff;
2003                                         }
2004                                 } else {
2005                                         delta = x.delta;
2006                                         ack_diff_min = ack_diff;
2007                                 }
2008                         }
2009                 }
2010         }
2011         return (delta);
2012 }
2013
2014
2015 int
2016 GetDeltaSeqOut(struct ip *pip, struct alias_link *lnk)
2017 {
2018 /*
2019 Find out how much the sequence number has been altered for an outgoing
2020 TCP packet.  To do this, a circular list of ACK numbers where the TCP
2021 packet size was altered is searched.
2022 */
2023
2024         int i;
2025         struct tcphdr *tc;
2026         int delta, seq_diff_min;
2027         u_long seq;
2028
2029         tc = ip_next(pip);
2030         seq = tc->th_seq;
2031
2032         delta = 0;
2033         seq_diff_min = -1;
2034         for (i = 0; i < N_LINK_TCP_DATA; i++) {
2035                 struct ack_data_record x;
2036
2037                 x = lnk->data.tcp->ack[i];
2038                 if (x.active == 1) {
2039                         int seq_diff;
2040
2041                         seq_diff = SeqDiff(x.ack_old, seq);
2042                         if (seq_diff >= 0) {
2043                                 if (seq_diff_min >= 0) {
2044                                         if (seq_diff < seq_diff_min) {
2045                                                 delta = x.delta;
2046                                                 seq_diff_min = seq_diff;
2047                                         }
2048                                 } else {
2049                                         delta = x.delta;
2050                                         seq_diff_min = seq_diff;
2051                                 }
2052                         }
2053                 }
2054         }
2055         return (delta);
2056 }
2057
2058
2059 void
2060 AddSeq(struct ip *pip, struct alias_link *lnk, int delta)
2061 {
2062 /*
2063 When a TCP packet has been altered in length, save this
2064 information in a circular list.  If enough packets have
2065 been altered, then this list will begin to overwrite itself.
2066 */
2067
2068         struct tcphdr *tc;
2069         struct ack_data_record x;
2070         int hlen, tlen, dlen;
2071         int i;
2072
2073         tc = ip_next(pip);
2074
2075         hlen = (pip->ip_hl + tc->th_off) << 2;
2076         tlen = ntohs(pip->ip_len);
2077         dlen = tlen - hlen;
2078
2079         x.ack_old = htonl(ntohl(tc->th_seq) + dlen);
2080         x.ack_new = htonl(ntohl(tc->th_seq) + dlen + delta);
2081         x.delta = delta;
2082         x.active = 1;
2083
2084         i = lnk->data.tcp->state.index;
2085         lnk->data.tcp->ack[i] = x;
2086
2087         i++;
2088         if (i == N_LINK_TCP_DATA)
2089                 lnk->data.tcp->state.index = 0;
2090         else
2091                 lnk->data.tcp->state.index = i;
2092 }
2093
2094 void
2095 SetExpire(struct alias_link *lnk, int expire)
2096 {
2097         if (expire == 0) {
2098                 lnk->flags &= ~LINK_PERMANENT;
2099                 DeleteLink(lnk);
2100         } else if (expire == -1) {
2101                 lnk->flags |= LINK_PERMANENT;
2102         } else if (expire > 0) {
2103                 lnk->expire_time = expire;
2104         } else {
2105 #ifdef LIBALIAS_DEBUG
2106                 fprintf(stderr, "PacketAlias/SetExpire(): ");
2107                 fprintf(stderr, "error in expire parameter\n");
2108 #endif
2109         }
2110 }
2111
2112 void
2113 ClearCheckNewLink(struct libalias *la)
2114 {
2115         la->newDefaultLink = 0;
2116 }
2117
2118 void
2119 SetProtocolFlags(struct alias_link *lnk, int pflags)
2120 {
2121
2122         lnk->pflags = pflags;;
2123 }
2124
2125 int
2126 GetProtocolFlags(struct alias_link *lnk)
2127 {
2128
2129         return (lnk->pflags);
2130 }
2131
2132 void
2133 SetDestCallId(struct alias_link *lnk, u_int16_t cid)
2134 {
2135         struct libalias *la = lnk->la;
2136
2137         la->deleteAllLinks = 1;
2138         lnk = ReLink(lnk, lnk->src_addr, lnk->dst_addr, lnk->alias_addr,
2139             lnk->src_port, cid, lnk->alias_port, lnk->link_type);
2140         la->deleteAllLinks = 0;
2141 }
2142
2143
2144 /* Miscellaneous Functions
2145
2146     HouseKeeping()
2147     InitPacketAliasLog()
2148     UninitPacketAliasLog()
2149 */
2150
2151 /*
2152     Whenever an outgoing or incoming packet is handled, HouseKeeping()
2153     is called to find and remove timed-out aliasing links.  Logic exists
2154     to sweep through the entire table and linked list structure
2155     every 60 seconds.
2156
2157     (prototype in alias_local.h)
2158 */
2159
2160 void
2161 HouseKeeping(struct libalias *la)
2162 {
2163         int i, n, n100;
2164 #ifndef _KERNEL
2165         struct timeval tv;
2166         struct timezone tz;
2167 #endif
2168
2169         /*
2170          * Save system time (seconds) in global variable timeStamp for use
2171          * by other functions. This is done so as not to unnecessarily
2172          * waste timeline by making system calls.
2173          */
2174 #ifdef  _KERNEL
2175         la->timeStamp = time_uptime;
2176 #else
2177         gettimeofday(&tv, &tz);
2178         la->timeStamp = tv.tv_sec;
2179 #endif
2180
2181         /* Compute number of spokes (output table link chains) to cover */
2182         n100 = LINK_TABLE_OUT_SIZE * 100 + la->houseKeepingResidual;
2183         n100 *= la->timeStamp - la->lastCleanupTime;
2184         n100 /= ALIAS_CLEANUP_INTERVAL_SECS;
2185
2186         n = n100 / 100;
2187
2188         /* Handle different cases */
2189         if (n > ALIAS_CLEANUP_MAX_SPOKES) {
2190                 n = ALIAS_CLEANUP_MAX_SPOKES;
2191                 la->lastCleanupTime = la->timeStamp;
2192                 la->houseKeepingResidual = 0;
2193
2194                 for (i = 0; i < n; i++)
2195                         IncrementalCleanup(la);
2196         } else if (n > 0) {
2197                 la->lastCleanupTime = la->timeStamp;
2198                 la->houseKeepingResidual = n100 - 100 * n;
2199
2200                 for (i = 0; i < n; i++)
2201                         IncrementalCleanup(la);
2202         } else if (n < 0) {
2203 #ifdef LIBALIAS_DEBUG
2204                 fprintf(stderr, "PacketAlias/HouseKeeping(): ");
2205                 fprintf(stderr, "something unexpected in time values\n");
2206 #endif
2207                 la->lastCleanupTime = la->timeStamp;
2208                 la->houseKeepingResidual = 0;
2209         }
2210 }
2211
2212 /* Init the log file and enable logging */
2213 static int
2214 InitPacketAliasLog(struct libalias *la)
2215 {
2216         if (~la->packetAliasMode & PKT_ALIAS_LOG) {
2217 #ifdef _KERNEL
2218                 if ((la->logDesc = malloc(LIBALIAS_BUF_SIZE)))
2219                         ;
2220 #else           
2221                 if ((la->logDesc = fopen("/var/log/alias.log", "w")))
2222                         fprintf(la->logDesc, "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");               
2223 #endif
2224                 else 
2225                         return (ENOMEM); /* log initialization failed */
2226                 la->packetAliasMode |= PKT_ALIAS_LOG;
2227         }
2228
2229         return (1);
2230 }
2231
2232 /* Close the log-file and disable logging. */
2233 static void
2234 UninitPacketAliasLog(struct libalias *la)
2235 {
2236                 if (la->logDesc) {
2237 #ifdef _KERNEL
2238                         free(la->logDesc);
2239 #else
2240                         fclose(la->logDesc);
2241 #endif
2242                         la->logDesc = NULL;
2243                 }
2244         la->packetAliasMode &= ~PKT_ALIAS_LOG;
2245 }
2246
2247 /* Outside world interfaces
2248
2249 -- "outside world" means other than alias*.c routines --
2250
2251     PacketAliasRedirectPort()
2252     PacketAliasAddServer()
2253     PacketAliasRedirectProto()
2254     PacketAliasRedirectAddr()
2255     PacketAliasRedirectDynamic()
2256     PacketAliasRedirectDelete()
2257     PacketAliasSetAddress()
2258     PacketAliasInit()
2259     PacketAliasUninit()
2260     PacketAliasSetMode()
2261
2262 (prototypes in alias.h)
2263 */
2264
2265 /* Redirection from a specific public addr:port to a
2266    private addr:port */
2267 struct alias_link *
2268 LibAliasRedirectPort(struct libalias *la, struct in_addr src_addr, u_short src_port,
2269     struct in_addr dst_addr, u_short dst_port,
2270     struct in_addr alias_addr, u_short alias_port,
2271     u_char proto)
2272 {
2273         int link_type;
2274         struct alias_link *lnk;
2275
2276         switch (proto) {
2277         case IPPROTO_UDP:
2278                 link_type = LINK_UDP;
2279                 break;
2280         case IPPROTO_TCP:
2281                 link_type = LINK_TCP;
2282                 break;
2283         default:
2284 #ifdef LIBALIAS_DEBUG
2285                 fprintf(stderr, "PacketAliasRedirectPort(): ");
2286                 fprintf(stderr, "only TCP and UDP protocols allowed\n");
2287 #endif
2288                 return (NULL);
2289         }
2290
2291         lnk = AddLink(la, src_addr, dst_addr, alias_addr,
2292             src_port, dst_port, alias_port,
2293             link_type);
2294
2295         if (lnk != NULL) {
2296                 lnk->flags |= LINK_PERMANENT;
2297         }
2298 #ifdef LIBALIAS_DEBUG
2299         else {
2300                 fprintf(stderr, "PacketAliasRedirectPort(): "
2301                     "call to AddLink() failed\n");
2302         }
2303 #endif
2304
2305         return (lnk);
2306 }
2307
2308 /* Add server to the pool of servers */
2309 int
2310 LibAliasAddServer(struct libalias *la, struct alias_link *lnk, struct in_addr addr, u_short port)
2311 {
2312         struct server *server;
2313
2314         (void)la;
2315
2316         server = malloc(sizeof(struct server));
2317
2318         if (server != NULL) {
2319                 struct server *head;
2320
2321                 server->addr = addr;
2322                 server->port = port;
2323
2324                 head = lnk->server;
2325                 if (head == NULL)
2326                         server->next = server;
2327                 else {
2328                         struct server *s;
2329
2330                         for (s = head; s->next != head; s = s->next);
2331                         s->next = server;
2332                         server->next = head;
2333                 }
2334                 lnk->server = server;
2335                 return (0);
2336         } else
2337                 return (-1);
2338 }
2339
2340 /* Redirect packets of a given IP protocol from a specific
2341    public address to a private address */
2342 struct alias_link *
2343 LibAliasRedirectProto(struct libalias *la, struct in_addr src_addr,
2344     struct in_addr dst_addr,
2345     struct in_addr alias_addr,
2346     u_char proto)
2347 {
2348         struct alias_link *lnk;
2349
2350         lnk = AddLink(la, src_addr, dst_addr, alias_addr,
2351             NO_SRC_PORT, NO_DEST_PORT, 0,
2352             proto);
2353
2354         if (lnk != NULL) {
2355                 lnk->flags |= LINK_PERMANENT;
2356         }
2357 #ifdef LIBALIAS_DEBUG
2358         else {
2359                 fprintf(stderr, "PacketAliasRedirectProto(): "
2360                     "call to AddLink() failed\n");
2361         }
2362 #endif
2363
2364         return (lnk);
2365 }
2366
2367 /* Static address translation */
2368 struct alias_link *
2369 LibAliasRedirectAddr(struct libalias *la, struct in_addr src_addr,
2370     struct in_addr alias_addr)
2371 {
2372         struct alias_link *lnk;
2373
2374         lnk = AddLink(la, src_addr, la->nullAddress, alias_addr,
2375             0, 0, 0,
2376             LINK_ADDR);
2377
2378         if (lnk != NULL) {
2379                 lnk->flags |= LINK_PERMANENT;
2380         }
2381 #ifdef LIBALIAS_DEBUG
2382         else {
2383                 fprintf(stderr, "PacketAliasRedirectAddr(): "
2384                     "call to AddLink() failed\n");
2385         }
2386 #endif
2387
2388         return (lnk);
2389 }
2390
2391
2392 /* Mark the aliasing link dynamic */
2393 int
2394 LibAliasRedirectDynamic(struct libalias *la, struct alias_link *lnk)
2395 {
2396
2397         (void)la;
2398
2399         if (lnk->flags & LINK_PARTIALLY_SPECIFIED)
2400                 return (-1);
2401         else {
2402                 lnk->flags &= ~LINK_PERMANENT;
2403                 return (0);
2404         }
2405 }
2406
2407
2408 void
2409 LibAliasRedirectDelete(struct libalias *la, struct alias_link *lnk)
2410 {
2411 /* This is a dangerous function to put in the API,
2412    because an invalid pointer can crash the program. */
2413
2414         la->deleteAllLinks = 1;
2415         DeleteLink(lnk);
2416         la->deleteAllLinks = 0;
2417 }
2418
2419
2420 void
2421 LibAliasSetAddress(struct libalias *la, struct in_addr addr)
2422 {
2423         if (la->packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE
2424             && la->aliasAddress.s_addr != addr.s_addr)
2425                 CleanupAliasData(la);
2426
2427         la->aliasAddress = addr;
2428 }
2429
2430
2431 void
2432 LibAliasSetTarget(struct libalias *la, struct in_addr target_addr)
2433 {
2434         la->targetAddress = target_addr;
2435 }
2436
2437 static void
2438 finishoff(void)
2439 {
2440
2441         while (!LIST_EMPTY(&instancehead))
2442                 LibAliasUninit(LIST_FIRST(&instancehead));
2443 }
2444
2445 struct libalias *
2446 LibAliasInit(struct libalias *la)
2447 {
2448         int i;
2449 #ifndef _KERNEL
2450         struct timeval tv;
2451         struct timezone tz;
2452 #endif
2453
2454         if (la == NULL) {
2455                 la = calloc(sizeof *la, 1);
2456                 if (la == NULL)
2457                         return (la);
2458
2459 #ifndef _KERNEL         /* kernel cleans up on module unload */
2460                 if (LIST_EMPTY(&instancehead))
2461                         atexit(finishoff);
2462 #endif
2463                 LIST_INSERT_HEAD(&instancehead, la, instancelist);
2464
2465 #ifdef  _KERNEL
2466                 la->timeStamp = time_uptime;
2467                 la->lastCleanupTime = time_uptime;
2468 #else
2469                 gettimeofday(&tv, &tz);
2470                 la->timeStamp = tv.tv_sec;
2471                 la->lastCleanupTime = tv.tv_sec;
2472 #endif
2473                 la->houseKeepingResidual = 0;
2474
2475                 for (i = 0; i < LINK_TABLE_OUT_SIZE; i++)
2476                         LIST_INIT(&la->linkTableOut[i]);
2477                 for (i = 0; i < LINK_TABLE_IN_SIZE; i++)
2478                         LIST_INIT(&la->linkTableIn[i]);
2479
2480         } else {
2481                 la->deleteAllLinks = 1;
2482                 CleanupAliasData(la);
2483                 la->deleteAllLinks = 0;
2484         }
2485
2486         la->aliasAddress.s_addr = INADDR_ANY;
2487         la->targetAddress.s_addr = INADDR_ANY;
2488
2489         la->icmpLinkCount = 0;
2490         la->udpLinkCount = 0;
2491         la->tcpLinkCount = 0;
2492         la->pptpLinkCount = 0;
2493         la->protoLinkCount = 0;
2494         la->fragmentIdLinkCount = 0;
2495         la->fragmentPtrLinkCount = 0;
2496         la->sockCount = 0;
2497
2498         la->cleanupIndex = 0;
2499
2500         la->packetAliasMode = PKT_ALIAS_SAME_PORTS
2501 #ifndef NO_USE_SOCKETS
2502             | PKT_ALIAS_USE_SOCKETS
2503 #endif
2504             | PKT_ALIAS_RESET_ON_ADDR_CHANGE;
2505 #ifndef NO_FW_PUNCH
2506         la->fireWallFD = -1;
2507 #endif
2508 #ifndef _KERNEL
2509         LibAliasRefreshModules();
2510 #endif
2511         return (la);
2512 }
2513
2514 void
2515 LibAliasUninit(struct libalias *la)
2516 {
2517         la->deleteAllLinks = 1;
2518         CleanupAliasData(la);
2519         la->deleteAllLinks = 0;
2520         UninitPacketAliasLog(la);
2521 #ifndef NO_FW_PUNCH
2522         UninitPunchFW(la);
2523 #endif
2524         LIST_REMOVE(la, instancelist);
2525         free(la);
2526 }
2527
2528 /* Change mode for some operations */
2529 unsigned int
2530 LibAliasSetMode(
2531     struct libalias *la,
2532     unsigned int flags,         /* Which state to bring flags to */
2533     unsigned int mask           /* Mask of which flags to affect (use 0 to
2534                                  * do a probe for flag values) */
2535 )
2536 {
2537 /* Enable logging? */
2538         if (flags & mask & PKT_ALIAS_LOG) {
2539                 /* Do the enable */
2540                 if (InitPacketAliasLog(la) == ENOMEM)
2541                         return (-1);
2542         } else
2543 /* _Disable_ logging? */
2544         if (~flags & mask & PKT_ALIAS_LOG) {
2545                 UninitPacketAliasLog(la);
2546         }
2547 #ifndef NO_FW_PUNCH
2548 /* Start punching holes in the firewall? */
2549         if (flags & mask & PKT_ALIAS_PUNCH_FW) {
2550                 InitPunchFW(la);
2551         } else
2552 /* Stop punching holes in the firewall? */
2553         if (~flags & mask & PKT_ALIAS_PUNCH_FW) {
2554                 UninitPunchFW(la);
2555         }
2556 #endif
2557
2558 /* Other flags can be set/cleared without special action */
2559         la->packetAliasMode = (flags & mask) | (la->packetAliasMode & ~mask);
2560         return (la->packetAliasMode);
2561 }
2562
2563
2564 int
2565 LibAliasCheckNewLink(struct libalias *la)
2566 {
2567         return (la->newDefaultLink);
2568 }
2569
2570
2571 #ifndef NO_FW_PUNCH
2572
2573 /*****************
2574   Code to support firewall punching.  This shouldn't really be in this
2575   file, but making variables global is evil too.
2576   ****************/
2577
2578 /* Firewall include files */
2579 #include <net/if.h>
2580 #include <netinet/ip_fw.h>
2581 #include <string.h>
2582 #include <err.h>
2583
2584 /*
2585  * helper function, updates the pointer to cmd with the length
2586  * of the current command, and also cleans up the first word of
2587  * the new command in case it has been clobbered before.
2588  */
2589 static ipfw_insn *
2590 next_cmd(ipfw_insn * cmd)
2591 {
2592         cmd += F_LEN(cmd);
2593         bzero(cmd, sizeof(*cmd));
2594         return (cmd);
2595 }
2596
2597 /*
2598  * A function to fill simple commands of size 1.
2599  * Existing flags are preserved.
2600  */
2601 static ipfw_insn *
2602 fill_cmd(ipfw_insn * cmd, enum ipfw_opcodes opcode, int size,
2603     int flags, u_int16_t arg)
2604 {
2605         cmd->opcode = opcode;
2606         cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | (size & F_LEN_MASK);
2607         cmd->arg1 = arg;
2608         return next_cmd(cmd);
2609 }
2610
2611 static ipfw_insn *
2612 fill_ip(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int32_t addr)
2613 {
2614         ipfw_insn_ip *cmd = (ipfw_insn_ip *) cmd1;
2615
2616         cmd->addr.s_addr = addr;
2617         return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u32), 0, 0);
2618 }
2619
2620 static ipfw_insn *
2621 fill_one_port(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int16_t port)
2622 {
2623         ipfw_insn_u16 *cmd = (ipfw_insn_u16 *) cmd1;
2624
2625         cmd->ports[0] = cmd->ports[1] = port;
2626         return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u16), 0, 0);
2627 }
2628
2629 static int
2630 fill_rule(void *buf, int bufsize, int rulenum,
2631     enum ipfw_opcodes action, int proto,
2632     struct in_addr sa, u_int16_t sp, struct in_addr da, u_int16_t dp)
2633 {
2634         struct ip_fw *rule = (struct ip_fw *)buf;
2635         ipfw_insn *cmd = (ipfw_insn *) rule->cmd;
2636
2637         bzero(buf, bufsize);
2638         rule->rulenum = rulenum;
2639
2640         cmd = fill_cmd(cmd, O_PROTO, F_INSN_SIZE(ipfw_insn), 0, proto);
2641         cmd = fill_ip(cmd, O_IP_SRC, sa.s_addr);
2642         cmd = fill_one_port(cmd, O_IP_SRCPORT, sp);
2643         cmd = fill_ip(cmd, O_IP_DST, da.s_addr);
2644         cmd = fill_one_port(cmd, O_IP_DSTPORT, dp);
2645
2646         rule->act_ofs = (u_int32_t *) cmd - (u_int32_t *) rule->cmd;
2647         cmd = fill_cmd(cmd, action, F_INSN_SIZE(ipfw_insn), 0, 0);
2648
2649         rule->cmd_len = (u_int32_t *) cmd - (u_int32_t *) rule->cmd;
2650
2651         return ((char *)cmd - (char *)buf);
2652 }
2653
2654 static void     ClearAllFWHoles(struct libalias *la);
2655
2656
2657 #define fw_setfield(la, field, num)                         \
2658 do {                                                    \
2659     (field)[(num) - la->fireWallBaseNum] = 1;               \
2660 } /*lint -save -e717 */ while(0)/* lint -restore */
2661
2662 #define fw_clrfield(la, field, num)                         \
2663 do {                                                    \
2664     (field)[(num) - la->fireWallBaseNum] = 0;               \
2665 } /*lint -save -e717 */ while(0)/* lint -restore */
2666
2667 #define fw_tstfield(la, field, num) ((field)[(num) - la->fireWallBaseNum])
2668
2669 static void
2670 InitPunchFW(struct libalias *la)
2671 {
2672
2673         la->fireWallField = malloc(la->fireWallNumNums);
2674         if (la->fireWallField) {
2675                 memset(la->fireWallField, 0, la->fireWallNumNums);
2676                 if (la->fireWallFD < 0) {
2677                         la->fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
2678                 }
2679                 ClearAllFWHoles(la);
2680                 la->fireWallActiveNum = la->fireWallBaseNum;
2681         }
2682 }
2683
2684 static void
2685 UninitPunchFW(struct libalias *la)
2686 {
2687         ClearAllFWHoles(la);
2688         if (la->fireWallFD >= 0)
2689                 close(la->fireWallFD);
2690         la->fireWallFD = -1;
2691         if (la->fireWallField)
2692                 free(la->fireWallField);
2693         la->fireWallField = NULL;
2694         la->packetAliasMode &= ~PKT_ALIAS_PUNCH_FW;
2695 }
2696
2697 /* Make a certain link go through the firewall */
2698 void
2699 PunchFWHole(struct alias_link *lnk)
2700 {
2701         struct libalias *la;
2702         int r;                  /* Result code */
2703         struct ip_fw rule;      /* On-the-fly built rule */
2704         int fwhole;             /* Where to punch hole */
2705
2706         la = lnk->la;
2707
2708 /* Don't do anything unless we are asked to */
2709         if (!(la->packetAliasMode & PKT_ALIAS_PUNCH_FW) ||
2710             la->fireWallFD < 0 ||
2711             lnk->link_type != LINK_TCP)
2712                 return;
2713
2714         memset(&rule, 0, sizeof rule);
2715
2716 /** Build rule **/
2717
2718         /* Find empty slot */
2719         for (fwhole = la->fireWallActiveNum;
2720             fwhole < la->fireWallBaseNum + la->fireWallNumNums &&
2721             fw_tstfield(la, la->fireWallField, fwhole);
2722             fwhole++);
2723         if (fwhole == la->fireWallBaseNum + la->fireWallNumNums) {
2724                 for (fwhole = la->fireWallBaseNum;
2725                     fwhole < la->fireWallActiveNum &&
2726                     fw_tstfield(la, la->fireWallField, fwhole);
2727                     fwhole++);
2728                 if (fwhole == la->fireWallActiveNum) {
2729                         /* No rule point empty - we can't punch more holes. */
2730                         la->fireWallActiveNum = la->fireWallBaseNum;
2731 #ifdef LIBALIAS_DEBUG
2732                         fprintf(stderr, "libalias: Unable to create firewall hole!\n");
2733 #endif
2734                         return;
2735                 }
2736         }
2737         /* Start next search at next position */
2738         la->fireWallActiveNum = fwhole + 1;
2739
2740         /*
2741          * generate two rules of the form
2742          *
2743          * add fwhole accept tcp from OAddr OPort to DAddr DPort add fwhole
2744          * accept tcp from DAddr DPort to OAddr OPort
2745          */
2746         if (GetOriginalPort(lnk) != 0 && GetDestPort(lnk) != 0) {
2747                 u_int32_t rulebuf[255];
2748                 int i;
2749
2750                 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2751                     O_ACCEPT, IPPROTO_TCP,
2752                     GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)),
2753                     GetDestAddress(lnk), ntohs(GetDestPort(lnk)));
2754                 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2755                 if (r)
2756                         err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
2757
2758                 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2759                     O_ACCEPT, IPPROTO_TCP,
2760                     GetDestAddress(lnk), ntohs(GetDestPort(lnk)),
2761                     GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)));
2762                 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2763                 if (r)
2764                         err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
2765         }
2766
2767 /* Indicate hole applied */
2768         lnk->data.tcp->fwhole = fwhole;
2769         fw_setfield(la, la->fireWallField, fwhole);
2770 }
2771
2772 /* Remove a hole in a firewall associated with a particular alias
2773    lnk.  Calling this too often is harmless. */
2774 static void
2775 ClearFWHole(struct alias_link *lnk)
2776 {
2777
2778         struct libalias *la;
2779
2780         la = lnk->la;
2781         if (lnk->link_type == LINK_TCP) {
2782                 int fwhole = lnk->data.tcp->fwhole;     /* Where is the firewall
2783                                                          * hole? */
2784                 struct ip_fw rule;
2785
2786                 if (fwhole < 0)
2787                         return;
2788
2789                 memset(&rule, 0, sizeof rule);  /* useless for ipfw2 */
2790                 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL,
2791                     &fwhole, sizeof fwhole));
2792                 fw_clrfield(la, la->fireWallField, fwhole);
2793                 lnk->data.tcp->fwhole = -1;
2794         }
2795 }
2796
2797 /* Clear out the entire range dedicated to firewall holes. */
2798 static void
2799 ClearAllFWHoles(struct libalias *la)
2800 {
2801         struct ip_fw rule;      /* On-the-fly built rule */
2802         int i;
2803
2804         if (la->fireWallFD < 0)
2805                 return;
2806
2807         memset(&rule, 0, sizeof rule);
2808         for (i = la->fireWallBaseNum; i < la->fireWallBaseNum + la->fireWallNumNums; i++) {
2809                 int r = i;
2810
2811                 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, &r, sizeof r));
2812         }
2813         /* XXX: third arg correct here ? /phk */
2814         memset(la->fireWallField, 0, la->fireWallNumNums);
2815 }
2816
2817 #endif
2818
2819 void
2820 LibAliasSetFWBase(struct libalias *la, unsigned int base, unsigned int num)
2821 {
2822 #ifndef NO_FW_PUNCH
2823         la->fireWallBaseNum = base;
2824         la->fireWallNumNums = num;
2825 #endif
2826 }
2827
2828 void
2829 LibAliasSetSkinnyPort(struct libalias *la, unsigned int port)
2830 {
2831         la->skinnyPort = port;
2832 }