-/*
- * 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 <cmott@scientech.com>
- * 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.
-
- 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 <syslog.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"
-
-
-
-/*
- Constants (note: constants are also defined
- near relevant functions or structs)
-*/
-
-/* Sizes of input and output link tables */
-#define LINK_TABLE_OUT_SIZE 101
-#define LINK_TABLE_IN_SIZE 4001
-
-/* 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
-
-
-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. */
-
-#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 */
-{
- __uint32_t ack_old;
- __uint32_t 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 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 */
-
-/* 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
-#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 */
-
- 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;
-};
-
-
-
-
-
-/* Global Variables
-
- The global variables listed here are only accessed from
- within alias_db.c and so are prefixed with the static
- designation.
-*/
-
-int packetAliasMode; /* Mode flags */
- /* - documented in alias.h */
-
-static struct in_addr aliasAddress; /* Address written onto source */
- /* field of IP packet. */
-
-static struct in_addr targetAddress; /* IP address incoming packets */
- /* are sent to if no aliasing */
- /* link already exists */
-
-static struct in_addr nullAddress; /* Used as a dummy parameter for */
- /* some function calls */
-static LIST_HEAD(, alias_link)
-linkTableOut[LINK_TABLE_OUT_SIZE]; /* Lookup table of pointers to */
- /* chains of link records. Each */
-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;
-
-static int cleanupIndex; /* Index to chain of link table */
- /* being inspected for old links */
-
-static int timeStamp; /* System time in seconds for */
- /* current packet */
-
-static int lastCleanupTime; /* Last time IncrementalCleanup() */
- /* was called */
-
-static int houseKeepingResidual; /* used by HouseKeeping() */
-
-static int deleteAllLinks; /* If equal to zero, DeleteLink() */
- /* will not remove permanent links */
-
-static FILE *monitorFile; /* File descriptor for link */
- /* statistics monitoring file */
-
-static int newDefaultLink; /* Indicates if a new aliasing */
- /* link has been created after a */
- /* call to PacketAliasIn/Out(). */
-
-#ifndef NO_FW_PUNCH
-static int fireWallFD = -1; /* File descriptor to be able to */
- /* control firewall. Opened by */
- /* PacketAliasSetMode on first */
- /* setting the PKT_ALIAS_PUNCH_FW */
- /* flag. */
-#endif
-
-
-
-
-
-
-
-/* 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(__uint32_t, __uint32_t);
-
-#ifndef DEBUG
-static void ShowAliasStats(void);
-#endif
-
-#ifndef NO_FW_PUNCH
-/* Firewall control */
-static void InitPunchFW(void);
-static void UninitPunchFW(void);
-static void ClearFWHole(struct alias_link *link);
-#endif
-
-/* Log file control */
-static void InitPacketAliasLog(void);
-static void UninitPacketAliasLog(void);
-
-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(__uint32_t x, __uint32_t 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));
-}
-
-
-#ifndef DEBUG
-static void
-ShowAliasStats(void)
-{
-/* Used for debugging */
-
- if (monitorFile)
- {
- 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);
-
- fflush(monitorFile);
- }
-}
-#endif
-
-
-
-
-
-/* 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 alias_link *, int);
-
-static u_short GetSocket(u_short, int *, int);
-
-static void CleanupAliasData(void);
-
-static void IncrementalCleanup(void);
-
-static void DeleteLink(struct alias_link *);
-
-static struct alias_link *
-AddLink(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 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);
-
-
-#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)
-{
- int i;
- int max_trials;
- 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.
-
- 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 (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 = link->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)
- {
- link->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(link->dst_addr, link->alias_addr,
- link->dst_port, port_net,
- link->link_type, 0);
-
- if (search_result == NULL)
- go_ahead = 1;
- else if (!(link->flags & LINK_PARTIALLY_SPECIFIED)
- && (search_result->flags & LINK_PARTIALLY_SPECIFIED))
- go_ahead = 1;
- else
- go_ahead = 0;
-
- if (go_ahead)
- {
- 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))
- {
- link->alias_port = port_net;
- return(0);
- }
- }
- else
- {
- link->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(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)
- {
- 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 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)
-{
- struct alias_link *link;
- int i, icount;
-
- icount = 0;
- for (i=0; i<LINK_TABLE_OUT_SIZE; i++)
- {
- link = LIST_FIRST(&linkTableOut[i]);
- while (link != NULL)
- {
- struct alias_link *link_next;
- link_next = LIST_NEXT(link, list_out);
- icount++;
- DeleteLink(link);
- link = link_next;
- }
- }
-
- cleanupIndex =0;
-}
-
-
-static void
-IncrementalCleanup(void)
-{
- int icount;
- struct alias_link *link;
-
- icount = 0;
- link = LIST_FIRST(&linkTableOut[cleanupIndex++]);
- while (link != NULL)
- {
- int idelta;
- struct alias_link *link_next;
-
- link_next = LIST_NEXT(link, list_out);
- idelta = timeStamp - link->timestamp;
- switch (link->link_type)
- {
- case LINK_TCP:
- if (idelta > link->expire_time)
- {
- struct tcp_dat *tcp_aux;
-
- tcp_aux = link->data.tcp;
- if (tcp_aux->state.in != ALIAS_TCP_STATE_CONNECTED
- || tcp_aux->state.out != ALIAS_TCP_STATE_CONNECTED)
- {
- DeleteLink(link);
- icount++;
- }
- }
- break;
- default:
- if (idelta > link->expire_time)
- {
- DeleteLink(link);
- icount++;
- }
- break;
- }
- link = link_next;
- }
-
- if (cleanupIndex == LINK_TABLE_OUT_SIZE)
- cleanupIndex = 0;
-}
-
-static void
-DeleteLink(struct alias_link *link)
-{
-
-/* Don't do anything if the link is marked permanent */
- if (deleteAllLinks == 0 && link->flags & LINK_PERMANENT)
- return;
-
-#ifndef NO_FW_PUNCH
-/* Delete associated firewall hole, if any */
- ClearFWHole(link);
-#endif
-
-/* Free memory allocated for LSNAT server pool */
- if (link->server != NULL) {
- struct server *head, *curr, *next;
-
- head = curr = link->server;
- do {
- next = curr->next;
- free(curr);
- } while ((curr = next) != head);
- }
-
-/* Adjust output table pointers */
- LIST_REMOVE(link, list_out);
-
-/* Adjust input table pointers */
- LIST_REMOVE(link, list_in);
-
-/* Close socket, if one has been allocated */
- if (link->sockfd != -1)
- {
- sockCount--;
- close(link->sockfd);
- }
-
-/* Link-type dependent cleanup */
- switch(link->link_type)
- {
- case LINK_ICMP:
- icmpLinkCount--;
- break;
- case LINK_UDP:
- udpLinkCount--;
- break;
- case LINK_TCP:
- tcpLinkCount--;
- free(link->data.tcp);
- break;
- case LINK_PPTP:
- pptpLinkCount--;
- break;
- case LINK_FRAGMENT_ID:
- fragmentIdLinkCount--;
- break;
- case LINK_FRAGMENT_PTR:
- fragmentPtrLinkCount--;
- if (link->data.frag_ptr != NULL)
- free(link->data.frag_ptr);
- break;
- case LINK_ADDR:
- break;
- default:
- protoLinkCount--;
- break;
- }
-
-#ifdef DEBUG
- if ((packetAliasMode & PKT_ALIAS_LOG) != 0 &&
- !IN_MULTICAST(link->src_addr.s_addr) &&
- !IN_MULTICAST(link->dst_addr.s_addr))
- {
- 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);
-}
-
-
-static struct alias_link *
-AddLink(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 *link;
-
- link = malloc(sizeof(struct alias_link));
- if (link != NULL)
- {
- /* Basic initialization */
- link->src_addr = src_addr;
- link->dst_addr = dst_addr;
- link->alias_addr = alias_addr;
- 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;
- link->timestamp = timeStamp;
-
- /* Expiration time */
- switch (link_type)
- {
- case LINK_ICMP:
- link->expire_time = ICMP_EXPIRE_TIME;
- break;
- case LINK_UDP:
- 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 == INADDR_ANY)
- link->flags |= LINK_UNKNOWN_DEST_ADDR;
- if (dst_port == 0)
- link->flags |= LINK_UNKNOWN_DEST_PORT;
-
- /* Determine alias port */
- if (GetNewPort(link, alias_port_param) != 0)
- {
- free(link);
- return(NULL);
- }
- /* Link-type dependent initialization */
- switch(link_type)
- {
- struct tcp_dat *aux_tcp;
-
- case LINK_ICMP:
- icmpLinkCount++;
- break;
- case LINK_UDP:
- udpLinkCount++;
- break;
- case LINK_TCP:
- aux_tcp = malloc(sizeof(struct tcp_dat));
- if (aux_tcp != NULL)
- {
- int i;
-
- 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;
- link->data.tcp = aux_tcp;
- }
- else
- {
-#ifdef DEBUG
- 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
- {
-#ifdef DEBUG
- fprintf(stderr, "PacketAlias/AddLink(): ");
- fprintf(stderr, "malloc() call failed.\n");
-#endif
- }
-
-#ifdef DEBUG
- if ((packetAliasMode & PKT_ALIAS_LOG) != 0 &&
- !IN_MULTICAST(link->src_addr.s_addr) &&
- !IN_MULTICAST(link->dst_addr.s_addr))
- {
- 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);
-}
-
-static struct alias_link *
-ReLink(struct alias_link *old_link,
- 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_link; /* zero, equal to alias port */
-
- new_link = AddLink(src_addr, dst_addr, alias_addr,
- src_port, dst_port, alias_port_param,
- link_type);
-#ifndef NO_FW_PUNCH
- if (new_link != NULL &&
- old_link->link_type == LINK_TCP &&
- old_link->data.tcp->fwhole > 0) {
- PunchFWHole(new_link);
- }
-#endif
- if ((old_link->flags & LINK_CONE) == 0)
- DeleteLink(old_link);
- return new_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)
-{
- u_int i;
- struct alias_link *link;
-
- i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type);
- 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
- && link->link_type == link_type)
- {
- link->timestamp = timeStamp;
- break;
- }
- }
-
-/* 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;
-
- 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,
- int link_type,
- int replace_partial_links)
-{
- int flags_in;
- u_int start_point;
- struct alias_link *link;
- struct alias_link *link_fully_specified;
- struct alias_link *link_unknown_all;
- struct alias_link *link_unknown_dst_addr;
- struct alias_link *link_unknown_dst_port;
-
-/* Initialize pointers */
- link_fully_specified = NULL;
- link_unknown_all = NULL;
- link_unknown_dst_addr = NULL;
- link_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(link, &linkTableIn[start_point], list_in)
- {
- int flags;
-
- flags = flags_in | link->flags;
- if (!(flags & LINK_PARTIALLY_SPECIFIED))
- {
- if (link->alias_addr.s_addr == alias_addr.s_addr
- && link->alias_port == alias_port
- && link->dst_addr.s_addr == dst_addr.s_addr
- && link->dst_port == dst_port
- && link->link_type == link_type)
- {
- link_fully_specified = link;
- break;
- }
- }
- else if ((flags & LINK_UNKNOWN_DEST_ADDR)
- && (flags & LINK_UNKNOWN_DEST_PORT))
- {
- if (link->alias_addr.s_addr == alias_addr.s_addr
- && link->alias_port == alias_port
- && link->link_type == link_type)
- {
- if (link_unknown_all == NULL)
- link_unknown_all = link;
- }
- }
- else if (flags & LINK_UNKNOWN_DEST_ADDR)
- {
- if (link->alias_addr.s_addr == alias_addr.s_addr
- && link->alias_port == alias_port
- && link->link_type == link_type
- && link->dst_port == dst_port)
- {
- if (link_unknown_dst_addr == NULL)
- link_unknown_dst_addr = link;
- }
- }
- else if (flags & LINK_UNKNOWN_DEST_PORT)
- {
- if (link->alias_addr.s_addr == alias_addr.s_addr
- && link->alias_port == alias_port
- && link->link_type == link_type
- && link->dst_addr.s_addr == dst_addr.s_addr)
- {
- if (link_unknown_dst_port == NULL)
- link_unknown_dst_port = link;
- }
- }
- }
-
-
-
- if (link_fully_specified != NULL)
- {
- link_fully_specified->timestamp = timeStamp;
- link = link_fully_specified;
- }
- else if (link_unknown_dst_port != NULL)
- link = link_unknown_dst_port;
- else if (link_unknown_dst_addr != NULL)
- 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))
- {
- 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);
- }
-
- 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)
- {
- /* 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);
-}
-
-
-
-
-/* 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 in_addr dst_addr,
- struct in_addr alias_addr,
- u_short id_alias,
- int create)
-{
- 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,
- int create)
-{
- struct alias_link * link;
-
- link = FindLinkOut(src_addr, dst_addr,
- id, NO_DEST_PORT,
- LINK_ICMP, 0);
- if (link == NULL && create)
- {
- struct in_addr alias_addr;
-
- alias_addr = FindAliasAddress(src_addr);
- link = AddLink(src_addr, dst_addr, alias_addr,
- id, NO_DEST_PORT, GET_ALIAS_ID,
- LINK_ICMP);
- }
-
- return(link);
-}
-
-
-struct alias_link *
-FindFragmentIn1(struct in_addr dst_addr,
- struct in_addr alias_addr,
- u_short ip_id)
-{
- struct alias_link *link;
-
- link = FindLinkIn(dst_addr, alias_addr,
- NO_DEST_PORT, ip_id,
- LINK_FRAGMENT_ID, 0);
-
- if (link == NULL)
- {
- link = AddLink(nullAddress, dst_addr, alias_addr,
- NO_SRC_PORT, NO_DEST_PORT, ip_id,
- LINK_FRAGMENT_ID);
- }
-
- return(link);
-}
-
-
-struct alias_link *
-FindFragmentIn2(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(dst_addr, alias_addr,
- NO_DEST_PORT, ip_id,
- LINK_FRAGMENT_ID, 0);
-}
-
-
-struct alias_link *
-AddFragmentPtrLink(struct in_addr dst_addr,
- u_short ip_id)
-{
- return AddLink(nullAddress, dst_addr, nullAddress,
- NO_SRC_PORT, NO_DEST_PORT, ip_id,
- LINK_FRAGMENT_PTR);
-}
-
-
-struct alias_link *
-FindFragmentPtr(struct in_addr dst_addr,
- u_short ip_id)
-{
- return FindLinkIn(dst_addr, nullAddress,
- NO_DEST_PORT, ip_id,
- LINK_FRAGMENT_PTR, 0);
-}
-
-
-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,
- int create)
-{
- 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 = FindLinkIn(dst_addr, alias_addr,
- dst_port, alias_port,
- link_type, create);
-
- 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,
- alias_port, dst_port, alias_port,
- link_type);
- }
-
- return(link);
-}
-
-
-struct alias_link *
-FindUdpTcpOut(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 *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, 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)
- {
- struct in_addr alias_addr;
-
- alias_addr = FindAliasAddress(src_addr);
- link = AddLink(src_addr, dst_addr, alias_addr,
- src_port, 0, alias_port,
- link_type);
- }
-
- return(link);
-}
-
-
-struct in_addr
-FindOriginalAddress(struct in_addr alias_addr)
-{
- struct alias_link *link;
-
- link = FindLinkIn(nullAddress, alias_addr,
- 0, 0, LINK_ADDR, 0);
- if (link == NULL)
- {
- newDefaultLink = 1;
- if (targetAddress.s_addr == INADDR_ANY)
- return alias_addr;
- else if (targetAddress.s_addr == INADDR_NONE)
- return aliasAddress;
- else
- return targetAddress;
- }
- else
- {
- 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;
- }
-}
-
-
-struct in_addr
-FindAliasAddress(struct in_addr original_addr)
-{
- struct alias_link *link;
-
- link = FindLinkOut(original_addr, nullAddress,
- 0, 0, LINK_ADDR, 0);
- if (link == NULL)
- {
- return aliasAddress;
- }
- else
- {
- 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; i<LINK_TABLE_OUT_SIZE; i++)
- {
- link = LIST_FIRST(&linkTableOut[i]);
- while (link != NULL)
- {
- struct alias_link *link_next;
- char src_str[32], dst_str[32], alias_str[32];
-
- snprintf(src_str, sizeof(src_str), "%s:%u",
- inet_ntoa(link->src_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)
-
- SetFragmentData(), GetFragmentData()
- SetFragmentPtr(), GetFragmentPtr()
- SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut()
- GetOriginalAddress(), GetDestAddress(), GetAliasAddress()
- GetOriginalPort(), GetAliasPort()
- SetAckModified(), GetAckModified()
- GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq()
- SetLastLineCrlfTermed(), GetLastLineCrlfTermed()
- SetDestCallId()
-*/
-
-
-void
-SetFragmentAddr(struct alias_link *link, struct in_addr src_addr)
-{
- link->data.frag_addr = src_addr;
-}
-
-
-void
-GetFragmentAddr(struct alias_link *link, struct in_addr *src_addr)
-{
- *src_addr = link->data.frag_addr;
-}
-
-
-void
-SetFragmentPtr(struct alias_link *link, char *fptr)
-{
- link->data.frag_ptr = fptr;
-}
-
-
-void
-GetFragmentPtr(struct alias_link *link, char **fptr)
-{
- *fptr = link->data.frag_ptr;
-}
-
-
-void
-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)
- link->expire_time = TCP_EXPIRE_DEAD;
- else
- link->expire_time = TCP_EXPIRE_SINGLEDEAD;
- break;
- case ALIAS_TCP_STATE_CONNECTED:
- 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;
-}
-
-
-void
-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)
- link->expire_time = TCP_EXPIRE_DEAD;
- else
- link->expire_time = TCP_EXPIRE_SINGLEDEAD;
- break;
- case ALIAS_TCP_STATE_CONNECTED:
- 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;
-}
-
-
-int
-GetStateIn(struct alias_link *link)
-{
- /* TCP input state */
- return link->data.tcp->state.in;
-}
-
-
-int
-GetStateOut(struct alias_link *link)
-{
- /* TCP output state */
- return link->data.tcp->state.out;
-}
-
-
-struct in_addr
-GetOriginalAddress(struct alias_link *link)
-{
- if (link->src_addr.s_addr == INADDR_ANY)
- return aliasAddress;
- else
- return(link->src_addr);
-}
-
-
-struct in_addr
-GetDestAddress(struct alias_link *link)
-{
- return(link->dst_addr);
-}
-
-
-struct in_addr
-GetAliasAddress(struct alias_link *link)
-{
- if (link->alias_addr.s_addr == INADDR_ANY)
- return aliasAddress;
- else
- return link->alias_addr;
-}
-
-
-struct in_addr
-GetDefaultAliasAddress()
-{
- return aliasAddress;
-}
-
-
-void
-SetDefaultAliasAddress(struct in_addr alias_addr)
-{
- aliasAddress = alias_addr;
-}
-
-
-u_short
-GetOriginalPort(struct alias_link *link)
-{
- return(link->src_port);
-}
-
-
-u_short
-GetAliasPort(struct alias_link *link)
-{
- return(link->alias_port);
-}
-
-#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 */
- link->data.tcp->state.ack_modified = 1;
-}
-
-
-struct in_addr
-GetProxyAddress(struct alias_link *link)
-{
- return link->proxy_addr;
-}
-
-
-void
-SetProxyAddress(struct alias_link *link, struct in_addr addr)
-{
- link->proxy_addr = addr;
-}
-
-
-u_short
-GetProxyPort(struct alias_link *link)
-{
- return link->proxy_port;
-}
-
-
-void
-SetProxyPort(struct alias_link *link, u_short port)
-{
- link->proxy_port = port;
-}
-
-
-int
-GetAckModified(struct alias_link *link)
-{
-/* See if ACK numbers have been modified */
- return link->data.tcp->state.ack_modified;
-}
-
-
-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 of ACK numbers where the TCP
-packet size was altered is searched.
-*/
-
- int i;
- struct tcphdr *tc;
- int delta, ack_diff_min;
- __uint32_t ack;
-
- tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
- 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 = link->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 *link)
-{
-/*
-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;
- __uint32_t seq;
-
- tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
- 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 = link->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 *link, 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 = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
-
- 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 = link->data.tcp->state.index;
- link->data.tcp->ack[i] = x;
-
- i++;
- if (i == N_LINK_TCP_DATA)
- link->data.tcp->state.index = 0;
- else
- link->data.tcp->state.index = i;
-}
-
-void
-SetExpire(struct alias_link *link, int expire)
-{
- if (expire == 0)
- {
- link->flags &= ~LINK_PERMANENT;
- DeleteLink(link);
- }
- else if (expire == -1)
- {
- link->flags |= LINK_PERMANENT;
- }
- else if (expire > 0)
- {
- link->expire_time = expire;
- }
- else
- {
-#ifdef DEBUG
- fprintf(stderr, "PacketAlias/SetExpire(): ");
- fprintf(stderr, "error in expire parameter\n");
-#endif
- }
-}
-
-void
-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
-
- 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(void)
-{
- 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);
- timeStamp = tv.tv_sec;
-
- /* Compute number of spokes (output table link chains) to cover */
- n100 = LINK_TABLE_OUT_SIZE * 100 + houseKeepingResidual;
- n100 *= timeStamp - lastCleanupTime;
- n100 /= ALIAS_CLEANUP_INTERVAL_SECS;
-
- n = n100/100;
-
- /* Handle different cases */
- if (n > ALIAS_CLEANUP_MAX_SPOKES)
- {
- n = ALIAS_CLEANUP_MAX_SPOKES;
- lastCleanupTime = timeStamp;
- houseKeepingResidual = 0;
-
- for (i=0; i<n; i++)
- IncrementalCleanup();
- }
- else if (n > 0)
- {
- lastCleanupTime = timeStamp;
- houseKeepingResidual = n100 - 100*n;
-
- for (i=0; i<n; i++)
- IncrementalCleanup();
- }
- else if (n < 0)
- {
-#ifdef DEBUG
- fprintf(stderr, "PacketAlias/HouseKeeping(): ");
- fprintf(stderr, "something unexpected in time values\n");
-#endif
- lastCleanupTime = timeStamp;
- houseKeepingResidual = 0;
- }
-}
-
-
-/* Init the log file and enable logging */
-static void
-InitPacketAliasLog(void)
-{
- if ((~packetAliasMode & PKT_ALIAS_LOG)
- && (monitorFile = fopen("/var/log/alias.log", "w")))
- {
- packetAliasMode |= PKT_ALIAS_LOG;
- fprintf(monitorFile,
- "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");
- }
-}
-
-
-/* Close the log-file and disable logging. */
-static void
-UninitPacketAliasLog(void)
-{
- if (monitorFile) {
- fclose(monitorFile);
- monitorFile = NULL;
- }
- packetAliasMode &= ~PKT_ALIAS_LOG;
-}
-
-
-
-
-
-
-/* Outside world interfaces
-
--- "outside world" means other than alias*.c routines --
-
- PacketAliasRedirectPort()
- PacketAliasAddServer()
- PacketAliasRedirectProto()
- PacketAliasRedirectAddr()
- PacketAliasRedirectDelete()
- PacketAliasSetAddress()
- PacketAliasInit()
- PacketAliasUninit()
- PacketAliasSetMode()
-
-(prototypes in alias.h)
-*/
-
-/* Redirection from a specific public addr:port to a
- 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,
- struct in_addr alias_addr, 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:
-#ifdef DEBUG
- fprintf(stderr, "PacketAliasRedirectPort(): ");
- fprintf(stderr, "only TCP and UDP protocols allowed\n");
-#endif
- return NULL;
- }
-
- link = AddLink(src_addr, dst_addr, alias_addr,
- src_port, dst_port, alias_port,
- link_type);
-
- if (link != NULL)
- {
- link->flags |= LINK_PERMANENT;
- }
-#ifdef DEBUG
- else
- {
- fprintf(stderr, "PacketAliasRedirectPort(): "
- "call to AddLink() failed\n");
- }
-#endif
-
- return link;
-}
-
-/* Add server to the pool of servers */
-int
-PacketAliasAddServer(struct alias_link *link, struct in_addr addr, u_short port)
-{
- struct server *server;
-
- server = malloc(sizeof(struct server));
-
- 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);
-}
-
-/* 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)
-{
- 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 link;
-}
-
-/* Static address translation */
-struct alias_link *
-PacketAliasRedirectAddr(struct in_addr src_addr,
- struct in_addr alias_addr)
-{
- struct alias_link *link;
-
- link = AddLink(src_addr, nullAddress, alias_addr,
- 0, 0, 0,
- LINK_ADDR);
-
- if (link != NULL)
- {
- link->flags |= LINK_PERMANENT;
- }
-#ifdef DEBUG
- else
- {
- fprintf(stderr, "PacketAliasRedirectAddr(): "
- "call to AddLink() failed\n");
- }
-#endif
-
- return link;
-}
-
-
-void
-PacketAliasRedirectDelete(struct alias_link *link)
-{
-/* This is a dangerous function to put in the API,
- because an invalid pointer can crash the program. */
-
- deleteAllLinks = 1;
- DeleteLink(link);
- deleteAllLinks = 0;
-}
-
-
-void
-PacketAliasSetAddress(struct in_addr addr)
-{
- if (packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE
- && aliasAddress.s_addr != addr.s_addr)
- CleanupAliasData();
-
- aliasAddress = addr;
-}
-
-
-void
-PacketAliasSetTarget(struct in_addr target_addr)
-{
- targetAddress = target_addr;
-}
-
-
-void
-PacketAliasInit(void)
-{
- int i;
- struct timeval tv;
- struct timezone tz;
- static int firstCall = 1;
-
- if (firstCall == 1)
- {
- gettimeofday(&tv, &tz);
- timeStamp = tv.tv_sec;
- lastCleanupTime = tv.tv_sec;
- houseKeepingResidual = 0;
-
- for (i=0; i<LINK_TABLE_OUT_SIZE; i++)
- LIST_INIT(&linkTableOut[i]);
- for (i=0; i<LINK_TABLE_IN_SIZE; i++)
- LIST_INIT(&linkTableIn[i]);
-
- atexit(PacketAliasUninit);
- firstCall = 0;
- }
- else
- {
- deleteAllLinks = 1;
- CleanupAliasData();
- deleteAllLinks = 0;
- }
-
- aliasAddress.s_addr = INADDR_ANY;
- targetAddress.s_addr = INADDR_ANY;
-
- icmpLinkCount = 0;
- udpLinkCount = 0;
- tcpLinkCount = 0;
- pptpLinkCount = 0;
- protoLinkCount = 0;
- fragmentIdLinkCount = 0;
- fragmentPtrLinkCount = 0;
- sockCount = 0;
-
- cleanupIndex =0;
-
- packetAliasMode = PKT_ALIAS_SAME_PORTS
- | PKT_ALIAS_USE_SOCKETS
- | PKT_ALIAS_RESET_ON_ADDR_CHANGE;
-}
-
-void
-PacketAliasUninit(void) {
- deleteAllLinks = 1;
- CleanupAliasData();
- deleteAllLinks = 0;
- UninitPacketAliasLog();
-#ifndef NO_FW_PUNCH
- UninitPunchFW();
-#endif
-}
-
-
-/* Change mode for some operations */
-unsigned int
-PacketAliasSetMode(
- 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(); /* Do the enable */
- } else
-/* _Disable_ logging? */
- if (~flags & mask & PKT_ALIAS_LOG) {
- UninitPacketAliasLog();
- }
-
-#ifndef NO_FW_PUNCH
-/* Start punching holes in the firewall? */
- if (flags & mask & PKT_ALIAS_PUNCH_FW) {
- InitPunchFW();
- } else
-/* Stop punching holes in the firewall? */
- if (~flags & mask & PKT_ALIAS_PUNCH_FW) {
- UninitPunchFW();
- }
-#endif
-
-/* Other flags can be set/cleared without special action */
- packetAliasMode = (flags & mask) | (packetAliasMode & ~mask);
- return packetAliasMode;
-}
-
-
-int
-PacketAliasCheckNewLink(void)
-{
- return 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.
- ****************/
-
-/* Firewall include files */
-#include <net/if.h>
-#include <netinet/ip_fw.h>
-#include <string.h>
-#include <err.h>
-
-static void ClearAllFWHoles(void);
-
-static int fireWallBaseNum; /* The first firewall entry free for our use */
-static int fireWallNumNums; /* How many entries can we use? */
-static int fireWallActiveNum; /* Which entry did we last use? */
-static char *fireWallField; /* bool array for entries */
-
-#define fw_setfield(field, num) \
-do { \
- (field)[(num) - fireWallBaseNum] = 1; \
-} /*lint -save -e717 */ while(0) /*lint -restore */
-#define fw_clrfield(field, num) \
-do { \
- (field)[(num) - fireWallBaseNum] = 0; \
-} /*lint -save -e717 */ while(0) /*lint -restore */
-#define fw_tstfield(field, num) ((field)[(num) - fireWallBaseNum])
-
-static void
-InitPunchFW(void) {
- fireWallField = malloc(fireWallNumNums);
- if (fireWallField) {
- memset(fireWallField, 0, fireWallNumNums);
- if (fireWallFD < 0) {
- fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
- }
- ClearAllFWHoles();
- fireWallActiveNum = fireWallBaseNum;
- }
-}
-
-static void
-UninitPunchFW(void) {
- ClearAllFWHoles();
- if (fireWallFD >= 0)
- close(fireWallFD);
- fireWallFD = -1;
- if (fireWallField)
- free(fireWallField);
- fireWallField = NULL;
- packetAliasMode &= ~PKT_ALIAS_PUNCH_FW;
-}
-
-/* Make a certain link go through the firewall */
-void
-PunchFWHole(struct alias_link *link) {
- int r; /* Result code */
- struct ip_fw rule; /* On-the-fly built rule */
- int fwhole; /* Where to punch hole */
-
-/* Don't do anything unless we are asked to */
- if ( !(packetAliasMode & PKT_ALIAS_PUNCH_FW) ||
- fireWallFD < 0 ||
- link->link_type != LINK_TCP)
- return;
-
- memset(&rule, 0, sizeof rule);
-
-/** Build rule **/
-
- /* Find empty slot */
- for (fwhole = fireWallActiveNum;
- fwhole < fireWallBaseNum + fireWallNumNums &&
- fw_tstfield(fireWallField, fwhole);
- fwhole++)
- ;
- if (fwhole == fireWallBaseNum + fireWallNumNums) {
- for (fwhole = fireWallBaseNum;
- fwhole < fireWallActiveNum &&
- fw_tstfield(fireWallField, fwhole);
- fwhole++)
- ;
- if (fwhole == fireWallActiveNum) {
- /* No rule point empty - we can't punch more holes. */
- fireWallActiveNum = fireWallBaseNum;
-#ifdef DEBUG
- fprintf(stderr, "libalias: Unable to create firewall hole!\n");
-#endif
- return;
- }
- }
- /* Start next search at next position */
- fireWallActiveNum = fwhole+1;
-
- /* 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(link);
- rule.fw_dst = GetDestAddress(link);
- rule.fw_uar.fw_pts[0] = ntohs(GetOriginalPort(link));
- rule.fw_uar.fw_pts[1] = ntohs(GetDestPort(link));
-
- /* 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(link);
- rule.fw_dst = GetOriginalAddress(link);
- rule.fw_uar.fw_pts[0] = ntohs(GetDestPort(link));
- rule.fw_uar.fw_pts[1] = ntohs(GetOriginalPort(link));
- 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
- }
-/* Indicate hole applied */
- link->data.tcp->fwhole = fwhole;
- fw_setfield(fireWallField, fwhole);
-}
-
-/* Remove a hole in a firewall associated with a particular alias
- link. Calling this too often is harmless. */
-static void
-ClearFWHole(struct alias_link *link) {
- if (link->link_type == LINK_TCP) {
- int fwhole = link->data.tcp->fwhole; /* Where is the firewall hole? */
- struct ip_fw rule;
-
- if (fwhole < 0)
- return;
-
- memset(&rule, 0, sizeof rule);
- rule.fw_number = fwhole;
- while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule))
- ;
- fw_clrfield(fireWallField, fwhole);
- link->data.tcp->fwhole = -1;
- }
-}
-
-/* Clear out the entire range dedicated to firewall holes. */
-static void
-ClearAllFWHoles(void) {
- struct ip_fw rule; /* On-the-fly built rule */
- int i;
-
- if (fireWallFD < 0)
- return;
-
- memset(&rule, 0, sizeof rule);
- for (i = fireWallBaseNum; i < fireWallBaseNum + fireWallNumNums; i++) {
- rule.fw_number = i;
- while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule))
- ;
- }
- 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; i<LINK_TABLE_OUT_SIZE; i++)
- {
- link = LIST_FIRST(&linkTableOut[i]);
- while (link != NULL)
- {
- struct alias_link *link_next;
- char src_str[32], dst_str[32], alias_str[32];
-
- snprintf(src_str, sizeof(src_str), "%s:%u",
- inet_ntoa(link->src_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;
- }
- }
-
-}