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