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