Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/libalias/alias_db.c
Show All 23 Lines | |||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||||
* SUCH DAMAGE. | * SUCH DAMAGE. | ||||
*/ | */ | ||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
/* | |||||
Alias_db.c encapsulates all data structures used for storing | |||||
packet aliasing data. Other parts of the aliasing software | |||||
access data through functions provided in this file. | |||||
Data storage is based on the notion of a "link", which is | |||||
established for ICMP echo/reply packets, UDP datagrams and | |||||
TCP stream connections. A link stores the original source | |||||
and destination addresses. For UDP and TCP, it also stores | |||||
source and destination port numbers, as well as an alias | |||||
port number. Links are also used to store information about | |||||
fragments. | |||||
There is a facility for sweeping through and deleting old | |||||
links as new packets are sent through. A simple timeout is | |||||
used for ICMP and UDP links. TCP links are left alone unless | |||||
there is an incomplete connection, in which case the link | |||||
can be deleted after a certain amount of time. | |||||
Initial version: August, 1996 (cjm) | |||||
Version 1.4: September 16, 1996 (cjm) | |||||
Facility for handling incoming links added. | |||||
Version 1.6: September 18, 1996 (cjm) | |||||
ICMP data handling simplified. | |||||
Version 1.7: January 9, 1997 (cjm) | |||||
Fragment handling simplified. | |||||
Saves pointers for unresolved fragments. | |||||
Permits links for unspecified remote ports | |||||
or unspecified remote addresses. | |||||
Fixed bug which did not properly zero port | |||||
table entries after a link was deleted. | |||||
Cleaned up some obsolete comments. | |||||
Version 1.8: January 14, 1997 (cjm) | |||||
Fixed data type error in StartPoint(). | |||||
(This error did not exist prior to v1.7 | |||||
and was discovered and fixed by Ari Suutari) | |||||
Version 1.9: February 1, 1997 | |||||
Optionally, connections initiated from packet aliasing host | |||||
machine will will not have their port number aliased unless it | |||||
conflicts with an aliasing port already being used. (cjm) | |||||
All options earlier being #ifdef'ed are now available through | |||||
a new interface, SetPacketAliasMode(). This allows run time | |||||
control (which is now available in PPP+pktAlias through the | |||||
'alias' keyword). (ee) | |||||
Added ability to create an alias port without | |||||
either destination address or port specified. | |||||
port type = ALIAS_PORT_UNKNOWN_DEST_ALL (ee) | |||||
Removed K&R style function headers | |||||
and general cleanup. (ee) | |||||
Added packetAliasMode to replace compiler #defines's (ee) | |||||
Allocates sockets for partially specified | |||||
ports if ALIAS_USE_SOCKETS defined. (cjm) | |||||
Version 2.0: March, 1997 | |||||
SetAliasAddress() will now clean up alias links | |||||
if the aliasing address is changed. (cjm) | |||||
PacketAliasPermanentLink() function added to support permanent | |||||
links. (J. Fortes suggested the need for this.) | |||||
Examples: | |||||
(192.168.0.1, port 23) <-> alias port 6002, unknown dest addr/port | |||||
(192.168.0.2, port 21) <-> alias port 3604, known dest addr | |||||
unknown dest port | |||||
These permanent links allow for incoming connections to | |||||
machines on the local network. They can be given with a | |||||
user-chosen amount of specificity, with increasing specificity | |||||
meaning more security. (cjm) | |||||
Quite a bit of rework to the basic engine. The portTable[] | |||||
array, which kept track of which ports were in use was replaced | |||||
by a table/linked list structure. (cjm) | |||||
SetExpire() function added. (cjm) | |||||
DeleteLink() no longer frees memory association with a pointer | |||||
to a fragment (this bug was first recognized by E. Eklund in | |||||
v1.9). | |||||
Version 2.1: May, 1997 (cjm) | |||||
Packet aliasing engine reworked so that it can handle | |||||
multiple external addresses rather than just a single | |||||
host address. | |||||
PacketAliasRedirectPort() and PacketAliasRedirectAddr() | |||||
added to the API. The first function is a more generalized | |||||
version of PacketAliasPermanentLink(). The second function | |||||
implements static network address translation. | |||||
Version 3.2: July, 2000 (salander and satoh) | |||||
Added FindNewPortGroup to get contiguous range of port values. | |||||
Added QueryUdpTcpIn and QueryUdpTcpOut to look for an aliasing | |||||
link but not actually add one. | |||||
Added FindRtspOut, which is closely derived from FindUdpTcpOut, | |||||
except that the alias port (from FindNewPortGroup) is provided | |||||
as input. | |||||
See HISTORY file for additional revisions. | |||||
*/ | |||||
#ifdef _KERNEL | #ifdef _KERNEL | ||||
#include <machine/stdarg.h> | #include <machine/stdarg.h> | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
#include <sys/lock.h> | #include <sys/lock.h> | ||||
#include <sys/module.h> | #include <sys/module.h> | ||||
#include <sys/rwlock.h> | #include <sys/rwlock.h> | ||||
Show All 16 Lines | |||||
#include <netinet/libalias/alias_mod.h> | #include <netinet/libalias/alias_mod.h> | ||||
#include <net/if.h> | #include <net/if.h> | ||||
#else | #else | ||||
#include "alias.h" | #include "alias.h" | ||||
#include "alias_local.h" | #include "alias_local.h" | ||||
#include "alias_mod.h" | #include "alias_mod.h" | ||||
#endif | #endif | ||||
#include "alias_db.h" | |||||
static LIST_HEAD(, libalias) instancehead = LIST_HEAD_INITIALIZER(instancehead); | static LIST_HEAD(, libalias) instancehead = LIST_HEAD_INITIALIZER(instancehead); | ||||
int LibAliasTime; | int LibAliasTime; | ||||
/* | |||||
Constants (note: constants are also defined | |||||
near relevant functions or structs) | |||||
*/ | |||||
/* Timeouts (in seconds) for different link types */ | |||||
#define ICMP_EXPIRE_TIME 60 | |||||
#define UDP_EXPIRE_TIME 60 | |||||
#define PROTO_EXPIRE_TIME 60 | |||||
#define FRAGMENT_ID_EXPIRE_TIME 10 | |||||
#define FRAGMENT_PTR_EXPIRE_TIME 30 | |||||
/* TCP link expire time for different cases */ | |||||
/* When the link has been used and closed - minimal grace time to | |||||
allow ACKs and potential re-connect in FTP (XXX - is this allowed?) */ | |||||
#ifndef TCP_EXPIRE_DEAD | |||||
#define TCP_EXPIRE_DEAD 10 | |||||
#endif | |||||
/* When the link has been used and closed on one side - the other side | |||||
is allowed to still send data */ | |||||
#ifndef TCP_EXPIRE_SINGLEDEAD | |||||
#define TCP_EXPIRE_SINGLEDEAD 90 | |||||
#endif | |||||
/* When the link isn't yet up */ | |||||
#ifndef TCP_EXPIRE_INITIAL | |||||
#define TCP_EXPIRE_INITIAL 300 | |||||
#endif | |||||
/* When the link is up */ | |||||
#ifndef TCP_EXPIRE_CONNECTED | |||||
#define TCP_EXPIRE_CONNECTED 86400 | |||||
#endif | |||||
/* Dummy port number codes used for FindLinkIn/Out() and AddLink(). | |||||
These constants can be anything except zero, which indicates an | |||||
unknown port number. */ | |||||
#define NO_DEST_PORT 1 | |||||
#define NO_SRC_PORT 1 | |||||
/* Matches any/unknown address in FindLinkIn/Out() and AddLink(). */ | |||||
static struct in_addr const ANY_ADDR = { INADDR_ANY }; | |||||
/* Data Structures | |||||
The fundamental data structure used in this program is | |||||
"struct alias_link". Whenever a TCP connection is made, | |||||
a UDP datagram is sent out, or an ICMP echo request is made, | |||||
a link record is made (if it has not already been created). | |||||
The link record is identified by the source address/port | |||||
and the destination address/port. In the case of an ICMP | |||||
echo request, the source port is treated as being equivalent | |||||
with the 16-bit ID number of the ICMP packet. | |||||
The link record also can store some auxiliary data. For | |||||
TCP connections that have had sequence and acknowledgment | |||||
modifications, data space is available to track these changes. | |||||
A state field is used to keep track in changes to the TCP | |||||
connection state. ID numbers of fragments can also be | |||||
stored in the auxiliary space. Pointers to unresolved | |||||
fragments can also be stored. | |||||
The link records support two independent chainings. Lookup | |||||
tables for input and out tables hold the initial pointers | |||||
the link chains. On input, the lookup table indexes on alias | |||||
port and link type. On output, the lookup table indexes on | |||||
source address, destination address, source port, destination | |||||
port and link type. | |||||
*/ | |||||
/* used to save changes to ACK/sequence numbers */ | |||||
struct ack_data_record { | |||||
u_long ack_old; | |||||
u_long ack_new; | |||||
int delta; | |||||
int active; | |||||
}; | |||||
/* Information about TCP connection */ | |||||
struct tcp_state { | |||||
int in; /* State for outside -> inside */ | |||||
int out; /* State for inside -> outside */ | |||||
int index; /* Index to ACK data array */ | |||||
/* Indicates whether ACK and sequence numbers been modified */ | |||||
int ack_modified; | |||||
}; | |||||
/* Number of distinct ACK number changes | |||||
* saved for a modified TCP stream */ | |||||
#define N_LINK_TCP_DATA 3 | |||||
struct tcp_dat { | |||||
struct tcp_state state; | |||||
struct ack_data_record ack[N_LINK_TCP_DATA]; | |||||
/* Which firewall record is used for this hole? */ | |||||
int fwhole; | |||||
}; | |||||
/* LSNAT server pool (circular list) */ | |||||
struct server { | |||||
struct in_addr addr; | |||||
u_short port; | |||||
struct server *next; | |||||
}; | |||||
/* Main data structure */ | |||||
struct alias_link { | |||||
struct libalias *la; | |||||
/* Address and port information */ | |||||
struct in_addr src_addr; | |||||
struct in_addr dst_addr; | |||||
struct in_addr alias_addr; | |||||
struct in_addr proxy_addr; | |||||
u_short src_port; | |||||
u_short dst_port; | |||||
u_short alias_port; | |||||
u_short proxy_port; | |||||
struct server *server; | |||||
/* Type of link: TCP, UDP, ICMP, proto, frag */ | |||||
int link_type; | |||||
/* values for link_type */ | |||||
#define LINK_ICMP IPPROTO_ICMP | |||||
#define LINK_UDP IPPROTO_UDP | |||||
#define LINK_TCP IPPROTO_TCP | |||||
#define LINK_FRAGMENT_ID (IPPROTO_MAX + 1) | |||||
#define LINK_FRAGMENT_PTR (IPPROTO_MAX + 2) | |||||
#define LINK_ADDR (IPPROTO_MAX + 3) | |||||
#define LINK_PPTP (IPPROTO_MAX + 4) | |||||
int flags; /* indicates special characteristics */ | |||||
int pflags; /* protocol-specific flags */ | |||||
/* flag bits */ | |||||
#define LINK_UNKNOWN_DEST_PORT 0x01 | |||||
#define LINK_UNKNOWN_DEST_ADDR 0x02 | |||||
#define LINK_PERMANENT 0x04 | |||||
#define LINK_PARTIALLY_SPECIFIED 0x03 /* logical-or of first two bits */ | |||||
#define LINK_UNFIREWALLED 0x08 | |||||
int timestamp; /* Time link was last accessed */ | |||||
#ifndef NO_USE_SOCKETS | |||||
int sockfd; /* socket descriptor */ | |||||
#endif | |||||
/* Linked list of pointers for input and output lookup tables */ | |||||
union { | |||||
struct { | |||||
SPLAY_ENTRY(alias_link) out; | |||||
LIST_ENTRY (alias_link) in; | |||||
} all; | |||||
struct { | |||||
LIST_ENTRY (alias_link) list; | |||||
} pptp; | |||||
}; | |||||
struct { | |||||
TAILQ_ENTRY(alias_link) list; | |||||
int time; /* Expire time for link */ | |||||
} expire; | |||||
/* Auxiliary data */ | |||||
union { | |||||
char *frag_ptr; | |||||
struct in_addr frag_addr; | |||||
struct tcp_dat *tcp; | |||||
} data; | |||||
}; | |||||
/* Clean up procedure. */ | |||||
static void finishoff(void); | |||||
/* Kernel module definition. */ | /* Kernel module definition. */ | ||||
#ifdef _KERNEL | #ifdef _KERNEL | ||||
MALLOC_DEFINE(M_ALIAS, "libalias", "packet aliasing"); | MALLOC_DEFINE(M_ALIAS, "libalias", "packet aliasing"); | ||||
MODULE_VERSION(libalias, 1); | MODULE_VERSION(libalias, 1); | ||||
static int | static int | ||||
alias_mod_handler(module_t mod, int type, void *data) | alias_mod_handler(module_t mod, int type, void *data) | ||||
Show All 11 Lines | |||||
static moduledata_t alias_mod = { | static moduledata_t alias_mod = { | ||||
"alias", alias_mod_handler, NULL | "alias", alias_mod_handler, NULL | ||||
}; | }; | ||||
DECLARE_MODULE(alias, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND); | DECLARE_MODULE(alias, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND); | ||||
#endif | #endif | ||||
/* Internal utility routines (used only in alias_db.c) | |||||
Lookup table starting points: | |||||
StartPointIn() -- link table initial search point for | |||||
incoming packets | |||||
StartPointOut() -- link table initial search point for | |||||
outgoing packets | |||||
Miscellaneous: | |||||
SeqDiff() -- difference between two TCP sequences | |||||
ShowAliasStats() -- send alias statistics to a monitor file | |||||
*/ | |||||
/* Local prototypes */ | |||||
static struct group_in * | |||||
StartPointIn(struct libalias *, struct in_addr, u_short, int, int); | |||||
static int SeqDiff(u_long, u_long); | |||||
#ifndef NO_FW_PUNCH | |||||
/* Firewall control */ | |||||
static void InitPunchFW(struct libalias *); | |||||
static void UninitPunchFW(struct libalias *); | |||||
static void ClearFWHole(struct alias_link *); | |||||
#endif | |||||
/* Log file control */ | |||||
static void ShowAliasStats(struct libalias *); | |||||
static int InitPacketAliasLog(struct libalias *); | |||||
static void UninitPacketAliasLog(struct libalias *); | |||||
void SctpShowAliasStats(struct libalias *la); | |||||
/* Splay handling */ | |||||
static inline int | |||||
cmp_out(struct alias_link *a, struct alias_link *b) { | |||||
int i = a->src_port - b->src_port; | |||||
if (i != 0) return (i); | |||||
i = a->src_addr.s_addr - b->src_addr.s_addr; | |||||
if (i != 0) return (i); | |||||
i = a->dst_addr.s_addr - b->dst_addr.s_addr; | |||||
if (i != 0) return (i); | |||||
i = a->dst_port - b->dst_port; | |||||
if (i != 0) return (i); | |||||
i = a->link_type - b->link_type; | |||||
return (i); | |||||
} | |||||
SPLAY_PROTOTYPE(splay_out, alias_link, all.out, cmp_out); | |||||
SPLAY_GENERATE(splay_out, alias_link, all.out, cmp_out); | SPLAY_GENERATE(splay_out, alias_link, all.out, cmp_out); | ||||
static inline int | |||||
cmp_in(struct group_in *a, struct group_in *b) { | |||||
int i = a->alias_port - b->alias_port; | |||||
if (i != 0) return (i); | |||||
i = a->link_type - b->link_type; | |||||
if (i != 0) return (i); | |||||
i = a->alias_addr.s_addr - b->alias_addr.s_addr; | |||||
return (i); | |||||
} | |||||
SPLAY_PROTOTYPE(splay_in, group_in, in, cmp_in); | |||||
SPLAY_GENERATE(splay_in, group_in, in, cmp_in); | SPLAY_GENERATE(splay_in, group_in, in, cmp_in); | ||||
static struct group_in * | static struct group_in * | ||||
StartPointIn(struct libalias *la, | StartPointIn(struct libalias *la, | ||||
struct in_addr alias_addr, u_short alias_port, int link_type, | struct in_addr alias_addr, u_short alias_port, int link_type, | ||||
int create) | int create) | ||||
{ | { | ||||
struct group_in *grp; | struct group_in *grp; | ||||
▲ Show 20 Lines • Show All 78 Lines • ▼ Show 20 Lines | #endif | ||||
} | } | ||||
} | } | ||||
void SctpShowAliasStats(struct libalias *la) | void SctpShowAliasStats(struct libalias *la) | ||||
{ | { | ||||
ShowAliasStats(la); | ShowAliasStats(la); | ||||
} | } | ||||
/* Internal routines for finding, deleting and adding links | |||||
Port Allocation: | |||||
GetNewPort() -- find and reserve new alias port number | |||||
GetSocket() -- try to allocate a socket for a given port | |||||
Link creation and deletion: | |||||
CleanupAliasData() - remove all link chains from lookup table | |||||
CleanupLink() - look for a stale link | |||||
DeleteLink() - remove link | |||||
AddLink() - add link | |||||
ReLink() - change link | |||||
Link search: | |||||
FindLinkOut() - find link for outgoing packets | |||||
FindLinkIn() - find link for incoming packets | |||||
Port search: | |||||
FindNewPortGroup() - find an available group of ports | |||||
*/ | |||||
/* Local prototypes */ | |||||
static int GetNewPort(struct libalias *, struct alias_link *, int); | |||||
#ifndef NO_USE_SOCKETS | |||||
static u_short GetSocket(struct libalias *, u_short, int *, int); | |||||
#endif | |||||
static void CleanupAliasData(struct libalias *, int); | |||||
static void CleanupLink(struct libalias *, struct alias_link **, int); | |||||
static void DeleteLink(struct alias_link **, int); | |||||
static struct alias_link * | |||||
UseLink(struct libalias *, struct alias_link *); | |||||
static struct alias_link * | |||||
ReLink(struct alias_link *, | |||||
struct in_addr, struct in_addr, struct in_addr, | |||||
u_short, u_short, int, int, int); | |||||
static struct alias_link * | |||||
FindLinkOut(struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int); | |||||
static struct alias_link * | |||||
FindLinkIn(struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int); | |||||
static u_short _RandomPort(struct libalias *la); | |||||
#define GET_NEW_PORT_MAX_ATTEMPTS 20 | |||||
/* get random port in network byte order */ | /* get random port in network byte order */ | ||||
static u_short | static u_short | ||||
_RandomPort(struct libalias *la) { | _RandomPort(struct libalias *la) { | ||||
u_short port; | u_short port; | ||||
port = la->aliasPortLower + | port = la->aliasPortLower + | ||||
arc4random_uniform(la->aliasPortLength); | arc4random_uniform(la->aliasPortLength); | ||||
▲ Show 20 Lines • Show All 2,078 Lines • ▼ Show 20 Lines | fill_rule(void *buf, int bufsize, int rulenum, | ||||
rule->act_ofs = (u_int32_t *)cmd - (u_int32_t *)rule->cmd; | rule->act_ofs = (u_int32_t *)cmd - (u_int32_t *)rule->cmd; | ||||
cmd = fill_cmd(cmd, action, F_INSN_SIZE(ipfw_insn), 0, 0); | cmd = fill_cmd(cmd, action, F_INSN_SIZE(ipfw_insn), 0, 0); | ||||
rule->cmd_len = (u_int32_t *)cmd - (u_int32_t *)rule->cmd; | rule->cmd_len = (u_int32_t *)cmd - (u_int32_t *)rule->cmd; | ||||
return ((char *)cmd - (char *)buf); | return ((char *)cmd - (char *)buf); | ||||
} | } | ||||
static void ClearAllFWHoles(struct libalias *la); | |||||
#define fw_setfield(la, field, num) \ | |||||
do { \ | |||||
(field)[(num) - la->fireWallBaseNum] = 1; \ | |||||
} /*lint -save -e717 */ while(0)/* lint -restore */ | |||||
#define fw_clrfield(la, field, num) \ | |||||
do { \ | |||||
(field)[(num) - la->fireWallBaseNum] = 0; \ | |||||
} /*lint -save -e717 */ while(0)/* lint -restore */ | |||||
#define fw_tstfield(la, field, num) ((field)[(num) - la->fireWallBaseNum]) | |||||
static void | static void | ||||
InitPunchFW(struct libalias *la) | InitPunchFW(struct libalias *la) | ||||
{ | { | ||||
la->fireWallField = malloc(la->fireWallNumNums); | la->fireWallField = malloc(la->fireWallNumNums); | ||||
if (la->fireWallField) { | if (la->fireWallField) { | ||||
memset(la->fireWallField, 0, la->fireWallNumNums); | memset(la->fireWallField, 0, la->fireWallNumNums); | ||||
if (la->fireWallFD < 0) { | if (la->fireWallFD < 0) { | ||||
▲ Show 20 Lines • Show All 188 Lines • Show Last 20 Lines |