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