]> git.saurik.com Git - apple/network_cmds.git/blob - alias/alias_db.c
9d6b99609a771314a698557134915118b9f07757
[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 if (alias_port_param == GET_ALIAS_PORT)
626 {
627 /*
628 * The aliasing port is automatically selected
629 * by one of two methods below:
630 */
631 max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
632
633 if (packetAliasMode & PKT_ALIAS_SAME_PORTS)
634 {
635 /*
636 * When the PKT_ALIAS_SAME_PORTS option is
637 * chosen, the first try will be the
638 * actual source port. If this is already
639 * in use, the remainder of the trials
640 * will be random.
641 */
642 port_net = link->src_port;
643 port_sys = ntohs(port_net);
644 }
645 else
646 {
647 /* First trial and all subsequent are random. */
648 port_sys = random() & ALIAS_PORT_MASK;
649 port_sys += ALIAS_PORT_BASE;
650 port_net = htons(port_sys);
651 }
652 }
653 else if (alias_port_param >= 0 && alias_port_param < 0x10000)
654 {
655 link->alias_port = (u_short) alias_port_param;
656 return(0);
657 }
658 else
659 {
660 #ifdef DEBUG
661 fprintf(stderr, "PacketAlias/GetNewPort(): ");
662 fprintf(stderr, "input parameter error\n");
663 #endif
664 return(-1);
665 }
666
667
668 /* Port number search */
669 for (i=0; i<max_trials; i++)
670 {
671 int go_ahead;
672 struct alias_link *search_result;
673
674 search_result = FindLinkIn(link->dst_addr, link->alias_addr,
675 link->dst_port, port_net,
676 link->link_type, 0);
677
678 if (search_result == NULL)
679 go_ahead = 1;
680 else if (!(link->flags & LINK_PARTIALLY_SPECIFIED)
681 && (search_result->flags & LINK_PARTIALLY_SPECIFIED))
682 go_ahead = 1;
683 else
684 go_ahead = 0;
685
686 if (go_ahead)
687 {
688 if ((packetAliasMode & PKT_ALIAS_USE_SOCKETS)
689 && (link->flags & LINK_PARTIALLY_SPECIFIED)
690 && ((link->link_type == LINK_TCP) ||
691 (link->link_type == LINK_UDP)))
692 {
693 if (GetSocket(port_net, &link->sockfd, link->link_type))
694 {
695 link->alias_port = port_net;
696 return(0);
697 }
698 }
699 else
700 {
701 link->alias_port = port_net;
702 return(0);
703 }
704 }
705
706 port_sys = random() & ALIAS_PORT_MASK;
707 port_sys += ALIAS_PORT_BASE;
708 port_net = htons(port_sys);
709 }
710 #ifdef DEBUG
711 fprintf(stderr, "PacketAlias/GetnewPort(): ");
712 fprintf(stderr, "could not find free port\n");
713 #endif
714
715 return(-1);
716 }
717
718
719 static u_short
720 GetSocket(u_short port_net, int *sockfd, int link_type)
721 {
722 int err;
723 int sock;
724 struct sockaddr_in sock_addr;
725
726 if (link_type == LINK_TCP)
727 sock = socket(AF_INET, SOCK_STREAM, 0);
728 else if (link_type == LINK_UDP)
729 sock = socket(AF_INET, SOCK_DGRAM, 0);
730 else
731 {
732 #ifdef DEBUG
733 fprintf(stderr, "PacketAlias/GetSocket(): ");
734 fprintf(stderr, "incorrect link type\n");
735 #endif
736 return(0);
737 }
738
739 if (sock < 0)
740 {
741 #ifdef DEBUG
742 fprintf(stderr, "PacketAlias/GetSocket(): ");
743 fprintf(stderr, "socket() error %d\n", *sockfd);
744 #endif
745 return(0);
746 }
747
748 sock_addr.sin_family = AF_INET;
749 sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
750 sock_addr.sin_port = port_net;
751
752 err = bind(sock,
753 (struct sockaddr *) &sock_addr,
754 sizeof(sock_addr));
755 if (err == 0)
756 {
757 sockCount++;
758 *sockfd = sock;
759 return(1);
760 }
761 else
762 {
763 close(sock);
764 return(0);
765 }
766 }
767
768
769 /* FindNewPortGroup() returns a base port number for an available
770 range of contiguous port numbers. Note that if a port number
771 is already in use, that does not mean that it cannot be used by
772 another link concurrently. This is because FindNewPortGroup()
773 looks for unused triplets: (dest addr, dest port, alias port). */
774
775 int
776 FindNewPortGroup(struct in_addr dst_addr,
777 struct in_addr alias_addr,
778 u_short src_port,
779 u_short dst_port,
780 u_short port_count,
781 u_char proto,
782 u_char align)
783 {
784 int i, j;
785 int max_trials;
786 u_short port_sys;
787 int link_type;
788
789 /*
790 * Get link_type from protocol
791 */
792
793 switch (proto)
794 {
795 case IPPROTO_UDP:
796 link_type = LINK_UDP;
797 break;
798 case IPPROTO_TCP:
799 link_type = LINK_TCP;
800 break;
801 default:
802 return (0);
803 break;
804 }
805
806 /*
807 * The aliasing port is automatically selected
808 * by one of two methods below:
809 */
810 max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
811
812 if (packetAliasMode & PKT_ALIAS_SAME_PORTS) {
813 /*
814 * When the ALIAS_SAME_PORTS option is
815 * chosen, the first try will be the
816 * actual source port. If this is already
817 * in use, the remainder of the trials
818 * will be random.
819 */
820 port_sys = ntohs(src_port);
821
822 } else {
823
824 /* First trial and all subsequent are random. */
825 if (align == FIND_EVEN_ALIAS_BASE)
826 port_sys = random() & ALIAS_PORT_MASK_EVEN;
827 else
828 port_sys = random() & ALIAS_PORT_MASK;
829
830 port_sys += ALIAS_PORT_BASE;
831 }
832
833 /* Port number search */
834 for (i = 0; i < max_trials; i++) {
835
836 struct alias_link *search_result;
837
838 for (j = 0; j < port_count; j++)
839 if (0 != (search_result = FindLinkIn(dst_addr, alias_addr,
840 dst_port, htons(port_sys + j),
841 link_type, 0)))
842 break;
843
844 /* Found a good range, return base */
845 if (j == port_count)
846 return (htons(port_sys));
847
848 /* Find a new base to try */
849 if (align == FIND_EVEN_ALIAS_BASE)
850 port_sys = random() & ALIAS_PORT_MASK_EVEN;
851 else
852 port_sys = random() & ALIAS_PORT_MASK;
853
854 port_sys += ALIAS_PORT_BASE;
855 }
856
857 #ifdef DEBUG
858 fprintf(stderr, "PacketAlias/FindNewPortGroup(): ");
859 fprintf(stderr, "could not find free port(s)\n");
860 #endif
861
862 return(0);
863 }
864
865 static void
866 CleanupAliasData(void)
867 {
868 struct alias_link *link;
869 int i, icount;
870
871 icount = 0;
872 for (i=0; i<LINK_TABLE_OUT_SIZE; i++)
873 {
874 link = LIST_FIRST(&linkTableOut[i]);
875 while (link != NULL)
876 {
877 struct alias_link *link_next;
878 link_next = LIST_NEXT(link, list_out);
879 icount++;
880 DeleteLink(link);
881 link = link_next;
882 }
883 }
884
885 cleanupIndex =0;
886 }
887
888
889 static void
890 IncrementalCleanup(void)
891 {
892 int icount;
893 struct alias_link *link;
894
895 icount = 0;
896 link = LIST_FIRST(&linkTableOut[cleanupIndex++]);
897 while (link != NULL)
898 {
899 int idelta;
900 struct alias_link *link_next;
901
902 link_next = LIST_NEXT(link, list_out);
903 idelta = timeStamp - link->timestamp;
904 switch (link->link_type)
905 {
906 case LINK_TCP:
907 if (idelta > link->expire_time)
908 {
909 struct tcp_dat *tcp_aux;
910
911 tcp_aux = link->data.tcp;
912 if (tcp_aux->state.in != ALIAS_TCP_STATE_CONNECTED
913 || tcp_aux->state.out != ALIAS_TCP_STATE_CONNECTED)
914 {
915 DeleteLink(link);
916 icount++;
917 }
918 }
919 break;
920 default:
921 if (idelta > link->expire_time)
922 {
923 DeleteLink(link);
924 icount++;
925 }
926 break;
927 }
928 link = link_next;
929 }
930
931 if (cleanupIndex == LINK_TABLE_OUT_SIZE)
932 cleanupIndex = 0;
933 }
934
935 static void
936 DeleteLink(struct alias_link *link)
937 {
938
939 /* Don't do anything if the link is marked permanent */
940 if (deleteAllLinks == 0 && link->flags & LINK_PERMANENT)
941 return;
942
943 #ifndef NO_FW_PUNCH
944 /* Delete associated firewall hole, if any */
945 ClearFWHole(link);
946 #endif
947
948 /* Free memory allocated for LSNAT server pool */
949 if (link->server != NULL) {
950 struct server *head, *curr, *next;
951
952 head = curr = link->server;
953 do {
954 next = curr->next;
955 free(curr);
956 } while ((curr = next) != head);
957 }
958
959 /* Adjust output table pointers */
960 LIST_REMOVE(link, list_out);
961
962 /* Adjust input table pointers */
963 LIST_REMOVE(link, list_in);
964
965 /* Close socket, if one has been allocated */
966 if (link->sockfd != -1)
967 {
968 sockCount--;
969 close(link->sockfd);
970 }
971
972 /* Link-type dependent cleanup */
973 switch(link->link_type)
974 {
975 case LINK_ICMP:
976 icmpLinkCount--;
977 break;
978 case LINK_UDP:
979 udpLinkCount--;
980 break;
981 case LINK_TCP:
982 tcpLinkCount--;
983 free(link->data.tcp);
984 break;
985 case LINK_PPTP:
986 pptpLinkCount--;
987 break;
988 case LINK_FRAGMENT_ID:
989 fragmentIdLinkCount--;
990 break;
991 case LINK_FRAGMENT_PTR:
992 fragmentPtrLinkCount--;
993 if (link->data.frag_ptr != NULL)
994 free(link->data.frag_ptr);
995 break;
996 case LINK_ADDR:
997 break;
998 default:
999 protoLinkCount--;
1000 break;
1001 }
1002
1003 #ifdef DEBUG
1004 if ((packetAliasMode & PKT_ALIAS_LOG) != 0 &&
1005 !IN_MULTICAST(link->src_addr.s_addr) &&
1006 !IN_MULTICAST(link->dst_addr.s_addr))
1007 {
1008 char src[16];
1009 char dst[16];
1010 char alias[16];
1011 char *proto;
1012 switch(link->link_type)
1013 {
1014 case LINK_TCP:
1015 proto = " [TCP]";
1016 break;
1017 case LINK_UDP:
1018 proto = " [UDP]";
1019 break;
1020 default:
1021 proto = "";
1022 }
1023 fprintf(monitorFile, "Deleted%s %s:%d<->%s:%d to %s:%d<->%s:%d\n",
1024 proto,
1025 inet_ntop(AF_INET, &link->src_addr, src, sizeof(src)), link->src_port,
1026 inet_ntop(AF_INET, &link->dst_addr, dst, sizeof(dst)), link->dst_port,
1027 inet_ntop(AF_INET, &link->alias_addr, alias, sizeof(alias)), link->alias_port,
1028 dst, link->dst_port);
1029 fflush(monitorFile);
1030 }
1031 #else
1032 if (packetAliasMode & PKT_ALIAS_LOG)
1033 ShowAliasStats();
1034 #endif
1035
1036 /* Free memory */
1037 free(link);
1038 }
1039
1040
1041 static struct alias_link *
1042 AddLink(struct in_addr src_addr,
1043 struct in_addr dst_addr,
1044 struct in_addr alias_addr,
1045 u_short src_port,
1046 u_short dst_port,
1047 int alias_port_param, /* if less than zero, alias */
1048 int link_type) /* port will be automatically */
1049 { /* chosen. If greater than */
1050 u_int start_point; /* zero, equal to alias port */
1051 struct alias_link *link;
1052
1053 link = malloc(sizeof(struct alias_link));
1054 if (link != NULL)
1055 {
1056 /* Basic initialization */
1057 link->src_addr = src_addr;
1058 link->dst_addr = dst_addr;
1059 link->alias_addr = alias_addr;
1060 link->proxy_addr.s_addr = INADDR_ANY;
1061 link->src_port = src_port;
1062 link->dst_port = dst_port;
1063 link->proxy_port = 0;
1064 link->server = NULL;
1065 link->link_type = link_type;
1066 link->sockfd = -1;
1067 link->flags = 0;
1068 link->timestamp = timeStamp;
1069
1070 /* Expiration time */
1071 switch (link_type)
1072 {
1073 case LINK_ICMP:
1074 link->expire_time = ICMP_EXPIRE_TIME;
1075 break;
1076 case LINK_UDP:
1077 if (dst_addr.s_addr == 0 && dst_port == 0)
1078 link->expire_time = UDP_EXPIRE_TIME * 5;
1079 else
1080 link->expire_time = UDP_EXPIRE_TIME;
1081 break;
1082 case LINK_TCP:
1083 link->expire_time = TCP_EXPIRE_INITIAL;
1084 break;
1085 case LINK_PPTP:
1086 link->flags |= LINK_PERMANENT; /* no timeout. */
1087 break;
1088 case LINK_FRAGMENT_ID:
1089 link->expire_time = FRAGMENT_ID_EXPIRE_TIME;
1090 break;
1091 case LINK_FRAGMENT_PTR:
1092 link->expire_time = FRAGMENT_PTR_EXPIRE_TIME;
1093 break;
1094 case LINK_ADDR:
1095 break;
1096 default:
1097 link->expire_time = PROTO_EXPIRE_TIME;
1098 break;
1099 }
1100
1101 /* Determine alias flags */
1102 if (dst_addr.s_addr == INADDR_ANY)
1103 link->flags |= LINK_UNKNOWN_DEST_ADDR;
1104 if (dst_port == 0)
1105 link->flags |= LINK_UNKNOWN_DEST_PORT;
1106
1107 /* Determine alias port */
1108 if (GetNewPort(link, alias_port_param) != 0)
1109 {
1110 free(link);
1111 return(NULL);
1112 }
1113 /* Link-type dependent initialization */
1114 switch(link_type)
1115 {
1116 struct tcp_dat *aux_tcp;
1117
1118 case LINK_ICMP:
1119 icmpLinkCount++;
1120 break;
1121 case LINK_UDP:
1122 udpLinkCount++;
1123 break;
1124 case LINK_TCP:
1125 aux_tcp = malloc(sizeof(struct tcp_dat));
1126 if (aux_tcp != NULL)
1127 {
1128 int i;
1129
1130 tcpLinkCount++;
1131 aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED;
1132 aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED;
1133 aux_tcp->state.index = 0;
1134 aux_tcp->state.ack_modified = 0;
1135 for (i=0; i<N_LINK_TCP_DATA; i++)
1136 aux_tcp->ack[i].active = 0;
1137 aux_tcp->fwhole = -1;
1138 link->data.tcp = aux_tcp;
1139 }
1140 else
1141 {
1142 #ifdef DEBUG
1143 fprintf(stderr, "PacketAlias/AddLink: ");
1144 fprintf(stderr, " cannot allocate auxiliary TCP data\n");
1145 #endif
1146 free(link);
1147 return (NULL);
1148 }
1149 break;
1150 case LINK_PPTP:
1151 pptpLinkCount++;
1152 break;
1153 case LINK_FRAGMENT_ID:
1154 fragmentIdLinkCount++;
1155 break;
1156 case LINK_FRAGMENT_PTR:
1157 fragmentPtrLinkCount++;
1158 break;
1159 case LINK_ADDR:
1160 break;
1161 default:
1162 protoLinkCount++;
1163 break;
1164 }
1165
1166 /* Set up pointers for output lookup table */
1167 start_point = StartPointOut(src_addr, dst_addr,
1168 src_port, dst_port, link_type);
1169 LIST_INSERT_HEAD(&linkTableOut[start_point], link, list_out);
1170
1171 /* Set up pointers for input lookup table */
1172 start_point = StartPointIn(alias_addr, link->alias_port, link_type);
1173 LIST_INSERT_HEAD(&linkTableIn[start_point], link, list_in);
1174 }
1175 else
1176 {
1177 #ifdef DEBUG
1178 fprintf(stderr, "PacketAlias/AddLink(): ");
1179 fprintf(stderr, "malloc() call failed.\n");
1180 #endif
1181 }
1182
1183 #ifdef DEBUG
1184 if ((packetAliasMode & PKT_ALIAS_LOG) != 0 &&
1185 !IN_MULTICAST(link->src_addr.s_addr) &&
1186 !IN_MULTICAST(link->dst_addr.s_addr))
1187 {
1188 char src[16];
1189 char dst[16];
1190 char alias[16];
1191 char *proto;
1192 switch(link->link_type)
1193 {
1194 case LINK_TCP:
1195 proto = " [TCP]";
1196 break;
1197 case LINK_UDP:
1198 proto = " [UDP]";
1199 break;
1200 default:
1201 proto = "";
1202 }
1203 fprintf(monitorFile, "Added %s %s:%d<->%s:%d to %s:%d<->%s:%d\n",
1204 proto,
1205 inet_ntop(AF_INET, &link->src_addr, src, sizeof(src)), link->src_port,
1206 inet_ntop(AF_INET, &link->dst_addr, dst, sizeof(dst)), link->dst_port,
1207 inet_ntop(AF_INET, &link->alias_addr, alias, sizeof(alias)), link->alias_port,
1208 dst, link->dst_port);
1209 }
1210 #else
1211 if (packetAliasMode & PKT_ALIAS_LOG)
1212 ShowAliasStats();
1213 #endif
1214
1215 return(link);
1216 }
1217
1218 static struct alias_link *
1219 ReLink(struct alias_link *old_link,
1220 struct in_addr src_addr,
1221 struct in_addr dst_addr,
1222 struct in_addr alias_addr,
1223 u_short src_port,
1224 u_short dst_port,
1225 int alias_port_param, /* if less than zero, alias */
1226 int link_type) /* port will be automatically */
1227 { /* chosen. If greater than */
1228 struct alias_link *new_link; /* zero, equal to alias port */
1229
1230 new_link = AddLink(src_addr, dst_addr, alias_addr,
1231 src_port, dst_port, alias_port_param,
1232 link_type);
1233 #ifndef NO_FW_PUNCH
1234 if (new_link != NULL &&
1235 old_link->link_type == LINK_TCP &&
1236 old_link->data.tcp->fwhole > 0) {
1237 PunchFWHole(new_link);
1238 }
1239 #endif
1240 if ((old_link->flags & LINK_CONE) == 0)
1241 DeleteLink(old_link);
1242 return new_link;
1243 }
1244
1245 static struct alias_link *
1246 _FindLinkOut(struct in_addr src_addr,
1247 struct in_addr dst_addr,
1248 u_short src_port,
1249 u_short dst_port,
1250 int link_type,
1251 int replace_partial_links)
1252 {
1253 u_int i;
1254 struct alias_link *link;
1255
1256 i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type);
1257 LIST_FOREACH(link, &linkTableOut[i], list_out)
1258 {
1259 if (link->src_addr.s_addr == src_addr.s_addr
1260 && link->server == NULL
1261 && link->dst_addr.s_addr == dst_addr.s_addr
1262 && link->dst_port == dst_port
1263 && link->src_port == src_port
1264 && link->link_type == link_type)
1265 {
1266 link->timestamp = timeStamp;
1267 break;
1268 }
1269 }
1270
1271 /* Search for partially specified links. */
1272 if (link == NULL && replace_partial_links)
1273 {
1274 if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY)
1275 {
1276 link = _FindLinkOut(src_addr, dst_addr, src_port, 0,
1277 link_type, 0);
1278 if (link == NULL)
1279 link = _FindLinkOut(src_addr, nullAddress, src_port,
1280 dst_port, link_type, 0);
1281 }
1282 if (link == NULL &&
1283 (dst_port != 0 || dst_addr.s_addr != INADDR_ANY))
1284 {
1285 link = _FindLinkOut(src_addr, nullAddress, src_port, 0,
1286 link_type, 0);
1287 }
1288 if (link != NULL)
1289 {
1290 link = ReLink(link,
1291 src_addr, dst_addr, link->alias_addr,
1292 src_port, dst_port, link->alias_port,
1293 link_type);
1294 }
1295 }
1296
1297 return(link);
1298 }
1299
1300 static struct alias_link *
1301 FindLinkOut(struct in_addr src_addr,
1302 struct in_addr dst_addr,
1303 u_short src_port,
1304 u_short dst_port,
1305 int link_type,
1306 int replace_partial_links)
1307 {
1308 struct alias_link *link;
1309
1310 link = _FindLinkOut(src_addr, dst_addr, src_port, dst_port,
1311 link_type, replace_partial_links);
1312
1313 if (link == NULL)
1314 {
1315 /* The following allows permanent links to be
1316 specified as using the default source address
1317 (i.e. device interface address) without knowing
1318 in advance what that address is. */
1319 if (aliasAddress.s_addr != 0 &&
1320 src_addr.s_addr == aliasAddress.s_addr)
1321 {
1322 link = _FindLinkOut(nullAddress, dst_addr, src_port, dst_port,
1323 link_type, replace_partial_links);
1324 }
1325 }
1326
1327 return(link);
1328 }
1329
1330
1331 static struct alias_link *
1332 _FindLinkIn(struct in_addr dst_addr,
1333 struct in_addr alias_addr,
1334 u_short dst_port,
1335 u_short alias_port,
1336 int link_type,
1337 int replace_partial_links)
1338 {
1339 int flags_in;
1340 u_int start_point;
1341 struct alias_link *link;
1342 struct alias_link *link_fully_specified;
1343 struct alias_link *link_unknown_all;
1344 struct alias_link *link_unknown_dst_addr;
1345 struct alias_link *link_unknown_dst_port;
1346
1347 /* Initialize pointers */
1348 link_fully_specified = NULL;
1349 link_unknown_all = NULL;
1350 link_unknown_dst_addr = NULL;
1351 link_unknown_dst_port = NULL;
1352
1353 /* If either the dest addr or port is unknown, the search
1354 loop will have to know about this. */
1355
1356 flags_in = 0;
1357 if (dst_addr.s_addr == INADDR_ANY)
1358 flags_in |= LINK_UNKNOWN_DEST_ADDR;
1359 if (dst_port == 0)
1360 flags_in |= LINK_UNKNOWN_DEST_PORT;
1361
1362 /* Search loop */
1363 start_point = StartPointIn(alias_addr, alias_port, link_type);
1364 LIST_FOREACH(link, &linkTableIn[start_point], list_in)
1365 {
1366 int flags;
1367
1368 flags = flags_in | link->flags;
1369 if (!(flags & LINK_PARTIALLY_SPECIFIED))
1370 {
1371 if (link->alias_addr.s_addr == alias_addr.s_addr
1372 && link->alias_port == alias_port
1373 && link->dst_addr.s_addr == dst_addr.s_addr
1374 && link->dst_port == dst_port
1375 && link->link_type == link_type)
1376 {
1377 link_fully_specified = link;
1378 break;
1379 }
1380 }
1381 else if ((flags & LINK_UNKNOWN_DEST_ADDR)
1382 && (flags & LINK_UNKNOWN_DEST_PORT))
1383 {
1384 if (link->alias_addr.s_addr == alias_addr.s_addr
1385 && link->alias_port == alias_port
1386 && link->link_type == link_type)
1387 {
1388 if (link_unknown_all == NULL)
1389 link_unknown_all = link;
1390 }
1391 }
1392 else if (flags & LINK_UNKNOWN_DEST_ADDR)
1393 {
1394 if (link->alias_addr.s_addr == alias_addr.s_addr
1395 && link->alias_port == alias_port
1396 && link->link_type == link_type
1397 && link->dst_port == dst_port)
1398 {
1399 if (link_unknown_dst_addr == NULL)
1400 link_unknown_dst_addr = link;
1401 }
1402 }
1403 else if (flags & LINK_UNKNOWN_DEST_PORT)
1404 {
1405 if (link->alias_addr.s_addr == alias_addr.s_addr
1406 && link->alias_port == alias_port
1407 && link->link_type == link_type
1408 && link->dst_addr.s_addr == dst_addr.s_addr)
1409 {
1410 if (link_unknown_dst_port == NULL)
1411 link_unknown_dst_port = link;
1412 }
1413 }
1414 }
1415
1416
1417
1418 if (link_fully_specified != NULL)
1419 {
1420 link_fully_specified->timestamp = timeStamp;
1421 link = link_fully_specified;
1422 }
1423 else if (link_unknown_dst_port != NULL)
1424 link = link_unknown_dst_port;
1425 else if (link_unknown_dst_addr != NULL)
1426 link = link_unknown_dst_addr;
1427 else if (link_unknown_all != NULL)
1428 link = link_unknown_all;
1429 else
1430 return (NULL);
1431
1432 if (replace_partial_links &&
1433 (link->flags & LINK_PARTIALLY_SPECIFIED || link->server != NULL))
1434 {
1435 struct in_addr src_addr;
1436 u_short src_port;
1437
1438 if (link->server != NULL) { /* LSNAT link */
1439 src_addr = link->server->addr;
1440 src_port = link->server->port;
1441 link->server = link->server->next;
1442 } else {
1443 src_addr = link->src_addr;
1444 src_port = link->src_port;
1445 }
1446
1447 link = ReLink(link,
1448 src_addr, dst_addr, alias_addr,
1449 src_port, dst_port, alias_port,
1450 link_type);
1451 }
1452
1453 return (link);
1454 }
1455
1456 static struct alias_link *
1457 FindLinkIn(struct in_addr dst_addr,
1458 struct in_addr alias_addr,
1459 u_short dst_port,
1460 u_short alias_port,
1461 int link_type,
1462 int replace_partial_links)
1463 {
1464 struct alias_link *link;
1465
1466 link = _FindLinkIn(dst_addr, alias_addr, dst_port, alias_port,
1467 link_type, replace_partial_links);
1468
1469 if (link == NULL)
1470 {
1471 /* The following allows permanent links to be
1472 specified as using the default aliasing address
1473 (i.e. device interface address) without knowing
1474 in advance what that address is. */
1475 if (aliasAddress.s_addr != 0 &&
1476 alias_addr.s_addr == aliasAddress.s_addr)
1477 {
1478 link = _FindLinkIn(dst_addr, nullAddress, dst_port, alias_port,
1479 link_type, replace_partial_links);
1480 }
1481 }
1482
1483 return(link);
1484 }
1485
1486
1487
1488
1489 /* External routines for finding/adding links
1490
1491 -- "external" means outside alias_db.c, but within alias*.c --
1492
1493 FindIcmpIn(), FindIcmpOut()
1494 FindFragmentIn1(), FindFragmentIn2()
1495 AddFragmentPtrLink(), FindFragmentPtr()
1496 FindProtoIn(), FindProtoOut()
1497 FindUdpTcpIn(), FindUdpTcpOut()
1498 AddPptp(), FindPptpOutByCallId(), FindPptpInByCallId(),
1499 FindPptpOutByPeerCallId(), FindPptpInByPeerCallId()
1500 FindOriginalAddress(), FindAliasAddress()
1501
1502 (prototypes in alias_local.h)
1503 */
1504
1505
1506 struct alias_link *
1507 FindIcmpIn(struct in_addr dst_addr,
1508 struct in_addr alias_addr,
1509 u_short id_alias,
1510 int create)
1511 {
1512 struct alias_link *link;
1513
1514 link = FindLinkIn(dst_addr, alias_addr,
1515 NO_DEST_PORT, id_alias,
1516 LINK_ICMP, 0);
1517 if (link == NULL && create && !(packetAliasMode & PKT_ALIAS_DENY_INCOMING))
1518 {
1519 struct in_addr target_addr;
1520
1521 target_addr = FindOriginalAddress(alias_addr);
1522 link = AddLink(target_addr, dst_addr, alias_addr,
1523 id_alias, NO_DEST_PORT, id_alias,
1524 LINK_ICMP);
1525 }
1526
1527 return (link);
1528 }
1529
1530
1531 struct alias_link *
1532 FindIcmpOut(struct in_addr src_addr,
1533 struct in_addr dst_addr,
1534 u_short id,
1535 int create)
1536 {
1537 struct alias_link * link;
1538
1539 link = FindLinkOut(src_addr, dst_addr,
1540 id, NO_DEST_PORT,
1541 LINK_ICMP, 0);
1542 if (link == NULL && create)
1543 {
1544 struct in_addr alias_addr;
1545
1546 alias_addr = FindAliasAddress(src_addr);
1547 link = AddLink(src_addr, dst_addr, alias_addr,
1548 id, NO_DEST_PORT, GET_ALIAS_ID,
1549 LINK_ICMP);
1550 }
1551
1552 return(link);
1553 }
1554
1555
1556 struct alias_link *
1557 FindFragmentIn1(struct in_addr dst_addr,
1558 struct in_addr alias_addr,
1559 u_short ip_id)
1560 {
1561 struct alias_link *link;
1562
1563 link = FindLinkIn(dst_addr, alias_addr,
1564 NO_DEST_PORT, ip_id,
1565 LINK_FRAGMENT_ID, 0);
1566
1567 if (link == NULL)
1568 {
1569 link = AddLink(nullAddress, dst_addr, alias_addr,
1570 NO_SRC_PORT, NO_DEST_PORT, ip_id,
1571 LINK_FRAGMENT_ID);
1572 }
1573
1574 return(link);
1575 }
1576
1577
1578 struct alias_link *
1579 FindFragmentIn2(struct in_addr dst_addr, /* Doesn't add a link if one */
1580 struct in_addr alias_addr, /* is not found. */
1581 u_short ip_id)
1582 {
1583 return FindLinkIn(dst_addr, alias_addr,
1584 NO_DEST_PORT, ip_id,
1585 LINK_FRAGMENT_ID, 0);
1586 }
1587
1588
1589 struct alias_link *
1590 AddFragmentPtrLink(struct in_addr dst_addr,
1591 u_short ip_id)
1592 {
1593 return AddLink(nullAddress, dst_addr, nullAddress,
1594 NO_SRC_PORT, NO_DEST_PORT, ip_id,
1595 LINK_FRAGMENT_PTR);
1596 }
1597
1598
1599 struct alias_link *
1600 FindFragmentPtr(struct in_addr dst_addr,
1601 u_short ip_id)
1602 {
1603 return FindLinkIn(dst_addr, nullAddress,
1604 NO_DEST_PORT, ip_id,
1605 LINK_FRAGMENT_PTR, 0);
1606 }
1607
1608
1609 struct alias_link *
1610 FindProtoIn(struct in_addr dst_addr,
1611 struct in_addr alias_addr,
1612 u_char proto)
1613 {
1614 struct alias_link *link;
1615
1616 link = FindLinkIn(dst_addr, alias_addr,
1617 NO_DEST_PORT, 0,
1618 proto, 1);
1619
1620 if (link == NULL && !(packetAliasMode & PKT_ALIAS_DENY_INCOMING))
1621 {
1622 struct in_addr target_addr;
1623
1624 target_addr = FindOriginalAddress(alias_addr);
1625 link = AddLink(target_addr, dst_addr, alias_addr,
1626 NO_SRC_PORT, NO_DEST_PORT, 0,
1627 proto);
1628 }
1629
1630 return (link);
1631 }
1632
1633
1634 struct alias_link *
1635 FindProtoOut(struct in_addr src_addr,
1636 struct in_addr dst_addr,
1637 u_char proto)
1638 {
1639 struct alias_link *link;
1640
1641 link = FindLinkOut(src_addr, dst_addr,
1642 NO_SRC_PORT, NO_DEST_PORT,
1643 proto, 1);
1644
1645 if (link == NULL)
1646 {
1647 struct in_addr alias_addr;
1648
1649 alias_addr = FindAliasAddress(src_addr);
1650 link = AddLink(src_addr, dst_addr, alias_addr,
1651 NO_SRC_PORT, NO_DEST_PORT, 0,
1652 proto);
1653 }
1654
1655 return (link);
1656 }
1657
1658
1659 struct alias_link *
1660 FindUdpTcpIn(struct in_addr dst_addr,
1661 struct in_addr alias_addr,
1662 u_short dst_port,
1663 u_short alias_port,
1664 u_char proto,
1665 int create)
1666 {
1667 int link_type;
1668 struct alias_link *link;
1669
1670 switch (proto)
1671 {
1672 case IPPROTO_UDP:
1673 link_type = LINK_UDP;
1674 break;
1675 case IPPROTO_TCP:
1676 link_type = LINK_TCP;
1677 break;
1678 default:
1679 return NULL;
1680 break;
1681 }
1682
1683 link = FindLinkIn(dst_addr, alias_addr,
1684 dst_port, alias_port,
1685 link_type, create);
1686
1687 if (link == NULL && create && !(packetAliasMode & PKT_ALIAS_DENY_INCOMING))
1688 {
1689 struct in_addr target_addr;
1690
1691 target_addr = FindOriginalAddress(alias_addr);
1692 link = AddLink(target_addr, dst_addr, alias_addr,
1693 alias_port, dst_port, alias_port,
1694 link_type);
1695 }
1696
1697 return(link);
1698 }
1699
1700
1701 struct alias_link *
1702 FindUdpTcpOut(struct in_addr src_addr,
1703 struct in_addr dst_addr,
1704 u_short src_port,
1705 u_short dst_port,
1706 u_char proto,
1707 int create)
1708 {
1709 int link_type;
1710 struct alias_link *link;
1711
1712 switch (proto)
1713 {
1714 case IPPROTO_UDP:
1715 link_type = LINK_UDP;
1716 break;
1717 case IPPROTO_TCP:
1718 link_type = LINK_TCP;
1719 break;
1720 default:
1721 return NULL;
1722 break;
1723 }
1724
1725 link = FindLinkOut(src_addr, dst_addr, src_port, dst_port, link_type, create);
1726
1727 if (link == NULL && create)
1728 {
1729 struct in_addr alias_addr;
1730 struct in_addr dst_addr2 = dst_addr;
1731 u_short dst_port2 = dst_port;
1732
1733 alias_addr = FindAliasAddress(src_addr);
1734
1735 if (iChatAVHack && link_type == LINK_UDP && dst_port == htons(5678)) {
1736 dst_addr2.s_addr = 0;
1737 dst_port2 = 0;
1738 }
1739 link = AddLink(src_addr, dst_addr2, alias_addr,
1740 src_port, dst_port2, GET_ALIAS_PORT,
1741 link_type);
1742 if (link != NULL &&
1743 (link->flags & (LINK_UNKNOWN_DEST_ADDR | LINK_UNKNOWN_DEST_PORT)) != 0)
1744 {
1745 link->flags |= LINK_CONE;
1746 link = ReLink(link, link->src_addr, dst_addr, link->alias_addr,
1747 link->src_port, dst_port, link->alias_port, link_type);
1748 }
1749 }
1750
1751 return(link);
1752 }
1753
1754
1755 struct alias_link *
1756 AddPptp(struct in_addr src_addr,
1757 struct in_addr dst_addr,
1758 struct in_addr alias_addr,
1759 u_int16_t src_call_id)
1760 {
1761 struct alias_link *link;
1762
1763 link = AddLink(src_addr, dst_addr, alias_addr,
1764 src_call_id, 0, GET_ALIAS_PORT,
1765 LINK_PPTP);
1766
1767 return (link);
1768 }
1769
1770
1771 struct alias_link *
1772 FindPptpOutByCallId(struct in_addr src_addr,
1773 struct in_addr dst_addr,
1774 u_int16_t src_call_id)
1775 {
1776 u_int i;
1777 struct alias_link *link;
1778
1779 i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1780 LIST_FOREACH(link, &linkTableOut[i], list_out)
1781 if (link->link_type == LINK_PPTP &&
1782 link->src_addr.s_addr == src_addr.s_addr &&
1783 link->dst_addr.s_addr == dst_addr.s_addr &&
1784 link->src_port == src_call_id)
1785 break;
1786
1787 return (link);
1788 }
1789
1790
1791 struct alias_link *
1792 FindPptpOutByPeerCallId(struct in_addr src_addr,
1793 struct in_addr dst_addr,
1794 u_int16_t dst_call_id)
1795 {
1796 u_int i;
1797 struct alias_link *link;
1798
1799 i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1800 LIST_FOREACH(link, &linkTableOut[i], list_out)
1801 if (link->link_type == LINK_PPTP &&
1802 link->src_addr.s_addr == src_addr.s_addr &&
1803 link->dst_addr.s_addr == dst_addr.s_addr &&
1804 link->dst_port == dst_call_id)
1805 break;
1806
1807 return (link);
1808 }
1809
1810
1811 struct alias_link *
1812 FindPptpInByCallId(struct in_addr dst_addr,
1813 struct in_addr alias_addr,
1814 u_int16_t dst_call_id)
1815 {
1816 u_int i;
1817 struct alias_link *link;
1818
1819 i = StartPointIn(alias_addr, 0, LINK_PPTP);
1820 LIST_FOREACH(link, &linkTableIn[i], list_in)
1821 if (link->link_type == LINK_PPTP &&
1822 link->dst_addr.s_addr == dst_addr.s_addr &&
1823 link->alias_addr.s_addr == alias_addr.s_addr &&
1824 link->dst_port == dst_call_id)
1825 break;
1826
1827 return (link);
1828 }
1829
1830
1831 struct alias_link *
1832 FindPptpInByPeerCallId(struct in_addr dst_addr,
1833 struct in_addr alias_addr,
1834 u_int16_t alias_call_id)
1835 {
1836 struct alias_link *link;
1837
1838 link = FindLinkIn(dst_addr, alias_addr,
1839 0/* any */, alias_call_id,
1840 LINK_PPTP, 0);
1841
1842
1843 return (link);
1844 }
1845
1846
1847 struct alias_link *
1848 FindRtspOut(struct in_addr src_addr,
1849 struct in_addr dst_addr,
1850 u_short src_port,
1851 u_short alias_port,
1852 u_char proto)
1853 {
1854 int link_type;
1855 struct alias_link *link;
1856
1857 switch (proto)
1858 {
1859 case IPPROTO_UDP:
1860 link_type = LINK_UDP;
1861 break;
1862 case IPPROTO_TCP:
1863 link_type = LINK_TCP;
1864 break;
1865 default:
1866 return NULL;
1867 break;
1868 }
1869
1870 link = FindLinkOut(src_addr, dst_addr, src_port, 0, link_type, 1);
1871
1872 if (link == NULL)
1873 {
1874 struct in_addr alias_addr;
1875
1876 alias_addr = FindAliasAddress(src_addr);
1877 link = AddLink(src_addr, dst_addr, alias_addr,
1878 src_port, 0, alias_port,
1879 link_type);
1880 }
1881
1882 return(link);
1883 }
1884
1885
1886 struct in_addr
1887 FindOriginalAddress(struct in_addr alias_addr)
1888 {
1889 struct alias_link *link;
1890
1891 link = FindLinkIn(nullAddress, alias_addr,
1892 0, 0, LINK_ADDR, 0);
1893 if (link == NULL)
1894 {
1895 newDefaultLink = 1;
1896 if (targetAddress.s_addr == INADDR_ANY)
1897 return alias_addr;
1898 else if (targetAddress.s_addr == INADDR_NONE)
1899 return aliasAddress;
1900 else
1901 return targetAddress;
1902 }
1903 else
1904 {
1905 if (link->server != NULL) { /* LSNAT link */
1906 struct in_addr src_addr;
1907
1908 src_addr = link->server->addr;
1909 link->server = link->server->next;
1910 return (src_addr);
1911 } else if (link->src_addr.s_addr == INADDR_ANY)
1912 return aliasAddress;
1913 else
1914 return link->src_addr;
1915 }
1916 }
1917
1918
1919 struct in_addr
1920 FindAliasAddress(struct in_addr original_addr)
1921 {
1922 struct alias_link *link;
1923
1924 link = FindLinkOut(original_addr, nullAddress,
1925 0, 0, LINK_ADDR, 0);
1926 if (link == NULL)
1927 {
1928 return aliasAddress;
1929 }
1930 else
1931 {
1932 if (link->alias_addr.s_addr == INADDR_ANY)
1933 return aliasAddress;
1934 else
1935 return link->alias_addr;
1936 }
1937 }
1938
1939 /* FindAliasPortOut */
1940 /* external routine for NatPortMap */
1941 /* return alias port for the src_addr,dst_addr,src_port and proto */
1942 /* if one doesn't existed, create a mapping with providing pub_port if it's not 0 */
1943 /* delete mapping if addmapping is not true */
1944 int
1945 FindAliasPortOut(struct in_addr src_addr, struct in_addr dst_addr, u_short src_port, u_short pub_port, u_char proto, int lifetime, char addmapping)
1946 {
1947 u_int i;
1948 struct alias_link *link;
1949 int link_type;
1950
1951 switch (proto)
1952 {
1953 case IPPROTO_UDP:
1954 link_type = LINK_UDP;
1955 break;
1956 case IPPROTO_TCP:
1957 link_type = LINK_TCP;
1958 break;
1959 default:
1960 return NULL;
1961 break;
1962 }
1963
1964 #ifdef DEBUG
1965 {
1966 int icount;
1967
1968 printf("PORTMAP::srcaddr = 0x%x.%d, dstaddr = 0x%x.%d link_type = %d, lifetime = %d\n",
1969 src_addr.s_addr, src_port, dst_addr.s_addr, pub_port, link_type, lifetime);
1970
1971 for (i=0; i<LINK_TABLE_OUT_SIZE; i++)
1972 {
1973 link = LIST_FIRST(&linkTableOut[i]);
1974 while (link != NULL)
1975 {
1976 struct alias_link *link_next;
1977
1978 printf("PORTMAP:: linksrcaddr = 0x%x.%d, linkdstaddr = 0x%x.%d, aliasaddr=0x%x.%d, linktype = %d\n",
1979 link->src_addr.s_addr,link->src_port,link->dst_addr.s_addr,link->dst_port, link->alias_addr.s_addr,link->alias_port,
1980 link->link_type);
1981
1982 link_next = LIST_NEXT(link, list_out);
1983 icount++;
1984 link = link_next;
1985 }
1986 }
1987
1988 }
1989 #endif
1990
1991 i = StartPointOut(src_addr, dst_addr, src_port, 0, link_type);
1992 #ifdef DEBUG
1993 printf("PORTMAP::StartPointOut returns %d\n", i);
1994 #endif
1995 LIST_FOREACH(link, &linkTableOut[i], list_out)
1996 {
1997 if (link->src_addr.s_addr == src_addr.s_addr &&
1998 link->dst_addr.s_addr == dst_addr.s_addr &&
1999 link->src_port == src_port && link->link_type == link_type)
2000 break;
2001 }
2002
2003 if ( link == NULL && addmapping)
2004 {
2005 struct in_addr alias_addr;
2006 #ifdef DEBUG
2007 printf("PORTMAP:: cannot find mapping, adding mapping private port =%d, public port = %d\n",src_port, pub_port);
2008 #endif
2009 /* address/port in not in list, create new mapping */
2010
2011 alias_addr = FindAliasAddress(src_addr);
2012 /* create new mapping */
2013 if ( !pub_port )
2014 pub_port = GET_ALIAS_PORT;
2015 link = AddLink(src_addr, dst_addr, alias_addr,
2016 src_port, 0, pub_port,
2017 link_type);
2018 if ( link != NULL )
2019 /* link was create, set new lifetime */
2020 SetExpire(link, lifetime);
2021 }
2022 if ( link )
2023 {
2024 if ( addmapping )
2025 return( GetAliasPort(link));
2026 else
2027 {
2028 SetExpire(link, 0); /* delete mapping */
2029 return 0;
2030 }
2031 }
2032
2033 return -1;
2034 }
2035
2036
2037 /* External routines for getting or changing link data
2038 (external to alias_db.c, but internal to alias*.c)
2039
2040 SetFragmentData(), GetFragmentData()
2041 SetFragmentPtr(), GetFragmentPtr()
2042 SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut()
2043 GetOriginalAddress(), GetDestAddress(), GetAliasAddress()
2044 GetOriginalPort(), GetAliasPort()
2045 SetAckModified(), GetAckModified()
2046 GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq()
2047 SetLastLineCrlfTermed(), GetLastLineCrlfTermed()
2048 SetDestCallId()
2049 */
2050
2051
2052 void
2053 SetFragmentAddr(struct alias_link *link, struct in_addr src_addr)
2054 {
2055 link->data.frag_addr = src_addr;
2056 }
2057
2058
2059 void
2060 GetFragmentAddr(struct alias_link *link, struct in_addr *src_addr)
2061 {
2062 *src_addr = link->data.frag_addr;
2063 }
2064
2065
2066 void
2067 SetFragmentPtr(struct alias_link *link, char *fptr)
2068 {
2069 link->data.frag_ptr = fptr;
2070 }
2071
2072
2073 void
2074 GetFragmentPtr(struct alias_link *link, char **fptr)
2075 {
2076 *fptr = link->data.frag_ptr;
2077 }
2078
2079
2080 void
2081 SetStateIn(struct alias_link *link, int state)
2082 {
2083 /* TCP input state */
2084 switch (state) {
2085 case ALIAS_TCP_STATE_DISCONNECTED:
2086 if (link->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED)
2087 link->expire_time = TCP_EXPIRE_DEAD;
2088 else
2089 link->expire_time = TCP_EXPIRE_SINGLEDEAD;
2090 break;
2091 case ALIAS_TCP_STATE_CONNECTED:
2092 if (link->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED)
2093 link->expire_time = TCP_EXPIRE_CONNECTED;
2094 break;
2095 default:
2096 abort();
2097 }
2098 link->data.tcp->state.in = state;
2099 }
2100
2101
2102 void
2103 SetStateOut(struct alias_link *link, int state)
2104 {
2105 /* TCP output state */
2106 switch (state) {
2107 case ALIAS_TCP_STATE_DISCONNECTED:
2108 if (link->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED)
2109 link->expire_time = TCP_EXPIRE_DEAD;
2110 else
2111 link->expire_time = TCP_EXPIRE_SINGLEDEAD;
2112 break;
2113 case ALIAS_TCP_STATE_CONNECTED:
2114 if (link->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED)
2115 link->expire_time = TCP_EXPIRE_CONNECTED;
2116 break;
2117 default:
2118 abort();
2119 }
2120 link->data.tcp->state.out = state;
2121 }
2122
2123
2124 int
2125 GetStateIn(struct alias_link *link)
2126 {
2127 /* TCP input state */
2128 return link->data.tcp->state.in;
2129 }
2130
2131
2132 int
2133 GetStateOut(struct alias_link *link)
2134 {
2135 /* TCP output state */
2136 return link->data.tcp->state.out;
2137 }
2138
2139
2140 struct in_addr
2141 GetOriginalAddress(struct alias_link *link)
2142 {
2143 if (link->src_addr.s_addr == INADDR_ANY)
2144 return aliasAddress;
2145 else
2146 return(link->src_addr);
2147 }
2148
2149
2150 struct in_addr
2151 GetDestAddress(struct alias_link *link)
2152 {
2153 return(link->dst_addr);
2154 }
2155
2156
2157 struct in_addr
2158 GetAliasAddress(struct alias_link *link)
2159 {
2160 if (link->alias_addr.s_addr == INADDR_ANY)
2161 return aliasAddress;
2162 else
2163 return link->alias_addr;
2164 }
2165
2166
2167 struct in_addr
2168 GetDefaultAliasAddress()
2169 {
2170 return aliasAddress;
2171 }
2172
2173
2174 void
2175 SetDefaultAliasAddress(struct in_addr alias_addr)
2176 {
2177 aliasAddress = alias_addr;
2178 }
2179
2180
2181 u_short
2182 GetOriginalPort(struct alias_link *link)
2183 {
2184 return(link->src_port);
2185 }
2186
2187
2188 u_short
2189 GetAliasPort(struct alias_link *link)
2190 {
2191 return(link->alias_port);
2192 }
2193
2194 #ifndef NO_FW_PUNCH
2195 static u_short
2196 GetDestPort(struct alias_link *link)
2197 {
2198 return(link->dst_port);
2199 }
2200 #endif
2201
2202 void
2203 SetAckModified(struct alias_link *link)
2204 {
2205 /* Indicate that ACK numbers have been modified in a TCP connection */
2206 link->data.tcp->state.ack_modified = 1;
2207 }
2208
2209
2210 struct in_addr
2211 GetProxyAddress(struct alias_link *link)
2212 {
2213 return link->proxy_addr;
2214 }
2215
2216
2217 void
2218 SetProxyAddress(struct alias_link *link, struct in_addr addr)
2219 {
2220 link->proxy_addr = addr;
2221 }
2222
2223
2224 u_short
2225 GetProxyPort(struct alias_link *link)
2226 {
2227 return link->proxy_port;
2228 }
2229
2230
2231 void
2232 SetProxyPort(struct alias_link *link, u_short port)
2233 {
2234 link->proxy_port = port;
2235 }
2236
2237
2238 int
2239 GetAckModified(struct alias_link *link)
2240 {
2241 /* See if ACK numbers have been modified */
2242 return link->data.tcp->state.ack_modified;
2243 }
2244
2245
2246 int
2247 GetDeltaAckIn(struct ip *pip, struct alias_link *link)
2248 {
2249 /*
2250 Find out how much the ACK number has been altered for an incoming
2251 TCP packet. To do this, a circular list of ACK numbers where the TCP
2252 packet size was altered is searched.
2253 */
2254
2255 int i;
2256 struct tcphdr *tc;
2257 int delta, ack_diff_min;
2258 u_long ack;
2259
2260 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
2261 ack = tc->th_ack;
2262
2263 delta = 0;
2264 ack_diff_min = -1;
2265 for (i=0; i<N_LINK_TCP_DATA; i++)
2266 {
2267 struct ack_data_record x;
2268
2269 x = link->data.tcp->ack[i];
2270 if (x.active == 1)
2271 {
2272 int ack_diff;
2273
2274 ack_diff = SeqDiff(x.ack_new, ack);
2275 if (ack_diff >= 0)
2276 {
2277 if (ack_diff_min >= 0)
2278 {
2279 if (ack_diff < ack_diff_min)
2280 {
2281 delta = x.delta;
2282 ack_diff_min = ack_diff;
2283 }
2284 }
2285 else
2286 {
2287 delta = x.delta;
2288 ack_diff_min = ack_diff;
2289 }
2290 }
2291 }
2292 }
2293 return (delta);
2294 }
2295
2296
2297 int
2298 GetDeltaSeqOut(struct ip *pip, struct alias_link *link)
2299 {
2300 /*
2301 Find out how much the sequence number has been altered for an outgoing
2302 TCP packet. To do this, a circular list of ACK numbers where the TCP
2303 packet size was altered is searched.
2304 */
2305
2306 int i;
2307 struct tcphdr *tc;
2308 int delta, seq_diff_min;
2309 u_long seq;
2310
2311 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
2312 seq = tc->th_seq;
2313
2314 delta = 0;
2315 seq_diff_min = -1;
2316 for (i=0; i<N_LINK_TCP_DATA; i++)
2317 {
2318 struct ack_data_record x;
2319
2320 x = link->data.tcp->ack[i];
2321 if (x.active == 1)
2322 {
2323 int seq_diff;
2324
2325 seq_diff = SeqDiff(x.ack_old, seq);
2326 if (seq_diff >= 0)
2327 {
2328 if (seq_diff_min >= 0)
2329 {
2330 if (seq_diff < seq_diff_min)
2331 {
2332 delta = x.delta;
2333 seq_diff_min = seq_diff;
2334 }
2335 }
2336 else
2337 {
2338 delta = x.delta;
2339 seq_diff_min = seq_diff;
2340 }
2341 }
2342 }
2343 }
2344 return (delta);
2345 }
2346
2347
2348 void
2349 AddSeq(struct ip *pip, struct alias_link *link, int delta)
2350 {
2351 /*
2352 When a TCP packet has been altered in length, save this
2353 information in a circular list. If enough packets have
2354 been altered, then this list will begin to overwrite itself.
2355 */
2356
2357 struct tcphdr *tc;
2358 struct ack_data_record x;
2359 int hlen, tlen, dlen;
2360 int i;
2361
2362 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
2363
2364 hlen = (pip->ip_hl + tc->th_off) << 2;
2365 tlen = ntohs(pip->ip_len);
2366 dlen = tlen - hlen;
2367
2368 x.ack_old = htonl(ntohl(tc->th_seq) + dlen);
2369 x.ack_new = htonl(ntohl(tc->th_seq) + dlen + delta);
2370 x.delta = delta;
2371 x.active = 1;
2372
2373 i = link->data.tcp->state.index;
2374 link->data.tcp->ack[i] = x;
2375
2376 i++;
2377 if (i == N_LINK_TCP_DATA)
2378 link->data.tcp->state.index = 0;
2379 else
2380 link->data.tcp->state.index = i;
2381 }
2382
2383 void
2384 SetExpire(struct alias_link *link, int expire)
2385 {
2386 if (expire == 0)
2387 {
2388 link->flags &= ~LINK_PERMANENT;
2389 DeleteLink(link);
2390 }
2391 else if (expire == -1)
2392 {
2393 link->flags |= LINK_PERMANENT;
2394 }
2395 else if (expire > 0)
2396 {
2397 link->expire_time = expire;
2398 }
2399 else
2400 {
2401 #ifdef DEBUG
2402 fprintf(stderr, "PacketAlias/SetExpire(): ");
2403 fprintf(stderr, "error in expire parameter\n");
2404 #endif
2405 }
2406 }
2407
2408 void
2409 ClearCheckNewLink(void)
2410 {
2411 newDefaultLink = 0;
2412 }
2413
2414 void
2415 SetLastLineCrlfTermed(struct alias_link *link, int yes)
2416 {
2417
2418 if (yes)
2419 link->flags |= LINK_LAST_LINE_CRLF_TERMED;
2420 else
2421 link->flags &= ~LINK_LAST_LINE_CRLF_TERMED;
2422 }
2423
2424 int
2425 GetLastLineCrlfTermed(struct alias_link *link)
2426 {
2427
2428 return (link->flags & LINK_LAST_LINE_CRLF_TERMED);
2429 }
2430
2431 void
2432 SetDestCallId(struct alias_link *link, u_int16_t cid)
2433 {
2434
2435 deleteAllLinks = 1;
2436 link = ReLink(link, link->src_addr, link->dst_addr, link->alias_addr,
2437 link->src_port, cid, link->alias_port, link->link_type);
2438 deleteAllLinks = 0;
2439 }
2440
2441
2442 /* Miscellaneous Functions
2443
2444 HouseKeeping()
2445 InitPacketAliasLog()
2446 UninitPacketAliasLog()
2447 */
2448
2449 /*
2450 Whenever an outgoing or incoming packet is handled, HouseKeeping()
2451 is called to find and remove timed-out aliasing links. Logic exists
2452 to sweep through the entire table and linked list structure
2453 every 60 seconds.
2454
2455 (prototype in alias_local.h)
2456 */
2457
2458 void
2459 HouseKeeping(void)
2460 {
2461 int i, n, n100;
2462 struct timeval tv;
2463 struct timezone tz;
2464
2465 /*
2466 * Save system time (seconds) in global variable timeStamp for
2467 * use by other functions. This is done so as not to unnecessarily
2468 * waste timeline by making system calls.
2469 */
2470 gettimeofday(&tv, &tz);
2471 timeStamp = tv.tv_sec;
2472
2473 /* Compute number of spokes (output table link chains) to cover */
2474 n100 = LINK_TABLE_OUT_SIZE * 100 + houseKeepingResidual;
2475 n100 *= timeStamp - lastCleanupTime;
2476 n100 /= ALIAS_CLEANUP_INTERVAL_SECS;
2477
2478 n = n100/100;
2479
2480 /* Handle different cases */
2481 if (n > ALIAS_CLEANUP_MAX_SPOKES)
2482 {
2483 n = ALIAS_CLEANUP_MAX_SPOKES;
2484 lastCleanupTime = timeStamp;
2485 houseKeepingResidual = 0;
2486
2487 for (i=0; i<n; i++)
2488 IncrementalCleanup();
2489 }
2490 else if (n > 0)
2491 {
2492 lastCleanupTime = timeStamp;
2493 houseKeepingResidual = n100 - 100*n;
2494
2495 for (i=0; i<n; i++)
2496 IncrementalCleanup();
2497 }
2498 else if (n < 0)
2499 {
2500 #ifdef DEBUG
2501 fprintf(stderr, "PacketAlias/HouseKeeping(): ");
2502 fprintf(stderr, "something unexpected in time values\n");
2503 #endif
2504 lastCleanupTime = timeStamp;
2505 houseKeepingResidual = 0;
2506 }
2507 }
2508
2509
2510 /* Init the log file and enable logging */
2511 static void
2512 InitPacketAliasLog(void)
2513 {
2514 if ((~packetAliasMode & PKT_ALIAS_LOG)
2515 && (monitorFile = fopen("/var/log/alias.log", "w")))
2516 {
2517 packetAliasMode |= PKT_ALIAS_LOG;
2518 fprintf(monitorFile,
2519 "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");
2520 }
2521 }
2522
2523
2524 /* Close the log-file and disable logging. */
2525 static void
2526 UninitPacketAliasLog(void)
2527 {
2528 if (monitorFile) {
2529 fclose(monitorFile);
2530 monitorFile = NULL;
2531 }
2532 packetAliasMode &= ~PKT_ALIAS_LOG;
2533 }
2534
2535
2536
2537
2538
2539
2540 /* Outside world interfaces
2541
2542 -- "outside world" means other than alias*.c routines --
2543
2544 PacketAliasRedirectPort()
2545 PacketAliasAddServer()
2546 PacketAliasRedirectProto()
2547 PacketAliasRedirectAddr()
2548 PacketAliasRedirectDelete()
2549 PacketAliasSetAddress()
2550 PacketAliasInit()
2551 PacketAliasUninit()
2552 PacketAliasSetMode()
2553
2554 (prototypes in alias.h)
2555 */
2556
2557 /* Redirection from a specific public addr:port to a
2558 private addr:port */
2559 struct alias_link *
2560 PacketAliasRedirectPort(struct in_addr src_addr, u_short src_port,
2561 struct in_addr dst_addr, u_short dst_port,
2562 struct in_addr alias_addr, u_short alias_port,
2563 u_char proto)
2564 {
2565 int link_type;
2566 struct alias_link *link;
2567
2568 switch(proto)
2569 {
2570 case IPPROTO_UDP:
2571 link_type = LINK_UDP;
2572 break;
2573 case IPPROTO_TCP:
2574 link_type = LINK_TCP;
2575 break;
2576 default:
2577 #ifdef DEBUG
2578 fprintf(stderr, "PacketAliasRedirectPort(): ");
2579 fprintf(stderr, "only TCP and UDP protocols allowed\n");
2580 #endif
2581 return NULL;
2582 }
2583
2584 link = AddLink(src_addr, dst_addr, alias_addr,
2585 src_port, dst_port, alias_port,
2586 link_type);
2587
2588 if (link != NULL)
2589 {
2590 link->flags |= LINK_PERMANENT;
2591 }
2592 #ifdef DEBUG
2593 else
2594 {
2595 fprintf(stderr, "PacketAliasRedirectPort(): "
2596 "call to AddLink() failed\n");
2597 }
2598 #endif
2599
2600 return link;
2601 }
2602
2603 /* Add server to the pool of servers */
2604 int
2605 PacketAliasAddServer(struct alias_link *link, struct in_addr addr, u_short port)
2606 {
2607 struct server *server;
2608
2609 server = malloc(sizeof(struct server));
2610
2611 if (server != NULL) {
2612 struct server *head;
2613
2614 server->addr = addr;
2615 server->port = port;
2616
2617 head = link->server;
2618 if (head == NULL)
2619 server->next = server;
2620 else {
2621 struct server *s;
2622
2623 for (s = head; s->next != head; s = s->next);
2624 s->next = server;
2625 server->next = head;
2626 }
2627 link->server = server;
2628 return (0);
2629 } else
2630 return (-1);
2631 }
2632
2633 /* Redirect packets of a given IP protocol from a specific
2634 public address to a private address */
2635 struct alias_link *
2636 PacketAliasRedirectProto(struct in_addr src_addr,
2637 struct in_addr dst_addr,
2638 struct in_addr alias_addr,
2639 u_char proto)
2640 {
2641 struct alias_link *link;
2642
2643 link = AddLink(src_addr, dst_addr, alias_addr,
2644 NO_SRC_PORT, NO_DEST_PORT, 0,
2645 proto);
2646
2647 if (link != NULL)
2648 {
2649 link->flags |= LINK_PERMANENT;
2650 }
2651 #ifdef DEBUG
2652 else
2653 {
2654 fprintf(stderr, "PacketAliasRedirectProto(): "
2655 "call to AddLink() failed\n");
2656 }
2657 #endif
2658
2659 return link;
2660 }
2661
2662 /* Static address translation */
2663 struct alias_link *
2664 PacketAliasRedirectAddr(struct in_addr src_addr,
2665 struct in_addr alias_addr)
2666 {
2667 struct alias_link *link;
2668
2669 link = AddLink(src_addr, nullAddress, alias_addr,
2670 0, 0, 0,
2671 LINK_ADDR);
2672
2673 if (link != NULL)
2674 {
2675 link->flags |= LINK_PERMANENT;
2676 }
2677 #ifdef DEBUG
2678 else
2679 {
2680 fprintf(stderr, "PacketAliasRedirectAddr(): "
2681 "call to AddLink() failed\n");
2682 }
2683 #endif
2684
2685 return link;
2686 }
2687
2688
2689 void
2690 PacketAliasRedirectDelete(struct alias_link *link)
2691 {
2692 /* This is a dangerous function to put in the API,
2693 because an invalid pointer can crash the program. */
2694
2695 deleteAllLinks = 1;
2696 DeleteLink(link);
2697 deleteAllLinks = 0;
2698 }
2699
2700
2701 void
2702 PacketAliasSetAddress(struct in_addr addr)
2703 {
2704 if (packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE
2705 && aliasAddress.s_addr != addr.s_addr)
2706 CleanupAliasData();
2707
2708 aliasAddress = addr;
2709 }
2710
2711
2712 void
2713 PacketAliasSetTarget(struct in_addr target_addr)
2714 {
2715 targetAddress = target_addr;
2716 }
2717
2718
2719 void
2720 PacketAliasInit(void)
2721 {
2722 int i;
2723 struct timeval tv;
2724 struct timezone tz;
2725 static int firstCall = 1;
2726
2727 if (firstCall == 1)
2728 {
2729 gettimeofday(&tv, &tz);
2730 timeStamp = tv.tv_sec;
2731 lastCleanupTime = tv.tv_sec;
2732 houseKeepingResidual = 0;
2733
2734 for (i=0; i<LINK_TABLE_OUT_SIZE; i++)
2735 LIST_INIT(&linkTableOut[i]);
2736 for (i=0; i<LINK_TABLE_IN_SIZE; i++)
2737 LIST_INIT(&linkTableIn[i]);
2738
2739 atexit(PacketAliasUninit);
2740 firstCall = 0;
2741 }
2742 else
2743 {
2744 deleteAllLinks = 1;
2745 CleanupAliasData();
2746 deleteAllLinks = 0;
2747 }
2748
2749 aliasAddress.s_addr = INADDR_ANY;
2750 targetAddress.s_addr = INADDR_ANY;
2751
2752 icmpLinkCount = 0;
2753 udpLinkCount = 0;
2754 tcpLinkCount = 0;
2755 pptpLinkCount = 0;
2756 protoLinkCount = 0;
2757 fragmentIdLinkCount = 0;
2758 fragmentPtrLinkCount = 0;
2759 sockCount = 0;
2760
2761 cleanupIndex =0;
2762
2763 packetAliasMode = PKT_ALIAS_SAME_PORTS
2764 | PKT_ALIAS_USE_SOCKETS
2765 | PKT_ALIAS_RESET_ON_ADDR_CHANGE;
2766 }
2767
2768 void
2769 PacketAliasUninit(void) {
2770 deleteAllLinks = 1;
2771 CleanupAliasData();
2772 deleteAllLinks = 0;
2773 UninitPacketAliasLog();
2774 #ifndef NO_FW_PUNCH
2775 UninitPunchFW();
2776 #endif
2777 }
2778
2779
2780 /* Change mode for some operations */
2781 unsigned int
2782 PacketAliasSetMode(
2783 unsigned int flags, /* Which state to bring flags to */
2784 unsigned int mask /* Mask of which flags to affect (use 0 to do a
2785 probe for flag values) */
2786 )
2787 {
2788 /* Enable logging? */
2789 if (flags & mask & PKT_ALIAS_LOG)
2790 {
2791 InitPacketAliasLog(); /* Do the enable */
2792 } else
2793 /* _Disable_ logging? */
2794 if (~flags & mask & PKT_ALIAS_LOG) {
2795 UninitPacketAliasLog();
2796 }
2797
2798 #ifndef NO_FW_PUNCH
2799 /* Start punching holes in the firewall? */
2800 if (flags & mask & PKT_ALIAS_PUNCH_FW) {
2801 InitPunchFW();
2802 } else
2803 /* Stop punching holes in the firewall? */
2804 if (~flags & mask & PKT_ALIAS_PUNCH_FW) {
2805 UninitPunchFW();
2806 }
2807 #endif
2808
2809 /* Other flags can be set/cleared without special action */
2810 packetAliasMode = (flags & mask) | (packetAliasMode & ~mask);
2811 return packetAliasMode;
2812 }
2813
2814
2815 int
2816 PacketAliasCheckNewLink(void)
2817 {
2818 return newDefaultLink;
2819 }
2820
2821
2822 #ifndef NO_FW_PUNCH
2823
2824 /*****************
2825 Code to support firewall punching. This shouldn't really be in this
2826 file, but making variables global is evil too.
2827 ****************/
2828
2829 /* Firewall include files */
2830 #include <net/if.h>
2831 #include <netinet/ip_fw.h>
2832 #include <string.h>
2833 #include <err.h>
2834
2835 static void ClearAllFWHoles(void);
2836
2837 static int fireWallBaseNum; /* The first firewall entry free for our use */
2838 static int fireWallNumNums; /* How many entries can we use? */
2839 static int fireWallActiveNum; /* Which entry did we last use? */
2840 static char *fireWallField; /* bool array for entries */
2841
2842 #define fw_setfield(field, num) \
2843 do { \
2844 (field)[(num) - fireWallBaseNum] = 1; \
2845 } /*lint -save -e717 */ while(0) /*lint -restore */
2846 #define fw_clrfield(field, num) \
2847 do { \
2848 (field)[(num) - fireWallBaseNum] = 0; \
2849 } /*lint -save -e717 */ while(0) /*lint -restore */
2850 #define fw_tstfield(field, num) ((field)[(num) - fireWallBaseNum])
2851
2852 static void
2853 InitPunchFW(void) {
2854 fireWallField = malloc(fireWallNumNums);
2855 if (fireWallField) {
2856 memset(fireWallField, 0, fireWallNumNums);
2857 if (fireWallFD < 0) {
2858 fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
2859 }
2860 ClearAllFWHoles();
2861 fireWallActiveNum = fireWallBaseNum;
2862 }
2863 }
2864
2865 static void
2866 UninitPunchFW(void) {
2867 ClearAllFWHoles();
2868 if (fireWallFD >= 0)
2869 close(fireWallFD);
2870 fireWallFD = -1;
2871 if (fireWallField)
2872 free(fireWallField);
2873 fireWallField = NULL;
2874 packetAliasMode &= ~PKT_ALIAS_PUNCH_FW;
2875 }
2876
2877 /* Make a certain link go through the firewall */
2878 void
2879 PunchFWHole(struct alias_link *link) {
2880 int r; /* Result code */
2881 struct ip_fw rule; /* On-the-fly built rule */
2882 int fwhole; /* Where to punch hole */
2883
2884 /* Don't do anything unless we are asked to */
2885 if ( !(packetAliasMode & PKT_ALIAS_PUNCH_FW) ||
2886 fireWallFD < 0 ||
2887 link->link_type != LINK_TCP)
2888 return;
2889
2890 memset(&rule, 0, sizeof rule);
2891
2892 /** Build rule **/
2893
2894 /* Find empty slot */
2895 for (fwhole = fireWallActiveNum;
2896 fwhole < fireWallBaseNum + fireWallNumNums &&
2897 fw_tstfield(fireWallField, fwhole);
2898 fwhole++)
2899 ;
2900 if (fwhole == fireWallBaseNum + fireWallNumNums) {
2901 for (fwhole = fireWallBaseNum;
2902 fwhole < fireWallActiveNum &&
2903 fw_tstfield(fireWallField, fwhole);
2904 fwhole++)
2905 ;
2906 if (fwhole == fireWallActiveNum) {
2907 /* No rule point empty - we can't punch more holes. */
2908 fireWallActiveNum = fireWallBaseNum;
2909 #ifdef DEBUG
2910 fprintf(stderr, "libalias: Unable to create firewall hole!\n");
2911 #endif
2912 return;
2913 }
2914 }
2915 /* Start next search at next position */
2916 fireWallActiveNum = fwhole+1;
2917
2918 /* Build generic part of the two rules */
2919 rule.fw_number = fwhole;
2920 IP_FW_SETNSRCP(&rule, 1); /* Number of source ports. */
2921 IP_FW_SETNDSTP(&rule, 1); /* Number of destination ports. */
2922 rule.fw_flg = IP_FW_F_ACCEPT | IP_FW_F_IN | IP_FW_F_OUT;
2923 rule.fw_prot = IPPROTO_TCP;
2924 rule.fw_smsk.s_addr = INADDR_BROADCAST;
2925 rule.fw_dmsk.s_addr = INADDR_BROADCAST;
2926
2927 /* Build and apply specific part of the rules */
2928 rule.fw_src = GetOriginalAddress(link);
2929 rule.fw_dst = GetDestAddress(link);
2930 rule.fw_uar.fw_pts[0] = ntohs(GetOriginalPort(link));
2931 rule.fw_uar.fw_pts[1] = ntohs(GetDestPort(link));
2932
2933 /* Skip non-bound links - XXX should not be strictly necessary,
2934 but seems to leave hole if not done. Leak of non-bound links?
2935 (Code should be left even if the problem is fixed - it is a
2936 clear optimization) */
2937 if (rule.fw_uar.fw_pts[0] != 0 && rule.fw_uar.fw_pts[1] != 0) {
2938 r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule);
2939 #ifdef DEBUG
2940 if (r)
2941 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
2942 #endif
2943 rule.fw_src = GetDestAddress(link);
2944 rule.fw_dst = GetOriginalAddress(link);
2945 rule.fw_uar.fw_pts[0] = ntohs(GetDestPort(link));
2946 rule.fw_uar.fw_pts[1] = ntohs(GetOriginalPort(link));
2947 r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule);
2948 #ifdef DEBUG
2949 if (r)
2950 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
2951 #endif
2952 }
2953 /* Indicate hole applied */
2954 link->data.tcp->fwhole = fwhole;
2955 fw_setfield(fireWallField, fwhole);
2956 }
2957
2958 /* Remove a hole in a firewall associated with a particular alias
2959 link. Calling this too often is harmless. */
2960 static void
2961 ClearFWHole(struct alias_link *link) {
2962 if (link->link_type == LINK_TCP) {
2963 int fwhole = link->data.tcp->fwhole; /* Where is the firewall hole? */
2964 struct ip_fw rule;
2965
2966 if (fwhole < 0)
2967 return;
2968
2969 memset(&rule, 0, sizeof rule);
2970 rule.fw_number = fwhole;
2971 while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule))
2972 ;
2973 fw_clrfield(fireWallField, fwhole);
2974 link->data.tcp->fwhole = -1;
2975 }
2976 }
2977
2978 /* Clear out the entire range dedicated to firewall holes. */
2979 static void
2980 ClearAllFWHoles(void) {
2981 struct ip_fw rule; /* On-the-fly built rule */
2982 int i;
2983
2984 if (fireWallFD < 0)
2985 return;
2986
2987 memset(&rule, 0, sizeof rule);
2988 for (i = fireWallBaseNum; i < fireWallBaseNum + fireWallNumNums; i++) {
2989 rule.fw_number = i;
2990 while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule))
2991 ;
2992 }
2993 memset(fireWallField, 0, fireWallNumNums);
2994 }
2995 #endif
2996
2997 void
2998 PacketAliasSetFWBase(unsigned int base, unsigned int num) {
2999 #ifndef NO_FW_PUNCH
3000 fireWallBaseNum = base;
3001 fireWallNumNums = num;
3002 #endif
3003 }