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