X-Git-Url: https://git.saurik.com/apple/network_cmds.git/blobdiff_plain/b7080c8e96625177072137d504eb8e9c9d748e49..fdfd5971fdda9c24d576337643161018a5281167:/alias/alias_db.c diff --git a/alias/alias_db.c b/alias/alias_db.c index d01188e..81dfff9 100644 --- a/alias/alias_db.c +++ b/alias/alias_db.c @@ -1,4 +1,54 @@ -/* -*- mode: c; tab-width: 8; c-basic-indent: 4; -*- +/* + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/*- + * Copyright (c) 2001 Charles Mott + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Based upon: + * $FreeBSD: src/lib/libalias/alias_db.c,v 1.21.2.12 2001/08/21 03:50:25 brian Exp $ + */ + +/* Alias_db.c encapsulates all data structures used for storing packet aliasing data. Other parts of the aliasing software access data through functions provided in this file. @@ -18,9 +68,6 @@ can be deleted after a certain amount of time. - This software is placed into the public domain with no restrictions - on its distribution. - Initial version: August, 1996 (cjm) Version 1.4: September 16, 1996 (cjm) @@ -32,7 +79,7 @@ Version 1.7: January 9, 1997 (cjm) Fragment handling simplified. Saves pointers for unresolved fragments. - Permits links for unspecied remote ports + Permits links for unspecified remote ports or unspecified remote addresses. Fixed bug which did not properly zero port table entries after a link was deleted. @@ -48,8 +95,8 @@ machine will will not have their port number aliased unless it conflicts with an aliasing port already being used. (cjm) - All options earlier being #ifdef'ed now are available through - a new interface, SetPacketAliasMode(). This allow run time + All options earlier being #ifdef'ed are now available through + a new interface, SetPacketAliasMode(). This allows run time control (which is now available in PPP+pktAlias through the 'alias' keyword). (ee) @@ -78,7 +125,7 @@ (192.168.0.2, port 21) <-> alias port 3604, known dest addr unknown dest port - These permament links allow for incoming connections to + These permanent links allow for incoming connections to machines on the local network. They can be given with a user-chosen amount of specificity, with increasing specificity meaning more security. (cjm) @@ -103,16 +150,28 @@ version of PacketAliasPermanentLink(). The second function implements static network address translation. + Version 3.2: July, 2000 (salander and satoh) + Added FindNewPortGroup to get contiguous range of port values. + + Added QueryUdpTcpIn and QueryUdpTcpOut to look for an aliasing + link but not actually add one. + + Added FindRtspOut, which is closely derived from FindUdpTcpOut, + except that the alias port (from FindNewPortGroup) is provided + as input. + See HISTORY file for additional revisions. */ /* System include files */ +#include #include #include #include +#include -#include +#include #include #include #include @@ -142,9 +201,10 @@ #define ALIAS_CLEANUP_INTERVAL_SECS 60 #define ALIAS_CLEANUP_MAX_SPOKES 30 -/* Timouts (in seconds) for different link types) */ +/* Timeouts (in seconds) for different link types */ #define ICMP_EXPIRE_TIME 60 #define UDP_EXPIRE_TIME 60 +#define PROTO_EXPIRE_TIME 60 #define FRAGMENT_ID_EXPIRE_TIME 10 #define FRAGMENT_PTR_EXPIRE_TIME 30 @@ -172,6 +232,9 @@ #endif +static int iChatAVHack = 1; + + /* Dummy port number codes used for FindLinkIn/Out() and AddLink(). These constants can be anything except zero, which indicates an unknown port number. */ @@ -190,42 +253,42 @@ The link record is identified by the source address/port and the destination address/port. In the case of an ICMP echo request, the source port is treated as being equivalent - with the 16-bit id number of the ICMP packet. + with the 16-bit ID number of the ICMP packet. The link record also can store some auxiliary data. For TCP connections that have had sequence and acknowledgment modifications, data space is available to track these changes. - A state field is used to keep track in changes to the tcp - connection state. Id numbers of fragments can also be + A state field is used to keep track in changes to the TCP + connection state. ID numbers of fragments can also be stored in the auxiliary space. Pointers to unresolved - framgents can also be stored. + fragments can also be stored. The link records support two independent chainings. Lookup tables for input and out tables hold the initial pointers the link chains. On input, the lookup table indexes on alias port and link type. On output, the lookup table indexes on - source addreess, destination address, source port, destination + source address, destination address, source port, destination port and link type. */ -struct ack_data_record /* used to save changes to ack/seq numbers */ +struct ack_data_record /* used to save changes to ACK/sequence numbers */ { - u_long ack_old; - u_long ack_new; + __uint32_t ack_old; + __uint32_t ack_new; int delta; int active; }; -struct tcp_state /* Information about tcp connection */ +struct tcp_state /* Information about TCP connection */ { int in; /* State for outside -> inside */ int out; /* State for inside -> outside */ - int index; /* Index to ack data array */ - int ack_modified; /* Indicates whether ack and seq numbers */ + int index; /* Index to ACK data array */ + int ack_modified; /* Indicates whether ACK and sequence numbers */ /* been modified */ }; -#define N_LINK_TCP_DATA 3 /* Number of distinct ack number changes +#define N_LINK_TCP_DATA 3 /* Number of distinct ACK number changes saved for a modified TCP stream */ struct tcp_dat { @@ -234,6 +297,13 @@ struct tcp_dat int fwhole; /* Which firewall record is used for this hole? */ }; +struct server /* LSNAT server pool (circular list) */ +{ + struct in_addr addr; + u_short port; + struct server *next; +}; + struct alias_link /* Main data structure */ { struct in_addr src_addr; /* Address and port information */ @@ -244,16 +314,18 @@ struct alias_link /* Main data structure */ u_short dst_port; u_short alias_port; u_short proxy_port; + struct server *server; - int link_type; /* Type of link: tcp, udp, icmp, frag */ + int link_type; /* Type of link: TCP, UDP, ICMP, proto, frag */ /* values for link_type */ -#define LINK_ICMP 1 -#define LINK_UDP 2 -#define LINK_TCP 3 -#define LINK_FRAGMENT_ID 4 -#define LINK_FRAGMENT_PTR 5 -#define LINK_ADDR 6 +#define LINK_ICMP IPPROTO_ICMP +#define LINK_UDP IPPROTO_UDP +#define LINK_TCP IPPROTO_TCP +#define LINK_FRAGMENT_ID (IPPROTO_MAX + 1) +#define LINK_FRAGMENT_PTR (IPPROTO_MAX + 2) +#define LINK_ADDR (IPPROTO_MAX + 3) +#define LINK_PPTP (IPPROTO_MAX + 4) int flags; /* indicates special characteristics */ @@ -263,18 +335,16 @@ struct alias_link /* Main data structure */ #define LINK_PERMANENT 0x04 #define LINK_PARTIALLY_SPECIFIED 0x03 /* logical-or of first two bits */ #define LINK_UNFIREWALLED 0x08 +#define LINK_LAST_LINE_CRLF_TERMED 0x10 +#define LINK_CONE 0x20 int timestamp; /* Time link was last accessed */ int expire_time; /* Expire time for link */ int sockfd; /* socket descriptor */ - u_int start_point_out; /* Index number in output lookup table */ - u_int start_point_in; - struct alias_link *next_out; /* Linked list pointers for input and */ - struct alias_link *last_out; /* output tables */ - struct alias_link *next_in; /* . */ - struct alias_link *last_in; /* . */ + LIST_ENTRY(alias_link) list_out; /* Linked list of pointers for */ + LIST_ENTRY(alias_link) list_in; /* input and output lookup tables */ union /* Auxiliary data */ { @@ -307,16 +377,18 @@ static struct in_addr targetAddress; /* IP address incoming packets */ static struct in_addr nullAddress; /* Used as a dummy parameter for */ /* some function calls */ -static struct alias_link * +static LIST_HEAD(, alias_link) linkTableOut[LINK_TABLE_OUT_SIZE]; /* Lookup table of pointers to */ /* chains of link records. Each */ -static struct alias_link * /* link record is doubly indexed */ +static LIST_HEAD(, alias_link) /* link record is doubly indexed */ linkTableIn[LINK_TABLE_IN_SIZE]; /* into input and output lookup */ /* tables. */ static int icmpLinkCount; /* Link statistics */ static int udpLinkCount; static int tcpLinkCount; +static int pptpLinkCount; +static int protoLinkCount; static int fragmentIdLinkCount; static int fragmentPtrLinkCount; static int sockCount; @@ -350,11 +422,6 @@ static int fireWallFD = -1; /* File descriptor to be able to */ /* flag. */ #endif -static int pptpAliasFlag; /* Indicates if PPTP aliasing is */ - /* on or off */ -static struct in_addr pptpAliasAddr; /* Address of source of PPTP */ - /* packets. */ - @@ -365,9 +432,9 @@ static struct in_addr pptpAliasAddr; /* Address of source of PPTP */ Lookup table starting points: StartPointIn() -- link table initial search point for - outgoing packets - StartPointOut() -- port table initial search point for incoming packets + StartPointOut() -- link table initial search point for + outgoing packets Miscellaneous: SeqDiff() -- difference between two TCP sequences @@ -381,9 +448,11 @@ static u_int StartPointIn(struct in_addr, u_short, int); static u_int StartPointOut(struct in_addr, struct in_addr, u_short, u_short, int); -static int SeqDiff(u_long, u_long); +static int SeqDiff(__uint32_t, __uint32_t); +#ifndef DEBUG static void ShowAliasStats(void); +#endif #ifndef NO_FW_PUNCH /* Firewall control */ @@ -404,7 +473,8 @@ StartPointIn(struct in_addr alias_addr, u_int n; n = alias_addr.s_addr; - n += alias_port; + if (link_type != LINK_PPTP) + n += alias_port; n += link_type; return(n % LINK_TABLE_IN_SIZE); } @@ -418,8 +488,10 @@ StartPointOut(struct in_addr src_addr, struct in_addr dst_addr, n = src_addr.s_addr; n += dst_addr.s_addr; - n += src_port; - n += dst_port; + if (link_type != LINK_PPTP) { + n += src_port; + n += dst_port; + } n += link_type; return(n % LINK_TABLE_OUT_SIZE); @@ -427,7 +499,7 @@ StartPointOut(struct in_addr src_addr, struct in_addr dst_addr, static int -SeqDiff(u_long x, u_long y) +SeqDiff(__uint32_t x, __uint32_t y) { /* Return the difference between two TCP sequence numbers */ @@ -440,6 +512,7 @@ SeqDiff(u_long x, u_long y) } +#ifndef DEBUG static void ShowAliasStats(void) { @@ -447,16 +520,20 @@ ShowAliasStats(void) if (monitorFile) { - fprintf(monitorFile, "icmp=%d, udp=%d, tcp=%d, frag_id=%d frag_ptr=%d", + fprintf(monitorFile, "icmp=%d, udp=%d, tcp=%d, pptp=%d, proto=%d, frag_id=%d frag_ptr=%d", icmpLinkCount, udpLinkCount, tcpLinkCount, + pptpLinkCount, + protoLinkCount, fragmentIdLinkCount, fragmentPtrLinkCount); fprintf(monitorFile, " / tot=%d (sock=%d)\n", icmpLinkCount + udpLinkCount + tcpLinkCount + + pptpLinkCount + + protoLinkCount + fragmentIdLinkCount + fragmentPtrLinkCount, sockCount); @@ -464,6 +541,7 @@ ShowAliasStats(void) fflush(monitorFile); } } +#endif @@ -485,6 +563,9 @@ Link creation and deletion: Link search: FindLinkOut() - find link for outgoing packets FindLinkIn() - find link for incoming packets + +Port search: + FindNewPortGroup() - find an available group of ports */ /* Local prototypes */ @@ -508,7 +589,7 @@ ReLink(struct alias_link *, u_short, u_short, int, int); static struct alias_link * -FindLinkOut(struct in_addr, struct in_addr, u_short, u_short, int); +FindLinkOut(struct in_addr, struct in_addr, u_short, u_short, int, int); static struct alias_link * FindLinkIn(struct in_addr, struct in_addr, u_short, u_short, int, int); @@ -516,16 +597,59 @@ FindLinkIn(struct in_addr, struct in_addr, u_short, u_short, int, int); #define ALIAS_PORT_BASE 0x08000 #define ALIAS_PORT_MASK 0x07fff +#define ALIAS_PORT_MASK_EVEN 0x07ffe #define GET_NEW_PORT_MAX_ATTEMPTS 20 #define GET_ALIAS_PORT -1 +#define GET_ALIAS_EPHEMERAL_PORT -2 #define GET_ALIAS_ID GET_ALIAS_PORT +#define FIND_EVEN_ALIAS_BASE 1 + /* GetNewPort() allocates port numbers. Note that if a port number is already in use, that does not mean that it cannot be used by another link concurrently. This is because GetNewPort() looks for unused triplets: (dest addr, dest port, alias port). */ +static int +GetEphemeralPort(struct alias_link *link) +{ + int i; + + /* Port number search */ + for (i=0; i < GET_NEW_PORT_MAX_ATTEMPTS; i++) + { + struct sockaddr_in sock_addr; + socklen_t salen; + u_short port_net; + struct alias_link *search_result; + + if (GetSocket(0, &link->sockfd, link->link_type) == 0) + return -1; + salen = sizeof(struct sockaddr_in); + if (getsockname(link->sockfd, (struct sockaddr *)&sock_addr, &salen) == -1) + return -1; + port_net = sock_addr.sin_port; + + search_result = FindLinkIn(link->dst_addr, link->alias_addr, + link->dst_port, port_net, + link->link_type, 0); + + if (search_result == NULL) { + link->alias_port = port_net; + return(0); + } + close(link->sockfd); + link->sockfd = -1; + } + #ifdef DEBUG + fprintf(stderr, "PacketAlias/GetEphemeralPort(): "); + fprintf(stderr, "could not find free port\n"); + #endif + + return(-1); +} + static int GetNewPort(struct alias_link *link, int alias_port_param) { @@ -534,16 +658,18 @@ GetNewPort(struct alias_link *link, int alias_port_param) u_short port_sys; u_short port_net; + if (alias_port_param == GET_ALIAS_EPHEMERAL_PORT) + return GetEphemeralPort(link); + /* Description of alias_port_param for GetNewPort(). When this parameter is zero or positive, it precisely specifies the port number. GetNewPort() will return this number without check that it is in use. - Whis this parameter is -1, it indicates to get a randomly + When this parameter is GET_ALIAS_PORT, it indicates to get a randomly selected port number. */ - if (alias_port_param == GET_ALIAS_PORT) { /* @@ -555,7 +681,7 @@ GetNewPort(struct alias_link *link, int alias_port_param) if (packetAliasMode & PKT_ALIAS_SAME_PORTS) { /* - * When the ALIAS_SAME_PORTS option is + * When the PKT_ALIAS_SAME_PORTS option is * chosen, the first try will be the * actual source port. If this is already * in use, the remainder of the trials @@ -607,8 +733,10 @@ GetNewPort(struct alias_link *link, int alias_port_param) if (go_ahead) { - if ((packetAliasMode && PKT_ALIAS_USE_SOCKETS) - && (link->flags & LINK_PARTIALLY_SPECIFIED)) + if ((packetAliasMode & PKT_ALIAS_USE_SOCKETS) + && (link->flags & LINK_PARTIALLY_SPECIFIED) + && ((link->link_type == LINK_TCP) || + (link->link_type == LINK_UDP))) { if (GetSocket(port_net, &link->sockfd, link->link_type)) { @@ -627,7 +755,6 @@ GetNewPort(struct alias_link *link, int alias_port_param) port_sys += ALIAS_PORT_BASE; port_net = htons(port_sys); } - #ifdef DEBUG fprintf(stderr, "PacketAlias/GetnewPort(): "); fprintf(stderr, "could not find free port\n"); @@ -687,6 +814,102 @@ GetSocket(u_short port_net, int *sockfd, int link_type) } +/* FindNewPortGroup() returns a base port number for an available + range of contiguous port numbers. Note that if a port number + is already in use, that does not mean that it cannot be used by + another link concurrently. This is because FindNewPortGroup() + looks for unused triplets: (dest addr, dest port, alias port). */ + +int +FindNewPortGroup(struct in_addr dst_addr, + struct in_addr alias_addr, + u_short src_port, + u_short dst_port, + u_short port_count, + u_char proto, + u_char align) +{ + int i, j; + int max_trials; + u_short port_sys; + int link_type; + + /* + * Get link_type from protocol + */ + + switch (proto) + { + case IPPROTO_UDP: + link_type = LINK_UDP; + break; + case IPPROTO_TCP: + link_type = LINK_TCP; + break; + default: + return (0); + break; + } + + /* + * The aliasing port is automatically selected + * by one of two methods below: + */ + max_trials = GET_NEW_PORT_MAX_ATTEMPTS; + + if (packetAliasMode & PKT_ALIAS_SAME_PORTS) { + /* + * When the ALIAS_SAME_PORTS option is + * chosen, the first try will be the + * actual source port. If this is already + * in use, the remainder of the trials + * will be random. + */ + port_sys = ntohs(src_port); + + } else { + + /* First trial and all subsequent are random. */ + if (align == FIND_EVEN_ALIAS_BASE) + port_sys = random() & ALIAS_PORT_MASK_EVEN; + else + port_sys = random() & ALIAS_PORT_MASK; + + port_sys += ALIAS_PORT_BASE; + } + +/* Port number search */ + for (i = 0; i < max_trials; i++) { + + struct alias_link *search_result; + + for (j = 0; j < port_count; j++) + if (0 != (search_result = FindLinkIn(dst_addr, alias_addr, + dst_port, htons(port_sys + j), + link_type, 0))) + break; + + /* Found a good range, return base */ + if (j == port_count) + return (htons(port_sys)); + + /* Find a new base to try */ + if (align == FIND_EVEN_ALIAS_BASE) + port_sys = random() & ALIAS_PORT_MASK_EVEN; + else + port_sys = random() & ALIAS_PORT_MASK; + + port_sys += ALIAS_PORT_BASE; + } + +#ifdef DEBUG + fprintf(stderr, "PacketAlias/FindNewPortGroup(): "); + fprintf(stderr, "could not find free port(s)\n"); +#endif + + return(0); +} + static void CleanupAliasData(void) { @@ -696,11 +919,11 @@ CleanupAliasData(void) icount = 0; for (i=0; inext_out; + link_next = LIST_NEXT(link, list_out); icount++; DeleteLink(link); link = link_next; @@ -718,26 +941,16 @@ IncrementalCleanup(void) struct alias_link *link; icount = 0; - link = linkTableOut[cleanupIndex++]; + link = LIST_FIRST(&linkTableOut[cleanupIndex++]); while (link != NULL) { int idelta; struct alias_link *link_next; - link_next = link->next_out; + link_next = LIST_NEXT(link, list_out); idelta = timeStamp - link->timestamp; switch (link->link_type) { - case LINK_ICMP: - case LINK_UDP: - case LINK_FRAGMENT_ID: - case LINK_FRAGMENT_PTR: - if (idelta > link->expire_time) - { - DeleteLink(link); - icount++; - } - break; case LINK_TCP: if (idelta > link->expire_time) { @@ -752,6 +965,13 @@ IncrementalCleanup(void) } } break; + default: + if (idelta > link->expire_time) + { + DeleteLink(link); + icount++; + } + break; } link = link_next; } @@ -760,44 +980,35 @@ IncrementalCleanup(void) cleanupIndex = 0; } -void +static void DeleteLink(struct alias_link *link) { - struct alias_link *link_last; - struct alias_link *link_next; /* Don't do anything if the link is marked permanent */ if (deleteAllLinks == 0 && link->flags & LINK_PERMANENT) return; #ifndef NO_FW_PUNCH -/* Delete associatied firewall hole, if any */ +/* Delete associated firewall hole, if any */ ClearFWHole(link); #endif -/* Adjust output table pointers */ - link_last = link->last_out; - link_next = link->next_out; +/* Free memory allocated for LSNAT server pool */ + if (link->server != NULL) { + struct server *head, *curr, *next; - if (link_last != NULL) - link_last->next_out = link_next; - else - linkTableOut[link->start_point_out] = link_next; + head = curr = link->server; + do { + next = curr->next; + free(curr); + } while ((curr = next) != head); + } - if (link_next != NULL) - link_next->last_out = link_last; +/* Adjust output table pointers */ + LIST_REMOVE(link, list_out); /* Adjust input table pointers */ - link_last = link->last_in; - link_next = link->next_in; - - if (link_last != NULL) - link_last->next_in = link_next; - else - linkTableIn[link->start_point_in] = link_next; - - if (link_next != NULL) - link_next->last_in = link_last; + LIST_REMOVE(link, list_in); /* Close socket, if one has been allocated */ if (link->sockfd != -1) @@ -817,8 +1028,10 @@ DeleteLink(struct alias_link *link) break; case LINK_TCP: tcpLinkCount--; - if (link->data.tcp != NULL) - free(link->data.tcp); + free(link->data.tcp); + break; + case LINK_PPTP: + pptpLinkCount--; break; case LINK_FRAGMENT_ID: fragmentIdLinkCount--; @@ -828,16 +1041,48 @@ DeleteLink(struct alias_link *link) if (link->data.frag_ptr != NULL) free(link->data.frag_ptr); break; + case LINK_ADDR: + break; + default: + protoLinkCount--; + break; } -/* Free memory */ - free(link); - -/* Write statistics, if logging enabled */ - if (packetAliasMode & PKT_ALIAS_LOG) +#ifdef DEBUG + if ((packetAliasMode & PKT_ALIAS_LOG) != 0 && + !IN_MULTICAST(link->src_addr.s_addr) && + !IN_MULTICAST(link->dst_addr.s_addr)) { - ShowAliasStats(); + char src[16]; + char dst[16]; + char alias[16]; + char *proto; + switch(link->link_type) + { + case LINK_TCP: + proto = " [TCP]"; + break; + case LINK_UDP: + proto = " [UDP]"; + break; + default: + proto = ""; + } + fprintf(monitorFile, "Deleted%s %s:%d<->%s:%d to %s:%d<->%s:%d\n", + proto, + inet_ntop(AF_INET, &link->src_addr, src, sizeof(src)), link->src_port, + inet_ntop(AF_INET, &link->dst_addr, dst, sizeof(dst)), link->dst_port, + inet_ntop(AF_INET, &link->alias_addr, alias, sizeof(alias)), link->alias_port, + dst, link->dst_port); + fflush(monitorFile); } +#else + if (packetAliasMode & PKT_ALIAS_LOG) + ShowAliasStats(); +#endif + +/* Free memory */ + free(link); } @@ -852,30 +1097,19 @@ AddLink(struct in_addr src_addr, { /* chosen. If greater than */ u_int start_point; /* zero, equal to alias port */ struct alias_link *link; - struct alias_link *first_link; link = malloc(sizeof(struct alias_link)); if (link != NULL) { - /* If either the aliasing address or source address are - equal to the default device address (equal to the - global variable aliasAddress), then set the alias - address field of the link record to zero */ - - if (src_addr.s_addr == aliasAddress.s_addr) - src_addr.s_addr = 0; - - if (alias_addr.s_addr == aliasAddress.s_addr) - alias_addr.s_addr = 0; - /* Basic initialization */ link->src_addr = src_addr; link->dst_addr = dst_addr; link->alias_addr = alias_addr; - link->proxy_addr.s_addr = 0; + link->proxy_addr.s_addr = INADDR_ANY; link->src_port = src_port; link->dst_port = dst_port; link->proxy_port = 0; + link->server = NULL; link->link_type = link_type; link->sockfd = -1; link->flags = 0; @@ -888,21 +1122,32 @@ AddLink(struct in_addr src_addr, link->expire_time = ICMP_EXPIRE_TIME; break; case LINK_UDP: - link->expire_time = UDP_EXPIRE_TIME; + if (dst_addr.s_addr == 0 && dst_port == 0) + link->expire_time = UDP_EXPIRE_TIME * 5; + else + link->expire_time = UDP_EXPIRE_TIME; break; case LINK_TCP: link->expire_time = TCP_EXPIRE_INITIAL; break; + case LINK_PPTP: + link->flags |= LINK_PERMANENT; /* no timeout. */ + break; case LINK_FRAGMENT_ID: link->expire_time = FRAGMENT_ID_EXPIRE_TIME; break; case LINK_FRAGMENT_PTR: link->expire_time = FRAGMENT_PTR_EXPIRE_TIME; break; + case LINK_ADDR: + break; + default: + link->expire_time = PROTO_EXPIRE_TIME; + break; } /* Determine alias flags */ - if (dst_addr.s_addr == 0) + if (dst_addr.s_addr == INADDR_ANY) link->flags |= LINK_UNKNOWN_DEST_ADDR; if (dst_port == 0) link->flags |= LINK_UNKNOWN_DEST_PORT; @@ -913,34 +1158,6 @@ AddLink(struct in_addr src_addr, free(link); return(NULL); } - - /* Set up pointers for output lookup table */ - start_point = StartPointOut(src_addr, dst_addr, - src_port, dst_port, link_type); - first_link = linkTableOut[start_point]; - - link->last_out = NULL; - link->next_out = first_link; - link->start_point_out = start_point; - - if (first_link != NULL) - first_link->last_out = link; - - linkTableOut[start_point] = link; - - /* Set up pointers for input lookup table */ - start_point = StartPointIn(alias_addr, link->alias_port, link_type); - first_link = linkTableIn[start_point]; - - link->last_in = NULL; - link->next_in = first_link; - link->start_point_in = start_point; - - if (first_link != NULL) - first_link->last_in = link; - - linkTableIn[start_point] = link; - /* Link-type dependent initialization */ switch(link_type) { @@ -954,7 +1171,6 @@ AddLink(struct in_addr src_addr, break; case LINK_TCP: aux_tcp = malloc(sizeof(struct tcp_dat)); - link->data.tcp = aux_tcp; if (aux_tcp != NULL) { int i; @@ -967,6 +1183,7 @@ AddLink(struct in_addr src_addr, for (i=0; iack[i].active = 0; aux_tcp->fwhole = -1; + link->data.tcp = aux_tcp; } else { @@ -974,15 +1191,34 @@ AddLink(struct in_addr src_addr, fprintf(stderr, "PacketAlias/AddLink: "); fprintf(stderr, " cannot allocate auxiliary TCP data\n"); #endif + free(link); + return (NULL); } break; + case LINK_PPTP: + pptpLinkCount++; + break; case LINK_FRAGMENT_ID: fragmentIdLinkCount++; break; case LINK_FRAGMENT_PTR: fragmentPtrLinkCount++; break; + case LINK_ADDR: + break; + default: + protoLinkCount++; + break; } + + /* Set up pointers for output lookup table */ + start_point = StartPointOut(src_addr, dst_addr, + src_port, dst_port, link_type); + LIST_INSERT_HEAD(&linkTableOut[start_point], link, list_out); + + /* Set up pointers for input lookup table */ + start_point = StartPointIn(alias_addr, link->alias_port, link_type); + LIST_INSERT_HEAD(&linkTableIn[start_point], link, list_in); } else { @@ -992,10 +1228,37 @@ AddLink(struct in_addr src_addr, #endif } - if (packetAliasMode & PKT_ALIAS_LOG) +#ifdef DEBUG + if ((packetAliasMode & PKT_ALIAS_LOG) != 0 && + !IN_MULTICAST(link->src_addr.s_addr) && + !IN_MULTICAST(link->dst_addr.s_addr)) { - ShowAliasStats(); + char src[16]; + char dst[16]; + char alias[16]; + char *proto; + switch(link->link_type) + { + case LINK_TCP: + proto = " [TCP]"; + break; + case LINK_UDP: + proto = " [UDP]"; + break; + default: + proto = ""; + } + fprintf(monitorFile, "Added %s %s:%d<->%s:%d to %s:%d<->%s:%d\n", + proto, + inet_ntop(AF_INET, &link->src_addr, src, sizeof(src)), link->src_port, + inet_ntop(AF_INET, &link->dst_addr, dst, sizeof(dst)), link->dst_port, + inet_ntop(AF_INET, &link->alias_addr, alias, sizeof(alias)), link->alias_port, + dst, link->dst_port); } +#else + if (packetAliasMode & PKT_ALIAS_LOG) + ShowAliasStats(); +#endif return(link); } @@ -1018,33 +1281,31 @@ ReLink(struct alias_link *old_link, #ifndef NO_FW_PUNCH if (new_link != NULL && old_link->link_type == LINK_TCP && - old_link->data.tcp && old_link->data.tcp->fwhole > 0) { PunchFWHole(new_link); } #endif - DeleteLink(old_link); + if ((old_link->flags & LINK_CONE) == 0) + DeleteLink(old_link); return new_link; } static struct alias_link * -FindLinkOut(struct in_addr src_addr, +_FindLinkOut(struct in_addr src_addr, struct in_addr dst_addr, u_short src_port, u_short dst_port, - int link_type) + int link_type, + int replace_partial_links) { u_int i; struct alias_link *link; - if (src_addr.s_addr == aliasAddress.s_addr) - src_addr.s_addr = 0; - i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type); - link = linkTableOut[i]; - while (link != NULL) + LIST_FOREACH(link, &linkTableOut[i], list_out) { if (link->src_addr.s_addr == src_addr.s_addr + && link->server == NULL && link->dst_addr.s_addr == dst_addr.s_addr && link->dst_port == dst_port && link->src_port == src_port @@ -1053,15 +1314,70 @@ FindLinkOut(struct in_addr src_addr, link->timestamp = timeStamp; break; } - link = link->next_out; + } + +/* Search for partially specified links. */ + if (link == NULL && replace_partial_links) + { + if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY) + { + link = _FindLinkOut(src_addr, dst_addr, src_port, 0, + link_type, 0); + if (link == NULL) + link = _FindLinkOut(src_addr, nullAddress, src_port, + dst_port, link_type, 0); + } + if (link == NULL && + (dst_port != 0 || dst_addr.s_addr != INADDR_ANY)) + { + link = _FindLinkOut(src_addr, nullAddress, src_port, 0, + link_type, 0); + } + if (link != NULL) + { + link = ReLink(link, + src_addr, dst_addr, link->alias_addr, + src_port, dst_port, link->alias_port, + link_type); + } } return(link); } +static struct alias_link * +FindLinkOut(struct in_addr src_addr, + struct in_addr dst_addr, + u_short src_port, + u_short dst_port, + int link_type, + int replace_partial_links) +{ + struct alias_link *link; -struct alias_link * -FindLinkIn(struct in_addr dst_addr, + link = _FindLinkOut(src_addr, dst_addr, src_port, dst_port, + link_type, replace_partial_links); + + if (link == NULL) + { + /* The following allows permanent links to be + specified as using the default source address + (i.e. device interface address) without knowing + in advance what that address is. */ + if (aliasAddress.s_addr != 0 && + src_addr.s_addr == aliasAddress.s_addr) + { + link = _FindLinkOut(nullAddress, dst_addr, src_port, dst_port, + link_type, replace_partial_links); + } + } + + return(link); +} + + +static struct alias_link * +_FindLinkIn(struct in_addr dst_addr, struct in_addr alias_addr, u_short dst_port, u_short alias_port, @@ -1086,23 +1402,14 @@ FindLinkIn(struct in_addr dst_addr, loop will have to know about this. */ flags_in = 0; - if (dst_addr.s_addr == 0) + if (dst_addr.s_addr == INADDR_ANY) flags_in |= LINK_UNKNOWN_DEST_ADDR; if (dst_port == 0) flags_in |= LINK_UNKNOWN_DEST_PORT; -/* The following allows permanent links to be - be specified as using the default aliasing address - (i.e. device interface address) without knowing - in advance what that address is. */ - - if (alias_addr.s_addr == aliasAddress.s_addr) - alias_addr.s_addr = 0; - /* Search loop */ start_point = StartPointIn(alias_addr, alias_port, link_type); - link = linkTableIn[start_point]; - while (link != NULL) + LIST_FOREACH(link, &linkTableIn[start_point], list_in) { int flags; @@ -1152,46 +1459,76 @@ FindLinkIn(struct in_addr dst_addr, link_unknown_dst_port = link; } } - link = link->next_in; } if (link_fully_specified != NULL) { - return link_fully_specified; + link_fully_specified->timestamp = timeStamp; + link = link_fully_specified; } else if (link_unknown_dst_port != NULL) - { - return replace_partial_links - ? ReLink(link_unknown_dst_port, - link_unknown_dst_port->src_addr, dst_addr, alias_addr, - link_unknown_dst_port->src_port, dst_port, alias_port, - link_type) - : link_unknown_dst_port; - } + link = link_unknown_dst_port; else if (link_unknown_dst_addr != NULL) - { - return replace_partial_links - ? ReLink(link_unknown_dst_addr, - link_unknown_dst_addr->src_addr, dst_addr, alias_addr, - link_unknown_dst_addr->src_port, dst_port, alias_port, - link_type) - : link_unknown_dst_addr; - } + link = link_unknown_dst_addr; else if (link_unknown_all != NULL) + link = link_unknown_all; + else + return (NULL); + + if (replace_partial_links && + (link->flags & LINK_PARTIALLY_SPECIFIED || link->server != NULL)) { - return replace_partial_links - ? ReLink(link_unknown_all, - link_unknown_all->src_addr, dst_addr, alias_addr, - link_unknown_all->src_port, dst_port, alias_port, - link_type) - : link_unknown_all; + struct in_addr src_addr; + u_short src_port; + + if (link->server != NULL) { /* LSNAT link */ + src_addr = link->server->addr; + src_port = link->server->port; + link->server = link->server->next; + } else { + src_addr = link->src_addr; + src_port = link->src_port; + } + + link = ReLink(link, + src_addr, dst_addr, alias_addr, + src_port, dst_port, alias_port, + link_type); } - else + + return (link); +} + +static struct alias_link * +FindLinkIn(struct in_addr dst_addr, + struct in_addr alias_addr, + u_short dst_port, + u_short alias_port, + int link_type, + int replace_partial_links) +{ + struct alias_link *link; + + link = _FindLinkIn(dst_addr, alias_addr, dst_port, alias_port, + link_type, replace_partial_links); + + if (link == NULL) { - return(NULL); + /* The following allows permanent links to be + specified as using the default aliasing address + (i.e. device interface address) without knowing + in advance what that address is. */ + if (aliasAddress.s_addr != 0 && + alias_addr.s_addr == aliasAddress.s_addr) + { + link = _FindLinkIn(dst_addr, nullAddress, dst_port, alias_port, + link_type, replace_partial_links); + } } + + return(link); } @@ -1204,7 +1541,10 @@ FindLinkIn(struct in_addr dst_addr, FindIcmpIn(), FindIcmpOut() FindFragmentIn1(), FindFragmentIn2() AddFragmentPtrLink(), FindFragmentPtr() + FindProtoIn(), FindProtoOut() FindUdpTcpIn(), FindUdpTcpOut() + AddPptp(), FindPptpOutByCallId(), FindPptpInByCallId(), + FindPptpOutByPeerCallId(), FindPptpInByPeerCallId() FindOriginalAddress(), FindAliasAddress() (prototypes in alias_local.h) @@ -1214,25 +1554,40 @@ FindLinkIn(struct in_addr dst_addr, struct alias_link * FindIcmpIn(struct in_addr dst_addr, struct in_addr alias_addr, - u_short id_alias) + u_short id_alias, + int create) { - return FindLinkIn(dst_addr, alias_addr, + struct alias_link *link; + + link = FindLinkIn(dst_addr, alias_addr, NO_DEST_PORT, id_alias, LINK_ICMP, 0); + if (link == NULL && create && !(packetAliasMode & PKT_ALIAS_DENY_INCOMING)) + { + struct in_addr target_addr; + + target_addr = FindOriginalAddress(alias_addr); + link = AddLink(target_addr, dst_addr, alias_addr, + id_alias, NO_DEST_PORT, id_alias, + LINK_ICMP); + } + + return (link); } struct alias_link * FindIcmpOut(struct in_addr src_addr, struct in_addr dst_addr, - u_short id) + u_short id, + int create) { struct alias_link * link; link = FindLinkOut(src_addr, dst_addr, id, NO_DEST_PORT, - LINK_ICMP); - if (link == NULL) + LINK_ICMP, 0); + if (link == NULL && create) { struct in_addr alias_addr; @@ -1299,12 +1654,63 @@ FindFragmentPtr(struct in_addr dst_addr, } +struct alias_link * +FindProtoIn(struct in_addr dst_addr, + struct in_addr alias_addr, + u_char proto) +{ + struct alias_link *link; + + link = FindLinkIn(dst_addr, alias_addr, + NO_DEST_PORT, 0, + proto, 1); + + if (link == NULL && !(packetAliasMode & PKT_ALIAS_DENY_INCOMING)) + { + struct in_addr target_addr; + + target_addr = FindOriginalAddress(alias_addr); + link = AddLink(target_addr, dst_addr, alias_addr, + NO_SRC_PORT, NO_DEST_PORT, 0, + proto); + } + + return (link); +} + + +struct alias_link * +FindProtoOut(struct in_addr src_addr, + struct in_addr dst_addr, + u_char proto) +{ + struct alias_link *link; + + link = FindLinkOut(src_addr, dst_addr, + NO_SRC_PORT, NO_DEST_PORT, + proto, 1); + + if (link == NULL) + { + struct in_addr alias_addr; + + alias_addr = FindAliasAddress(src_addr); + link = AddLink(src_addr, dst_addr, alias_addr, + NO_SRC_PORT, NO_DEST_PORT, 0, + proto); + } + + return (link); +} + + struct alias_link * FindUdpTcpIn(struct in_addr dst_addr, struct in_addr alias_addr, u_short dst_port, u_short alias_port, - u_char proto) + u_char proto, + int create) { int link_type; struct alias_link *link; @@ -1324,11 +1730,9 @@ FindUdpTcpIn(struct in_addr dst_addr, link = FindLinkIn(dst_addr, alias_addr, dst_port, alias_port, - link_type, 1); + link_type, create); - if (!(packetAliasMode & PKT_ALIAS_DENY_INCOMING) - && !(packetAliasMode & PKT_ALIAS_PROXY_ONLY) - && link == NULL) + if (link == NULL && create && !(packetAliasMode & PKT_ALIAS_DENY_INCOMING)) { struct in_addr target_addr; @@ -1347,7 +1751,8 @@ FindUdpTcpOut(struct in_addr src_addr, struct in_addr dst_addr, u_short src_port, u_short dst_port, - u_char proto) + u_char proto, + int create) { int link_type; struct alias_link *link; @@ -1365,7 +1770,152 @@ FindUdpTcpOut(struct in_addr src_addr, break; } - link = FindLinkOut(src_addr, dst_addr, src_port, dst_port, link_type); + link = FindLinkOut(src_addr, dst_addr, src_port, dst_port, link_type, create); + + if (link == NULL && create) + { + struct in_addr alias_addr; + struct in_addr dst_addr2 = dst_addr; + u_short dst_port2 = dst_port; + + alias_addr = FindAliasAddress(src_addr); + + if (iChatAVHack && link_type == LINK_UDP && dst_port == htons(5678)) { + dst_addr2.s_addr = 0; + dst_port2 = 0; + } + link = AddLink(src_addr, dst_addr2, alias_addr, + src_port, dst_port2, GET_ALIAS_PORT, + link_type); + if (link != NULL && + (link->flags & (LINK_UNKNOWN_DEST_ADDR | LINK_UNKNOWN_DEST_PORT)) != 0) + { + link->flags |= LINK_CONE; + link = ReLink(link, link->src_addr, dst_addr, link->alias_addr, + link->src_port, dst_port, link->alias_port, link_type); + } + } + + return(link); +} + + +struct alias_link * +AddPptp(struct in_addr src_addr, + struct in_addr dst_addr, + struct in_addr alias_addr, + u_int16_t src_call_id) +{ + struct alias_link *link; + + link = AddLink(src_addr, dst_addr, alias_addr, + src_call_id, 0, GET_ALIAS_PORT, + LINK_PPTP); + + return (link); +} + + +struct alias_link * +FindPptpOutByCallId(struct in_addr src_addr, + struct in_addr dst_addr, + u_int16_t src_call_id) +{ + u_int i; + struct alias_link *link; + + i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP); + LIST_FOREACH(link, &linkTableOut[i], list_out) + if (link->link_type == LINK_PPTP && + link->src_addr.s_addr == src_addr.s_addr && + link->dst_addr.s_addr == dst_addr.s_addr && + link->src_port == src_call_id) + break; + + return (link); +} + + +struct alias_link * +FindPptpOutByPeerCallId(struct in_addr src_addr, + struct in_addr dst_addr, + u_int16_t dst_call_id) +{ + u_int i; + struct alias_link *link; + + i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP); + LIST_FOREACH(link, &linkTableOut[i], list_out) + if (link->link_type == LINK_PPTP && + link->src_addr.s_addr == src_addr.s_addr && + link->dst_addr.s_addr == dst_addr.s_addr && + link->dst_port == dst_call_id) + break; + + return (link); +} + + +struct alias_link * +FindPptpInByCallId(struct in_addr dst_addr, + struct in_addr alias_addr, + u_int16_t dst_call_id) +{ + u_int i; + struct alias_link *link; + + i = StartPointIn(alias_addr, 0, LINK_PPTP); + LIST_FOREACH(link, &linkTableIn[i], list_in) + if (link->link_type == LINK_PPTP && + link->dst_addr.s_addr == dst_addr.s_addr && + link->alias_addr.s_addr == alias_addr.s_addr && + link->dst_port == dst_call_id) + break; + + return (link); +} + + +struct alias_link * +FindPptpInByPeerCallId(struct in_addr dst_addr, + struct in_addr alias_addr, + u_int16_t alias_call_id) +{ + struct alias_link *link; + + link = FindLinkIn(dst_addr, alias_addr, + 0/* any */, alias_call_id, + LINK_PPTP, 0); + + + return (link); +} + + +struct alias_link * +FindRtspOut(struct in_addr src_addr, + struct in_addr dst_addr, + u_short src_port, + u_short alias_port, + u_char proto) +{ + int link_type; + struct alias_link *link; + + switch (proto) + { + case IPPROTO_UDP: + link_type = LINK_UDP; + break; + case IPPROTO_TCP: + link_type = LINK_TCP; + break; + default: + return NULL; + break; + } + + link = FindLinkOut(src_addr, dst_addr, src_port, 0, link_type, 1); if (link == NULL) { @@ -1373,7 +1923,7 @@ FindUdpTcpOut(struct in_addr src_addr, alias_addr = FindAliasAddress(src_addr); link = AddLink(src_addr, dst_addr, alias_addr, - src_port, dst_port, GET_ALIAS_PORT, + src_port, 0, alias_port, link_type); } @@ -1391,14 +1941,22 @@ FindOriginalAddress(struct in_addr alias_addr) if (link == NULL) { newDefaultLink = 1; - if (targetAddress.s_addr != 0) - return targetAddress; - else + if (targetAddress.s_addr == INADDR_ANY) return alias_addr; + else if (targetAddress.s_addr == INADDR_NONE) + return aliasAddress; + else + return targetAddress; } else { - if (link->src_addr.s_addr == 0) + if (link->server != NULL) { /* LSNAT link */ + struct in_addr src_addr; + + src_addr = link->server->addr; + link->server = link->server->next; + return (src_addr); + } else if (link->src_addr.s_addr == INADDR_ANY) return aliasAddress; else return link->src_addr; @@ -1412,20 +1970,129 @@ FindAliasAddress(struct in_addr original_addr) struct alias_link *link; link = FindLinkOut(original_addr, nullAddress, - 0, 0, LINK_ADDR); + 0, 0, LINK_ADDR, 0); if (link == NULL) { return aliasAddress; } else { - if (link->alias_addr.s_addr == 0) + if (link->alias_addr.s_addr == INADDR_ANY) return aliasAddress; else return link->alias_addr; } } +/* FindAliasPortOut */ +/* external routine for NatPortMap */ +/* return alias port for the src_addr,dst_addr,src_port and proto */ +/* if one doesn't existed, create a mapping with providing pub_port if it's not 0 */ +/* delete mapping if addmapping is not true */ +int +FindAliasPortOut(struct in_addr src_addr, struct in_addr dst_addr, u_short src_port, u_short pub_port, u_char proto, int lifetime, char addmapping) +{ + u_int i; + struct alias_link *link; + int link_type; + + switch (proto) + { + case IPPROTO_UDP: + link_type = LINK_UDP; + break; + case IPPROTO_TCP: + link_type = LINK_TCP; + break; + default: + return 0; + break; + } + +#ifdef DEBUG + { + int icount = 0; + + printf("FindAliasPortOut:: srcaddr= %s:%u, ", + inet_ntoa(src_addr), ntohs(src_port)); + printf("dstadd= %s:%u link_type= %d, lifetime= %d\n", + inet_ntoa(dst_addr), ntohs(pub_port), link_type, lifetime); + + for (i=0; isrc_addr), ntohs(link->src_port)); + snprintf(dst_str, sizeof(dst_str), "%s:%u", + inet_ntoa(link->dst_addr), ntohs(link->dst_port)); + snprintf(alias_str, sizeof(alias_str), "%s:%u", + inet_ntoa(link->alias_addr), ntohs(link->alias_port)); + + printf(" linkTableOut[%d:%d] src= %s dst= %s alias= %s flags= 0x%x linktype= %d ts= %d exp= %d fd= %d\n", + i, icount, src_str, dst_str, alias_str, + link->flags, link->link_type, link->timestamp, link->expire_time, link->sockfd); + + link_next = LIST_NEXT(link, list_out); + icount++; + link = link_next; + } + } + + } +#endif + + i = StartPointOut(src_addr, dst_addr, src_port, 0, link_type); +#ifdef DEBUG + printf("PORTMAP::StartPointOut returns %d\n", i); +#endif + LIST_FOREACH(link, &linkTableOut[i], list_out) + { + if (link->src_addr.s_addr == src_addr.s_addr && + link->dst_addr.s_addr == dst_addr.s_addr && + link->src_port == src_port && link->link_type == link_type) + break; + } + + if ( link == NULL && addmapping) + { + struct in_addr alias_addr; +#ifdef DEBUG + printf("PORTMAP:: cannot find mapping, adding mapping private port =%d, public port = %d\n", + src_port, pub_port); +#endif + /* address/port in not in list, create new mapping */ + + alias_addr = FindAliasAddress(src_addr); + /* create new mapping */ + link = AddLink(src_addr, dst_addr, alias_addr, + src_port, 0, GET_ALIAS_EPHEMERAL_PORT, + link_type); + if ( link != NULL ) { + /* link was create, set new lifetime */ + SetExpire(link, lifetime); + /* Prevent link deletion when incoming connection arrive */ + link->flags |= LINK_CONE; + } + } + if ( link ) + { + if ( addmapping ) + return( GetAliasPort(link)); + else + { + SetExpire(link, 0); /* delete mapping */ + return 0; + } + } + + return -1; +} + /* External routines for getting or changing link data (external to alias_db.c, but internal to alias*.c) @@ -1437,6 +2104,8 @@ FindAliasAddress(struct in_addr original_addr) GetOriginalPort(), GetAliasPort() SetAckModified(), GetAckModified() GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq() + SetLastLineCrlfTermed(), GetLastLineCrlfTermed() + SetDestCallId() */ @@ -1474,22 +2143,19 @@ SetStateIn(struct alias_link *link, int state) /* TCP input state */ switch (state) { case ALIAS_TCP_STATE_DISCONNECTED: - if (link->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED) { + if (link->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED) link->expire_time = TCP_EXPIRE_DEAD; - } else { + else link->expire_time = TCP_EXPIRE_SINGLEDEAD; - } - link->data.tcp->state.in = state; break; case ALIAS_TCP_STATE_CONNECTED: - link->expire_time = TCP_EXPIRE_CONNECTED; - /*FALLTHROUGH*/ - case ALIAS_TCP_STATE_NOT_CONNECTED: - link->data.tcp->state.in = state; + if (link->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED) + link->expire_time = TCP_EXPIRE_CONNECTED; break; default: abort(); } + link->data.tcp->state.in = state; } @@ -1499,22 +2165,19 @@ SetStateOut(struct alias_link *link, int state) /* TCP output state */ switch (state) { case ALIAS_TCP_STATE_DISCONNECTED: - if (link->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED) { + if (link->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED) link->expire_time = TCP_EXPIRE_DEAD; - } else { + else link->expire_time = TCP_EXPIRE_SINGLEDEAD; - } - link->data.tcp->state.out = state; break; case ALIAS_TCP_STATE_CONNECTED: - link->expire_time = TCP_EXPIRE_CONNECTED; - /*FALLTHROUGH*/ - case ALIAS_TCP_STATE_NOT_CONNECTED: - link->data.tcp->state.out = state; + if (link->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED) + link->expire_time = TCP_EXPIRE_CONNECTED; break; default: abort(); } + link->data.tcp->state.out = state; } @@ -1537,7 +2200,7 @@ GetStateOut(struct alias_link *link) struct in_addr GetOriginalAddress(struct alias_link *link) { - if (link->src_addr.s_addr == 0) + if (link->src_addr.s_addr == INADDR_ANY) return aliasAddress; else return(link->src_addr); @@ -1554,7 +2217,7 @@ GetDestAddress(struct alias_link *link) struct in_addr GetAliasAddress(struct alias_link *link) { - if (link->alias_addr.s_addr == 0) + if (link->alias_addr.s_addr == INADDR_ANY) return aliasAddress; else return link->alias_addr; @@ -1588,16 +2251,18 @@ GetAliasPort(struct alias_link *link) return(link->alias_port); } -u_short +#ifndef NO_FW_PUNCH +static u_short GetDestPort(struct alias_link *link) { return(link->dst_port); } +#endif void SetAckModified(struct alias_link *link) { -/* Indicate that ack numbers have been modified in a TCP connection */ +/* Indicate that ACK numbers have been modified in a TCP connection */ link->data.tcp->state.ack_modified = 1; } @@ -1633,7 +2298,7 @@ SetProxyPort(struct alias_link *link, u_short port) int GetAckModified(struct alias_link *link) { -/* See if ack numbers have been modified */ +/* See if ACK numbers have been modified */ return link->data.tcp->state.ack_modified; } @@ -1642,15 +2307,15 @@ int GetDeltaAckIn(struct ip *pip, struct alias_link *link) { /* -Find out how much the ack number has been altered for an incoming -TCP packet. To do this, a circular list is ack numbers where the TCP +Find out how much the ACK number has been altered for an incoming +TCP packet. To do this, a circular list of ACK numbers where the TCP packet size was altered is searched. */ int i; struct tcphdr *tc; int delta, ack_diff_min; - u_long ack; + __uint32_t ack; tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); ack = tc->th_ack; @@ -1693,15 +2358,15 @@ int GetDeltaSeqOut(struct ip *pip, struct alias_link *link) { /* -Find out how much the seq number has been altered for an outgoing -TCP packet. To do this, a circular list is ack numbers where the TCP +Find out how much the sequence number has been altered for an outgoing +TCP packet. To do this, a circular list of ACK numbers where the TCP packet size was altered is searched. */ int i; struct tcphdr *tc; int delta, seq_diff_min; - u_long seq; + __uint32_t seq; tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); seq = tc->th_seq; @@ -1806,6 +2471,33 @@ ClearCheckNewLink(void) newDefaultLink = 0; } +void +SetLastLineCrlfTermed(struct alias_link *link, int yes) +{ + + if (yes) + link->flags |= LINK_LAST_LINE_CRLF_TERMED; + else + link->flags &= ~LINK_LAST_LINE_CRLF_TERMED; +} + +int +GetLastLineCrlfTermed(struct alias_link *link) +{ + + return (link->flags & LINK_LAST_LINE_CRLF_TERMED); +} + +void +SetDestCallId(struct alias_link *link, u_int16_t cid) +{ + + deleteAllLinks = 1; + link = ReLink(link, link->src_addr, link->dst_addr, link->alias_addr, + link->src_port, cid, link->alias_port, link->link_type); + deleteAllLinks = 0; +} + /* Miscellaneous Functions @@ -1910,6 +2602,8 @@ UninitPacketAliasLog(void) -- "outside world" means other than alias*.c routines -- PacketAliasRedirectPort() + PacketAliasAddServer() + PacketAliasRedirectProto() PacketAliasRedirectAddr() PacketAliasRedirectDelete() PacketAliasSetAddress() @@ -1921,7 +2615,7 @@ UninitPacketAliasLog(void) */ /* Redirection from a specific public addr:port to a - a private addr:port */ + private addr:port */ struct alias_link * PacketAliasRedirectPort(struct in_addr src_addr, u_short src_port, struct in_addr dst_addr, u_short dst_port, @@ -1966,24 +2660,63 @@ PacketAliasRedirectPort(struct in_addr src_addr, u_short src_port, return link; } -/* Translate PPTP packets to a machine on the inside - */ +/* Add server to the pool of servers */ int -PacketAliasPptp(struct in_addr src_addr) +PacketAliasAddServer(struct alias_link *link, struct in_addr addr, u_short port) { + struct server *server; - pptpAliasAddr = src_addr; /* Address of the inside PPTP machine */ - pptpAliasFlag = src_addr.s_addr != INADDR_NONE; + server = malloc(sizeof(struct server)); - return 1; + if (server != NULL) { + struct server *head; + + server->addr = addr; + server->port = port; + + head = link->server; + if (head == NULL) + server->next = server; + else { + struct server *s; + + for (s = head; s->next != head; s = s->next); + s->next = server; + server->next = head; + } + link->server = server; + return (0); + } else + return (-1); } -int GetPptpAlias (struct in_addr* alias_addr) +/* Redirect packets of a given IP protocol from a specific + public address to a private address */ +struct alias_link * +PacketAliasRedirectProto(struct in_addr src_addr, + struct in_addr dst_addr, + struct in_addr alias_addr, + u_char proto) { - if (pptpAliasFlag) - *alias_addr = pptpAliasAddr; + struct alias_link *link; + + link = AddLink(src_addr, dst_addr, alias_addr, + NO_SRC_PORT, NO_DEST_PORT, 0, + proto); + + if (link != NULL) + { + link->flags |= LINK_PERMANENT; + } +#ifdef DEBUG + else + { + fprintf(stderr, "PacketAliasRedirectProto(): " + "call to AddLink() failed\n"); + } +#endif - return pptpAliasFlag; + return link; } /* Static address translation */ @@ -2059,9 +2792,9 @@ PacketAliasInit(void) houseKeepingResidual = 0; for (i=0; i #include #include #include @@ -2169,19 +2901,13 @@ static char *fireWallField; /* bool array for entries */ #define fw_setfield(field, num) \ do { \ - (field)[num] = 1; \ + (field)[(num) - fireWallBaseNum] = 1; \ } /*lint -save -e717 */ while(0) /*lint -restore */ #define fw_clrfield(field, num) \ do { \ - (field)[num] = 0; \ + (field)[(num) - fireWallBaseNum] = 0; \ } /*lint -save -e717 */ while(0) /*lint -restore */ -#define fw_tstfield(field, num) ((field)[num]) - -void -PacketAliasSetFWBase(unsigned int base, unsigned int num) { - fireWallBaseNum = base; - fireWallNumNums = num; -} +#define fw_tstfield(field, num) ((field)[(num) - fireWallBaseNum]) static void InitPunchFW(void) { @@ -2218,8 +2944,7 @@ PunchFWHole(struct alias_link *link) { /* Don't do anything unless we are asked to */ if ( !(packetAliasMode & PKT_ALIAS_PUNCH_FW) || fireWallFD < 0 || - link->link_type != LINK_TCP || - !link->data.tcp) + link->link_type != LINK_TCP) return; memset(&rule, 0, sizeof rule); @@ -2232,8 +2957,7 @@ PunchFWHole(struct alias_link *link) { fw_tstfield(fireWallField, fwhole); fwhole++) ; - if (fwhole >= fireWallBaseNum + fireWallNumNums || - fw_tstfield(fireWallField, fwhole)) { + if (fwhole == fireWallBaseNum + fireWallNumNums) { for (fwhole = fireWallBaseNum; fwhole < fireWallActiveNum && fw_tstfield(fireWallField, fwhole); @@ -2253,8 +2977,9 @@ PunchFWHole(struct alias_link *link) { /* Build generic part of the two rules */ rule.fw_number = fwhole; - rule.fw_nports = 1; /* Number of source ports; dest ports follow */ - rule.fw_flg = IP_FW_F_ACCEPT; + IP_FW_SETNSRCP(&rule, 1); /* Number of source ports. */ + IP_FW_SETNDSTP(&rule, 1); /* Number of destination ports. */ + rule.fw_flg = IP_FW_F_ACCEPT | IP_FW_F_IN | IP_FW_F_OUT; rule.fw_prot = IPPROTO_TCP; rule.fw_smsk.s_addr = INADDR_BROADCAST; rule.fw_dmsk.s_addr = INADDR_BROADCAST; @@ -2294,7 +3019,7 @@ PunchFWHole(struct alias_link *link) { link. Calling this too often is harmless. */ static void ClearFWHole(struct alias_link *link) { - if (link->link_type == LINK_TCP && link->data.tcp) { + if (link->link_type == LINK_TCP) { int fwhole = link->data.tcp->fwhole; /* Where is the firewall hole? */ struct ip_fw rule; @@ -2328,3 +3053,44 @@ ClearAllFWHoles(void) { memset(fireWallField, 0, fireWallNumNums); } #endif + +void +PacketAliasSetFWBase(unsigned int base, unsigned int num) { +#ifndef NO_FW_PUNCH + fireWallBaseNum = base; + fireWallNumNums = num; +#endif +} + +void +DumpInfo(void) +{ + int i, icount = 0; + struct alias_link *link; + + for (i=0; isrc_addr), ntohs(link->src_port)); + snprintf(dst_str, sizeof(dst_str), "%s:%u", + inet_ntoa(link->dst_addr), ntohs(link->dst_port)); + snprintf(alias_str, sizeof(alias_str), "%s:%u", + inet_ntoa(link->alias_addr), ntohs(link->alias_port)); + + syslog(LOG_ERR, " linkTableOut[%d:%d] src= %s dst= %s alias= %s flags= 0x%x linktype= %d ts= %d exp= %d fd= %d", + i, icount, src_str, dst_str, alias_str, + link->flags, link->link_type, link->timestamp, link->expire_time, link->sockfd); + + link_next = LIST_NEXT(link, list_out); + icount++; + link = link_next; + } + } + +}