alias_db.c revision 131613
177701Sbrian/*-
285964Sbrian * Copyright (c) 2001 Charles Mott <cm@linktel.net>
377701Sbrian * All rights reserved.
477701Sbrian *
577701Sbrian * Redistribution and use in source and binary forms, with or without
677701Sbrian * modification, are permitted provided that the following conditions
777701Sbrian * are met:
877701Sbrian * 1. Redistributions of source code must retain the above copyright
977701Sbrian *    notice, this list of conditions and the following disclaimer.
1077701Sbrian * 2. Redistributions in binary form must reproduce the above copyright
1177701Sbrian *    notice, this list of conditions and the following disclaimer in the
1277701Sbrian *    documentation and/or other materials provided with the distribution.
1377701Sbrian *
1477701Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1577701Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1677701Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1777701Sbrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1877701Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1977701Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2077701Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2177701Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2277701Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2377701Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2477701Sbrian * SUCH DAMAGE.
2577701Sbrian */
2677701Sbrian
2784195Sdillon#include <sys/cdefs.h>
2884195Sdillon__FBSDID("$FreeBSD: head/sys/netinet/libalias/alias_db.c 131613 2004-07-05 10:55:23Z des $");
2984195Sdillon
3077701Sbrian/*
3126026Sbrian    Alias_db.c encapsulates all data structures used for storing
3226026Sbrian    packet aliasing data.  Other parts of the aliasing software
3326026Sbrian    access data through functions provided in this file.
3426026Sbrian
3526026Sbrian    Data storage is based on the notion of a "link", which is
3626026Sbrian    established for ICMP echo/reply packets, UDP datagrams and
3726026Sbrian    TCP stream connections.  A link stores the original source
3826026Sbrian    and destination addresses.  For UDP and TCP, it also stores
3926026Sbrian    source and destination port numbers, as well as an alias
4026026Sbrian    port number.  Links are also used to store information about
4126026Sbrian    fragments.
4226026Sbrian
4326026Sbrian    There is a facility for sweeping through and deleting old
4426026Sbrian    links as new packets are sent through.  A simple timeout is
4526026Sbrian    used for ICMP and UDP links.  TCP links are left alone unless
4626026Sbrian    there is an incomplete connection, in which case the link
4726026Sbrian    can be deleted after a certain amount of time.
4826026Sbrian
4926026Sbrian
5026026Sbrian    Initial version: August, 1996  (cjm)
5126026Sbrian
5226026Sbrian    Version 1.4: September 16, 1996 (cjm)
53131612Sdes	Facility for handling incoming links added.
5426026Sbrian
5526026Sbrian    Version 1.6: September 18, 1996 (cjm)
56131612Sdes	ICMP data handling simplified.
5726026Sbrian
5826026Sbrian    Version 1.7: January 9, 1997 (cjm)
59131612Sdes	Fragment handling simplified.
60131612Sdes	Saves pointers for unresolved fragments.
61131612Sdes	Permits links for unspecified remote ports
62131612Sdes	  or unspecified remote addresses.
63131612Sdes	Fixed bug which did not properly zero port
64131612Sdes	  table entries after a link was deleted.
65131612Sdes	Cleaned up some obsolete comments.
6626026Sbrian
6726026Sbrian    Version 1.8: January 14, 1997 (cjm)
68131612Sdes	Fixed data type error in StartPoint().
69131612Sdes	(This error did not exist prior to v1.7
70131612Sdes	and was discovered and fixed by Ari Suutari)
7126026Sbrian
7226026Sbrian    Version 1.9: February 1, 1997
73131612Sdes	Optionally, connections initiated from packet aliasing host
74131612Sdes	machine will will not have their port number aliased unless it
75131612Sdes	conflicts with an aliasing port already being used. (cjm)
7626026Sbrian
77131612Sdes	All options earlier being #ifdef'ed are now available through
78131612Sdes	a new interface, SetPacketAliasMode().  This allows run time
79131612Sdes	control (which is now available in PPP+pktAlias through the
80131612Sdes	'alias' keyword). (ee)
8126026Sbrian
82131612Sdes	Added ability to create an alias port without
83131612Sdes	either destination address or port specified.
84131612Sdes	port type = ALIAS_PORT_UNKNOWN_DEST_ALL (ee)
8544307Sbrian
86131612Sdes	Removed K&R style function headers
87131612Sdes	and general cleanup. (ee)
8826026Sbrian
89131612Sdes	Added packetAliasMode to replace compiler #defines's (ee)
9044307Sbrian
91131612Sdes	Allocates sockets for partially specified
92131612Sdes	ports if ALIAS_USE_SOCKETS defined. (cjm)
9326026Sbrian
9426026Sbrian    Version 2.0: March, 1997
95131612Sdes	SetAliasAddress() will now clean up alias links
96131612Sdes	if the aliasing address is changed. (cjm)
9726026Sbrian
98131612Sdes	PacketAliasPermanentLink() function added to support permanent
99131612Sdes	links.  (J. Fortes suggested the need for this.)
100131612Sdes	Examples:
10126026Sbrian
102131612Sdes	(192.168.0.1, port 23)  <-> alias port 6002, unknown dest addr/port
10326026Sbrian
104131612Sdes	(192.168.0.2, port 21)  <-> alias port 3604, known dest addr
105131612Sdes						     unknown dest port
10626026Sbrian
107131612Sdes	These permanent links allow for incoming connections to
108131612Sdes	machines on the local network.  They can be given with a
109131612Sdes	user-chosen amount of specificity, with increasing specificity
110131612Sdes	meaning more security. (cjm)
11126026Sbrian
112131612Sdes	Quite a bit of rework to the basic engine.  The portTable[]
113131612Sdes	array, which kept track of which ports were in use was replaced
114131612Sdes	by a table/linked list structure. (cjm)
11526026Sbrian
116131612Sdes	SetExpire() function added. (cjm)
11726026Sbrian
118131612Sdes	DeleteLink() no longer frees memory association with a pointer
119131612Sdes	to a fragment (this bug was first recognized by E. Eklund in
120131612Sdes	v1.9).
12126026Sbrian
12226026Sbrian    Version 2.1: May, 1997 (cjm)
123131612Sdes	Packet aliasing engine reworked so that it can handle
124131612Sdes	multiple external addresses rather than just a single
125131612Sdes	host address.
12626026Sbrian
127131612Sdes	PacketAliasRedirectPort() and PacketAliasRedirectAddr()
128131612Sdes	added to the API.  The first function is a more generalized
129131612Sdes	version of PacketAliasPermanentLink().  The second function
130131612Sdes	implements static network address translation.
13132377Seivind
13263899Sarchie    Version 3.2: July, 2000 (salander and satoh)
133131612Sdes	Added FindNewPortGroup to get contiguous range of port values.
13463899Sarchie
135131612Sdes	Added QueryUdpTcpIn and QueryUdpTcpOut to look for an aliasing
13663899Sarchie	link but not actually add one.
13763899Sarchie
138131612Sdes	Added FindRtspOut, which is closely derived from FindUdpTcpOut,
13963899Sarchie	except that the alias port (from FindNewPortGroup) is provided
14063899Sarchie	as input.
14163899Sarchie
14232377Seivind    See HISTORY file for additional revisions.
14326026Sbrian*/
14426026Sbrian
14526026Sbrian
14626026Sbrian/* System include files */
14751491Sbrian#include <errno.h>
14826026Sbrian#include <stdlib.h>
14926026Sbrian#include <stdio.h>
15026026Sbrian#include <unistd.h>
15144307Sbrian
15264643Sru#include <sys/queue.h>
15326026Sbrian#include <sys/socket.h>
15426026Sbrian#include <sys/time.h>
15526026Sbrian#include <sys/types.h>
15626026Sbrian
15726026Sbrian/* BSD network include files */
15826026Sbrian#include <netinet/in_systm.h>
15926026Sbrian#include <netinet/in.h>
16026026Sbrian#include <netinet/ip.h>
16126026Sbrian#include <netinet/tcp.h>
16226026Sbrian#include <arpa/inet.h>
16326026Sbrian
16426026Sbrian#include "alias.h"
16526026Sbrian#include "alias_local.h"
16626026Sbrian
16726026Sbrian
168127094Sdesstatic		LIST_HEAD(, libalias) instancehead = LIST_HEAD_INITIALIZER(instancehead);
16926026Sbrian
170124621Sphk
17126026Sbrian/*
17226026Sbrian   Constants (note: constants are also defined
173131612Sdes	      near relevant functions or structs)
17426026Sbrian*/
17526026Sbrian
17626026Sbrian/* Parameters used for cleanup of expired links */
17744307Sbrian#define ALIAS_CLEANUP_INTERVAL_SECS  60
17826026Sbrian#define ALIAS_CLEANUP_MAX_SPOKES     30
17926026Sbrian
18051494Sru/* Timeouts (in seconds) for different link types */
18126026Sbrian#define ICMP_EXPIRE_TIME             60
18226026Sbrian#define UDP_EXPIRE_TIME              60
18359726Sru#define PROTO_EXPIRE_TIME            60
18426026Sbrian#define FRAGMENT_ID_EXPIRE_TIME      10
18526026Sbrian#define FRAGMENT_PTR_EXPIRE_TIME     30
18626026Sbrian
18732377Seivind/* TCP link expire time for different cases */
18832377Seivind/* When the link has been used and closed - minimal grace time to
18932377Seivind   allow ACKs and potential re-connect in FTP (XXX - is this allowed?)  */
19032377Seivind#ifndef TCP_EXPIRE_DEAD
191127094Sdes#define TCP_EXPIRE_DEAD           10
19232377Seivind#endif
19332377Seivind
19432377Seivind/* When the link has been used and closed on one side - the other side
19532377Seivind   is allowed to still send data */
19632377Seivind#ifndef TCP_EXPIRE_SINGLEDEAD
197127094Sdes#define TCP_EXPIRE_SINGLEDEAD     90
19832377Seivind#endif
19932377Seivind
20032377Seivind/* When the link isn't yet up */
20132377Seivind#ifndef TCP_EXPIRE_INITIAL
202127094Sdes#define TCP_EXPIRE_INITIAL       300
20332377Seivind#endif
20432377Seivind
20532377Seivind/* When the link is up */
20632377Seivind#ifndef TCP_EXPIRE_CONNECTED
207127094Sdes#define TCP_EXPIRE_CONNECTED   86400
20832377Seivind#endif
20932377Seivind
21032377Seivind
21126026Sbrian/* Dummy port number codes used for FindLinkIn/Out() and AddLink().
21226026Sbrian   These constants can be anything except zero, which indicates an
21344307Sbrian   unknown port number. */
21426026Sbrian
21526026Sbrian#define NO_DEST_PORT     1
21626026Sbrian#define NO_SRC_PORT      1
21726026Sbrian
21826026Sbrian
21926026Sbrian
22044307Sbrian/* Data Structures
22126026Sbrian
22226026Sbrian    The fundamental data structure used in this program is
22326026Sbrian    "struct alias_link".  Whenever a TCP connection is made,
22426026Sbrian    a UDP datagram is sent out, or an ICMP echo request is made,
22526026Sbrian    a link record is made (if it has not already been created).
22626026Sbrian    The link record is identified by the source address/port
22726026Sbrian    and the destination address/port. In the case of an ICMP
22826026Sbrian    echo request, the source port is treated as being equivalent
22959356Sru    with the 16-bit ID number of the ICMP packet.
23026026Sbrian
23126026Sbrian    The link record also can store some auxiliary data.  For
23226026Sbrian    TCP connections that have had sequence and acknowledgment
23326026Sbrian    modifications, data space is available to track these changes.
23459356Sru    A state field is used to keep track in changes to the TCP
23559356Sru    connection state.  ID numbers of fragments can also be
23626026Sbrian    stored in the auxiliary space.  Pointers to unresolved
23759356Sru    fragments can also be stored.
23826026Sbrian
23926026Sbrian    The link records support two independent chainings.  Lookup
24026026Sbrian    tables for input and out tables hold the initial pointers
24126026Sbrian    the link chains.  On input, the lookup table indexes on alias
24226026Sbrian    port and link type.  On output, the lookup table indexes on
24359356Sru    source address, destination address, source port, destination
24426026Sbrian    port and link type.
24526026Sbrian*/
24626026Sbrian
247127094Sdesstruct ack_data_record {	/* used to save changes to ACK/sequence
248127094Sdes				 * numbers */
249127094Sdes	u_long		ack_old;
250127094Sdes	u_long		ack_new;
251127094Sdes	int		delta;
252127094Sdes	int		active;
25326026Sbrian};
25426026Sbrian
255127094Sdesstruct tcp_state {		/* Information about TCP connection        */
256127094Sdes	int		in;	/* State for outside -> inside             */
257127094Sdes	int		out;	/* State for inside  -> outside            */
258127094Sdes	int		index;	/* Index to ACK data array                 */
259127094Sdes	int		ack_modified;	/* Indicates whether ACK and
260127094Sdes					 * sequence numbers */
261127094Sdes	/* been modified                           */
26226026Sbrian};
26326026Sbrian
264127094Sdes#define N_LINK_TCP_DATA   3	/* Number of distinct ACK number changes
265127094Sdes				 * saved for a modified TCP stream */
266127094Sdesstruct tcp_dat {
267127094Sdes	struct tcp_state state;
268127094Sdes	struct ack_data_record ack[N_LINK_TCP_DATA];
269127094Sdes	int		fwhole;	/* Which firewall record is used for this
270127094Sdes				 * hole? */
27126026Sbrian};
27226026Sbrian
273127094Sdesstruct server {			/* LSNAT server pool (circular list) */
274127094Sdes	struct in_addr	addr;
275127094Sdes	u_short		port;
276127094Sdes	struct server  *next;
27759702Sru};
27859702Sru
279127094Sdesstruct alias_link {		/* Main data structure */
280127094Sdes	struct libalias *la;
281127094Sdes	struct in_addr	src_addr;	/* Address and port information        */
282127094Sdes	struct in_addr	dst_addr;
283127094Sdes	struct in_addr	alias_addr;
284127094Sdes	struct in_addr	proxy_addr;
285127094Sdes	u_short		src_port;
286127094Sdes	u_short		dst_port;
287127094Sdes	u_short		alias_port;
288127094Sdes	u_short		proxy_port;
289127094Sdes	struct server  *server;
29026026Sbrian
291127094Sdes	int		link_type;	/* Type of link: TCP, UDP, ICMP,
292127094Sdes					 * proto, frag */
29326026Sbrian
29426026Sbrian/* values for link_type */
29559726Sru#define LINK_ICMP                     IPPROTO_ICMP
29659726Sru#define LINK_UDP                      IPPROTO_UDP
29759726Sru#define LINK_TCP                      IPPROTO_TCP
29859726Sru#define LINK_FRAGMENT_ID              (IPPROTO_MAX + 1)
29959726Sru#define LINK_FRAGMENT_PTR             (IPPROTO_MAX + 2)
30059726Sru#define LINK_ADDR                     (IPPROTO_MAX + 3)
30161861Sru#define LINK_PPTP                     (IPPROTO_MAX + 4)
30226026Sbrian
303127094Sdes	int		flags;	/* indicates special characteristics   */
304127094Sdes	int		pflags;	/* protocol-specific flags */
30526026Sbrian
30626026Sbrian/* flag bits */
30726026Sbrian#define LINK_UNKNOWN_DEST_PORT     0x01
30826026Sbrian#define LINK_UNKNOWN_DEST_ADDR     0x02
30926026Sbrian#define LINK_PERMANENT             0x04
310127094Sdes#define LINK_PARTIALLY_SPECIFIED   0x03	/* logical-or of first two bits */
31132377Seivind#define LINK_UNFIREWALLED          0x08
31226026Sbrian
313127094Sdes	int		timestamp;	/* Time link was last accessed         */
314127094Sdes	int		expire_time;	/* Expire time for link                */
31526026Sbrian
316127094Sdes	int		sockfd;	/* socket descriptor                   */
31726026Sbrian
318127094Sdes			LIST_ENTRY    (alias_link) list_out;	/* Linked list of
319127094Sdes								 * pointers for     */
320127094Sdes			LIST_ENTRY    (alias_link) list_in;	/* input and output
321127094Sdes								 * lookup tables  */
32226026Sbrian
323127094Sdes	union {			/* Auxiliary data                      */
324127094Sdes		char           *frag_ptr;
325127094Sdes		struct in_addr	frag_addr;
326127094Sdes		struct tcp_dat *tcp;
327127094Sdes	}		data;
32826026Sbrian};
32926026Sbrian
33026026Sbrian/* Internal utility routines (used only in alias_db.c)
33126026Sbrian
33226026SbrianLookup table starting points:
33326026Sbrian    StartPointIn()           -- link table initial search point for
334131612Sdes				incoming packets
33559356Sru    StartPointOut()          -- link table initial search point for
336131612Sdes				outgoing packets
33799207Sbrian
33826026SbrianMiscellaneous:
33926026Sbrian    SeqDiff()                -- difference between two TCP sequences
34026026Sbrian    ShowAliasStats()         -- send alias statistics to a monitor file
34126026Sbrian*/
34226026Sbrian
34326026Sbrian
34426026Sbrian/* Local prototypes */
345127094Sdesstatic u_int	StartPointIn(struct in_addr, u_short, int);
34626026Sbrian
347127094Sdesstatic		u_int
348127094SdesStartPointOut(struct in_addr, struct in_addr,
349127094Sdes    u_short, u_short, int);
35026026Sbrian
351127094Sdesstatic int	SeqDiff(u_long, u_long);
35226026Sbrian
353127094Sdesstatic void	ShowAliasStats(struct libalias *);
35426026Sbrian
35535314Sbrian#ifndef NO_FW_PUNCH
35632377Seivind/* Firewall control */
357127094Sdesstatic void	InitPunchFW(struct libalias *la);
358127094Sdesstatic void	UninitPunchFW(struct libalias *la);
359127094Sdesstatic void	ClearFWHole(struct alias_link *link);
360127094Sdes
36135314Sbrian#endif
36226026Sbrian
36332377Seivind/* Log file control */
364127094Sdesstatic void	InitPacketAliasLog(struct libalias *la);
365127094Sdesstatic void	UninitPacketAliasLog(struct libalias *la);
36632377Seivind
367127094Sdesstatic		u_int
36826026SbrianStartPointIn(struct in_addr alias_addr,
369127094Sdes    u_short alias_port,
370127094Sdes    int link_type)
37126026Sbrian{
372127094Sdes	u_int n;
37326026Sbrian
374127094Sdes	n = alias_addr.s_addr;
375127094Sdes	if (link_type != LINK_PPTP)
376127094Sdes		n += alias_port;
377127094Sdes	n += link_type;
378127094Sdes	return (n % LINK_TABLE_IN_SIZE);
37926026Sbrian}
38026026Sbrian
38126026Sbrian
382127094Sdesstatic		u_int
38326026SbrianStartPointOut(struct in_addr src_addr, struct in_addr dst_addr,
384127094Sdes    u_short src_port, u_short dst_port, int link_type)
38526026Sbrian{
386127094Sdes	u_int n;
38726026Sbrian
388127094Sdes	n = src_addr.s_addr;
389127094Sdes	n += dst_addr.s_addr;
390127094Sdes	if (link_type != LINK_PPTP) {
391127094Sdes		n += src_port;
392127094Sdes		n += dst_port;
393127094Sdes	}
394127094Sdes	n += link_type;
39526026Sbrian
396127094Sdes	return (n % LINK_TABLE_OUT_SIZE);
39726026Sbrian}
39826026Sbrian
39926026Sbrian
40026026Sbrianstatic int
40126026SbrianSeqDiff(u_long x, u_long y)
40226026Sbrian{
40326026Sbrian/* Return the difference between two TCP sequence numbers */
40426026Sbrian
40526026Sbrian/*
40626026Sbrian    This function is encapsulated in case there are any unusual
40726026Sbrian    arithmetic conditions that need to be considered.
40826026Sbrian*/
40926026Sbrian
410127094Sdes	return (ntohl(y) - ntohl(x));
41126026Sbrian}
41226026Sbrian
41326026Sbrian
41426026Sbrianstatic void
415124621SphkShowAliasStats(struct libalias *la)
41626026Sbrian{
41726026Sbrian/* Used for debugging */
41826026Sbrian
419127094Sdes	if (la->monitorFile) {
420127094Sdes		fprintf(la->monitorFile,
421127094Sdes		    "icmp=%d, udp=%d, tcp=%d, pptp=%d, proto=%d, frag_id=%d frag_ptr=%d",
422127094Sdes		    la->icmpLinkCount,
423127094Sdes		    la->udpLinkCount,
424127094Sdes		    la->tcpLinkCount,
425127094Sdes		    la->pptpLinkCount,
426127094Sdes		    la->protoLinkCount,
427127094Sdes		    la->fragmentIdLinkCount,
428127094Sdes		    la->fragmentPtrLinkCount);
42926026Sbrian
430127094Sdes		fprintf(la->monitorFile, " / tot=%d  (sock=%d)\n",
431127094Sdes		    la->icmpLinkCount + la->udpLinkCount
432127094Sdes		    + la->tcpLinkCount
433127094Sdes		    + la->pptpLinkCount
434127094Sdes		    + la->protoLinkCount
435127094Sdes		    + la->fragmentIdLinkCount
436127094Sdes		    + la->fragmentPtrLinkCount,
437127094Sdes		    la->sockCount);
43826026Sbrian
439127094Sdes		fflush(la->monitorFile);
440127094Sdes	}
44126026Sbrian}
44226026Sbrian
44326026Sbrian
44426026Sbrian
44526026Sbrian
44626026Sbrian
44726026Sbrian/* Internal routines for finding, deleting and adding links
44826026Sbrian
44926026SbrianPort Allocation:
45026026Sbrian    GetNewPort()             -- find and reserve new alias port number
45126026Sbrian    GetSocket()              -- try to allocate a socket for a given port
45226026Sbrian
45326026SbrianLink creation and deletion:
45426026Sbrian    CleanupAliasData()      - remove all link chains from lookup table
45526026Sbrian    IncrementalCleanup()    - look for stale links in a single chain
45626026Sbrian    DeleteLink()            - remove link
45799207Sbrian    AddLink()               - add link
45899207Sbrian    ReLink()                - change link
45926026Sbrian
46026026SbrianLink search:
46126026Sbrian    FindLinkOut()           - find link for outgoing packets
46226026Sbrian    FindLinkIn()            - find link for incoming packets
46363899Sarchie
46463899SarchiePort search:
46599207Sbrian    FindNewPortGroup()      - find an available group of ports
46626026Sbrian*/
46726026Sbrian
46826026Sbrian/* Local prototypes */
469127094Sdesstatic int	GetNewPort(struct libalias *, struct alias_link *, int);
47026026Sbrian
471127094Sdesstatic u_short	GetSocket(struct libalias *, u_short, int *, int);
47226026Sbrian
473127094Sdesstatic void	CleanupAliasData(struct libalias *);
47426026Sbrian
475127094Sdesstatic void	IncrementalCleanup(struct libalias *);
47626026Sbrian
477127094Sdesstatic void	DeleteLink(struct alias_link *);
47826026Sbrian
47926026Sbrianstatic struct alias_link *
480124621SphkAddLink(struct libalias *, struct in_addr, struct in_addr, struct in_addr,
481127094Sdes    u_short, u_short, int, int);
48226026Sbrian
48326026Sbrianstatic struct alias_link *
48432377SeivindReLink(struct alias_link *,
485127094Sdes    struct in_addr, struct in_addr, struct in_addr,
486127094Sdes    u_short, u_short, int, int);
48732377Seivind
48832377Seivindstatic struct alias_link *
489127094Sdes		FindLinkOut   (struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int);
49026026Sbrian
49126026Sbrianstatic struct alias_link *
492127094Sdes		FindLinkIn    (struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int);
49326026Sbrian
49426026Sbrian
49526026Sbrian#define ALIAS_PORT_BASE            0x08000
49626026Sbrian#define ALIAS_PORT_MASK            0x07fff
49763899Sarchie#define ALIAS_PORT_MASK_EVEN       0x07ffe
49826026Sbrian#define GET_NEW_PORT_MAX_ATTEMPTS       20
49926026Sbrian
50026026Sbrian#define GET_ALIAS_PORT                  -1
50126026Sbrian#define GET_ALIAS_ID        GET_ALIAS_PORT
50226026Sbrian
50363899Sarchie#define FIND_EVEN_ALIAS_BASE             1
50463899Sarchie
50526026Sbrian/* GetNewPort() allocates port numbers.  Note that if a port number
50626026Sbrian   is already in use, that does not mean that it cannot be used by
50726026Sbrian   another link concurrently.  This is because GetNewPort() looks for
50826026Sbrian   unused triplets: (dest addr, dest port, alias port). */
50926026Sbrian
51026026Sbrianstatic int
511124621SphkGetNewPort(struct libalias *la, struct alias_link *link, int alias_port_param)
51226026Sbrian{
513127094Sdes	int i;
514127094Sdes	int max_trials;
515127094Sdes	u_short port_sys;
516127094Sdes	u_short port_net;
51726026Sbrian
51826026Sbrian/*
51926026Sbrian   Description of alias_port_param for GetNewPort().  When
52026026Sbrian   this parameter is zero or positive, it precisely specifies
52126026Sbrian   the port number.  GetNewPort() will return this number
52226026Sbrian   without check that it is in use.
52326026Sbrian
52461861Sru   When this parameter is GET_ALIAS_PORT, it indicates to get a randomly
52526026Sbrian   selected port number.
52626026Sbrian*/
52799207Sbrian
528127094Sdes	if (alias_port_param == GET_ALIAS_PORT) {
529127094Sdes		/*
530127094Sdes		 * The aliasing port is automatically selected by one of
531127094Sdes		 * two methods below:
532127094Sdes		 */
533127094Sdes		max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
53426026Sbrian
535127094Sdes		if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) {
536127094Sdes			/*
537127094Sdes			 * When the PKT_ALIAS_SAME_PORTS option is chosen,
538127094Sdes			 * the first try will be the actual source port. If
539127094Sdes			 * this is already in use, the remainder of the
540127094Sdes			 * trials will be random.
541127094Sdes			 */
542127094Sdes			port_net = link->src_port;
543127094Sdes			port_sys = ntohs(port_net);
544127094Sdes		} else {
545127094Sdes			/* First trial and all subsequent are random. */
546127094Sdes			port_sys = random() & ALIAS_PORT_MASK;
547127094Sdes			port_sys += ALIAS_PORT_BASE;
548127094Sdes			port_net = htons(port_sys);
549127094Sdes		}
550127094Sdes	} else if (alias_port_param >= 0 && alias_port_param < 0x10000) {
551127094Sdes		link->alias_port = (u_short) alias_port_param;
552127094Sdes		return (0);
553127094Sdes	} else {
55444616Sbrian#ifdef DEBUG
555127094Sdes		fprintf(stderr, "PacketAlias/GetNewPort(): ");
556127094Sdes		fprintf(stderr, "input parameter error\n");
55744616Sbrian#endif
558127094Sdes		return (-1);
559127094Sdes	}
56026026Sbrian
56126026Sbrian
56226026Sbrian/* Port number search */
563127094Sdes	for (i = 0; i < max_trials; i++) {
564127094Sdes		int go_ahead;
565127094Sdes		struct alias_link *search_result;
56626026Sbrian
567127094Sdes		search_result = FindLinkIn(la, link->dst_addr, link->alias_addr,
568127094Sdes		    link->dst_port, port_net,
569127094Sdes		    link->link_type, 0);
57026026Sbrian
571127094Sdes		if (search_result == NULL)
572127094Sdes			go_ahead = 1;
573127094Sdes		else if (!(link->flags & LINK_PARTIALLY_SPECIFIED)
574127094Sdes		    && (search_result->flags & LINK_PARTIALLY_SPECIFIED))
575127094Sdes			go_ahead = 1;
576127094Sdes		else
577127094Sdes			go_ahead = 0;
57826026Sbrian
579127094Sdes		if (go_ahead) {
580127094Sdes			if ((la->packetAliasMode & PKT_ALIAS_USE_SOCKETS)
581127094Sdes			    && (link->flags & LINK_PARTIALLY_SPECIFIED)
582127094Sdes			    && ((link->link_type == LINK_TCP) ||
583127094Sdes			    (link->link_type == LINK_UDP))) {
584127094Sdes				if (GetSocket(la, port_net, &link->sockfd, link->link_type)) {
585127094Sdes					link->alias_port = port_net;
586127094Sdes					return (0);
587127094Sdes				}
588127094Sdes			} else {
589127094Sdes				link->alias_port = port_net;
590127094Sdes				return (0);
591127094Sdes			}
592127094Sdes		}
593127094Sdes		port_sys = random() & ALIAS_PORT_MASK;
594127094Sdes		port_sys += ALIAS_PORT_BASE;
595127094Sdes		port_net = htons(port_sys);
596127094Sdes	}
59726026Sbrian
59844616Sbrian#ifdef DEBUG
599127094Sdes	fprintf(stderr, "PacketAlias/GetnewPort(): ");
600127094Sdes	fprintf(stderr, "could not find free port\n");
60144616Sbrian#endif
60226026Sbrian
603127094Sdes	return (-1);
60426026Sbrian}
60526026Sbrian
60626026Sbrian
607127094Sdesstatic		u_short
608124621SphkGetSocket(struct libalias *la, u_short port_net, int *sockfd, int link_type)
60926026Sbrian{
610127094Sdes	int err;
611127094Sdes	int sock;
612127094Sdes	struct sockaddr_in sock_addr;
61326026Sbrian
614127094Sdes	if (link_type == LINK_TCP)
615127094Sdes		sock = socket(AF_INET, SOCK_STREAM, 0);
616127094Sdes	else if (link_type == LINK_UDP)
617127094Sdes		sock = socket(AF_INET, SOCK_DGRAM, 0);
618127094Sdes	else {
61944616Sbrian#ifdef DEBUG
620127094Sdes		fprintf(stderr, "PacketAlias/GetSocket(): ");
621127094Sdes		fprintf(stderr, "incorrect link type\n");
62244616Sbrian#endif
623127094Sdes		return (0);
624127094Sdes	}
62526026Sbrian
626127094Sdes	if (sock < 0) {
62744616Sbrian#ifdef DEBUG
628127094Sdes		fprintf(stderr, "PacketAlias/GetSocket(): ");
629127094Sdes		fprintf(stderr, "socket() error %d\n", *sockfd);
63044616Sbrian#endif
631127094Sdes		return (0);
632127094Sdes	}
633127094Sdes	sock_addr.sin_family = AF_INET;
634127094Sdes	sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
635127094Sdes	sock_addr.sin_port = port_net;
63626026Sbrian
637127094Sdes	err = bind(sock,
638127094Sdes	    (struct sockaddr *)&sock_addr,
639127094Sdes	    sizeof(sock_addr));
640127094Sdes	if (err == 0) {
641127094Sdes		la->sockCount++;
642127094Sdes		*sockfd = sock;
643127094Sdes		return (1);
644127094Sdes	} else {
645127094Sdes		close(sock);
646127094Sdes		return (0);
647127094Sdes	}
64826026Sbrian}
64926026Sbrian
65026026Sbrian
65199207Sbrian/* FindNewPortGroup() returns a base port number for an available
65263899Sarchie   range of contiguous port numbers. Note that if a port number
65363899Sarchie   is already in use, that does not mean that it cannot be used by
65463899Sarchie   another link concurrently.  This is because FindNewPortGroup()
65563899Sarchie   looks for unused triplets: (dest addr, dest port, alias port). */
65663899Sarchie
65763899Sarchieint
658124621SphkFindNewPortGroup(struct libalias *la,
659127094Sdes    struct in_addr dst_addr,
660127094Sdes    struct in_addr alias_addr,
661127094Sdes    u_short src_port,
662127094Sdes    u_short dst_port,
663127094Sdes    u_short port_count,
664127094Sdes    u_char proto,
665127094Sdes    u_char align)
66663899Sarchie{
667127094Sdes	int i, j;
668127094Sdes	int max_trials;
669127094Sdes	u_short port_sys;
670127094Sdes	int link_type;
67163899Sarchie
672127094Sdes	/*
673127094Sdes	 * Get link_type from protocol
674127094Sdes	 */
67563899Sarchie
676127094Sdes	switch (proto) {
677127094Sdes	case IPPROTO_UDP:
678127094Sdes		link_type = LINK_UDP;
679127094Sdes		break;
680127094Sdes	case IPPROTO_TCP:
681127094Sdes		link_type = LINK_TCP;
682127094Sdes		break;
683127094Sdes	default:
684127094Sdes		return (0);
685127094Sdes		break;
686127094Sdes	}
68763899Sarchie
688127094Sdes	/*
689127094Sdes	 * The aliasing port is automatically selected by one of two
690127094Sdes	 * methods below:
691127094Sdes	 */
692127094Sdes	max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
69363899Sarchie
694127094Sdes	if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) {
695127094Sdes		/*
696127094Sdes		 * When the ALIAS_SAME_PORTS option is chosen, the first
697127094Sdes		 * try will be the actual source port. If this is already
698127094Sdes		 * in use, the remainder of the trials will be random.
699127094Sdes		 */
700127094Sdes		port_sys = ntohs(src_port);
70163899Sarchie
702127094Sdes	} else {
70363899Sarchie
704127094Sdes		/* First trial and all subsequent are random. */
705127094Sdes		if (align == FIND_EVEN_ALIAS_BASE)
706127094Sdes			port_sys = random() & ALIAS_PORT_MASK_EVEN;
707127094Sdes		else
708127094Sdes			port_sys = random() & ALIAS_PORT_MASK;
70963899Sarchie
710127094Sdes		port_sys += ALIAS_PORT_BASE;
711127094Sdes	}
71263899Sarchie
71363899Sarchie/* Port number search */
714127094Sdes	for (i = 0; i < max_trials; i++) {
71563899Sarchie
716127094Sdes		struct alias_link *search_result;
71763899Sarchie
718127094Sdes		for (j = 0; j < port_count; j++)
719127094Sdes			if (0 != (search_result = FindLinkIn(la, dst_addr, alias_addr,
720127094Sdes			    dst_port, htons(port_sys + j),
721127094Sdes			    link_type, 0)))
722127094Sdes				break;
72363899Sarchie
724127094Sdes		/* Found a good range, return base */
725127094Sdes		if (j == port_count)
726127094Sdes			return (htons(port_sys));
72763899Sarchie
728127094Sdes		/* Find a new base to try */
729127094Sdes		if (align == FIND_EVEN_ALIAS_BASE)
730127094Sdes			port_sys = random() & ALIAS_PORT_MASK_EVEN;
731127094Sdes		else
732127094Sdes			port_sys = random() & ALIAS_PORT_MASK;
73363899Sarchie
734127094Sdes		port_sys += ALIAS_PORT_BASE;
735127094Sdes	}
73663899Sarchie
73763899Sarchie#ifdef DEBUG
738127094Sdes	fprintf(stderr, "PacketAlias/FindNewPortGroup(): ");
739127094Sdes	fprintf(stderr, "could not find free port(s)\n");
74063899Sarchie#endif
74163899Sarchie
742127094Sdes	return (0);
74363899Sarchie}
74463899Sarchie
74526026Sbrianstatic void
746124621SphkCleanupAliasData(struct libalias *la)
74726026Sbrian{
748127094Sdes	struct alias_link *link;
749127094Sdes	int i, icount;
75026026Sbrian
751127094Sdes	icount = 0;
752127094Sdes	for (i = 0; i < LINK_TABLE_OUT_SIZE; i++) {
753127094Sdes		link = LIST_FIRST(&la->linkTableOut[i]);
754127094Sdes		while (link != NULL) {
755127094Sdes			struct alias_link *link_next;
75626026Sbrian
757127094Sdes			link_next = LIST_NEXT(link, list_out);
758127094Sdes			icount++;
759127094Sdes			DeleteLink(link);
760127094Sdes			link = link_next;
761127094Sdes		}
762127094Sdes	}
763127094Sdes
764127094Sdes	la->cleanupIndex = 0;
76526026Sbrian}
76626026Sbrian
76726026Sbrian
76826026Sbrianstatic void
769124621SphkIncrementalCleanup(struct libalias *la)
77026026Sbrian{
771127094Sdes	int icount;
772127094Sdes	struct alias_link *link;
77326026Sbrian
774127094Sdes	icount = 0;
775127094Sdes	link = LIST_FIRST(&la->linkTableOut[la->cleanupIndex++]);
776127094Sdes	while (link != NULL) {
777127094Sdes		int idelta;
778127094Sdes		struct alias_link *link_next;
77926026Sbrian
780127094Sdes		link_next = LIST_NEXT(link, list_out);
781127094Sdes		idelta = la->timeStamp - link->timestamp;
782127094Sdes		switch (link->link_type) {
783127094Sdes		case LINK_TCP:
784127094Sdes			if (idelta > link->expire_time) {
785127094Sdes				struct tcp_dat *tcp_aux;
78626026Sbrian
787127094Sdes				tcp_aux = link->data.tcp;
788127094Sdes				if (tcp_aux->state.in != ALIAS_TCP_STATE_CONNECTED
789127094Sdes				    || tcp_aux->state.out != ALIAS_TCP_STATE_CONNECTED) {
790127094Sdes					DeleteLink(link);
791127094Sdes					icount++;
792127094Sdes				}
793127094Sdes			}
794127094Sdes			break;
795127094Sdes		default:
796127094Sdes			if (idelta > link->expire_time) {
797127094Sdes				DeleteLink(link);
798127094Sdes				icount++;
799127094Sdes			}
800127094Sdes			break;
801127094Sdes		}
802127094Sdes		link = link_next;
803127094Sdes	}
80426026Sbrian
805127094Sdes	if (la->cleanupIndex == LINK_TABLE_OUT_SIZE)
806127094Sdes		la->cleanupIndex = 0;
80726026Sbrian}
80826026Sbrian
80964643Srustatic void
81026026SbrianDeleteLink(struct alias_link *link)
81126026Sbrian{
812127094Sdes	struct libalias *la = link->la;
81326026Sbrian
81426026Sbrian/* Don't do anything if the link is marked permanent */
815127094Sdes	if (la->deleteAllLinks == 0 && link->flags & LINK_PERMANENT)
816127094Sdes		return;
81726026Sbrian
81835314Sbrian#ifndef NO_FW_PUNCH
81959356Sru/* Delete associated firewall hole, if any */
820127094Sdes	ClearFWHole(link);
82135314Sbrian#endif
82232377Seivind
82359702Sru/* Free memory allocated for LSNAT server pool */
824127094Sdes	if (link->server != NULL) {
825127094Sdes		struct server *head, *curr, *next;
82659702Sru
827127094Sdes		head = curr = link->server;
828127094Sdes		do {
829127094Sdes			next = curr->next;
830127094Sdes			free(curr);
831127094Sdes		} while ((curr = next) != head);
832127094Sdes	}
83326026Sbrian/* Adjust output table pointers */
834127094Sdes	LIST_REMOVE(link, list_out);
83526026Sbrian
83626026Sbrian/* Adjust input table pointers */
837127094Sdes	LIST_REMOVE(link, list_in);
83826026Sbrian
83926026Sbrian/* Close socket, if one has been allocated */
840127094Sdes	if (link->sockfd != -1) {
841127094Sdes		la->sockCount--;
842127094Sdes		close(link->sockfd);
843127094Sdes	}
84426026Sbrian/* Link-type dependent cleanup */
845127094Sdes	switch (link->link_type) {
846127094Sdes	case LINK_ICMP:
847127094Sdes		la->icmpLinkCount--;
848127094Sdes		break;
849127094Sdes	case LINK_UDP:
850127094Sdes		la->udpLinkCount--;
851127094Sdes		break;
852127094Sdes	case LINK_TCP:
853127094Sdes		la->tcpLinkCount--;
854127094Sdes		free(link->data.tcp);
855127094Sdes		break;
856127094Sdes	case LINK_PPTP:
857127094Sdes		la->pptpLinkCount--;
858127094Sdes		break;
859127094Sdes	case LINK_FRAGMENT_ID:
860127094Sdes		la->fragmentIdLinkCount--;
861127094Sdes		break;
862127094Sdes	case LINK_FRAGMENT_PTR:
863127094Sdes		la->fragmentPtrLinkCount--;
864127094Sdes		if (link->data.frag_ptr != NULL)
865127094Sdes			free(link->data.frag_ptr);
866127094Sdes		break;
86759726Sru	case LINK_ADDR:
868127094Sdes		break;
869127094Sdes	default:
870127094Sdes		la->protoLinkCount--;
871127094Sdes		break;
872127094Sdes	}
87326026Sbrian
87426026Sbrian/* Free memory */
875127094Sdes	free(link);
87626026Sbrian
87726026Sbrian/* Write statistics, if logging enabled */
878127094Sdes	if (la->packetAliasMode & PKT_ALIAS_LOG) {
879127094Sdes		ShowAliasStats(la);
880127094Sdes	}
88126026Sbrian}
88226026Sbrian
88326026Sbrian
88426026Sbrianstatic struct alias_link *
885127094SdesAddLink(struct libalias *la, struct in_addr src_addr,
886127094Sdes    struct in_addr dst_addr,
887127094Sdes    struct in_addr alias_addr,
888127094Sdes    u_short src_port,
889127094Sdes    u_short dst_port,
890127094Sdes    int alias_port_param,	/* if less than zero, alias   */
891127094Sdes    int link_type)
892127094Sdes{				/* port will be automatically *//* chosen.
893127094Sdes				 * If greater than    */
894127094Sdes	u_int start_point;	/* zero, equal to alias port  */
895127094Sdes	struct alias_link *link;
89626026Sbrian
897127094Sdes	link = malloc(sizeof(struct alias_link));
898127094Sdes	if (link != NULL) {
899127094Sdes		/* Basic initialization */
900127094Sdes		link->la = la;
901127094Sdes		link->src_addr = src_addr;
902127094Sdes		link->dst_addr = dst_addr;
903127094Sdes		link->alias_addr = alias_addr;
904127094Sdes		link->proxy_addr.s_addr = INADDR_ANY;
905127094Sdes		link->src_port = src_port;
906127094Sdes		link->dst_port = dst_port;
907127094Sdes		link->proxy_port = 0;
908127094Sdes		link->server = NULL;
909127094Sdes		link->link_type = link_type;
910127094Sdes		link->sockfd = -1;
911127094Sdes		link->flags = 0;
912127094Sdes		link->pflags = 0;
913127094Sdes		link->timestamp = la->timeStamp;
91426026Sbrian
915127094Sdes		/* Expiration time */
916127094Sdes		switch (link_type) {
917127094Sdes		case LINK_ICMP:
918127094Sdes			link->expire_time = ICMP_EXPIRE_TIME;
919127094Sdes			break;
920127094Sdes		case LINK_UDP:
921127094Sdes			link->expire_time = UDP_EXPIRE_TIME;
922127094Sdes			break;
923127094Sdes		case LINK_TCP:
924127094Sdes			link->expire_time = TCP_EXPIRE_INITIAL;
925127094Sdes			break;
926127094Sdes		case LINK_PPTP:
927127094Sdes			link->flags |= LINK_PERMANENT;	/* no timeout. */
928127094Sdes			break;
929127094Sdes		case LINK_FRAGMENT_ID:
930127094Sdes			link->expire_time = FRAGMENT_ID_EXPIRE_TIME;
931127094Sdes			break;
932127094Sdes		case LINK_FRAGMENT_PTR:
933127094Sdes			link->expire_time = FRAGMENT_PTR_EXPIRE_TIME;
934127094Sdes			break;
935127094Sdes		case LINK_ADDR:
936127094Sdes			break;
937127094Sdes		default:
938127094Sdes			link->expire_time = PROTO_EXPIRE_TIME;
939127094Sdes			break;
940127094Sdes		}
94126026Sbrian
942127094Sdes		/* Determine alias flags */
943127094Sdes		if (dst_addr.s_addr == INADDR_ANY)
944127094Sdes			link->flags |= LINK_UNKNOWN_DEST_ADDR;
945127094Sdes		if (dst_port == 0)
946127094Sdes			link->flags |= LINK_UNKNOWN_DEST_PORT;
94726026Sbrian
948127094Sdes		/* Determine alias port */
949127094Sdes		if (GetNewPort(la, link, alias_port_param) != 0) {
950127094Sdes			free(link);
951127094Sdes			return (NULL);
952127094Sdes		}
953127094Sdes		/* Link-type dependent initialization */
954127094Sdes		switch (link_type) {
955127094Sdes			struct tcp_dat *aux_tcp;
95626026Sbrian
957127094Sdes		case LINK_ICMP:
958127094Sdes			la->icmpLinkCount++;
959127094Sdes			break;
960127094Sdes		case LINK_UDP:
961127094Sdes			la->udpLinkCount++;
962127094Sdes			break;
963127094Sdes		case LINK_TCP:
964127094Sdes			aux_tcp = malloc(sizeof(struct tcp_dat));
965127094Sdes			if (aux_tcp != NULL) {
966127094Sdes				int i;
96726026Sbrian
968127094Sdes				la->tcpLinkCount++;
969127094Sdes				aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED;
970127094Sdes				aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED;
971127094Sdes				aux_tcp->state.index = 0;
972127094Sdes				aux_tcp->state.ack_modified = 0;
973127094Sdes				for (i = 0; i < N_LINK_TCP_DATA; i++)
974127094Sdes					aux_tcp->ack[i].active = 0;
975127094Sdes				aux_tcp->fwhole = -1;
976127094Sdes				link->data.tcp = aux_tcp;
977127094Sdes			} else {
97844616Sbrian#ifdef DEBUG
979127094Sdes				fprintf(stderr, "PacketAlias/AddLink: ");
980127094Sdes				fprintf(stderr, " cannot allocate auxiliary TCP data\n");
98144616Sbrian#endif
982127094Sdes				free(link);
983127094Sdes				return (NULL);
984127094Sdes			}
985127094Sdes			break;
986127094Sdes		case LINK_PPTP:
987127094Sdes			la->pptpLinkCount++;
988127094Sdes			break;
989127094Sdes		case LINK_FRAGMENT_ID:
990127094Sdes			la->fragmentIdLinkCount++;
991127094Sdes			break;
992127094Sdes		case LINK_FRAGMENT_PTR:
993127094Sdes			la->fragmentPtrLinkCount++;
994127094Sdes			break;
995127094Sdes		case LINK_ADDR:
996127094Sdes			break;
997127094Sdes		default:
998127094Sdes			la->protoLinkCount++;
999127094Sdes			break;
1000127094Sdes		}
100167316Sru
1002127094Sdes		/* Set up pointers for output lookup table */
1003127094Sdes		start_point = StartPointOut(src_addr, dst_addr,
1004127094Sdes		    src_port, dst_port, link_type);
1005127094Sdes		LIST_INSERT_HEAD(&la->linkTableOut[start_point], link, list_out);
100667316Sru
1007127094Sdes		/* Set up pointers for input lookup table */
1008127094Sdes		start_point = StartPointIn(alias_addr, link->alias_port, link_type);
1009127094Sdes		LIST_INSERT_HEAD(&la->linkTableIn[start_point], link, list_in);
1010127094Sdes	} else {
101144616Sbrian#ifdef DEBUG
1012127094Sdes		fprintf(stderr, "PacketAlias/AddLink(): ");
1013127094Sdes		fprintf(stderr, "malloc() call failed.\n");
101444616Sbrian#endif
1015127094Sdes	}
101626026Sbrian
1017127094Sdes	if (la->packetAliasMode & PKT_ALIAS_LOG) {
1018127094Sdes		ShowAliasStats(la);
1019127094Sdes	}
1020127094Sdes	return (link);
102126026Sbrian}
102226026Sbrian
102332377Seivindstatic struct alias_link *
102432377SeivindReLink(struct alias_link *old_link,
1025127094Sdes    struct in_addr src_addr,
1026127094Sdes    struct in_addr dst_addr,
1027127094Sdes    struct in_addr alias_addr,
1028127094Sdes    u_short src_port,
1029127094Sdes    u_short dst_port,
1030127094Sdes    int alias_port_param,	/* if less than zero, alias   */
1031127094Sdes    int link_type)
1032127094Sdes{				/* port will be automatically *//* chosen.
1033127094Sdes				 * If greater than    */
1034127094Sdes	struct alias_link *new_link;	/* zero, equal to alias port  */
1035127094Sdes	struct libalias *la = old_link->la;
103626026Sbrian
1037127094Sdes	new_link = AddLink(la, src_addr, dst_addr, alias_addr,
1038127094Sdes	    src_port, dst_port, alias_port_param,
1039127094Sdes	    link_type);
104035314Sbrian#ifndef NO_FW_PUNCH
1041127094Sdes	if (new_link != NULL &&
1042127094Sdes	    old_link->link_type == LINK_TCP &&
1043127094Sdes	    old_link->data.tcp->fwhole > 0) {
1044127094Sdes		PunchFWHole(new_link);
1045127094Sdes	}
104635314Sbrian#endif
1047127094Sdes	DeleteLink(old_link);
1048131613Sdes	return (new_link);
104932377Seivind}
105032377Seivind
105126026Sbrianstatic struct alias_link *
1052124621Sphk_FindLinkOut(struct libalias *la, struct in_addr src_addr,
1053127094Sdes    struct in_addr dst_addr,
1054127094Sdes    u_short src_port,
1055127094Sdes    u_short dst_port,
1056127094Sdes    int link_type,
1057127094Sdes    int replace_partial_links)
105826026Sbrian{
1059127094Sdes	u_int i;
1060127094Sdes	struct alias_link *link;
106126026Sbrian
1062127094Sdes	i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type);
1063127094Sdes	LIST_FOREACH(link, &la->linkTableOut[i], list_out) {
1064127094Sdes		if (link->src_addr.s_addr == src_addr.s_addr
1065127094Sdes		    && link->server == NULL
1066127094Sdes		    && link->dst_addr.s_addr == dst_addr.s_addr
1067127094Sdes		    && link->dst_port == dst_port
1068127094Sdes		    && link->src_port == src_port
1069127094Sdes		    && link->link_type == link_type) {
1070127094Sdes			link->timestamp = la->timeStamp;
1071127094Sdes			break;
1072127094Sdes		}
1073127094Sdes	}
107426026Sbrian
107551494Sru/* Search for partially specified links. */
1076127094Sdes	if (link == NULL && replace_partial_links) {
1077127094Sdes		if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY) {
1078127094Sdes			link = _FindLinkOut(la, src_addr, dst_addr, src_port, 0,
1079127094Sdes			    link_type, 0);
1080127094Sdes			if (link == NULL)
1081127094Sdes				link = _FindLinkOut(la, src_addr, la->nullAddress, src_port,
1082127094Sdes				    dst_port, link_type, 0);
1083127094Sdes		}
1084127094Sdes		if (link == NULL &&
1085127094Sdes		    (dst_port != 0 || dst_addr.s_addr != INADDR_ANY)) {
1086127094Sdes			link = _FindLinkOut(la, src_addr, la->nullAddress, src_port, 0,
1087127094Sdes			    link_type, 0);
1088127094Sdes		}
1089127094Sdes		if (link != NULL) {
1090127094Sdes			link = ReLink(link,
1091127094Sdes			    src_addr, dst_addr, link->alias_addr,
1092127094Sdes			    src_port, dst_port, link->alias_port,
1093127094Sdes			    link_type);
1094127094Sdes		}
1095127094Sdes	}
1096127094Sdes	return (link);
109726026Sbrian}
109826026Sbrian
109951727Srustatic struct alias_link *
1100124621SphkFindLinkOut(struct libalias *la, struct in_addr src_addr,
1101127094Sdes    struct in_addr dst_addr,
1102127094Sdes    u_short src_port,
1103127094Sdes    u_short dst_port,
1104127094Sdes    int link_type,
1105127094Sdes    int replace_partial_links)
110651727Sru{
1107127094Sdes	struct alias_link *link;
110826026Sbrian
1109127094Sdes	link = _FindLinkOut(la, src_addr, dst_addr, src_port, dst_port,
1110127094Sdes	    link_type, replace_partial_links);
111151727Sru
1112127094Sdes	if (link == NULL) {
1113127094Sdes		/*
1114127094Sdes		 * The following allows permanent links to be specified as
1115127094Sdes		 * using the default source address (i.e. device interface
1116127094Sdes		 * address) without knowing in advance what that address
1117127094Sdes		 * is.
1118127094Sdes		 */
1119127094Sdes		if (la->aliasAddress.s_addr != INADDR_ANY &&
1120127094Sdes		    src_addr.s_addr == la->aliasAddress.s_addr) {
1121127094Sdes			link = _FindLinkOut(la, la->nullAddress, dst_addr, src_port, dst_port,
1122127094Sdes			    link_type, replace_partial_links);
1123127094Sdes		}
1124127094Sdes	}
1125127094Sdes	return (link);
112651727Sru}
112751727Sru
112851727Sru
112958279Sbrianstatic struct alias_link *
1130124621Sphk_FindLinkIn(struct libalias *la, struct in_addr dst_addr,
1131127094Sdes    struct in_addr alias_addr,
1132127094Sdes    u_short dst_port,
1133127094Sdes    u_short alias_port,
1134127094Sdes    int link_type,
1135127094Sdes    int replace_partial_links)
113626026Sbrian{
1137127094Sdes	int flags_in;
1138127094Sdes	u_int start_point;
1139127094Sdes	struct alias_link *link;
1140127094Sdes	struct alias_link *link_fully_specified;
1141127094Sdes	struct alias_link *link_unknown_all;
1142127094Sdes	struct alias_link *link_unknown_dst_addr;
1143127094Sdes	struct alias_link *link_unknown_dst_port;
114426026Sbrian
114526026Sbrian/* Initialize pointers */
1146127094Sdes	link_fully_specified = NULL;
1147127094Sdes	link_unknown_all = NULL;
1148127094Sdes	link_unknown_dst_addr = NULL;
1149127094Sdes	link_unknown_dst_port = NULL;
115026026Sbrian
115126026Sbrian/* If either the dest addr or port is unknown, the search
115226026Sbrian   loop will have to know about this. */
115326026Sbrian
1154127094Sdes	flags_in = 0;
1155127094Sdes	if (dst_addr.s_addr == INADDR_ANY)
1156127094Sdes		flags_in |= LINK_UNKNOWN_DEST_ADDR;
1157127094Sdes	if (dst_port == 0)
1158127094Sdes		flags_in |= LINK_UNKNOWN_DEST_PORT;
115926026Sbrian
116026026Sbrian/* Search loop */
1161127094Sdes	start_point = StartPointIn(alias_addr, alias_port, link_type);
1162127094Sdes	LIST_FOREACH(link, &la->linkTableIn[start_point], list_in) {
1163127094Sdes		int flags;
116426026Sbrian
1165127094Sdes		flags = flags_in | link->flags;
1166127094Sdes		if (!(flags & LINK_PARTIALLY_SPECIFIED)) {
1167127094Sdes			if (link->alias_addr.s_addr == alias_addr.s_addr
1168127094Sdes			    && link->alias_port == alias_port
1169127094Sdes			    && link->dst_addr.s_addr == dst_addr.s_addr
1170127094Sdes			    && link->dst_port == dst_port
1171127094Sdes			    && link->link_type == link_type) {
1172127094Sdes				link_fully_specified = link;
1173127094Sdes				break;
1174127094Sdes			}
1175127094Sdes		} else if ((flags & LINK_UNKNOWN_DEST_ADDR)
1176127094Sdes		    && (flags & LINK_UNKNOWN_DEST_PORT)) {
1177127094Sdes			if (link->alias_addr.s_addr == alias_addr.s_addr
1178127094Sdes			    && link->alias_port == alias_port
1179127094Sdes			    && link->link_type == link_type) {
1180127094Sdes				if (link_unknown_all == NULL)
1181127094Sdes					link_unknown_all = link;
1182127094Sdes			}
1183127094Sdes		} else if (flags & LINK_UNKNOWN_DEST_ADDR) {
1184127094Sdes			if (link->alias_addr.s_addr == alias_addr.s_addr
1185127094Sdes			    && link->alias_port == alias_port
1186127094Sdes			    && link->link_type == link_type
1187127094Sdes			    && link->dst_port == dst_port) {
1188127094Sdes				if (link_unknown_dst_addr == NULL)
1189127094Sdes					link_unknown_dst_addr = link;
1190127094Sdes			}
1191127094Sdes		} else if (flags & LINK_UNKNOWN_DEST_PORT) {
1192127094Sdes			if (link->alias_addr.s_addr == alias_addr.s_addr
1193127094Sdes			    && link->alias_port == alias_port
1194127094Sdes			    && link->link_type == link_type
1195127094Sdes			    && link->dst_addr.s_addr == dst_addr.s_addr) {
1196127094Sdes				if (link_unknown_dst_port == NULL)
1197127094Sdes					link_unknown_dst_port = link;
1198127094Sdes			}
1199127094Sdes		}
1200127094Sdes	}
120126026Sbrian
120226026Sbrian
120326026Sbrian
1204127094Sdes	if (link_fully_specified != NULL) {
1205127094Sdes		link_fully_specified->timestamp = la->timeStamp;
1206127094Sdes		link = link_fully_specified;
1207127094Sdes	} else if (link_unknown_dst_port != NULL)
1208127094Sdes		link = link_unknown_dst_port;
1209127094Sdes	else if (link_unknown_dst_addr != NULL)
1210127094Sdes		link = link_unknown_dst_addr;
1211127094Sdes	else if (link_unknown_all != NULL)
1212127094Sdes		link = link_unknown_all;
1213127094Sdes	else
1214127094Sdes		return (NULL);
121559702Sru
1216127094Sdes	if (replace_partial_links &&
1217127094Sdes	    (link->flags & LINK_PARTIALLY_SPECIFIED || link->server != NULL)) {
1218127094Sdes		struct in_addr src_addr;
1219127094Sdes		u_short src_port;
122059702Sru
1221127094Sdes		if (link->server != NULL) {	/* LSNAT link */
1222127094Sdes			src_addr = link->server->addr;
1223127094Sdes			src_port = link->server->port;
1224127094Sdes			link->server = link->server->next;
1225127094Sdes		} else {
1226127094Sdes			src_addr = link->src_addr;
1227127094Sdes			src_port = link->src_port;
1228127094Sdes		}
1229127094Sdes
1230127094Sdes		link = ReLink(link,
1231127094Sdes		    src_addr, dst_addr, alias_addr,
1232127094Sdes		    src_port, dst_port, alias_port,
1233127094Sdes		    link_type);
123459702Sru	}
1235127094Sdes	return (link);
123626026Sbrian}
123726026Sbrian
123859181Srustatic struct alias_link *
1239124621SphkFindLinkIn(struct libalias *la, struct in_addr dst_addr,
1240127094Sdes    struct in_addr alias_addr,
1241127094Sdes    u_short dst_port,
1242127094Sdes    u_short alias_port,
1243127094Sdes    int link_type,
1244127094Sdes    int replace_partial_links)
124551727Sru{
1246127094Sdes	struct alias_link *link;
124726026Sbrian
1248127094Sdes	link = _FindLinkIn(la, dst_addr, alias_addr, dst_port, alias_port,
1249127094Sdes	    link_type, replace_partial_links);
125026026Sbrian
1251127094Sdes	if (link == NULL) {
1252127094Sdes		/*
1253127094Sdes		 * The following allows permanent links to be specified as
1254127094Sdes		 * using the default aliasing address (i.e. device
1255127094Sdes		 * interface address) without knowing in advance what that
1256127094Sdes		 * address is.
1257127094Sdes		 */
1258127094Sdes		if (la->aliasAddress.s_addr != INADDR_ANY &&
1259127094Sdes		    alias_addr.s_addr == la->aliasAddress.s_addr) {
1260127094Sdes			link = _FindLinkIn(la, dst_addr, la->nullAddress, dst_port, alias_port,
1261127094Sdes			    link_type, replace_partial_links);
1262127094Sdes		}
1263127094Sdes	}
1264127094Sdes	return (link);
126551727Sru}
126651727Sru
126751727Sru
126851727Sru
126951727Sru
127026026Sbrian/* External routines for finding/adding links
127126026Sbrian
127226026Sbrian-- "external" means outside alias_db.c, but within alias*.c --
127326026Sbrian
127426026Sbrian    FindIcmpIn(), FindIcmpOut()
127526026Sbrian    FindFragmentIn1(), FindFragmentIn2()
127626026Sbrian    AddFragmentPtrLink(), FindFragmentPtr()
127759726Sru    FindProtoIn(), FindProtoOut()
127826026Sbrian    FindUdpTcpIn(), FindUdpTcpOut()
127967966Sru    AddPptp(), FindPptpOutByCallId(), FindPptpInByCallId(),
128067966Sru    FindPptpOutByPeerCallId(), FindPptpInByPeerCallId()
128126026Sbrian    FindOriginalAddress(), FindAliasAddress()
128226026Sbrian
128326026Sbrian(prototypes in alias_local.h)
128426026Sbrian*/
128526026Sbrian
128626026Sbrian
128726026Sbrianstruct alias_link *
1288124621SphkFindIcmpIn(struct libalias *la, struct in_addr dst_addr,
1289127094Sdes    struct in_addr alias_addr,
1290127094Sdes    u_short id_alias,
1291127094Sdes    int create)
129226026Sbrian{
1293127094Sdes	struct alias_link *link;
129465280Sru
1295127094Sdes	link = FindLinkIn(la, dst_addr, alias_addr,
1296127094Sdes	    NO_DEST_PORT, id_alias,
1297127094Sdes	    LINK_ICMP, 0);
1298127094Sdes	if (link == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1299127094Sdes		struct in_addr target_addr;
130065280Sru
1301127094Sdes		target_addr = FindOriginalAddress(la, alias_addr);
1302127094Sdes		link = AddLink(la, target_addr, dst_addr, alias_addr,
1303127094Sdes		    id_alias, NO_DEST_PORT, id_alias,
1304127094Sdes		    LINK_ICMP);
1305127094Sdes	}
1306127094Sdes	return (link);
130726026Sbrian}
130826026Sbrian
130926026Sbrian
131026026Sbrianstruct alias_link *
1311124621SphkFindIcmpOut(struct libalias *la, struct in_addr src_addr,
1312127094Sdes    struct in_addr dst_addr,
1313127094Sdes    u_short id,
1314127094Sdes    int create)
131526026Sbrian{
1316127094Sdes	struct alias_link *link;
131726026Sbrian
1318127094Sdes	link = FindLinkOut(la, src_addr, dst_addr,
1319127094Sdes	    id, NO_DEST_PORT,
1320127094Sdes	    LINK_ICMP, 0);
1321127094Sdes	if (link == NULL && create) {
1322127094Sdes		struct in_addr alias_addr;
132326026Sbrian
1324127094Sdes		alias_addr = FindAliasAddress(la, src_addr);
1325127094Sdes		link = AddLink(la, src_addr, dst_addr, alias_addr,
1326127094Sdes		    id, NO_DEST_PORT, GET_ALIAS_ID,
1327127094Sdes		    LINK_ICMP);
1328127094Sdes	}
1329127094Sdes	return (link);
133026026Sbrian}
133126026Sbrian
133226026Sbrian
133326026Sbrianstruct alias_link *
1334124621SphkFindFragmentIn1(struct libalias *la, struct in_addr dst_addr,
1335127094Sdes    struct in_addr alias_addr,
1336127094Sdes    u_short ip_id)
133726026Sbrian{
1338127094Sdes	struct alias_link *link;
133926026Sbrian
1340127094Sdes	link = FindLinkIn(la, dst_addr, alias_addr,
1341127094Sdes	    NO_DEST_PORT, ip_id,
1342127094Sdes	    LINK_FRAGMENT_ID, 0);
134326026Sbrian
1344127094Sdes	if (link == NULL) {
1345127094Sdes		link = AddLink(la, la->nullAddress, dst_addr, alias_addr,
1346127094Sdes		    NO_SRC_PORT, NO_DEST_PORT, ip_id,
1347127094Sdes		    LINK_FRAGMENT_ID);
1348127094Sdes	}
1349127094Sdes	return (link);
135026026Sbrian}
135126026Sbrian
135226026Sbrian
135326026Sbrianstruct alias_link *
1354127094SdesFindFragmentIn2(struct libalias *la, struct in_addr dst_addr,	/* Doesn't add a link if
1355127094Sdes								 * one */
1356127094Sdes    struct in_addr alias_addr,	/* is not found.           */
1357127094Sdes    u_short ip_id)
135826026Sbrian{
1359127094Sdes	return FindLinkIn(la, dst_addr, alias_addr,
1360127094Sdes	    NO_DEST_PORT, ip_id,
1361127094Sdes	    LINK_FRAGMENT_ID, 0);
136226026Sbrian}
136326026Sbrian
136426026Sbrian
136526026Sbrianstruct alias_link *
1366124621SphkAddFragmentPtrLink(struct libalias *la, struct in_addr dst_addr,
1367127094Sdes    u_short ip_id)
136826026Sbrian{
1369127094Sdes	return AddLink(la, la->nullAddress, dst_addr, la->nullAddress,
1370127094Sdes	    NO_SRC_PORT, NO_DEST_PORT, ip_id,
1371127094Sdes	    LINK_FRAGMENT_PTR);
137226026Sbrian}
137326026Sbrian
137426026Sbrian
137526026Sbrianstruct alias_link *
1376124621SphkFindFragmentPtr(struct libalias *la, struct in_addr dst_addr,
1377127094Sdes    u_short ip_id)
137826026Sbrian{
1379127094Sdes	return FindLinkIn(la, dst_addr, la->nullAddress,
1380127094Sdes	    NO_DEST_PORT, ip_id,
1381127094Sdes	    LINK_FRAGMENT_PTR, 0);
138226026Sbrian}
138326026Sbrian
138426026Sbrian
138526026Sbrianstruct alias_link *
1386124621SphkFindProtoIn(struct libalias *la, struct in_addr dst_addr,
1387127094Sdes    struct in_addr alias_addr,
1388127094Sdes    u_char proto)
138959356Sru{
1390127094Sdes	struct alias_link *link;
139159356Sru
1392127094Sdes	link = FindLinkIn(la, dst_addr, alias_addr,
1393127094Sdes	    NO_DEST_PORT, 0,
1394127094Sdes	    proto, 1);
139559356Sru
1396127094Sdes	if (link == NULL && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1397127094Sdes		struct in_addr target_addr;
139859356Sru
1399127094Sdes		target_addr = FindOriginalAddress(la, alias_addr);
1400127094Sdes		link = AddLink(la, target_addr, dst_addr, alias_addr,
1401127094Sdes		    NO_SRC_PORT, NO_DEST_PORT, 0,
1402127094Sdes		    proto);
1403127094Sdes	}
1404127094Sdes	return (link);
140559356Sru}
140659356Sru
140759356Sru
140859356Srustruct alias_link *
1409124621SphkFindProtoOut(struct libalias *la, struct in_addr src_addr,
1410127094Sdes    struct in_addr dst_addr,
1411127094Sdes    u_char proto)
141259356Sru{
1413127094Sdes	struct alias_link *link;
141459356Sru
1415127094Sdes	link = FindLinkOut(la, src_addr, dst_addr,
1416127094Sdes	    NO_SRC_PORT, NO_DEST_PORT,
1417127094Sdes	    proto, 1);
141859356Sru
1419127094Sdes	if (link == NULL) {
1420127094Sdes		struct in_addr alias_addr;
142159356Sru
1422127094Sdes		alias_addr = FindAliasAddress(la, src_addr);
1423127094Sdes		link = AddLink(la, src_addr, dst_addr, alias_addr,
1424127094Sdes		    NO_SRC_PORT, NO_DEST_PORT, 0,
1425127094Sdes		    proto);
1426127094Sdes	}
1427127094Sdes	return (link);
142859356Sru}
142959356Sru
143059356Sru
143159356Srustruct alias_link *
1432124621SphkFindUdpTcpIn(struct libalias *la, struct in_addr dst_addr,
1433127094Sdes    struct in_addr alias_addr,
1434127094Sdes    u_short dst_port,
1435127094Sdes    u_short alias_port,
1436127094Sdes    u_char proto,
1437127094Sdes    int create)
143826026Sbrian{
1439127094Sdes	int link_type;
1440127094Sdes	struct alias_link *link;
144126026Sbrian
1442127094Sdes	switch (proto) {
1443127094Sdes	case IPPROTO_UDP:
1444127094Sdes		link_type = LINK_UDP;
1445127094Sdes		break;
1446127094Sdes	case IPPROTO_TCP:
1447127094Sdes		link_type = LINK_TCP;
1448127094Sdes		break;
1449127094Sdes	default:
1450131613Sdes		return (NULL);
1451127094Sdes		break;
1452127094Sdes	}
145326026Sbrian
1454127094Sdes	link = FindLinkIn(la, dst_addr, alias_addr,
1455127094Sdes	    dst_port, alias_port,
1456127094Sdes	    link_type, create);
145726026Sbrian
1458127094Sdes	if (link == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1459127094Sdes		struct in_addr target_addr;
146026026Sbrian
1461127094Sdes		target_addr = FindOriginalAddress(la, alias_addr);
1462127094Sdes		link = AddLink(la, target_addr, dst_addr, alias_addr,
1463127094Sdes		    alias_port, dst_port, alias_port,
1464127094Sdes		    link_type);
1465127094Sdes	}
1466127094Sdes	return (link);
146726026Sbrian}
146826026Sbrian
146926026Sbrian
147099207Sbrianstruct alias_link *
1471127094SdesFindUdpTcpOut(struct libalias *la, struct in_addr src_addr,
1472127094Sdes    struct in_addr dst_addr,
1473127094Sdes    u_short src_port,
1474127094Sdes    u_short dst_port,
1475127094Sdes    u_char proto,
1476127094Sdes    int create)
147726026Sbrian{
1478127094Sdes	int link_type;
1479127094Sdes	struct alias_link *link;
148026026Sbrian
1481127094Sdes	switch (proto) {
1482127094Sdes	case IPPROTO_UDP:
1483127094Sdes		link_type = LINK_UDP;
1484127094Sdes		break;
1485127094Sdes	case IPPROTO_TCP:
1486127094Sdes		link_type = LINK_TCP;
1487127094Sdes		break;
1488127094Sdes	default:
1489131613Sdes		return (NULL);
1490127094Sdes		break;
1491127094Sdes	}
149226026Sbrian
1493127094Sdes	link = FindLinkOut(la, src_addr, dst_addr, src_port, dst_port, link_type, create);
149426026Sbrian
1495127094Sdes	if (link == NULL && create) {
1496127094Sdes		struct in_addr alias_addr;
149726026Sbrian
1498127094Sdes		alias_addr = FindAliasAddress(la, src_addr);
1499127094Sdes		link = AddLink(la, src_addr, dst_addr, alias_addr,
1500127094Sdes		    src_port, dst_port, GET_ALIAS_PORT,
1501127094Sdes		    link_type);
1502127094Sdes	}
1503127094Sdes	return (link);
150426026Sbrian}
150526026Sbrian
150626026Sbrian
150761861Srustruct alias_link *
1508127094SdesAddPptp(struct libalias *la, struct in_addr src_addr,
1509127094Sdes    struct in_addr dst_addr,
1510127094Sdes    struct in_addr alias_addr,
1511127094Sdes    u_int16_t src_call_id)
151267966Sru{
1513127094Sdes	struct alias_link *link;
151463899Sarchie
1515127094Sdes	link = AddLink(la, src_addr, dst_addr, alias_addr,
1516127094Sdes	    src_call_id, 0, GET_ALIAS_PORT,
1517127094Sdes	    LINK_PPTP);
151867966Sru
1519127094Sdes	return (link);
152067966Sru}
152167966Sru
152267966Sru
152367966Srustruct alias_link *
1524124621SphkFindPptpOutByCallId(struct libalias *la, struct in_addr src_addr,
1525127094Sdes    struct in_addr dst_addr,
1526127094Sdes    u_int16_t src_call_id)
152767966Sru{
1528127094Sdes	u_int i;
1529127094Sdes	struct alias_link *link;
153067966Sru
1531127094Sdes	i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1532127094Sdes	LIST_FOREACH(link, &la->linkTableOut[i], list_out)
1533127094Sdes	    if (link->link_type == LINK_PPTP &&
153467966Sru	    link->src_addr.s_addr == src_addr.s_addr &&
153567966Sru	    link->dst_addr.s_addr == dst_addr.s_addr &&
153667966Sru	    link->src_port == src_call_id)
153767966Sru		break;
153867966Sru
1539127094Sdes	return (link);
154067966Sru}
154167966Sru
154267966Sru
154367966Srustruct alias_link *
1544124621SphkFindPptpOutByPeerCallId(struct libalias *la, struct in_addr src_addr,
1545127094Sdes    struct in_addr dst_addr,
1546127094Sdes    u_int16_t dst_call_id)
154767966Sru{
1548127094Sdes	u_int i;
1549127094Sdes	struct alias_link *link;
155067966Sru
1551127094Sdes	i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1552127094Sdes	LIST_FOREACH(link, &la->linkTableOut[i], list_out)
1553127094Sdes	    if (link->link_type == LINK_PPTP &&
155467966Sru	    link->src_addr.s_addr == src_addr.s_addr &&
155567966Sru	    link->dst_addr.s_addr == dst_addr.s_addr &&
155667966Sru	    link->dst_port == dst_call_id)
155767966Sru		break;
155867966Sru
1559127094Sdes	return (link);
156067966Sru}
156167966Sru
156267966Sru
156367966Srustruct alias_link *
1564124621SphkFindPptpInByCallId(struct libalias *la, struct in_addr dst_addr,
1565127094Sdes    struct in_addr alias_addr,
1566127094Sdes    u_int16_t dst_call_id)
156767966Sru{
1568127094Sdes	u_int i;
1569127094Sdes	struct alias_link *link;
157067966Sru
1571127094Sdes	i = StartPointIn(alias_addr, 0, LINK_PPTP);
1572127094Sdes	LIST_FOREACH(link, &la->linkTableIn[i], list_in)
1573127094Sdes	    if (link->link_type == LINK_PPTP &&
157467966Sru	    link->dst_addr.s_addr == dst_addr.s_addr &&
157567966Sru	    link->alias_addr.s_addr == alias_addr.s_addr &&
157667966Sru	    link->dst_port == dst_call_id)
157767966Sru		break;
157867966Sru
1579127094Sdes	return (link);
158067966Sru}
158167966Sru
158267966Sru
158367966Srustruct alias_link *
1584124621SphkFindPptpInByPeerCallId(struct libalias *la, struct in_addr dst_addr,
1585127094Sdes    struct in_addr alias_addr,
1586127094Sdes    u_int16_t alias_call_id)
158767966Sru{
1588127094Sdes	struct alias_link *link;
158967966Sru
1590127094Sdes	link = FindLinkIn(la, dst_addr, alias_addr,
1591127094Sdes	    0 /* any */ , alias_call_id,
1592127094Sdes	    LINK_PPTP, 0);
159367966Sru
159467966Sru
1595127094Sdes	return (link);
159667966Sru}
159767966Sru
159867966Sru
159999207Sbrianstruct alias_link *
1600127094SdesFindRtspOut(struct libalias *la, struct in_addr src_addr,
1601127094Sdes    struct in_addr dst_addr,
1602127094Sdes    u_short src_port,
1603127094Sdes    u_short alias_port,
1604127094Sdes    u_char proto)
160563899Sarchie{
1606127094Sdes	int link_type;
1607127094Sdes	struct alias_link *link;
160863899Sarchie
1609127094Sdes	switch (proto) {
1610127094Sdes	case IPPROTO_UDP:
1611127094Sdes		link_type = LINK_UDP;
1612127094Sdes		break;
1613127094Sdes	case IPPROTO_TCP:
1614127094Sdes		link_type = LINK_TCP;
1615127094Sdes		break;
1616127094Sdes	default:
1617131613Sdes		return (NULL);
1618127094Sdes		break;
1619127094Sdes	}
162063899Sarchie
1621127094Sdes	link = FindLinkOut(la, src_addr, dst_addr, src_port, 0, link_type, 1);
162263899Sarchie
1623127094Sdes	if (link == NULL) {
1624127094Sdes		struct in_addr alias_addr;
162563899Sarchie
1626127094Sdes		alias_addr = FindAliasAddress(la, src_addr);
1627127094Sdes		link = AddLink(la, src_addr, dst_addr, alias_addr,
1628127094Sdes		    src_port, 0, alias_port,
1629127094Sdes		    link_type);
1630127094Sdes	}
1631127094Sdes	return (link);
163263899Sarchie}
163363899Sarchie
163463899Sarchie
163526026Sbrianstruct in_addr
1636124621SphkFindOriginalAddress(struct libalias *la, struct in_addr alias_addr)
163726026Sbrian{
1638127094Sdes	struct alias_link *link;
163999207Sbrian
1640127094Sdes	link = FindLinkIn(la, la->nullAddress, alias_addr,
1641127094Sdes	    0, 0, LINK_ADDR, 0);
1642127094Sdes	if (link == NULL) {
1643127094Sdes		la->newDefaultLink = 1;
1644127094Sdes		if (la->targetAddress.s_addr == INADDR_ANY)
1645131613Sdes			return (alias_addr);
1646127094Sdes		else if (la->targetAddress.s_addr == INADDR_NONE)
1647127094Sdes			return (la->aliasAddress.s_addr != INADDR_ANY) ?
1648127094Sdes			    la->aliasAddress : alias_addr;
1649127094Sdes		else
1650131613Sdes			return (la->targetAddress);
1651127094Sdes	} else {
1652127094Sdes		if (link->server != NULL) {	/* LSNAT link */
1653127094Sdes			struct in_addr src_addr;
165459702Sru
1655127094Sdes			src_addr = link->server->addr;
1656127094Sdes			link->server = link->server->next;
1657127094Sdes			return (src_addr);
1658127094Sdes		} else if (link->src_addr.s_addr == INADDR_ANY)
1659127094Sdes			return (la->aliasAddress.s_addr != INADDR_ANY) ?
1660127094Sdes			    la->aliasAddress : alias_addr;
1661127094Sdes		else
1662131613Sdes			return (link->src_addr);
1663127094Sdes	}
166426026Sbrian}
166526026Sbrian
166626026Sbrian
166726026Sbrianstruct in_addr
1668124621SphkFindAliasAddress(struct libalias *la, struct in_addr original_addr)
166926026Sbrian{
1670127094Sdes	struct alias_link *link;
167199207Sbrian
1672127094Sdes	link = FindLinkOut(la, original_addr, la->nullAddress,
1673127094Sdes	    0, 0, LINK_ADDR, 0);
1674127094Sdes	if (link == NULL) {
1675127094Sdes		return (la->aliasAddress.s_addr != INADDR_ANY) ?
1676127094Sdes		    la->aliasAddress : original_addr;
1677127094Sdes	} else {
1678127094Sdes		if (link->alias_addr.s_addr == INADDR_ANY)
1679127094Sdes			return (la->aliasAddress.s_addr != INADDR_ANY) ?
1680127094Sdes			    la->aliasAddress : original_addr;
1681127094Sdes		else
1682131613Sdes			return (link->alias_addr);
1683127094Sdes	}
168426026Sbrian}
168526026Sbrian
168626026Sbrian
168726026Sbrian/* External routines for getting or changing link data
168826026Sbrian   (external to alias_db.c, but internal to alias*.c)
168926026Sbrian
169026026Sbrian    SetFragmentData(), GetFragmentData()
169126026Sbrian    SetFragmentPtr(), GetFragmentPtr()
169226026Sbrian    SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut()
169326026Sbrian    GetOriginalAddress(), GetDestAddress(), GetAliasAddress()
169426026Sbrian    GetOriginalPort(), GetAliasPort()
169526026Sbrian    SetAckModified(), GetAckModified()
169626026Sbrian    GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq()
169777485Sru    SetProtocolFlags(), GetProtocolFlags()
169867966Sru    SetDestCallId()
169926026Sbrian*/
170026026Sbrian
170126026Sbrian
170226026Sbrianvoid
170326026SbrianSetFragmentAddr(struct alias_link *link, struct in_addr src_addr)
170426026Sbrian{
1705127094Sdes	link->data.frag_addr = src_addr;
170626026Sbrian}
170726026Sbrian
170826026Sbrian
170926026Sbrianvoid
171026026SbrianGetFragmentAddr(struct alias_link *link, struct in_addr *src_addr)
171126026Sbrian{
1712127094Sdes	*src_addr = link->data.frag_addr;
171326026Sbrian}
171426026Sbrian
171526026Sbrian
171626026Sbrianvoid
171726026SbrianSetFragmentPtr(struct alias_link *link, char *fptr)
171826026Sbrian{
1719127094Sdes	link->data.frag_ptr = fptr;
172026026Sbrian}
172126026Sbrian
172226026Sbrian
172326026Sbrianvoid
172426026SbrianGetFragmentPtr(struct alias_link *link, char **fptr)
172526026Sbrian{
1726127094Sdes	*fptr = link->data.frag_ptr;
172726026Sbrian}
172826026Sbrian
172926026Sbrian
173026026Sbrianvoid
173126026SbrianSetStateIn(struct alias_link *link, int state)
173226026Sbrian{
1733127094Sdes	/* TCP input state */
1734127094Sdes	switch (state) {
1735127094Sdes		case ALIAS_TCP_STATE_DISCONNECTED:
1736127094Sdes		if (link->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED)
1737127094Sdes			link->expire_time = TCP_EXPIRE_DEAD;
1738127094Sdes		else
1739127094Sdes			link->expire_time = TCP_EXPIRE_SINGLEDEAD;
1740127094Sdes		break;
1741127094Sdes	case ALIAS_TCP_STATE_CONNECTED:
1742127094Sdes		if (link->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED)
1743127094Sdes			link->expire_time = TCP_EXPIRE_CONNECTED;
1744127094Sdes		break;
1745127094Sdes	default:
1746127094Sdes		abort();
1747127094Sdes	}
1748127094Sdes	link->data.tcp->state.in = state;
174926026Sbrian}
175026026Sbrian
175126026Sbrian
175226026Sbrianvoid
175326026SbrianSetStateOut(struct alias_link *link, int state)
175426026Sbrian{
1755127094Sdes	/* TCP output state */
1756127094Sdes	switch (state) {
1757127094Sdes		case ALIAS_TCP_STATE_DISCONNECTED:
1758127094Sdes		if (link->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED)
1759127094Sdes			link->expire_time = TCP_EXPIRE_DEAD;
1760127094Sdes		else
1761127094Sdes			link->expire_time = TCP_EXPIRE_SINGLEDEAD;
1762127094Sdes		break;
1763127094Sdes	case ALIAS_TCP_STATE_CONNECTED:
1764127094Sdes		if (link->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED)
1765127094Sdes			link->expire_time = TCP_EXPIRE_CONNECTED;
1766127094Sdes		break;
1767127094Sdes	default:
1768127094Sdes		abort();
1769127094Sdes	}
1770127094Sdes	link->data.tcp->state.out = state;
177126026Sbrian}
177226026Sbrian
177326026Sbrian
177426026Sbrianint
177526026SbrianGetStateIn(struct alias_link *link)
177626026Sbrian{
1777127094Sdes	/* TCP input state */
1778131613Sdes	return (link->data.tcp->state.in);
177926026Sbrian}
178026026Sbrian
178126026Sbrian
178226026Sbrianint
178326026SbrianGetStateOut(struct alias_link *link)
178426026Sbrian{
1785127094Sdes	/* TCP output state */
1786131613Sdes	return (link->data.tcp->state.out);
178726026Sbrian}
178826026Sbrian
178926026Sbrian
179026026Sbrianstruct in_addr
179126026SbrianGetOriginalAddress(struct alias_link *link)
179226026Sbrian{
1793127094Sdes	if (link->src_addr.s_addr == INADDR_ANY)
1794131613Sdes		return (link->la->aliasAddress);
1795127094Sdes	else
1796127094Sdes		return (link->src_addr);
179726026Sbrian}
179826026Sbrian
179926026Sbrian
180026026Sbrianstruct in_addr
180126026SbrianGetDestAddress(struct alias_link *link)
180226026Sbrian{
1803127094Sdes	return (link->dst_addr);
180426026Sbrian}
180526026Sbrian
180626026Sbrian
180726026Sbrianstruct in_addr
180826026SbrianGetAliasAddress(struct alias_link *link)
180926026Sbrian{
1810127094Sdes	if (link->alias_addr.s_addr == INADDR_ANY)
1811131613Sdes		return (link->la->aliasAddress);
1812127094Sdes	else
1813131613Sdes		return (link->alias_addr);
181426026Sbrian}
181526026Sbrian
181626026Sbrian
181726026Sbrianstruct in_addr
1818124621SphkGetDefaultAliasAddress(struct libalias *la)
181926026Sbrian{
1820131613Sdes	return (la->aliasAddress);
182126026Sbrian}
182226026Sbrian
182326026Sbrian
182426026Sbrianvoid
1825124621SphkSetDefaultAliasAddress(struct libalias *la, struct in_addr alias_addr)
182626026Sbrian{
1827127094Sdes	la->aliasAddress = alias_addr;
182826026Sbrian}
182926026Sbrian
183026026Sbrian
183126026Sbrianu_short
183226026SbrianGetOriginalPort(struct alias_link *link)
183326026Sbrian{
1834127094Sdes	return (link->src_port);
183526026Sbrian}
183626026Sbrian
183726026Sbrian
183826026Sbrianu_short
183926026SbrianGetAliasPort(struct alias_link *link)
184026026Sbrian{
1841127094Sdes	return (link->alias_port);
184226026Sbrian}
184326026Sbrian
184458279Sbrian#ifndef NO_FW_PUNCH
1845127094Sdesstatic		u_short
184632377SeivindGetDestPort(struct alias_link *link)
184732377Seivind{
1848127094Sdes	return (link->dst_port);
184932377Seivind}
1850127094Sdes
185158279Sbrian#endif
185226026Sbrian
185326026Sbrianvoid
185426026SbrianSetAckModified(struct alias_link *link)
185526026Sbrian{
185659356Sru/* Indicate that ACK numbers have been modified in a TCP connection */
1857127094Sdes	link->data.tcp->state.ack_modified = 1;
185826026Sbrian}
185926026Sbrian
186026026Sbrian
186144307Sbrianstruct in_addr
186244307SbrianGetProxyAddress(struct alias_link *link)
186344307Sbrian{
1864131613Sdes	return (link->proxy_addr);
186544307Sbrian}
186644307Sbrian
186744307Sbrian
186844307Sbrianvoid
186944307SbrianSetProxyAddress(struct alias_link *link, struct in_addr addr)
187044307Sbrian{
1871127094Sdes	link->proxy_addr = addr;
187244307Sbrian}
187344307Sbrian
187444307Sbrian
187544307Sbrianu_short
187644307SbrianGetProxyPort(struct alias_link *link)
187744307Sbrian{
1878131613Sdes	return (link->proxy_port);
187944307Sbrian}
188044307Sbrian
188144307Sbrian
188244307Sbrianvoid
188344307SbrianSetProxyPort(struct alias_link *link, u_short port)
188444307Sbrian{
1885127094Sdes	link->proxy_port = port;
188644307Sbrian}
188744307Sbrian
188844307Sbrian
188926026Sbrianint
189026026SbrianGetAckModified(struct alias_link *link)
189126026Sbrian{
189259356Sru/* See if ACK numbers have been modified */
1893131613Sdes	return (link->data.tcp->state.ack_modified);
189426026Sbrian}
189526026Sbrian
189626026Sbrian
189726026Sbrianint
189826026SbrianGetDeltaAckIn(struct ip *pip, struct alias_link *link)
189926026Sbrian{
190026026Sbrian/*
190159356SruFind out how much the ACK number has been altered for an incoming
190259356SruTCP packet.  To do this, a circular list of ACK numbers where the TCP
190399207Sbrianpacket size was altered is searched.
190426026Sbrian*/
190526026Sbrian
1906127094Sdes	int i;
1907127094Sdes	struct tcphdr *tc;
1908127094Sdes	int delta, ack_diff_min;
1909127094Sdes	u_long ack;
191026026Sbrian
1911127094Sdes	tc = (struct tcphdr *)((char *)pip + (pip->ip_hl << 2));
1912127094Sdes	ack = tc->th_ack;
191326026Sbrian
1914127094Sdes	delta = 0;
1915127094Sdes	ack_diff_min = -1;
1916127094Sdes	for (i = 0; i < N_LINK_TCP_DATA; i++) {
1917127094Sdes		struct ack_data_record x;
191826026Sbrian
1919127094Sdes		x = link->data.tcp->ack[i];
1920127094Sdes		if (x.active == 1) {
1921127094Sdes			int ack_diff;
192226026Sbrian
1923127094Sdes			ack_diff = SeqDiff(x.ack_new, ack);
1924127094Sdes			if (ack_diff >= 0) {
1925127094Sdes				if (ack_diff_min >= 0) {
1926127094Sdes					if (ack_diff < ack_diff_min) {
1927127094Sdes						delta = x.delta;
1928127094Sdes						ack_diff_min = ack_diff;
1929127094Sdes					}
1930127094Sdes				} else {
1931127094Sdes					delta = x.delta;
1932127094Sdes					ack_diff_min = ack_diff;
1933127094Sdes				}
1934127094Sdes			}
1935127094Sdes		}
1936127094Sdes	}
1937127094Sdes	return (delta);
193826026Sbrian}
193926026Sbrian
194026026Sbrian
194126026Sbrianint
194226026SbrianGetDeltaSeqOut(struct ip *pip, struct alias_link *link)
194326026Sbrian{
194426026Sbrian/*
194559356SruFind out how much the sequence number has been altered for an outgoing
194659356SruTCP packet.  To do this, a circular list of ACK numbers where the TCP
194799207Sbrianpacket size was altered is searched.
194826026Sbrian*/
194926026Sbrian
1950127094Sdes	int i;
1951127094Sdes	struct tcphdr *tc;
1952127094Sdes	int delta, seq_diff_min;
1953127094Sdes	u_long seq;
195426026Sbrian
1955127094Sdes	tc = (struct tcphdr *)((char *)pip + (pip->ip_hl << 2));
1956127094Sdes	seq = tc->th_seq;
195726026Sbrian
1958127094Sdes	delta = 0;
1959127094Sdes	seq_diff_min = -1;
1960127094Sdes	for (i = 0; i < N_LINK_TCP_DATA; i++) {
1961127094Sdes		struct ack_data_record x;
196226026Sbrian
1963127094Sdes		x = link->data.tcp->ack[i];
1964127094Sdes		if (x.active == 1) {
1965127094Sdes			int seq_diff;
196626026Sbrian
1967127094Sdes			seq_diff = SeqDiff(x.ack_old, seq);
1968127094Sdes			if (seq_diff >= 0) {
1969127094Sdes				if (seq_diff_min >= 0) {
1970127094Sdes					if (seq_diff < seq_diff_min) {
1971127094Sdes						delta = x.delta;
1972127094Sdes						seq_diff_min = seq_diff;
1973127094Sdes					}
1974127094Sdes				} else {
1975127094Sdes					delta = x.delta;
1976127094Sdes					seq_diff_min = seq_diff;
1977127094Sdes				}
1978127094Sdes			}
1979127094Sdes		}
1980127094Sdes	}
1981127094Sdes	return (delta);
198226026Sbrian}
198326026Sbrian
198426026Sbrian
198526026Sbrianvoid
198626026SbrianAddSeq(struct ip *pip, struct alias_link *link, int delta)
198726026Sbrian{
198826026Sbrian/*
198926026SbrianWhen a TCP packet has been altered in length, save this
199026026Sbrianinformation in a circular list.  If enough packets have
199126026Sbrianbeen altered, then this list will begin to overwrite itself.
199226026Sbrian*/
199326026Sbrian
1994127094Sdes	struct tcphdr *tc;
1995127094Sdes	struct ack_data_record x;
1996127094Sdes	int hlen, tlen, dlen;
1997127094Sdes	int i;
199826026Sbrian
1999127094Sdes	tc = (struct tcphdr *)((char *)pip + (pip->ip_hl << 2));
200026026Sbrian
2001127094Sdes	hlen = (pip->ip_hl + tc->th_off) << 2;
2002127094Sdes	tlen = ntohs(pip->ip_len);
2003127094Sdes	dlen = tlen - hlen;
200426026Sbrian
2005127094Sdes	x.ack_old = htonl(ntohl(tc->th_seq) + dlen);
2006127094Sdes	x.ack_new = htonl(ntohl(tc->th_seq) + dlen + delta);
2007127094Sdes	x.delta = delta;
2008127094Sdes	x.active = 1;
200926026Sbrian
2010127094Sdes	i = link->data.tcp->state.index;
2011127094Sdes	link->data.tcp->ack[i] = x;
201226026Sbrian
2013127094Sdes	i++;
2014127094Sdes	if (i == N_LINK_TCP_DATA)
2015127094Sdes		link->data.tcp->state.index = 0;
2016127094Sdes	else
2017127094Sdes		link->data.tcp->state.index = i;
201826026Sbrian}
201926026Sbrian
202026026Sbrianvoid
202126026SbrianSetExpire(struct alias_link *link, int expire)
202226026Sbrian{
2023127094Sdes	if (expire == 0) {
2024127094Sdes		link->flags &= ~LINK_PERMANENT;
2025127094Sdes		DeleteLink(link);
2026127094Sdes	} else if (expire == -1) {
2027127094Sdes		link->flags |= LINK_PERMANENT;
2028127094Sdes	} else if (expire > 0) {
2029127094Sdes		link->expire_time = expire;
2030127094Sdes	} else {
203144616Sbrian#ifdef DEBUG
2032127094Sdes		fprintf(stderr, "PacketAlias/SetExpire(): ");
2033127094Sdes		fprintf(stderr, "error in expire parameter\n");
203444616Sbrian#endif
2035127094Sdes	}
203626026Sbrian}
203726026Sbrian
203826026Sbrianvoid
2039124621SphkClearCheckNewLink(struct libalias *la)
204026026Sbrian{
2041127094Sdes	la->newDefaultLink = 0;
204226026Sbrian}
204326026Sbrian
204461677Sruvoid
204577485SruSetProtocolFlags(struct alias_link *link, int pflags)
204661677Sru{
204726026Sbrian
2048127094Sdes	link->pflags = pflags;;
204961677Sru}
205061677Sru
205161677Sruint
205277485SruGetProtocolFlags(struct alias_link *link)
205361677Sru{
205461677Sru
2055127094Sdes	return (link->pflags);
205661677Sru}
205761677Sru
205867966Sruvoid
205967966SruSetDestCallId(struct alias_link *link, u_int16_t cid)
206067966Sru{
2061127094Sdes	struct libalias *la = link->la;
206261677Sru
2063127094Sdes	la->deleteAllLinks = 1;
2064127094Sdes	link = ReLink(link, link->src_addr, link->dst_addr, link->alias_addr,
2065127094Sdes	    link->src_port, cid, link->alias_port, link->link_type);
2066127094Sdes	la->deleteAllLinks = 0;
206767966Sru}
206867966Sru
206967966Sru
207027864Sbrian/* Miscellaneous Functions
207126026Sbrian
207227864Sbrian    HouseKeeping()
207327864Sbrian    InitPacketAliasLog()
207427864Sbrian    UninitPacketAliasLog()
207527864Sbrian*/
207626026Sbrian
207726026Sbrian/*
207826026Sbrian    Whenever an outgoing or incoming packet is handled, HouseKeeping()
207926026Sbrian    is called to find and remove timed-out aliasing links.  Logic exists
208026026Sbrian    to sweep through the entire table and linked list structure
208126026Sbrian    every 60 seconds.
208226026Sbrian
208326026Sbrian    (prototype in alias_local.h)
208426026Sbrian*/
208526026Sbrian
208626026Sbrianvoid
2087124621SphkHouseKeeping(struct libalias *la)
208826026Sbrian{
2089127094Sdes	int i, n, n100;
2090127094Sdes	struct timeval tv;
2091127094Sdes	struct timezone tz;
209226026Sbrian
2093127094Sdes	/*
2094127094Sdes	 * Save system time (seconds) in global variable timeStamp for use
2095127094Sdes	 * by other functions. This is done so as not to unnecessarily
2096127094Sdes	 * waste timeline by making system calls.
2097127094Sdes	 */
2098127094Sdes	gettimeofday(&tv, &tz);
2099127094Sdes	la->timeStamp = tv.tv_sec;
210026026Sbrian
2101127094Sdes	/* Compute number of spokes (output table link chains) to cover */
2102127094Sdes	n100 = LINK_TABLE_OUT_SIZE * 100 + la->houseKeepingResidual;
2103127094Sdes	n100 *= la->timeStamp - la->lastCleanupTime;
2104127094Sdes	n100 /= ALIAS_CLEANUP_INTERVAL_SECS;
210526026Sbrian
2106127094Sdes	n = n100 / 100;
210726026Sbrian
2108127094Sdes	/* Handle different cases */
2109127094Sdes	if (n > ALIAS_CLEANUP_MAX_SPOKES) {
2110127094Sdes		n = ALIAS_CLEANUP_MAX_SPOKES;
2111127094Sdes		la->lastCleanupTime = la->timeStamp;
2112127094Sdes		la->houseKeepingResidual = 0;
211326026Sbrian
2114127094Sdes		for (i = 0; i < n; i++)
2115127094Sdes			IncrementalCleanup(la);
2116127094Sdes	} else if (n > 0) {
2117127094Sdes		la->lastCleanupTime = la->timeStamp;
2118127094Sdes		la->houseKeepingResidual = n100 - 100 * n;
211926026Sbrian
2120127094Sdes		for (i = 0; i < n; i++)
2121127094Sdes			IncrementalCleanup(la);
2122127094Sdes	} else if (n < 0) {
212344616Sbrian#ifdef DEBUG
2124127094Sdes		fprintf(stderr, "PacketAlias/HouseKeeping(): ");
2125127094Sdes		fprintf(stderr, "something unexpected in time values\n");
212644616Sbrian#endif
2127127094Sdes		la->lastCleanupTime = la->timeStamp;
2128127094Sdes		la->houseKeepingResidual = 0;
2129127094Sdes	}
213026026Sbrian}
213126026Sbrian
213226026Sbrian
213327864Sbrian/* Init the log file and enable logging */
213432377Seivindstatic void
2135124621SphkInitPacketAliasLog(struct libalias *la)
213627864Sbrian{
2137127094Sdes	if ((~la->packetAliasMode & PKT_ALIAS_LOG)
2138127094Sdes	    && (la->monitorFile = fopen("/var/log/alias.log", "w"))) {
2139127094Sdes		la->packetAliasMode |= PKT_ALIAS_LOG;
2140127094Sdes		fprintf(la->monitorFile,
2141127094Sdes		    "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");
2142127094Sdes	}
214327864Sbrian}
214426026Sbrian
214526026Sbrian
214627864Sbrian/* Close the log-file and disable logging. */
214732377Seivindstatic void
2148124621SphkUninitPacketAliasLog(struct libalias *la)
214927864Sbrian{
2150127094Sdes	if (la->monitorFile) {
2151127094Sdes		fclose(la->monitorFile);
2152127094Sdes		la->monitorFile = NULL;
2153127094Sdes	}
2154127094Sdes	la->packetAliasMode &= ~PKT_ALIAS_LOG;
215527864Sbrian}
215626026Sbrian
215727864Sbrian
215827864Sbrian
215927864Sbrian
216027864Sbrian
216127864Sbrian
216226026Sbrian/* Outside world interfaces
216326026Sbrian
216426026Sbrian-- "outside world" means other than alias*.c routines --
216526026Sbrian
216626026Sbrian    PacketAliasRedirectPort()
216759702Sru    PacketAliasAddServer()
216859726Sru    PacketAliasRedirectProto()
216926026Sbrian    PacketAliasRedirectAddr()
2170115650Sru    PacketAliasRedirectDynamic()
217127864Sbrian    PacketAliasRedirectDelete()
217227864Sbrian    PacketAliasSetAddress()
217327864Sbrian    PacketAliasInit()
217432377Seivind    PacketAliasUninit()
217527864Sbrian    PacketAliasSetMode()
217626026Sbrian
217726026Sbrian(prototypes in alias.h)
217826026Sbrian*/
217926026Sbrian
218026026Sbrian/* Redirection from a specific public addr:port to a
218159356Sru   private addr:port */
218226026Sbrianstruct alias_link *
2183127094SdesLibAliasRedirectPort(struct libalias *la, struct in_addr src_addr, u_short src_port,
2184127094Sdes    struct in_addr dst_addr, u_short dst_port,
2185127094Sdes    struct in_addr alias_addr, u_short alias_port,
2186127094Sdes    u_char proto)
218726026Sbrian{
2188127094Sdes	int link_type;
2189127094Sdes	struct alias_link *link;
219026026Sbrian
2191127094Sdes	switch (proto) {
2192127094Sdes	case IPPROTO_UDP:
2193127094Sdes		link_type = LINK_UDP;
2194127094Sdes		break;
2195127094Sdes	case IPPROTO_TCP:
2196127094Sdes		link_type = LINK_TCP;
2197127094Sdes		break;
2198127094Sdes	default:
219944616Sbrian#ifdef DEBUG
2200127094Sdes		fprintf(stderr, "PacketAliasRedirectPort(): ");
2201127094Sdes		fprintf(stderr, "only TCP and UDP protocols allowed\n");
220244616Sbrian#endif
2203131613Sdes		return (NULL);
2204127094Sdes	}
220526026Sbrian
2206127094Sdes	link = AddLink(la, src_addr, dst_addr, alias_addr,
2207127094Sdes	    src_port, dst_port, alias_port,
2208127094Sdes	    link_type);
220926026Sbrian
2210127094Sdes	if (link != NULL) {
2211127094Sdes		link->flags |= LINK_PERMANENT;
2212127094Sdes	}
221344616Sbrian#ifdef DEBUG
2214127094Sdes	else {
2215127094Sdes		fprintf(stderr, "PacketAliasRedirectPort(): "
2216127094Sdes		    "call to AddLink() failed\n");
2217127094Sdes	}
221844616Sbrian#endif
221926026Sbrian
2220131613Sdes	return (link);
222126026Sbrian}
222226026Sbrian
222359702Sru/* Add server to the pool of servers */
222459702Sruint
2225124621SphkLibAliasAddServer(struct libalias *la, struct alias_link *link, struct in_addr addr, u_short port)
222659702Sru{
2227127094Sdes	struct server *server;
222859702Sru
2229127094Sdes	server = malloc(sizeof(struct server));
223059702Sru
2231127094Sdes	if (server != NULL) {
2232127094Sdes		struct server *head;
223359702Sru
2234127094Sdes		server->addr = addr;
2235127094Sdes		server->port = port;
223659702Sru
2237127094Sdes		head = link->server;
2238127094Sdes		if (head == NULL)
2239127094Sdes			server->next = server;
2240127094Sdes		else {
2241127094Sdes			struct server *s;
224259702Sru
2243127094Sdes			for (s = head; s->next != head; s = s->next);
2244127094Sdes			s->next = server;
2245127094Sdes			server->next = head;
2246127094Sdes		}
2247127094Sdes		link->server = server;
2248127094Sdes		return (0);
2249127094Sdes	} else
2250127094Sdes		return (-1);
225159702Sru}
225259702Sru
225359726Sru/* Redirect packets of a given IP protocol from a specific
225459356Sru   public address to a private address */
225559356Srustruct alias_link *
2256124621SphkLibAliasRedirectProto(struct libalias *la, struct in_addr src_addr,
2257127094Sdes    struct in_addr dst_addr,
2258127094Sdes    struct in_addr alias_addr,
2259127094Sdes    u_char proto)
226044307Sbrian{
2261127094Sdes	struct alias_link *link;
226244307Sbrian
2263127094Sdes	link = AddLink(la, src_addr, dst_addr, alias_addr,
2264127094Sdes	    NO_SRC_PORT, NO_DEST_PORT, 0,
2265127094Sdes	    proto);
226659356Sru
2267127094Sdes	if (link != NULL) {
2268127094Sdes		link->flags |= LINK_PERMANENT;
2269127094Sdes	}
227059356Sru#ifdef DEBUG
2271127094Sdes	else {
2272127094Sdes		fprintf(stderr, "PacketAliasRedirectProto(): "
2273127094Sdes		    "call to AddLink() failed\n");
2274127094Sdes	}
227559356Sru#endif
227659356Sru
2277131613Sdes	return (link);
227844307Sbrian}
227944307Sbrian
228026026Sbrian/* Static address translation */
228126026Sbrianstruct alias_link *
2282124621SphkLibAliasRedirectAddr(struct libalias *la, struct in_addr src_addr,
2283127094Sdes    struct in_addr alias_addr)
228426026Sbrian{
2285127094Sdes	struct alias_link *link;
228626026Sbrian
2287127094Sdes	link = AddLink(la, src_addr, la->nullAddress, alias_addr,
2288127094Sdes	    0, 0, 0,
2289127094Sdes	    LINK_ADDR);
229026026Sbrian
2291127094Sdes	if (link != NULL) {
2292127094Sdes		link->flags |= LINK_PERMANENT;
2293127094Sdes	}
229444616Sbrian#ifdef DEBUG
2295127094Sdes	else {
2296127094Sdes		fprintf(stderr, "PacketAliasRedirectAddr(): "
2297127094Sdes		    "call to AddLink() failed\n");
2298127094Sdes	}
229944616Sbrian#endif
230026026Sbrian
2301131613Sdes	return (link);
230226026Sbrian}
230326026Sbrian
230426026Sbrian
2305115650Sru/* Mark the aliasing link dynamic */
2306115650Sruint
2307124621SphkLibAliasRedirectDynamic(struct libalias *la, struct alias_link *link)
2308115650Sru{
2309115650Sru
2310127094Sdes	if (link->flags & LINK_PARTIALLY_SPECIFIED)
2311127094Sdes		return (-1);
2312127094Sdes	else {
2313127094Sdes		link->flags &= ~LINK_PERMANENT;
2314127094Sdes		return (0);
2315127094Sdes	}
2316115650Sru}
2317115650Sru
2318115650Sru
231926026Sbrianvoid
2320124621SphkLibAliasRedirectDelete(struct libalias *la, struct alias_link *link)
232126026Sbrian{
232227864Sbrian/* This is a dangerous function to put in the API,
232326026Sbrian   because an invalid pointer can crash the program. */
232426026Sbrian
2325127094Sdes	la->deleteAllLinks = 1;
2326127094Sdes	DeleteLink(link);
2327127094Sdes	la->deleteAllLinks = 0;
232826026Sbrian}
232926026Sbrian
233026026Sbrian
233126026Sbrianvoid
2332124621SphkLibAliasSetAddress(struct libalias *la, struct in_addr addr)
233326026Sbrian{
2334127094Sdes	if (la->packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE
2335127094Sdes	    && la->aliasAddress.s_addr != addr.s_addr)
2336127094Sdes		CleanupAliasData(la);
233733897Sbrian
2338127094Sdes	la->aliasAddress = addr;
233926026Sbrian}
234026026Sbrian
234126026Sbrian
234226026Sbrianvoid
2343124621SphkLibAliasSetTarget(struct libalias *la, struct in_addr target_addr)
234426026Sbrian{
2345127094Sdes	la->targetAddress = target_addr;
234626026Sbrian}
234726026Sbrian
2348124621Sphkstatic void
2349124621Sphkfinishoff(void)
2350124621Sphk{
235126026Sbrian
2352127094Sdes	while (!LIST_EMPTY(&instancehead))
2353124621Sphk		LibAliasUninit(LIST_FIRST(&instancehead));
2354124621Sphk}
2355124621Sphk
2356124621Sphkstruct libalias *
2357124621SphkLibAliasInit(struct libalias *la)
235826026Sbrian{
2359127094Sdes	int i;
2360127094Sdes	struct timeval tv;
2361127094Sdes	struct timezone tz;
236226026Sbrian
2363127094Sdes	if (la == NULL) {
2364127094Sdes		la = calloc(sizeof *la, 1);
2365127094Sdes		if (la == NULL)
2366127094Sdes			return (la);
2367127094Sdes		if (LIST_EMPTY(&instancehead))
2368127094Sdes			atexit(finishoff);
2369127094Sdes		LIST_INSERT_HEAD(&instancehead, la, instancelist);
237026026Sbrian
2371127094Sdes		gettimeofday(&tv, &tz);
2372127094Sdes		la->timeStamp = tv.tv_sec;
2373127094Sdes		la->lastCleanupTime = tv.tv_sec;
2374127094Sdes		la->houseKeepingResidual = 0;
237526026Sbrian
2376127094Sdes		for (i = 0; i < LINK_TABLE_OUT_SIZE; i++)
2377127094Sdes			LIST_INIT(&la->linkTableOut[i]);
2378127094Sdes		for (i = 0; i < LINK_TABLE_IN_SIZE; i++)
2379127094Sdes			LIST_INIT(&la->linkTableIn[i]);
238026026Sbrian
2381127094Sdes	} else {
2382127094Sdes		la->deleteAllLinks = 1;
2383127094Sdes		CleanupAliasData(la);
2384127094Sdes		la->deleteAllLinks = 0;
2385127094Sdes	}
238626026Sbrian
2387127094Sdes	la->aliasAddress.s_addr = INADDR_ANY;
2388127094Sdes	la->targetAddress.s_addr = INADDR_ANY;
238926026Sbrian
2390127094Sdes	la->icmpLinkCount = 0;
2391127094Sdes	la->udpLinkCount = 0;
2392127094Sdes	la->tcpLinkCount = 0;
2393127094Sdes	la->pptpLinkCount = 0;
2394127094Sdes	la->protoLinkCount = 0;
2395127094Sdes	la->fragmentIdLinkCount = 0;
2396127094Sdes	la->fragmentPtrLinkCount = 0;
2397127094Sdes	la->sockCount = 0;
239826026Sbrian
2399127094Sdes	la->cleanupIndex = 0;
2400127094Sdes
2401127094Sdes	la->packetAliasMode = PKT_ALIAS_SAME_PORTS
2402127094Sdes	    | PKT_ALIAS_USE_SOCKETS
2403127094Sdes	    | PKT_ALIAS_RESET_ON_ADDR_CHANGE;
2404124621Sphk#ifndef NO_FW_PUNCH
2405127094Sdes	la->fireWallFD = -1;
2406124621Sphk#endif
2407127094Sdes	return (la);
240826026Sbrian}
240926026Sbrian
241032377Seivindvoid
2411127094SdesLibAliasUninit(struct libalias *la)
2412127094Sdes{
2413127094Sdes	la->deleteAllLinks = 1;
2414127094Sdes	CleanupAliasData(la);
2415127094Sdes	la->deleteAllLinks = 0;
2416127094Sdes	UninitPacketAliasLog(la);
241735314Sbrian#ifndef NO_FW_PUNCH
2418127094Sdes	UninitPunchFW(la);
241935314Sbrian#endif
2420127094Sdes	LIST_REMOVE(la, instancelist);
2421127094Sdes	free(la);
242232377Seivind}
242326026Sbrian
242426026Sbrian/* Change mode for some operations */
242526026Sbrianunsigned int
2426124621SphkLibAliasSetMode(
2427124621Sphk    struct libalias *la,
2428127094Sdes    unsigned int flags,		/* Which state to bring flags to */
2429127094Sdes    unsigned int mask		/* Mask of which flags to affect (use 0 to
2430127094Sdes				 * do a probe for flag values) */
243126026Sbrian)
243226026Sbrian{
243326026Sbrian/* Enable logging? */
2434127094Sdes	if (flags & mask & PKT_ALIAS_LOG) {
2435127094Sdes		InitPacketAliasLog(la);	/* Do the enable */
2436127094Sdes	} else
243726026Sbrian/* _Disable_ logging? */
2438127094Sdes	if (~flags & mask & PKT_ALIAS_LOG) {
2439127094Sdes		UninitPacketAliasLog(la);
2440127094Sdes	}
244135314Sbrian#ifndef NO_FW_PUNCH
244232377Seivind/* Start punching holes in the firewall? */
2443127094Sdes	if (flags & mask & PKT_ALIAS_PUNCH_FW) {
2444127094Sdes		InitPunchFW(la);
2445127094Sdes	} else
244632377Seivind/* Stop punching holes in the firewall? */
2447127094Sdes	if (~flags & mask & PKT_ALIAS_PUNCH_FW) {
2448127094Sdes		UninitPunchFW(la);
2449127094Sdes	}
245035314Sbrian#endif
245132377Seivind
245226026Sbrian/* Other flags can be set/cleared without special action */
2453127094Sdes	la->packetAliasMode = (flags & mask) | (la->packetAliasMode & ~mask);
2454131613Sdes	return (la->packetAliasMode);
245526026Sbrian}
245626026Sbrian
245726026Sbrian
245827864Sbrianint
2459124621SphkLibAliasCheckNewLink(struct libalias *la)
246027864Sbrian{
2461131613Sdes	return (la->newDefaultLink);
246227864Sbrian}
246332377Seivind
246432377Seivind
246535314Sbrian#ifndef NO_FW_PUNCH
246635314Sbrian
246732377Seivind/*****************
246832377Seivind  Code to support firewall punching.  This shouldn't really be in this
246932377Seivind  file, but making variables global is evil too.
247032377Seivind  ****************/
247132377Seivind
2472100288Sluigi#ifndef IPFW2
2473127094Sdes#define IPFW2	1		/* use new ipfw code */
2474100288Sluigi#endif
2475100288Sluigi
247632377Seivind/* Firewall include files */
247732392Sjkh#include <net/if.h>
247832377Seivind#include <netinet/ip_fw.h>
247932377Seivind#include <string.h>
248032377Seivind#include <err.h>
248132377Seivind
2482127094Sdes#if IPFW2			/* support for new firewall code */
248398943Sluigi/*
248498943Sluigi * helper function, updates the pointer to cmd with the length
248598943Sluigi * of the current command, and also cleans up the first word of
248698943Sluigi * the new command in case it has been clobbered before.
248798943Sluigi */
248898943Sluigistatic ipfw_insn *
2489127094Sdesnext_cmd(ipfw_insn * cmd)
249098943Sluigi{
2491127094Sdes	cmd += F_LEN(cmd);
2492127094Sdes	bzero(cmd, sizeof(*cmd));
2493131613Sdes	return (cmd);
249498943Sluigi}
249598943Sluigi
249699623Sluigi/*
249799623Sluigi * A function to fill simple commands of size 1.
249899623Sluigi * Existing flags are preserved.
249999623Sluigi */
250099623Sluigistatic ipfw_insn *
2501127094Sdesfill_cmd(ipfw_insn * cmd, enum ipfw_opcodes opcode, int size,
2502127094Sdes    int flags, u_int16_t arg)
250398943Sluigi{
2504127094Sdes	cmd->opcode = opcode;
2505127094Sdes	cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | (size & F_LEN_MASK);
2506127094Sdes	cmd->arg1 = arg;
2507127094Sdes	return next_cmd(cmd);
250899623Sluigi}
250999623Sluigi
251099623Sluigistatic ipfw_insn *
2511127094Sdesfill_ip(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int32_t addr)
251299623Sluigi{
2513127094Sdes	ipfw_insn_ip *cmd = (ipfw_insn_ip *) cmd1;
251499623Sluigi
2515127094Sdes	cmd->addr.s_addr = addr;
2516127094Sdes	return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u32), 0, 0);
251798943Sluigi}
251898943Sluigi
251999623Sluigistatic ipfw_insn *
2520127094Sdesfill_one_port(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int16_t port)
252198943Sluigi{
2522127094Sdes	ipfw_insn_u16 *cmd = (ipfw_insn_u16 *) cmd1;
252399623Sluigi
2524127094Sdes	cmd->ports[0] = cmd->ports[1] = port;
2525127094Sdes	return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u16), 0, 0);
252698943Sluigi}
252798943Sluigi
252898943Sluigistatic int
252998943Sluigifill_rule(void *buf, int bufsize, int rulenum,
2530127094Sdes    enum ipfw_opcodes action, int proto,
2531127094Sdes    struct in_addr sa, u_int16_t sp, struct in_addr da, u_int16_t dp)
253298943Sluigi{
2533127094Sdes	struct ip_fw *rule = (struct ip_fw *)buf;
2534127094Sdes	ipfw_insn *cmd = (ipfw_insn *) rule->cmd;
253598943Sluigi
2536127094Sdes	bzero(buf, bufsize);
2537127094Sdes	rule->rulenum = rulenum;
253898943Sluigi
2539127094Sdes	cmd = fill_cmd(cmd, O_PROTO, F_INSN_SIZE(ipfw_insn), 0, proto);
2540127094Sdes	cmd = fill_ip(cmd, O_IP_SRC, sa.s_addr);
2541127094Sdes	cmd = fill_one_port(cmd, O_IP_SRCPORT, sp);
2542127094Sdes	cmd = fill_ip(cmd, O_IP_DST, da.s_addr);
2543127094Sdes	cmd = fill_one_port(cmd, O_IP_DSTPORT, dp);
254498943Sluigi
2545127094Sdes	rule->act_ofs = (u_int32_t *) cmd - (u_int32_t *) rule->cmd;
2546127094Sdes	cmd = fill_cmd(cmd, action, F_INSN_SIZE(ipfw_insn), 0, 0);
254799207Sbrian
2548127094Sdes	rule->cmd_len = (u_int32_t *) cmd - (u_int32_t *) rule->cmd;
254998943Sluigi
2550127094Sdes	return ((char *)cmd - (char *)buf);
255198943Sluigi}
255298943Sluigi
2553127094Sdes#endif				/* IPFW2 */
255432377Seivind
2555127094Sdesstatic void	ClearAllFWHoles(struct libalias *la);
255632377Seivind
2557127094Sdes
2558124621Sphk#define fw_setfield(la, field, num)                         \
255932377Seivinddo {                                                    \
2560124621Sphk    (field)[(num) - la->fireWallBaseNum] = 1;               \
2561127094Sdes} /*lint -save -e717 */ while(0)/* lint -restore */
2562124621Sphk
2563124621Sphk#define fw_clrfield(la, field, num)                         \
256432377Seivinddo {                                                    \
2565124621Sphk    (field)[(num) - la->fireWallBaseNum] = 0;               \
2566127094Sdes} /*lint -save -e717 */ while(0)/* lint -restore */
256732377Seivind
2568124621Sphk#define fw_tstfield(la, field, num) ((field)[(num) - la->fireWallBaseNum])
2569124621Sphk
257032377Seivindstatic void
2571124621SphkInitPunchFW(struct libalias *la)
2572124621Sphk{
2573124621Sphk
2574127094Sdes	la->fireWallField = malloc(la->fireWallNumNums);
2575127094Sdes	if (la->fireWallField) {
2576127094Sdes		memset(la->fireWallField, 0, la->fireWallNumNums);
2577127094Sdes		if (la->fireWallFD < 0) {
2578127094Sdes			la->fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
2579127094Sdes		}
2580127094Sdes		ClearAllFWHoles(la);
2581127094Sdes		la->fireWallActiveNum = la->fireWallBaseNum;
2582127094Sdes	}
258332377Seivind}
258432377Seivind
258532377Seivindstatic void
2586124621SphkUninitPunchFW(struct libalias *la)
2587124621Sphk{
2588127094Sdes	ClearAllFWHoles(la);
2589127094Sdes	if (la->fireWallFD >= 0)
2590127094Sdes		close(la->fireWallFD);
2591127094Sdes	la->fireWallFD = -1;
2592127094Sdes	if (la->fireWallField)
2593127094Sdes		free(la->fireWallField);
2594127094Sdes	la->fireWallField = NULL;
2595127094Sdes	la->packetAliasMode &= ~PKT_ALIAS_PUNCH_FW;
259632377Seivind}
259732377Seivind
259832377Seivind/* Make a certain link go through the firewall */
259932377Seivindvoid
2600124621SphkPunchFWHole(struct alias_link *link)
2601124621Sphk{
2602127094Sdes	struct libalias *la;
2603127094Sdes	int r;			/* Result code */
2604127094Sdes	struct ip_fw rule;	/* On-the-fly built rule */
2605127094Sdes	int fwhole;		/* Where to punch hole */
260632377Seivind
2607127094Sdes	la = link->la;
2608124621Sphk
260932377Seivind/* Don't do anything unless we are asked to */
2610127094Sdes	if (!(la->packetAliasMode & PKT_ALIAS_PUNCH_FW) ||
2611127094Sdes	    la->fireWallFD < 0 ||
2612127094Sdes	    link->link_type != LINK_TCP)
2613127094Sdes		return;
261432377Seivind
2615127094Sdes	memset(&rule, 0, sizeof rule);
261632377Seivind
261732377Seivind/** Build rule **/
261832377Seivind
2619127094Sdes	/* Find empty slot */
2620127094Sdes	for (fwhole = la->fireWallActiveNum;
2621127094Sdes	    fwhole < la->fireWallBaseNum + la->fireWallNumNums &&
2622127094Sdes	    fw_tstfield(la, la->fireWallField, fwhole);
2623127094Sdes	    fwhole++);
2624127094Sdes	if (fwhole == la->fireWallBaseNum + la->fireWallNumNums) {
2625127094Sdes		for (fwhole = la->fireWallBaseNum;
2626127094Sdes		    fwhole < la->fireWallActiveNum &&
2627127094Sdes		    fw_tstfield(la, la->fireWallField, fwhole);
2628127094Sdes		    fwhole++);
2629127094Sdes		if (fwhole == la->fireWallActiveNum) {
2630127094Sdes			/* No rule point empty - we can't punch more holes. */
2631127094Sdes			la->fireWallActiveNum = la->fireWallBaseNum;
263244616Sbrian#ifdef DEBUG
2633127094Sdes			fprintf(stderr, "libalias: Unable to create firewall hole!\n");
263444616Sbrian#endif
2635127094Sdes			return;
2636127094Sdes		}
2637127094Sdes	}
2638127094Sdes	/* Start next search at next position */
2639127094Sdes	la->fireWallActiveNum = fwhole + 1;
264032377Seivind
2641127094Sdes	/*
2642127094Sdes	 * generate two rules of the form
2643131612Sdes	 *
2644127094Sdes	 * add fwhole accept tcp from OAddr OPort to DAddr DPort add fwhole
2645127094Sdes	 * accept tcp from DAddr DPort to OAddr OPort
2646127094Sdes	 */
264799623Sluigi#if IPFW2
2648127094Sdes	if (GetOriginalPort(link) != 0 && GetDestPort(link) != 0) {
2649127094Sdes		u_int32_t rulebuf[255];
2650127094Sdes		int i;
265198943Sluigi
2652127094Sdes		i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2653127094Sdes		    O_ACCEPT, IPPROTO_TCP,
2654127094Sdes		    GetOriginalAddress(link), ntohs(GetOriginalPort(link)),
2655127094Sdes		    GetDestAddress(link), ntohs(GetDestPort(link)));
2656127094Sdes		r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2657127094Sdes		if (r)
2658127094Sdes			err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
265998943Sluigi
2660127094Sdes		i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2661127094Sdes		    O_ACCEPT, IPPROTO_TCP,
2662127094Sdes		    GetDestAddress(link), ntohs(GetDestPort(link)),
2663127094Sdes		    GetOriginalAddress(link), ntohs(GetOriginalPort(link)));
2664127094Sdes		r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2665127094Sdes		if (r)
2666127094Sdes			err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
2667127094Sdes	}
2668127094Sdes#else				/* !IPFW2, old code to generate ipfw rule */
266998943Sluigi
2670127094Sdes	/* Build generic part of the two rules */
2671127094Sdes	rule.fw_number = fwhole;
2672127094Sdes	IP_FW_SETNSRCP(&rule, 1);	/* Number of source ports. */
2673127094Sdes	IP_FW_SETNDSTP(&rule, 1);	/* Number of destination ports. */
2674127094Sdes	rule.fw_flg = IP_FW_F_ACCEPT | IP_FW_F_IN | IP_FW_F_OUT;
2675127094Sdes	rule.fw_prot = IPPROTO_TCP;
2676127094Sdes	rule.fw_smsk.s_addr = INADDR_BROADCAST;
2677127094Sdes	rule.fw_dmsk.s_addr = INADDR_BROADCAST;
267832377Seivind
2679127094Sdes	/* Build and apply specific part of the rules */
2680127094Sdes	rule.fw_src = GetOriginalAddress(link);
2681127094Sdes	rule.fw_dst = GetDestAddress(link);
2682127094Sdes	rule.fw_uar.fw_pts[0] = ntohs(GetOriginalPort(link));
2683127094Sdes	rule.fw_uar.fw_pts[1] = ntohs(GetDestPort(link));
268432377Seivind
2685127094Sdes	/*
2686127094Sdes	 * Skip non-bound links - XXX should not be strictly necessary, but
2687127094Sdes	 * seems to leave hole if not done.  Leak of non-bound links? (Code
2688127094Sdes	 * should be left even if the problem is fixed - it is a clear
2689127094Sdes	 * optimization)
2690127094Sdes	 */
2691127094Sdes	if (rule.fw_uar.fw_pts[0] != 0 && rule.fw_uar.fw_pts[1] != 0) {
2692127094Sdes		r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule);
269344616Sbrian#ifdef DEBUG
2694127094Sdes		if (r)
2695127094Sdes			err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
269644616Sbrian#endif
2697127094Sdes		rule.fw_src = GetDestAddress(link);
2698127094Sdes		rule.fw_dst = GetOriginalAddress(link);
2699127094Sdes		rule.fw_uar.fw_pts[0] = ntohs(GetDestPort(link));
2700127094Sdes		rule.fw_uar.fw_pts[1] = ntohs(GetOriginalPort(link));
2701127094Sdes		r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule);
270244616Sbrian#ifdef DEBUG
2703127094Sdes		if (r)
2704127094Sdes			err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
270544616Sbrian#endif
2706127094Sdes	}
2707127094Sdes#endif				/* !IPFW2 */
270832377Seivind/* Indicate hole applied */
2709127094Sdes	link->data.tcp->fwhole = fwhole;
2710127094Sdes	fw_setfield(la, la->fireWallField, fwhole);
271132377Seivind}
271232377Seivind
271332377Seivind/* Remove a hole in a firewall associated with a particular alias
271432377Seivind   link.  Calling this too often is harmless. */
271532377Seivindstatic void
2716124621SphkClearFWHole(struct alias_link *link)
2717124621Sphk{
2718124621Sphk
2719127094Sdes	struct libalias *la;
2720124621Sphk
2721127094Sdes	la = link->la;
2722127094Sdes	if (link->link_type == LINK_TCP) {
2723127094Sdes		int fwhole = link->data.tcp->fwhole;	/* Where is the firewall
2724127094Sdes							 * hole? */
2725127094Sdes		struct ip_fw rule;
272632377Seivind
2727127094Sdes		if (fwhole < 0)
2728127094Sdes			return;
272932377Seivind
2730127094Sdes		memset(&rule, 0, sizeof rule);	/* useless for ipfw2 */
273199623Sluigi#if IPFW2
2732127094Sdes		while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL,
2733127094Sdes		    &fwhole, sizeof fwhole));
2734127094Sdes#else				/* !IPFW2 */
2735127094Sdes		rule.fw_number = fwhole;
2736127094Sdes		while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL,
2737127094Sdes		    &rule, sizeof rule));
2738127094Sdes#endif				/* !IPFW2 */
2739127094Sdes		fw_clrfield(la, la->fireWallField, fwhole);
2740127094Sdes		link->data.tcp->fwhole = -1;
2741127094Sdes	}
274232377Seivind}
274332377Seivind
274432377Seivind/* Clear out the entire range dedicated to firewall holes. */
274532377Seivindstatic void
2746127094SdesClearAllFWHoles(struct libalias *la)
2747127094Sdes{
2748127094Sdes	struct ip_fw rule;	/* On-the-fly built rule */
2749127094Sdes	int i;
275099207Sbrian
2751127094Sdes	if (la->fireWallFD < 0)
2752127094Sdes		return;
275332377Seivind
2754127094Sdes	memset(&rule, 0, sizeof rule);
2755127094Sdes	for (i = la->fireWallBaseNum; i < la->fireWallBaseNum + la->fireWallNumNums; i++) {
275699623Sluigi#if IPFW2
2757127094Sdes		int r = i;
2758127094Sdes
2759127094Sdes		while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, &r, sizeof r));
2760127094Sdes#else				/* !IPFW2 */
2761127094Sdes		rule.fw_number = i;
2762127094Sdes		while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule));
2763127094Sdes#endif				/* !IPFW2 */
2764127094Sdes	}
2765127094Sdes	/* XXX: third arg correct here ? /phk */
2766127094Sdes	memset(la->fireWallField, 0, la->fireWallNumNums);
276732377Seivind}
2768127094Sdes
276935314Sbrian#endif
277074778Sbrian
277174778Sbrianvoid
2772127094SdesLibAliasSetFWBase(struct libalias *la, unsigned int base, unsigned int num)
2773127094Sdes{
277474778Sbrian#ifndef NO_FW_PUNCH
2775127094Sdes	la->fireWallBaseNum = base;
2776127094Sdes	la->fireWallNumNums = num;
277774778Sbrian#endif
277874778Sbrian}
2779120372Smarcus
2780120372Smarcusvoid
2781127094SdesLibAliasSetSkinnyPort(struct libalias *la, unsigned int port)
2782127094Sdes{
2783127094Sdes	la->skinnyPort = port;
2784120372Smarcus}
2785