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