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