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