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