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