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