diff options
author | glebius <glebius@FreeBSD.org> | 2005-05-04 12:49:44 +0000 |
---|---|---|
committer | glebius <glebius@FreeBSD.org> | 2005-05-04 12:49:44 +0000 |
commit | c9c0d4d0d6f2957fc31eff768b148f2b7bd0055a (patch) | |
tree | ff67c2e32d850de98f6b748dae2602e636f9905b /lib/libalias/alias_db.c | |
parent | 5542bd31ad4b03bd09d973ddb03a5b35664bbaea (diff) | |
download | FreeBSD-src-c9c0d4d0d6f2957fc31eff768b148f2b7bd0055a.zip FreeBSD-src-c9c0d4d0d6f2957fc31eff768b148f2b7bd0055a.tar.gz |
Build userland libalias using src/sys/netinet/libalias.
Reviewed by: ru
Repocopy by: peter
Diffstat (limited to 'lib/libalias/alias_db.c')
-rw-r--r-- | lib/libalias/alias_db.c | 2788 |
1 files changed, 0 insertions, 2788 deletions
diff --git a/lib/libalias/alias_db.c b/lib/libalias/alias_db.c deleted file mode 100644 index f9c953b..0000000 --- a/lib/libalias/alias_db.c +++ /dev/null @@ -1,2788 +0,0 @@ -/*- - * Copyright (c) 2001 Charles Mott <cm@linktel.net> - * 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. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -/* - 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. - - Data storage is based on the notion of a "link", which is - established for ICMP echo/reply packets, UDP datagrams and - TCP stream connections. A link stores the original source - and destination addresses. For UDP and TCP, it also stores - source and destination port numbers, as well as an alias - port number. Links are also used to store information about - fragments. - - There is a facility for sweeping through and deleting old - links as new packets are sent through. A simple timeout is - used for ICMP and UDP links. TCP links are left alone unless - there is an incomplete connection, in which case the link - can be deleted after a certain amount of time. - - - Initial version: August, 1996 (cjm) - - Version 1.4: September 16, 1996 (cjm) - Facility for handling incoming links added. - - Version 1.6: September 18, 1996 (cjm) - ICMP data handling simplified. - - Version 1.7: January 9, 1997 (cjm) - Fragment handling simplified. - Saves pointers for unresolved fragments. - 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. - Cleaned up some obsolete comments. - - Version 1.8: January 14, 1997 (cjm) - Fixed data type error in StartPoint(). - (This error did not exist prior to v1.7 - and was discovered and fixed by Ari Suutari) - - Version 1.9: February 1, 1997 - Optionally, connections initiated from packet aliasing host - 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 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) - - Added ability to create an alias port without - either destination address or port specified. - port type = ALIAS_PORT_UNKNOWN_DEST_ALL (ee) - - Removed K&R style function headers - and general cleanup. (ee) - - Added packetAliasMode to replace compiler #defines's (ee) - - Allocates sockets for partially specified - ports if ALIAS_USE_SOCKETS defined. (cjm) - - Version 2.0: March, 1997 - SetAliasAddress() will now clean up alias links - if the aliasing address is changed. (cjm) - - PacketAliasPermanentLink() function added to support permanent - links. (J. Fortes suggested the need for this.) - Examples: - - (192.168.0.1, port 23) <-> alias port 6002, unknown dest addr/port - - (192.168.0.2, port 21) <-> alias port 3604, known dest addr - unknown dest port - - 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) - - Quite a bit of rework to the basic engine. The portTable[] - array, which kept track of which ports were in use was replaced - by a table/linked list structure. (cjm) - - SetExpire() function added. (cjm) - - DeleteLink() no longer frees memory association with a pointer - to a fragment (this bug was first recognized by E. Eklund in - v1.9). - - Version 2.1: May, 1997 (cjm) - Packet aliasing engine reworked so that it can handle - multiple external addresses rather than just a single - host address. - - PacketAliasRedirectPort() and PacketAliasRedirectAddr() - added to the API. The first function is a more generalized - 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 <errno.h> -#include <stdlib.h> -#include <stdio.h> -#include <unistd.h> - -#include <sys/queue.h> -#include <sys/socket.h> -#include <sys/time.h> -#include <sys/types.h> - -/* BSD network include files */ -#include <netinet/in_systm.h> -#include <netinet/in.h> -#include <netinet/ip.h> -#include <netinet/tcp.h> -#include <arpa/inet.h> - -#include "alias.h" -#include "alias_local.h" - - -static LIST_HEAD(, libalias) instancehead = LIST_HEAD_INITIALIZER(instancehead); - - -/* - Constants (note: constants are also defined - near relevant functions or structs) -*/ - -/* Parameters used for cleanup of expired links */ -#define ALIAS_CLEANUP_INTERVAL_SECS 60 -#define ALIAS_CLEANUP_MAX_SPOKES 30 - -/* 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 - -/* TCP link expire time for different cases */ -/* When the link has been used and closed - minimal grace time to - allow ACKs and potential re-connect in FTP (XXX - is this allowed?) */ -#ifndef TCP_EXPIRE_DEAD -#define TCP_EXPIRE_DEAD 10 -#endif - -/* When the link has been used and closed on one side - the other side - is allowed to still send data */ -#ifndef TCP_EXPIRE_SINGLEDEAD -#define TCP_EXPIRE_SINGLEDEAD 90 -#endif - -/* When the link isn't yet up */ -#ifndef TCP_EXPIRE_INITIAL -#define TCP_EXPIRE_INITIAL 300 -#endif - -/* When the link is up */ -#ifndef TCP_EXPIRE_CONNECTED -#define TCP_EXPIRE_CONNECTED 86400 -#endif - - -/* Dummy port number codes used for FindLinkIn/Out() and AddLink(). - These constants can be anything except zero, which indicates an - unknown port number. */ - -#define NO_DEST_PORT 1 -#define NO_SRC_PORT 1 - - - -/* Data Structures - - The fundamental data structure used in this program is - "struct alias_link". Whenever a TCP connection is made, - a UDP datagram is sent out, or an ICMP echo request is made, - a link record is made (if it has not already been created). - 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. - - 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 - stored in the auxiliary space. Pointers to unresolved - 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 address, destination address, source port, destination - port and link type. -*/ - -struct ack_data_record { /* used to save changes to ACK/sequence - * numbers */ - u_long ack_old; - u_long ack_new; - int delta; - int active; -}; - -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 - * sequence numbers */ - /* been modified */ -}; - -#define N_LINK_TCP_DATA 3 /* Number of distinct ACK number changes - * saved for a modified TCP stream */ -struct tcp_dat { - struct tcp_state state; - struct ack_data_record ack[N_LINK_TCP_DATA]; - 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 libalias *la; - struct in_addr src_addr; /* Address and port information */ - struct in_addr dst_addr; - struct in_addr alias_addr; - struct in_addr proxy_addr; - u_short src_port; - u_short dst_port; - u_short alias_port; - u_short proxy_port; - struct server *server; - - int link_type; /* Type of link: TCP, UDP, ICMP, - * proto, frag */ - -/* values for link_type */ -#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 */ - int pflags; /* protocol-specific flags */ - -/* flag bits */ -#define LINK_UNKNOWN_DEST_PORT 0x01 -#define LINK_UNKNOWN_DEST_ADDR 0x02 -#define LINK_PERMANENT 0x04 -#define LINK_PARTIALLY_SPECIFIED 0x03 /* logical-or of first two bits */ -#define LINK_UNFIREWALLED 0x08 - - int timestamp; /* Time link was last accessed */ - int expire_time; /* Expire time for link */ - - int sockfd; /* socket descriptor */ - - 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 */ - char *frag_ptr; - struct in_addr frag_addr; - struct tcp_dat *tcp; - } data; -}; - -/* Internal utility routines (used only in alias_db.c) - -Lookup table starting points: - StartPointIn() -- link table initial search point for - incoming packets - StartPointOut() -- link table initial search point for - outgoing packets - -Miscellaneous: - SeqDiff() -- difference between two TCP sequences - ShowAliasStats() -- send alias statistics to a monitor file -*/ - - -/* Local prototypes */ -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 void ShowAliasStats(struct libalias *); - -#ifndef NO_FW_PUNCH -/* Firewall control */ -static void InitPunchFW(struct libalias *); -static void UninitPunchFW(struct libalias *); -static void ClearFWHole(struct alias_link *); - -#endif - -/* Log file control */ -static void InitPacketAliasLog(struct libalias *); -static void UninitPacketAliasLog(struct libalias *); - -static u_int -StartPointIn(struct in_addr alias_addr, - u_short alias_port, - int link_type) -{ - u_int n; - - n = alias_addr.s_addr; - if (link_type != LINK_PPTP) - n += alias_port; - n += link_type; - return (n % LINK_TABLE_IN_SIZE); -} - - -static u_int -StartPointOut(struct in_addr src_addr, struct in_addr dst_addr, - u_short src_port, u_short dst_port, int link_type) -{ - u_int n; - - n = src_addr.s_addr; - n += dst_addr.s_addr; - if (link_type != LINK_PPTP) { - n += src_port; - n += dst_port; - } - n += link_type; - - return (n % LINK_TABLE_OUT_SIZE); -} - - -static int -SeqDiff(u_long x, u_long y) -{ -/* Return the difference between two TCP sequence numbers */ - -/* - This function is encapsulated in case there are any unusual - arithmetic conditions that need to be considered. -*/ - - return (ntohl(y) - ntohl(x)); -} - - -static void -ShowAliasStats(struct libalias *la) -{ -/* Used for debugging */ - - if (la->monitorFile) { - fprintf(la->monitorFile, - "icmp=%d, udp=%d, tcp=%d, pptp=%d, proto=%d, frag_id=%d frag_ptr=%d", - la->icmpLinkCount, - la->udpLinkCount, - la->tcpLinkCount, - la->pptpLinkCount, - la->protoLinkCount, - la->fragmentIdLinkCount, - la->fragmentPtrLinkCount); - - fprintf(la->monitorFile, " / tot=%d (sock=%d)\n", - la->icmpLinkCount + la->udpLinkCount - + la->tcpLinkCount - + la->pptpLinkCount - + la->protoLinkCount - + la->fragmentIdLinkCount - + la->fragmentPtrLinkCount, - la->sockCount); - - fflush(la->monitorFile); - } -} - - - - - -/* Internal routines for finding, deleting and adding links - -Port Allocation: - GetNewPort() -- find and reserve new alias port number - GetSocket() -- try to allocate a socket for a given port - -Link creation and deletion: - CleanupAliasData() - remove all link chains from lookup table - IncrementalCleanup() - look for stale links in a single chain - DeleteLink() - remove link - AddLink() - add link - ReLink() - change link - -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 */ -static int GetNewPort(struct libalias *, struct alias_link *, int); - -static u_short GetSocket(struct libalias *, u_short, int *, int); - -static void CleanupAliasData(struct libalias *); - -static void IncrementalCleanup(struct libalias *); - -static void DeleteLink(struct alias_link *); - -static struct alias_link * -AddLink(struct libalias *, struct in_addr, struct in_addr, struct in_addr, - u_short, u_short, int, int); - -static struct alias_link * -ReLink(struct alias_link *, - struct in_addr, struct in_addr, struct in_addr, - u_short, u_short, int, int); - -static struct alias_link * - FindLinkOut (struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int); - -static struct alias_link * - FindLinkIn (struct libalias *, 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_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 -GetNewPort(struct libalias *la, struct alias_link *lnk, int alias_port_param) -{ - int i; - int max_trials; - u_short port_sys; - u_short port_net; - -/* - 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. - - When this parameter is GET_ALIAS_PORT, it indicates to get a randomly - selected port number. -*/ - - if (alias_port_param == GET_ALIAS_PORT) { - /* - * The aliasing port is automatically selected by one of - * two methods below: - */ - max_trials = GET_NEW_PORT_MAX_ATTEMPTS; - - if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) { - /* - * 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 will be random. - */ - port_net = lnk->src_port; - port_sys = ntohs(port_net); - } else { - /* First trial and all subsequent are random. */ - port_sys = random() & ALIAS_PORT_MASK; - port_sys += ALIAS_PORT_BASE; - port_net = htons(port_sys); - } - } else if (alias_port_param >= 0 && alias_port_param < 0x10000) { - lnk->alias_port = (u_short) alias_port_param; - return (0); - } else { -#ifdef DEBUG - fprintf(stderr, "PacketAlias/GetNewPort(): "); - fprintf(stderr, "input parameter error\n"); -#endif - return (-1); - } - - -/* Port number search */ - for (i = 0; i < max_trials; i++) { - int go_ahead; - struct alias_link *search_result; - - search_result = FindLinkIn(la, lnk->dst_addr, lnk->alias_addr, - lnk->dst_port, port_net, - lnk->link_type, 0); - - if (search_result == NULL) - go_ahead = 1; - else if (!(lnk->flags & LINK_PARTIALLY_SPECIFIED) - && (search_result->flags & LINK_PARTIALLY_SPECIFIED)) - go_ahead = 1; - else - go_ahead = 0; - - if (go_ahead) { - if ((la->packetAliasMode & PKT_ALIAS_USE_SOCKETS) - && (lnk->flags & LINK_PARTIALLY_SPECIFIED) - && ((lnk->link_type == LINK_TCP) || - (lnk->link_type == LINK_UDP))) { - if (GetSocket(la, port_net, &lnk->sockfd, lnk->link_type)) { - lnk->alias_port = port_net; - return (0); - } - } else { - lnk->alias_port = port_net; - return (0); - } - } - port_sys = random() & ALIAS_PORT_MASK; - port_sys += ALIAS_PORT_BASE; - port_net = htons(port_sys); - } - -#ifdef DEBUG - fprintf(stderr, "PacketAlias/GetnewPort(): "); - fprintf(stderr, "could not find free port\n"); -#endif - - return (-1); -} - - -static u_short -GetSocket(struct libalias *la, u_short port_net, int *sockfd, int link_type) -{ - int err; - int sock; - struct sockaddr_in sock_addr; - - if (link_type == LINK_TCP) - sock = socket(AF_INET, SOCK_STREAM, 0); - else if (link_type == LINK_UDP) - sock = socket(AF_INET, SOCK_DGRAM, 0); - else { -#ifdef DEBUG - fprintf(stderr, "PacketAlias/GetSocket(): "); - fprintf(stderr, "incorrect link type\n"); -#endif - return (0); - } - - if (sock < 0) { -#ifdef DEBUG - fprintf(stderr, "PacketAlias/GetSocket(): "); - fprintf(stderr, "socket() error %d\n", *sockfd); -#endif - return (0); - } - sock_addr.sin_family = AF_INET; - sock_addr.sin_addr.s_addr = htonl(INADDR_ANY); - sock_addr.sin_port = port_net; - - err = bind(sock, - (struct sockaddr *)&sock_addr, - sizeof(sock_addr)); - if (err == 0) { - la->sockCount++; - *sockfd = sock; - return (1); - } else { - close(sock); - return (0); - } -} - - -/* 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 libalias *la, - 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 (la->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(la, 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(struct libalias *la) -{ - struct alias_link *lnk; - int i, icount; - - icount = 0; - for (i = 0; i < LINK_TABLE_OUT_SIZE; i++) { - lnk = LIST_FIRST(&la->linkTableOut[i]); - while (lnk != NULL) { - struct alias_link *link_next; - - link_next = LIST_NEXT(lnk, list_out); - icount++; - DeleteLink(lnk); - lnk = link_next; - } - } - - la->cleanupIndex = 0; -} - - -static void -IncrementalCleanup(struct libalias *la) -{ - int icount; - struct alias_link *lnk; - - icount = 0; - lnk = LIST_FIRST(&la->linkTableOut[la->cleanupIndex++]); - while (lnk != NULL) { - int idelta; - struct alias_link *link_next; - - link_next = LIST_NEXT(lnk, list_out); - idelta = la->timeStamp - lnk->timestamp; - switch (lnk->link_type) { - case LINK_TCP: - if (idelta > lnk->expire_time) { - struct tcp_dat *tcp_aux; - - tcp_aux = lnk->data.tcp; - if (tcp_aux->state.in != ALIAS_TCP_STATE_CONNECTED - || tcp_aux->state.out != ALIAS_TCP_STATE_CONNECTED) { - DeleteLink(lnk); - icount++; - } - } - break; - default: - if (idelta > lnk->expire_time) { - DeleteLink(lnk); - icount++; - } - break; - } - lnk = link_next; - } - - if (la->cleanupIndex == LINK_TABLE_OUT_SIZE) - la->cleanupIndex = 0; -} - -static void -DeleteLink(struct alias_link *lnk) -{ - struct libalias *la = lnk->la; - -/* Don't do anything if the link is marked permanent */ - if (la->deleteAllLinks == 0 && lnk->flags & LINK_PERMANENT) - return; - -#ifndef NO_FW_PUNCH -/* Delete associated firewall hole, if any */ - ClearFWHole(lnk); -#endif - -/* Free memory allocated for LSNAT server pool */ - if (lnk->server != NULL) { - struct server *head, *curr, *next; - - head = curr = lnk->server; - do { - next = curr->next; - free(curr); - } while ((curr = next) != head); - } -/* Adjust output table pointers */ - LIST_REMOVE(lnk, list_out); - -/* Adjust input table pointers */ - LIST_REMOVE(lnk, list_in); - -/* Close socket, if one has been allocated */ - if (lnk->sockfd != -1) { - la->sockCount--; - close(lnk->sockfd); - } -/* Link-type dependent cleanup */ - switch (lnk->link_type) { - case LINK_ICMP: - la->icmpLinkCount--; - break; - case LINK_UDP: - la->udpLinkCount--; - break; - case LINK_TCP: - la->tcpLinkCount--; - free(lnk->data.tcp); - break; - case LINK_PPTP: - la->pptpLinkCount--; - break; - case LINK_FRAGMENT_ID: - la->fragmentIdLinkCount--; - break; - case LINK_FRAGMENT_PTR: - la->fragmentPtrLinkCount--; - if (lnk->data.frag_ptr != NULL) - free(lnk->data.frag_ptr); - break; - case LINK_ADDR: - break; - default: - la->protoLinkCount--; - break; - } - -/* Free memory */ - free(lnk); - -/* Write statistics, if logging enabled */ - if (la->packetAliasMode & PKT_ALIAS_LOG) { - ShowAliasStats(la); - } -} - - -static struct alias_link * -AddLink(struct libalias *la, struct in_addr src_addr, - struct in_addr dst_addr, - struct in_addr alias_addr, - u_short src_port, - u_short dst_port, - int alias_port_param, /* if less than zero, alias */ - int link_type) -{ /* port will be automatically *//* chosen. - * If greater than */ - u_int start_point; /* zero, equal to alias port */ - struct alias_link *lnk; - - lnk = malloc(sizeof(struct alias_link)); - if (lnk != NULL) { - /* Basic initialization */ - lnk->la = la; - lnk->src_addr = src_addr; - lnk->dst_addr = dst_addr; - lnk->alias_addr = alias_addr; - lnk->proxy_addr.s_addr = INADDR_ANY; - lnk->src_port = src_port; - lnk->dst_port = dst_port; - lnk->proxy_port = 0; - lnk->server = NULL; - lnk->link_type = link_type; - lnk->sockfd = -1; - lnk->flags = 0; - lnk->pflags = 0; - lnk->timestamp = la->timeStamp; - - /* Expiration time */ - switch (link_type) { - case LINK_ICMP: - lnk->expire_time = ICMP_EXPIRE_TIME; - break; - case LINK_UDP: - lnk->expire_time = UDP_EXPIRE_TIME; - break; - case LINK_TCP: - lnk->expire_time = TCP_EXPIRE_INITIAL; - break; - case LINK_PPTP: - lnk->flags |= LINK_PERMANENT; /* no timeout. */ - break; - case LINK_FRAGMENT_ID: - lnk->expire_time = FRAGMENT_ID_EXPIRE_TIME; - break; - case LINK_FRAGMENT_PTR: - lnk->expire_time = FRAGMENT_PTR_EXPIRE_TIME; - break; - case LINK_ADDR: - break; - default: - lnk->expire_time = PROTO_EXPIRE_TIME; - break; - } - - /* Determine alias flags */ - if (dst_addr.s_addr == INADDR_ANY) - lnk->flags |= LINK_UNKNOWN_DEST_ADDR; - if (dst_port == 0) - lnk->flags |= LINK_UNKNOWN_DEST_PORT; - - /* Determine alias port */ - if (GetNewPort(la, lnk, alias_port_param) != 0) { - free(lnk); - return (NULL); - } - /* Link-type dependent initialization */ - switch (link_type) { - struct tcp_dat *aux_tcp; - - case LINK_ICMP: - la->icmpLinkCount++; - break; - case LINK_UDP: - la->udpLinkCount++; - break; - case LINK_TCP: - aux_tcp = malloc(sizeof(struct tcp_dat)); - if (aux_tcp != NULL) { - int i; - - la->tcpLinkCount++; - aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED; - aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED; - aux_tcp->state.index = 0; - aux_tcp->state.ack_modified = 0; - for (i = 0; i < N_LINK_TCP_DATA; i++) - aux_tcp->ack[i].active = 0; - aux_tcp->fwhole = -1; - lnk->data.tcp = aux_tcp; - } else { -#ifdef DEBUG - fprintf(stderr, "PacketAlias/AddLink: "); - fprintf(stderr, " cannot allocate auxiliary TCP data\n"); -#endif - free(lnk); - return (NULL); - } - break; - case LINK_PPTP: - la->pptpLinkCount++; - break; - case LINK_FRAGMENT_ID: - la->fragmentIdLinkCount++; - break; - case LINK_FRAGMENT_PTR: - la->fragmentPtrLinkCount++; - break; - case LINK_ADDR: - break; - default: - la->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(&la->linkTableOut[start_point], lnk, list_out); - - /* Set up pointers for input lookup table */ - start_point = StartPointIn(alias_addr, lnk->alias_port, link_type); - LIST_INSERT_HEAD(&la->linkTableIn[start_point], lnk, list_in); - } else { -#ifdef DEBUG - fprintf(stderr, "PacketAlias/AddLink(): "); - fprintf(stderr, "malloc() call failed.\n"); -#endif - } - - if (la->packetAliasMode & PKT_ALIAS_LOG) { - ShowAliasStats(la); - } - return (lnk); -} - -static struct alias_link * -ReLink(struct alias_link *old_lnk, - struct in_addr src_addr, - struct in_addr dst_addr, - struct in_addr alias_addr, - u_short src_port, - u_short dst_port, - int alias_port_param, /* if less than zero, alias */ - int link_type) -{ /* port will be automatically *//* chosen. - * If greater than */ - struct alias_link *new_lnk; /* zero, equal to alias port */ - struct libalias *la = old_lnk->la; - - new_lnk = AddLink(la, src_addr, dst_addr, alias_addr, - src_port, dst_port, alias_port_param, - link_type); -#ifndef NO_FW_PUNCH - if (new_lnk != NULL && - old_lnk->link_type == LINK_TCP && - old_lnk->data.tcp->fwhole > 0) { - PunchFWHole(new_lnk); - } -#endif - DeleteLink(old_lnk); - return (new_lnk); -} - -static struct alias_link * -_FindLinkOut(struct libalias *la, 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) -{ - u_int i; - struct alias_link *lnk; - - i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type); - LIST_FOREACH(lnk, &la->linkTableOut[i], list_out) { - if (lnk->src_addr.s_addr == src_addr.s_addr - && lnk->server == NULL - && lnk->dst_addr.s_addr == dst_addr.s_addr - && lnk->dst_port == dst_port - && lnk->src_port == src_port - && lnk->link_type == link_type) { - lnk->timestamp = la->timeStamp; - break; - } - } - -/* Search for partially specified links. */ - if (lnk == NULL && replace_partial_links) { - if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY) { - lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, 0, - link_type, 0); - if (lnk == NULL) - lnk = _FindLinkOut(la, src_addr, la->nullAddress, src_port, - dst_port, link_type, 0); - } - if (lnk == NULL && - (dst_port != 0 || dst_addr.s_addr != INADDR_ANY)) { - lnk = _FindLinkOut(la, src_addr, la->nullAddress, src_port, 0, - link_type, 0); - } - if (lnk != NULL) { - lnk = ReLink(lnk, - src_addr, dst_addr, lnk->alias_addr, - src_port, dst_port, lnk->alias_port, - link_type); - } - } - return (lnk); -} - -static struct alias_link * -FindLinkOut(struct libalias *la, 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 *lnk; - - lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, dst_port, - link_type, replace_partial_links); - - if (lnk == 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 (la->aliasAddress.s_addr != INADDR_ANY && - src_addr.s_addr == la->aliasAddress.s_addr) { - lnk = _FindLinkOut(la, la->nullAddress, dst_addr, src_port, dst_port, - link_type, replace_partial_links); - } - } - return (lnk); -} - - -static struct alias_link * -_FindLinkIn(struct libalias *la, 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) -{ - int flags_in; - u_int start_point; - struct alias_link *lnk; - struct alias_link *lnk_fully_specified; - struct alias_link *lnk_unknown_all; - struct alias_link *lnk_unknown_dst_addr; - struct alias_link *lnk_unknown_dst_port; - -/* Initialize pointers */ - lnk_fully_specified = NULL; - lnk_unknown_all = NULL; - lnk_unknown_dst_addr = NULL; - lnk_unknown_dst_port = NULL; - -/* If either the dest addr or port is unknown, the search - loop will have to know about this. */ - - flags_in = 0; - if (dst_addr.s_addr == INADDR_ANY) - flags_in |= LINK_UNKNOWN_DEST_ADDR; - if (dst_port == 0) - flags_in |= LINK_UNKNOWN_DEST_PORT; - -/* Search loop */ - start_point = StartPointIn(alias_addr, alias_port, link_type); - LIST_FOREACH(lnk, &la->linkTableIn[start_point], list_in) { - int flags; - - flags = flags_in | lnk->flags; - if (!(flags & LINK_PARTIALLY_SPECIFIED)) { - if (lnk->alias_addr.s_addr == alias_addr.s_addr - && lnk->alias_port == alias_port - && lnk->dst_addr.s_addr == dst_addr.s_addr - && lnk->dst_port == dst_port - && lnk->link_type == link_type) { - lnk_fully_specified = lnk; - break; - } - } else if ((flags & LINK_UNKNOWN_DEST_ADDR) - && (flags & LINK_UNKNOWN_DEST_PORT)) { - if (lnk->alias_addr.s_addr == alias_addr.s_addr - && lnk->alias_port == alias_port - && lnk->link_type == link_type) { - if (lnk_unknown_all == NULL) - lnk_unknown_all = lnk; - } - } else if (flags & LINK_UNKNOWN_DEST_ADDR) { - if (lnk->alias_addr.s_addr == alias_addr.s_addr - && lnk->alias_port == alias_port - && lnk->link_type == link_type - && lnk->dst_port == dst_port) { - if (lnk_unknown_dst_addr == NULL) - lnk_unknown_dst_addr = lnk; - } - } else if (flags & LINK_UNKNOWN_DEST_PORT) { - if (lnk->alias_addr.s_addr == alias_addr.s_addr - && lnk->alias_port == alias_port - && lnk->link_type == link_type - && lnk->dst_addr.s_addr == dst_addr.s_addr) { - if (lnk_unknown_dst_port == NULL) - lnk_unknown_dst_port = lnk; - } - } - } - - - - if (lnk_fully_specified != NULL) { - lnk_fully_specified->timestamp = la->timeStamp; - lnk = lnk_fully_specified; - } else if (lnk_unknown_dst_port != NULL) - lnk = lnk_unknown_dst_port; - else if (lnk_unknown_dst_addr != NULL) - lnk = lnk_unknown_dst_addr; - else if (lnk_unknown_all != NULL) - lnk = lnk_unknown_all; - else - return (NULL); - - if (replace_partial_links && - (lnk->flags & LINK_PARTIALLY_SPECIFIED || lnk->server != NULL)) { - struct in_addr src_addr; - u_short src_port; - - if (lnk->server != NULL) { /* LSNAT link */ - src_addr = lnk->server->addr; - src_port = lnk->server->port; - lnk->server = lnk->server->next; - } else { - src_addr = lnk->src_addr; - src_port = lnk->src_port; - } - - lnk = ReLink(lnk, - src_addr, dst_addr, alias_addr, - src_port, dst_port, alias_port, - link_type); - } - return (lnk); -} - -static struct alias_link * -FindLinkIn(struct libalias *la, 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 *lnk; - - lnk = _FindLinkIn(la, dst_addr, alias_addr, dst_port, alias_port, - link_type, replace_partial_links); - - if (lnk == 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 (la->aliasAddress.s_addr != INADDR_ANY && - alias_addr.s_addr == la->aliasAddress.s_addr) { - lnk = _FindLinkIn(la, dst_addr, la->nullAddress, dst_port, alias_port, - link_type, replace_partial_links); - } - } - return (lnk); -} - - - - -/* External routines for finding/adding links - --- "external" means outside alias_db.c, but within alias*.c -- - - FindIcmpIn(), FindIcmpOut() - FindFragmentIn1(), FindFragmentIn2() - AddFragmentPtrLink(), FindFragmentPtr() - FindProtoIn(), FindProtoOut() - FindUdpTcpIn(), FindUdpTcpOut() - AddPptp(), FindPptpOutByCallId(), FindPptpInByCallId(), - FindPptpOutByPeerCallId(), FindPptpInByPeerCallId() - FindOriginalAddress(), FindAliasAddress() - -(prototypes in alias_local.h) -*/ - - -struct alias_link * -FindIcmpIn(struct libalias *la, struct in_addr dst_addr, - struct in_addr alias_addr, - u_short id_alias, - int create) -{ - struct alias_link *lnk; - - lnk = FindLinkIn(la, dst_addr, alias_addr, - NO_DEST_PORT, id_alias, - LINK_ICMP, 0); - if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) { - struct in_addr target_addr; - - target_addr = FindOriginalAddress(la, alias_addr); - lnk = AddLink(la, target_addr, dst_addr, alias_addr, - id_alias, NO_DEST_PORT, id_alias, - LINK_ICMP); - } - return (lnk); -} - - -struct alias_link * -FindIcmpOut(struct libalias *la, struct in_addr src_addr, - struct in_addr dst_addr, - u_short id, - int create) -{ - struct alias_link *lnk; - - lnk = FindLinkOut(la, src_addr, dst_addr, - id, NO_DEST_PORT, - LINK_ICMP, 0); - if (lnk == NULL && create) { - struct in_addr alias_addr; - - alias_addr = FindAliasAddress(la, src_addr); - lnk = AddLink(la, src_addr, dst_addr, alias_addr, - id, NO_DEST_PORT, GET_ALIAS_ID, - LINK_ICMP); - } - return (lnk); -} - - -struct alias_link * -FindFragmentIn1(struct libalias *la, struct in_addr dst_addr, - struct in_addr alias_addr, - u_short ip_id) -{ - struct alias_link *lnk; - - lnk = FindLinkIn(la, dst_addr, alias_addr, - NO_DEST_PORT, ip_id, - LINK_FRAGMENT_ID, 0); - - if (lnk == NULL) { - lnk = AddLink(la, la->nullAddress, dst_addr, alias_addr, - NO_SRC_PORT, NO_DEST_PORT, ip_id, - LINK_FRAGMENT_ID); - } - return (lnk); -} - - -struct alias_link * -FindFragmentIn2(struct libalias *la, struct in_addr dst_addr, /* Doesn't add a link if - * one */ - struct in_addr alias_addr, /* is not found. */ - u_short ip_id) -{ - return FindLinkIn(la, dst_addr, alias_addr, - NO_DEST_PORT, ip_id, - LINK_FRAGMENT_ID, 0); -} - - -struct alias_link * -AddFragmentPtrLink(struct libalias *la, struct in_addr dst_addr, - u_short ip_id) -{ - return AddLink(la, la->nullAddress, dst_addr, la->nullAddress, - NO_SRC_PORT, NO_DEST_PORT, ip_id, - LINK_FRAGMENT_PTR); -} - - -struct alias_link * -FindFragmentPtr(struct libalias *la, struct in_addr dst_addr, - u_short ip_id) -{ - return FindLinkIn(la, dst_addr, la->nullAddress, - NO_DEST_PORT, ip_id, - LINK_FRAGMENT_PTR, 0); -} - - -struct alias_link * -FindProtoIn(struct libalias *la, struct in_addr dst_addr, - struct in_addr alias_addr, - u_char proto) -{ - struct alias_link *lnk; - - lnk = FindLinkIn(la, dst_addr, alias_addr, - NO_DEST_PORT, 0, - proto, 1); - - if (lnk == NULL && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) { - struct in_addr target_addr; - - target_addr = FindOriginalAddress(la, alias_addr); - lnk = AddLink(la, target_addr, dst_addr, alias_addr, - NO_SRC_PORT, NO_DEST_PORT, 0, - proto); - } - return (lnk); -} - - -struct alias_link * -FindProtoOut(struct libalias *la, struct in_addr src_addr, - struct in_addr dst_addr, - u_char proto) -{ - struct alias_link *lnk; - - lnk = FindLinkOut(la, src_addr, dst_addr, - NO_SRC_PORT, NO_DEST_PORT, - proto, 1); - - if (lnk == NULL) { - struct in_addr alias_addr; - - alias_addr = FindAliasAddress(la, src_addr); - lnk = AddLink(la, src_addr, dst_addr, alias_addr, - NO_SRC_PORT, NO_DEST_PORT, 0, - proto); - } - return (lnk); -} - - -struct alias_link * -FindUdpTcpIn(struct libalias *la, struct in_addr dst_addr, - struct in_addr alias_addr, - u_short dst_port, - u_short alias_port, - u_char proto, - int create) -{ - int link_type; - struct alias_link *lnk; - - switch (proto) { - case IPPROTO_UDP: - link_type = LINK_UDP; - break; - case IPPROTO_TCP: - link_type = LINK_TCP; - break; - default: - return (NULL); - break; - } - - lnk = FindLinkIn(la, dst_addr, alias_addr, - dst_port, alias_port, - link_type, create); - - if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) { - struct in_addr target_addr; - - target_addr = FindOriginalAddress(la, alias_addr); - lnk = AddLink(la, target_addr, dst_addr, alias_addr, - alias_port, dst_port, alias_port, - link_type); - } - return (lnk); -} - - -struct alias_link * -FindUdpTcpOut(struct libalias *la, struct in_addr src_addr, - struct in_addr dst_addr, - u_short src_port, - u_short dst_port, - u_char proto, - int create) -{ - int link_type; - struct alias_link *lnk; - - switch (proto) { - case IPPROTO_UDP: - link_type = LINK_UDP; - break; - case IPPROTO_TCP: - link_type = LINK_TCP; - break; - default: - return (NULL); - break; - } - - lnk = FindLinkOut(la, src_addr, dst_addr, src_port, dst_port, link_type, create); - - if (lnk == NULL && create) { - struct in_addr alias_addr; - - alias_addr = FindAliasAddress(la, src_addr); - lnk = AddLink(la, src_addr, dst_addr, alias_addr, - src_port, dst_port, GET_ALIAS_PORT, - link_type); - } - return (lnk); -} - - -struct alias_link * -AddPptp(struct libalias *la, struct in_addr src_addr, - struct in_addr dst_addr, - struct in_addr alias_addr, - u_int16_t src_call_id) -{ - struct alias_link *lnk; - - lnk = AddLink(la, src_addr, dst_addr, alias_addr, - src_call_id, 0, GET_ALIAS_PORT, - LINK_PPTP); - - return (lnk); -} - - -struct alias_link * -FindPptpOutByCallId(struct libalias *la, struct in_addr src_addr, - struct in_addr dst_addr, - u_int16_t src_call_id) -{ - u_int i; - struct alias_link *lnk; - - i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP); - LIST_FOREACH(lnk, &la->linkTableOut[i], list_out) - if (lnk->link_type == LINK_PPTP && - lnk->src_addr.s_addr == src_addr.s_addr && - lnk->dst_addr.s_addr == dst_addr.s_addr && - lnk->src_port == src_call_id) - break; - - return (lnk); -} - - -struct alias_link * -FindPptpOutByPeerCallId(struct libalias *la, struct in_addr src_addr, - struct in_addr dst_addr, - u_int16_t dst_call_id) -{ - u_int i; - struct alias_link *lnk; - - i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP); - LIST_FOREACH(lnk, &la->linkTableOut[i], list_out) - if (lnk->link_type == LINK_PPTP && - lnk->src_addr.s_addr == src_addr.s_addr && - lnk->dst_addr.s_addr == dst_addr.s_addr && - lnk->dst_port == dst_call_id) - break; - - return (lnk); -} - - -struct alias_link * -FindPptpInByCallId(struct libalias *la, struct in_addr dst_addr, - struct in_addr alias_addr, - u_int16_t dst_call_id) -{ - u_int i; - struct alias_link *lnk; - - i = StartPointIn(alias_addr, 0, LINK_PPTP); - LIST_FOREACH(lnk, &la->linkTableIn[i], list_in) - if (lnk->link_type == LINK_PPTP && - lnk->dst_addr.s_addr == dst_addr.s_addr && - lnk->alias_addr.s_addr == alias_addr.s_addr && - lnk->dst_port == dst_call_id) - break; - - return (lnk); -} - - -struct alias_link * -FindPptpInByPeerCallId(struct libalias *la, struct in_addr dst_addr, - struct in_addr alias_addr, - u_int16_t alias_call_id) -{ - struct alias_link *lnk; - - lnk = FindLinkIn(la, dst_addr, alias_addr, - 0 /* any */ , alias_call_id, - LINK_PPTP, 0); - - - return (lnk); -} - - -struct alias_link * -FindRtspOut(struct libalias *la, 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 *lnk; - - switch (proto) { - case IPPROTO_UDP: - link_type = LINK_UDP; - break; - case IPPROTO_TCP: - link_type = LINK_TCP; - break; - default: - return (NULL); - break; - } - - lnk = FindLinkOut(la, src_addr, dst_addr, src_port, 0, link_type, 1); - - if (lnk == NULL) { - struct in_addr alias_addr; - - alias_addr = FindAliasAddress(la, src_addr); - lnk = AddLink(la, src_addr, dst_addr, alias_addr, - src_port, 0, alias_port, - link_type); - } - return (lnk); -} - - -struct in_addr -FindOriginalAddress(struct libalias *la, struct in_addr alias_addr) -{ - struct alias_link *lnk; - - lnk = FindLinkIn(la, la->nullAddress, alias_addr, - 0, 0, LINK_ADDR, 0); - if (lnk == NULL) { - la->newDefaultLink = 1; - if (la->targetAddress.s_addr == INADDR_ANY) - return (alias_addr); - else if (la->targetAddress.s_addr == INADDR_NONE) - return (la->aliasAddress.s_addr != INADDR_ANY) ? - la->aliasAddress : alias_addr; - else - return (la->targetAddress); - } else { - if (lnk->server != NULL) { /* LSNAT link */ - struct in_addr src_addr; - - src_addr = lnk->server->addr; - lnk->server = lnk->server->next; - return (src_addr); - } else if (lnk->src_addr.s_addr == INADDR_ANY) - return (la->aliasAddress.s_addr != INADDR_ANY) ? - la->aliasAddress : alias_addr; - else - return (lnk->src_addr); - } -} - - -struct in_addr -FindAliasAddress(struct libalias *la, struct in_addr original_addr) -{ - struct alias_link *lnk; - - lnk = FindLinkOut(la, original_addr, la->nullAddress, - 0, 0, LINK_ADDR, 0); - if (lnk == NULL) { - return (la->aliasAddress.s_addr != INADDR_ANY) ? - la->aliasAddress : original_addr; - } else { - if (lnk->alias_addr.s_addr == INADDR_ANY) - return (la->aliasAddress.s_addr != INADDR_ANY) ? - la->aliasAddress : original_addr; - else - return (lnk->alias_addr); - } -} - - -/* External routines for getting or changing link data - (external to alias_db.c, but internal to alias*.c) - - SetFragmentData(), GetFragmentData() - SetFragmentPtr(), GetFragmentPtr() - SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut() - GetOriginalAddress(), GetDestAddress(), GetAliasAddress() - GetOriginalPort(), GetAliasPort() - SetAckModified(), GetAckModified() - GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq() - SetProtocolFlags(), GetProtocolFlags() - SetDestCallId() -*/ - - -void -SetFragmentAddr(struct alias_link *lnk, struct in_addr src_addr) -{ - lnk->data.frag_addr = src_addr; -} - - -void -GetFragmentAddr(struct alias_link *lnk, struct in_addr *src_addr) -{ - *src_addr = lnk->data.frag_addr; -} - - -void -SetFragmentPtr(struct alias_link *lnk, char *fptr) -{ - lnk->data.frag_ptr = fptr; -} - - -void -GetFragmentPtr(struct alias_link *lnk, char **fptr) -{ - *fptr = lnk->data.frag_ptr; -} - - -void -SetStateIn(struct alias_link *lnk, int state) -{ - /* TCP input state */ - switch (state) { - case ALIAS_TCP_STATE_DISCONNECTED: - if (lnk->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED) - lnk->expire_time = TCP_EXPIRE_DEAD; - else - lnk->expire_time = TCP_EXPIRE_SINGLEDEAD; - break; - case ALIAS_TCP_STATE_CONNECTED: - if (lnk->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED) - lnk->expire_time = TCP_EXPIRE_CONNECTED; - break; - default: - abort(); - } - lnk->data.tcp->state.in = state; -} - - -void -SetStateOut(struct alias_link *lnk, int state) -{ - /* TCP output state */ - switch (state) { - case ALIAS_TCP_STATE_DISCONNECTED: - if (lnk->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED) - lnk->expire_time = TCP_EXPIRE_DEAD; - else - lnk->expire_time = TCP_EXPIRE_SINGLEDEAD; - break; - case ALIAS_TCP_STATE_CONNECTED: - if (lnk->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED) - lnk->expire_time = TCP_EXPIRE_CONNECTED; - break; - default: - abort(); - } - lnk->data.tcp->state.out = state; -} - - -int -GetStateIn(struct alias_link *lnk) -{ - /* TCP input state */ - return (lnk->data.tcp->state.in); -} - - -int -GetStateOut(struct alias_link *lnk) -{ - /* TCP output state */ - return (lnk->data.tcp->state.out); -} - - -struct in_addr -GetOriginalAddress(struct alias_link *lnk) -{ - if (lnk->src_addr.s_addr == INADDR_ANY) - return (lnk->la->aliasAddress); - else - return (lnk->src_addr); -} - - -struct in_addr -GetDestAddress(struct alias_link *lnk) -{ - return (lnk->dst_addr); -} - - -struct in_addr -GetAliasAddress(struct alias_link *lnk) -{ - if (lnk->alias_addr.s_addr == INADDR_ANY) - return (lnk->la->aliasAddress); - else - return (lnk->alias_addr); -} - - -struct in_addr -GetDefaultAliasAddress(struct libalias *la) -{ - return (la->aliasAddress); -} - - -void -SetDefaultAliasAddress(struct libalias *la, struct in_addr alias_addr) -{ - la->aliasAddress = alias_addr; -} - - -u_short -GetOriginalPort(struct alias_link *lnk) -{ - return (lnk->src_port); -} - - -u_short -GetAliasPort(struct alias_link *lnk) -{ - return (lnk->alias_port); -} - -#ifndef NO_FW_PUNCH -static u_short -GetDestPort(struct alias_link *lnk) -{ - return (lnk->dst_port); -} - -#endif - -void -SetAckModified(struct alias_link *lnk) -{ -/* Indicate that ACK numbers have been modified in a TCP connection */ - lnk->data.tcp->state.ack_modified = 1; -} - - -struct in_addr -GetProxyAddress(struct alias_link *lnk) -{ - return (lnk->proxy_addr); -} - - -void -SetProxyAddress(struct alias_link *lnk, struct in_addr addr) -{ - lnk->proxy_addr = addr; -} - - -u_short -GetProxyPort(struct alias_link *lnk) -{ - return (lnk->proxy_port); -} - - -void -SetProxyPort(struct alias_link *lnk, u_short port) -{ - lnk->proxy_port = port; -} - - -int -GetAckModified(struct alias_link *lnk) -{ -/* See if ACK numbers have been modified */ - return (lnk->data.tcp->state.ack_modified); -} - - -int -GetDeltaAckIn(struct ip *pip, struct alias_link *lnk) -{ -/* -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; - - tc = ip_next(pip); - ack = tc->th_ack; - - delta = 0; - ack_diff_min = -1; - for (i = 0; i < N_LINK_TCP_DATA; i++) { - struct ack_data_record x; - - x = lnk->data.tcp->ack[i]; - if (x.active == 1) { - int ack_diff; - - ack_diff = SeqDiff(x.ack_new, ack); - if (ack_diff >= 0) { - if (ack_diff_min >= 0) { - if (ack_diff < ack_diff_min) { - delta = x.delta; - ack_diff_min = ack_diff; - } - } else { - delta = x.delta; - ack_diff_min = ack_diff; - } - } - } - } - return (delta); -} - - -int -GetDeltaSeqOut(struct ip *pip, struct alias_link *lnk) -{ -/* -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; - - tc = ip_next(pip); - seq = tc->th_seq; - - delta = 0; - seq_diff_min = -1; - for (i = 0; i < N_LINK_TCP_DATA; i++) { - struct ack_data_record x; - - x = lnk->data.tcp->ack[i]; - if (x.active == 1) { - int seq_diff; - - seq_diff = SeqDiff(x.ack_old, seq); - if (seq_diff >= 0) { - if (seq_diff_min >= 0) { - if (seq_diff < seq_diff_min) { - delta = x.delta; - seq_diff_min = seq_diff; - } - } else { - delta = x.delta; - seq_diff_min = seq_diff; - } - } - } - } - return (delta); -} - - -void -AddSeq(struct ip *pip, struct alias_link *lnk, int delta) -{ -/* -When a TCP packet has been altered in length, save this -information in a circular list. If enough packets have -been altered, then this list will begin to overwrite itself. -*/ - - struct tcphdr *tc; - struct ack_data_record x; - int hlen, tlen, dlen; - int i; - - tc = ip_next(pip); - - hlen = (pip->ip_hl + tc->th_off) << 2; - tlen = ntohs(pip->ip_len); - dlen = tlen - hlen; - - x.ack_old = htonl(ntohl(tc->th_seq) + dlen); - x.ack_new = htonl(ntohl(tc->th_seq) + dlen + delta); - x.delta = delta; - x.active = 1; - - i = lnk->data.tcp->state.index; - lnk->data.tcp->ack[i] = x; - - i++; - if (i == N_LINK_TCP_DATA) - lnk->data.tcp->state.index = 0; - else - lnk->data.tcp->state.index = i; -} - -void -SetExpire(struct alias_link *lnk, int expire) -{ - if (expire == 0) { - lnk->flags &= ~LINK_PERMANENT; - DeleteLink(lnk); - } else if (expire == -1) { - lnk->flags |= LINK_PERMANENT; - } else if (expire > 0) { - lnk->expire_time = expire; - } else { -#ifdef DEBUG - fprintf(stderr, "PacketAlias/SetExpire(): "); - fprintf(stderr, "error in expire parameter\n"); -#endif - } -} - -void -ClearCheckNewLink(struct libalias *la) -{ - la->newDefaultLink = 0; -} - -void -SetProtocolFlags(struct alias_link *lnk, int pflags) -{ - - lnk->pflags = pflags;; -} - -int -GetProtocolFlags(struct alias_link *lnk) -{ - - return (lnk->pflags); -} - -void -SetDestCallId(struct alias_link *lnk, u_int16_t cid) -{ - struct libalias *la = lnk->la; - - la->deleteAllLinks = 1; - lnk = ReLink(lnk, lnk->src_addr, lnk->dst_addr, lnk->alias_addr, - lnk->src_port, cid, lnk->alias_port, lnk->link_type); - la->deleteAllLinks = 0; -} - - -/* Miscellaneous Functions - - HouseKeeping() - InitPacketAliasLog() - UninitPacketAliasLog() -*/ - -/* - Whenever an outgoing or incoming packet is handled, HouseKeeping() - is called to find and remove timed-out aliasing links. Logic exists - to sweep through the entire table and linked list structure - every 60 seconds. - - (prototype in alias_local.h) -*/ - -void -HouseKeeping(struct libalias *la) -{ - int i, n, n100; - struct timeval tv; - struct timezone tz; - - /* - * Save system time (seconds) in global variable timeStamp for use - * by other functions. This is done so as not to unnecessarily - * waste timeline by making system calls. - */ - gettimeofday(&tv, &tz); - la->timeStamp = tv.tv_sec; - - /* Compute number of spokes (output table link chains) to cover */ - n100 = LINK_TABLE_OUT_SIZE * 100 + la->houseKeepingResidual; - n100 *= la->timeStamp - la->lastCleanupTime; - n100 /= ALIAS_CLEANUP_INTERVAL_SECS; - - n = n100 / 100; - - /* Handle different cases */ - if (n > ALIAS_CLEANUP_MAX_SPOKES) { - n = ALIAS_CLEANUP_MAX_SPOKES; - la->lastCleanupTime = la->timeStamp; - la->houseKeepingResidual = 0; - - for (i = 0; i < n; i++) - IncrementalCleanup(la); - } else if (n > 0) { - la->lastCleanupTime = la->timeStamp; - la->houseKeepingResidual = n100 - 100 * n; - - for (i = 0; i < n; i++) - IncrementalCleanup(la); - } else if (n < 0) { -#ifdef DEBUG - fprintf(stderr, "PacketAlias/HouseKeeping(): "); - fprintf(stderr, "something unexpected in time values\n"); -#endif - la->lastCleanupTime = la->timeStamp; - la->houseKeepingResidual = 0; - } -} - - -/* Init the log file and enable logging */ -static void -InitPacketAliasLog(struct libalias *la) -{ - if ((~la->packetAliasMode & PKT_ALIAS_LOG) - && (la->monitorFile = fopen("/var/log/alias.log", "w"))) { - la->packetAliasMode |= PKT_ALIAS_LOG; - fprintf(la->monitorFile, - "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n"); - } -} - - -/* Close the log-file and disable logging. */ -static void -UninitPacketAliasLog(struct libalias *la) -{ - if (la->monitorFile) { - fclose(la->monitorFile); - la->monitorFile = NULL; - } - la->packetAliasMode &= ~PKT_ALIAS_LOG; -} - - - - - - -/* Outside world interfaces - --- "outside world" means other than alias*.c routines -- - - PacketAliasRedirectPort() - PacketAliasAddServer() - PacketAliasRedirectProto() - PacketAliasRedirectAddr() - PacketAliasRedirectDynamic() - PacketAliasRedirectDelete() - PacketAliasSetAddress() - PacketAliasInit() - PacketAliasUninit() - PacketAliasSetMode() - -(prototypes in alias.h) -*/ - -/* Redirection from a specific public addr:port to a - private addr:port */ -struct alias_link * -LibAliasRedirectPort(struct libalias *la, struct in_addr src_addr, u_short src_port, - struct in_addr dst_addr, u_short dst_port, - struct in_addr alias_addr, u_short alias_port, - u_char proto) -{ - int link_type; - struct alias_link *lnk; - - switch (proto) { - case IPPROTO_UDP: - link_type = LINK_UDP; - break; - case IPPROTO_TCP: - link_type = LINK_TCP; - break; - default: -#ifdef DEBUG - fprintf(stderr, "PacketAliasRedirectPort(): "); - fprintf(stderr, "only TCP and UDP protocols allowed\n"); -#endif - return (NULL); - } - - lnk = AddLink(la, src_addr, dst_addr, alias_addr, - src_port, dst_port, alias_port, - link_type); - - if (lnk != NULL) { - lnk->flags |= LINK_PERMANENT; - } -#ifdef DEBUG - else { - fprintf(stderr, "PacketAliasRedirectPort(): " - "call to AddLink() failed\n"); - } -#endif - - return (lnk); -} - -/* Add server to the pool of servers */ -int -LibAliasAddServer(struct libalias *la, struct alias_link *lnk, struct in_addr addr, u_short port) -{ - struct server *server; - - (void)la; - - server = malloc(sizeof(struct server)); - - if (server != NULL) { - struct server *head; - - server->addr = addr; - server->port = port; - - head = lnk->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; - } - lnk->server = server; - return (0); - } else - return (-1); -} - -/* Redirect packets of a given IP protocol from a specific - public address to a private address */ -struct alias_link * -LibAliasRedirectProto(struct libalias *la, struct in_addr src_addr, - struct in_addr dst_addr, - struct in_addr alias_addr, - u_char proto) -{ - struct alias_link *lnk; - - lnk = AddLink(la, src_addr, dst_addr, alias_addr, - NO_SRC_PORT, NO_DEST_PORT, 0, - proto); - - if (lnk != NULL) { - lnk->flags |= LINK_PERMANENT; - } -#ifdef DEBUG - else { - fprintf(stderr, "PacketAliasRedirectProto(): " - "call to AddLink() failed\n"); - } -#endif - - return (lnk); -} - -/* Static address translation */ -struct alias_link * -LibAliasRedirectAddr(struct libalias *la, struct in_addr src_addr, - struct in_addr alias_addr) -{ - struct alias_link *lnk; - - lnk = AddLink(la, src_addr, la->nullAddress, alias_addr, - 0, 0, 0, - LINK_ADDR); - - if (lnk != NULL) { - lnk->flags |= LINK_PERMANENT; - } -#ifdef DEBUG - else { - fprintf(stderr, "PacketAliasRedirectAddr(): " - "call to AddLink() failed\n"); - } -#endif - - return (lnk); -} - - -/* Mark the aliasing link dynamic */ -int -LibAliasRedirectDynamic(struct libalias *la, struct alias_link *lnk) -{ - - (void)la; - - if (lnk->flags & LINK_PARTIALLY_SPECIFIED) - return (-1); - else { - lnk->flags &= ~LINK_PERMANENT; - return (0); - } -} - - -void -LibAliasRedirectDelete(struct libalias *la, struct alias_link *lnk) -{ -/* This is a dangerous function to put in the API, - because an invalid pointer can crash the program. */ - - la->deleteAllLinks = 1; - DeleteLink(lnk); - la->deleteAllLinks = 0; -} - - -void -LibAliasSetAddress(struct libalias *la, struct in_addr addr) -{ - if (la->packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE - && la->aliasAddress.s_addr != addr.s_addr) - CleanupAliasData(la); - - la->aliasAddress = addr; -} - - -void -LibAliasSetTarget(struct libalias *la, struct in_addr target_addr) -{ - la->targetAddress = target_addr; -} - -static void -finishoff(void) -{ - - while (!LIST_EMPTY(&instancehead)) - LibAliasUninit(LIST_FIRST(&instancehead)); -} - -struct libalias * -LibAliasInit(struct libalias *la) -{ - int i; - struct timeval tv; - struct timezone tz; - - if (la == NULL) { - la = calloc(sizeof *la, 1); - if (la == NULL) - return (la); - if (LIST_EMPTY(&instancehead)) - atexit(finishoff); - LIST_INSERT_HEAD(&instancehead, la, instancelist); - - gettimeofday(&tv, &tz); - la->timeStamp = tv.tv_sec; - la->lastCleanupTime = tv.tv_sec; - la->houseKeepingResidual = 0; - - for (i = 0; i < LINK_TABLE_OUT_SIZE; i++) - LIST_INIT(&la->linkTableOut[i]); - for (i = 0; i < LINK_TABLE_IN_SIZE; i++) - LIST_INIT(&la->linkTableIn[i]); - - } else { - la->deleteAllLinks = 1; - CleanupAliasData(la); - la->deleteAllLinks = 0; - } - - la->aliasAddress.s_addr = INADDR_ANY; - la->targetAddress.s_addr = INADDR_ANY; - - la->icmpLinkCount = 0; - la->udpLinkCount = 0; - la->tcpLinkCount = 0; - la->pptpLinkCount = 0; - la->protoLinkCount = 0; - la->fragmentIdLinkCount = 0; - la->fragmentPtrLinkCount = 0; - la->sockCount = 0; - - la->cleanupIndex = 0; - - la->packetAliasMode = PKT_ALIAS_SAME_PORTS - | PKT_ALIAS_USE_SOCKETS - | PKT_ALIAS_RESET_ON_ADDR_CHANGE; -#ifndef NO_FW_PUNCH - la->fireWallFD = -1; -#endif - return (la); -} - -void -LibAliasUninit(struct libalias *la) -{ - la->deleteAllLinks = 1; - CleanupAliasData(la); - la->deleteAllLinks = 0; - UninitPacketAliasLog(la); -#ifndef NO_FW_PUNCH - UninitPunchFW(la); -#endif - LIST_REMOVE(la, instancelist); - free(la); -} - -/* Change mode for some operations */ -unsigned int -LibAliasSetMode( - struct libalias *la, - unsigned int flags, /* Which state to bring flags to */ - unsigned int mask /* Mask of which flags to affect (use 0 to - * do a probe for flag values) */ -) -{ -/* Enable logging? */ - if (flags & mask & PKT_ALIAS_LOG) { - InitPacketAliasLog(la); /* Do the enable */ - } else -/* _Disable_ logging? */ - if (~flags & mask & PKT_ALIAS_LOG) { - UninitPacketAliasLog(la); - } -#ifndef NO_FW_PUNCH -/* Start punching holes in the firewall? */ - if (flags & mask & PKT_ALIAS_PUNCH_FW) { - InitPunchFW(la); - } else -/* Stop punching holes in the firewall? */ - if (~flags & mask & PKT_ALIAS_PUNCH_FW) { - UninitPunchFW(la); - } -#endif - -/* Other flags can be set/cleared without special action */ - la->packetAliasMode = (flags & mask) | (la->packetAliasMode & ~mask); - return (la->packetAliasMode); -} - - -int -LibAliasCheckNewLink(struct libalias *la) -{ - return (la->newDefaultLink); -} - - -#ifndef NO_FW_PUNCH - -/***************** - Code to support firewall punching. This shouldn't really be in this - file, but making variables global is evil too. - ****************/ - -#ifndef IPFW2 -#define IPFW2 1 /* use new ipfw code */ -#endif - -/* Firewall include files */ -#include <net/if.h> -#include <netinet/ip_fw.h> -#include <string.h> -#include <err.h> - -#if IPFW2 /* support for new firewall code */ -/* - * helper function, updates the pointer to cmd with the length - * of the current command, and also cleans up the first word of - * the new command in case it has been clobbered before. - */ -static ipfw_insn * -next_cmd(ipfw_insn * cmd) -{ - cmd += F_LEN(cmd); - bzero(cmd, sizeof(*cmd)); - return (cmd); -} - -/* - * A function to fill simple commands of size 1. - * Existing flags are preserved. - */ -static ipfw_insn * -fill_cmd(ipfw_insn * cmd, enum ipfw_opcodes opcode, int size, - int flags, u_int16_t arg) -{ - cmd->opcode = opcode; - cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | (size & F_LEN_MASK); - cmd->arg1 = arg; - return next_cmd(cmd); -} - -static ipfw_insn * -fill_ip(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int32_t addr) -{ - ipfw_insn_ip *cmd = (ipfw_insn_ip *) cmd1; - - cmd->addr.s_addr = addr; - return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u32), 0, 0); -} - -static ipfw_insn * -fill_one_port(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int16_t port) -{ - ipfw_insn_u16 *cmd = (ipfw_insn_u16 *) cmd1; - - cmd->ports[0] = cmd->ports[1] = port; - return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u16), 0, 0); -} - -static int -fill_rule(void *buf, int bufsize, int rulenum, - enum ipfw_opcodes action, int proto, - struct in_addr sa, u_int16_t sp, struct in_addr da, u_int16_t dp) -{ - struct ip_fw *rule = (struct ip_fw *)buf; - ipfw_insn *cmd = (ipfw_insn *) rule->cmd; - - bzero(buf, bufsize); - rule->rulenum = rulenum; - - cmd = fill_cmd(cmd, O_PROTO, F_INSN_SIZE(ipfw_insn), 0, proto); - cmd = fill_ip(cmd, O_IP_SRC, sa.s_addr); - cmd = fill_one_port(cmd, O_IP_SRCPORT, sp); - cmd = fill_ip(cmd, O_IP_DST, da.s_addr); - cmd = fill_one_port(cmd, O_IP_DSTPORT, dp); - - rule->act_ofs = (u_int32_t *) cmd - (u_int32_t *) rule->cmd; - cmd = fill_cmd(cmd, action, F_INSN_SIZE(ipfw_insn), 0, 0); - - rule->cmd_len = (u_int32_t *) cmd - (u_int32_t *) rule->cmd; - - return ((char *)cmd - (char *)buf); -} - -#endif /* IPFW2 */ - -static void ClearAllFWHoles(struct libalias *la); - - -#define fw_setfield(la, field, num) \ -do { \ - (field)[(num) - la->fireWallBaseNum] = 1; \ -} /*lint -save -e717 */ while(0)/* lint -restore */ - -#define fw_clrfield(la, field, num) \ -do { \ - (field)[(num) - la->fireWallBaseNum] = 0; \ -} /*lint -save -e717 */ while(0)/* lint -restore */ - -#define fw_tstfield(la, field, num) ((field)[(num) - la->fireWallBaseNum]) - -static void -InitPunchFW(struct libalias *la) -{ - - la->fireWallField = malloc(la->fireWallNumNums); - if (la->fireWallField) { - memset(la->fireWallField, 0, la->fireWallNumNums); - if (la->fireWallFD < 0) { - la->fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); - } - ClearAllFWHoles(la); - la->fireWallActiveNum = la->fireWallBaseNum; - } -} - -static void -UninitPunchFW(struct libalias *la) -{ - ClearAllFWHoles(la); - if (la->fireWallFD >= 0) - close(la->fireWallFD); - la->fireWallFD = -1; - if (la->fireWallField) - free(la->fireWallField); - la->fireWallField = NULL; - la->packetAliasMode &= ~PKT_ALIAS_PUNCH_FW; -} - -/* Make a certain link go through the firewall */ -void -PunchFWHole(struct alias_link *lnk) -{ - struct libalias *la; - int r; /* Result code */ - struct ip_fw rule; /* On-the-fly built rule */ - int fwhole; /* Where to punch hole */ - - la = lnk->la; - -/* Don't do anything unless we are asked to */ - if (!(la->packetAliasMode & PKT_ALIAS_PUNCH_FW) || - la->fireWallFD < 0 || - lnk->link_type != LINK_TCP) - return; - - memset(&rule, 0, sizeof rule); - -/** Build rule **/ - - /* Find empty slot */ - for (fwhole = la->fireWallActiveNum; - fwhole < la->fireWallBaseNum + la->fireWallNumNums && - fw_tstfield(la, la->fireWallField, fwhole); - fwhole++); - if (fwhole == la->fireWallBaseNum + la->fireWallNumNums) { - for (fwhole = la->fireWallBaseNum; - fwhole < la->fireWallActiveNum && - fw_tstfield(la, la->fireWallField, fwhole); - fwhole++); - if (fwhole == la->fireWallActiveNum) { - /* No rule point empty - we can't punch more holes. */ - la->fireWallActiveNum = la->fireWallBaseNum; -#ifdef DEBUG - fprintf(stderr, "libalias: Unable to create firewall hole!\n"); -#endif - return; - } - } - /* Start next search at next position */ - la->fireWallActiveNum = fwhole + 1; - - /* - * generate two rules of the form - * - * add fwhole accept tcp from OAddr OPort to DAddr DPort add fwhole - * accept tcp from DAddr DPort to OAddr OPort - */ -#if IPFW2 - if (GetOriginalPort(lnk) != 0 && GetDestPort(lnk) != 0) { - u_int32_t rulebuf[255]; - int i; - - i = fill_rule(rulebuf, sizeof(rulebuf), fwhole, - O_ACCEPT, IPPROTO_TCP, - GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)), - GetDestAddress(lnk), ntohs(GetDestPort(lnk))); - r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i); - if (r) - err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)"); - - i = fill_rule(rulebuf, sizeof(rulebuf), fwhole, - O_ACCEPT, IPPROTO_TCP, - GetDestAddress(lnk), ntohs(GetDestPort(lnk)), - GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk))); - r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i); - if (r) - err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)"); - } -#else /* !IPFW2, old code to generate ipfw rule */ - - /* Build generic part of the two rules */ - rule.fw_number = fwhole; - 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; - - /* Build and apply specific part of the rules */ - rule.fw_src = GetOriginalAddress(lnk); - rule.fw_dst = GetDestAddress(lnk); - rule.fw_uar.fw_pts[0] = ntohs(GetOriginalPort(lnk)); - rule.fw_uar.fw_pts[1] = ntohs(GetDestPort(lnk)); - - /* - * Skip non-bound links - XXX should not be strictly necessary, but - * seems to leave hole if not done. Leak of non-bound links? (Code - * should be left even if the problem is fixed - it is a clear - * optimization) - */ - if (rule.fw_uar.fw_pts[0] != 0 && rule.fw_uar.fw_pts[1] != 0) { - r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule); -#ifdef DEBUG - if (r) - err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)"); -#endif - rule.fw_src = GetDestAddress(lnk); - rule.fw_dst = GetOriginalAddress(lnk); - rule.fw_uar.fw_pts[0] = ntohs(GetDestPort(lnk)); - rule.fw_uar.fw_pts[1] = ntohs(GetOriginalPort(lnk)); - r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule); -#ifdef DEBUG - if (r) - err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)"); -#endif - } -#endif /* !IPFW2 */ -/* Indicate hole applied */ - lnk->data.tcp->fwhole = fwhole; - fw_setfield(la, la->fireWallField, fwhole); -} - -/* Remove a hole in a firewall associated with a particular alias - lnk. Calling this too often is harmless. */ -static void -ClearFWHole(struct alias_link *lnk) -{ - - struct libalias *la; - - la = lnk->la; - if (lnk->link_type == LINK_TCP) { - int fwhole = lnk->data.tcp->fwhole; /* Where is the firewall - * hole? */ - struct ip_fw rule; - - if (fwhole < 0) - return; - - memset(&rule, 0, sizeof rule); /* useless for ipfw2 */ -#if IPFW2 - while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, - &fwhole, sizeof fwhole)); -#else /* !IPFW2 */ - rule.fw_number = fwhole; - while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, - &rule, sizeof rule)); -#endif /* !IPFW2 */ - fw_clrfield(la, la->fireWallField, fwhole); - lnk->data.tcp->fwhole = -1; - } -} - -/* Clear out the entire range dedicated to firewall holes. */ -static void -ClearAllFWHoles(struct libalias *la) -{ - struct ip_fw rule; /* On-the-fly built rule */ - int i; - - if (la->fireWallFD < 0) - return; - - memset(&rule, 0, sizeof rule); - for (i = la->fireWallBaseNum; i < la->fireWallBaseNum + la->fireWallNumNums; i++) { -#if IPFW2 - int r = i; - - while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, &r, sizeof r)); -#else /* !IPFW2 */ - rule.fw_number = i; - while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule)); -#endif /* !IPFW2 */ - } - /* XXX: third arg correct here ? /phk */ - memset(la->fireWallField, 0, la->fireWallNumNums); -} - -#endif - -void -LibAliasSetFWBase(struct libalias *la, unsigned int base, unsigned int num) -{ -#ifndef NO_FW_PUNCH - la->fireWallBaseNum = base; - la->fireWallNumNums = num; -#endif -} - -void -LibAliasSetSkinnyPort(struct libalias *la, unsigned int port) -{ - la->skinnyPort = port; -} |