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