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