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