summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/libalias/HISTORY4
-rw-r--r--lib/libalias/Makefile3
-rw-r--r--lib/libalias/alias.c135
-rw-r--r--lib/libalias/alias.h3
-rw-r--r--lib/libalias/alias_db.c213
-rw-r--r--lib/libalias/alias_local.h14
-rw-r--r--lib/libalias/alias_smedia.c427
-rw-r--r--lib/libalias/libalias.323
-rw-r--r--sys/netinet/libalias/HISTORY4
-rw-r--r--sys/netinet/libalias/Makefile3
-rw-r--r--sys/netinet/libalias/alias.c135
-rw-r--r--sys/netinet/libalias/alias.h3
-rw-r--r--sys/netinet/libalias/alias_db.c213
-rw-r--r--sys/netinet/libalias/alias_local.h14
-rw-r--r--sys/netinet/libalias/alias_smedia.c427
-rw-r--r--sys/netinet/libalias/libalias.323
16 files changed, 1638 insertions, 6 deletions
diff --git a/lib/libalias/HISTORY b/lib/libalias/HISTORY
index 8760d92..c5bca59 100644
--- a/lib/libalias/HISTORY
+++ b/lib/libalias/HISTORY
@@ -139,3 +139,7 @@ Version 3.1: May, 2000 (Erik Salander, erik@whistle.com)
- Added support to alias 227 replies, allows aliasing for
FTP servers in passive mode.
- Added support for PPTP aliasing.
+
+Version 3.2: July, 2000 (Erik Salander, erik@whistle.com and
+ Junichi Satoh, junichi@junichi.org)
+ - Added support for streaming media (RTSP and PNA) aliasing.
diff --git a/lib/libalias/Makefile b/lib/libalias/Makefile
index 2ee0675..14ace0f 100644
--- a/lib/libalias/Makefile
+++ b/lib/libalias/Makefile
@@ -5,7 +5,8 @@ SHLIB_MAJOR= 4
SHLIB_MINOR= 0
CFLAGS+= -Wall -I${.CURDIR}
SRCS= alias.c alias_cuseeme.c alias_db.c alias_ftp.c alias_irc.c \
- alias_nbt.c alias_pptp.c alias_proxy.c alias_util.c
+ alias_nbt.c alias_pptp.c alias_proxy.c alias_smedia.c \
+ alias_util.c
INCS= alias.h
MAN3= libalias.3
diff --git a/lib/libalias/alias.c b/lib/libalias/alias.c
index e4770fe..d70efb8 100644
--- a/lib/libalias/alias.c
+++ b/lib/libalias/alias.c
@@ -76,9 +76,13 @@
Version 2.3 Dec 1998 (dillon)
- Major bounds checking additions, see FreeBSD/CVS
- Version 3.1 May, 2000 (eds)
+ Version 3.1 May, 2000 (salander)
- Added hooks to handle PPTP.
+ Version 3.2 July, 2000 (salander and satoh)
+ - Added PacketUnaliasOut routine.
+ - Added hooks to handle RTSP/RTP.
+
See HISTORY file for additional revisions.
$FreeBSD$
@@ -102,6 +106,8 @@
#define IRC_CONTROL_PORT_NUMBER_1 6667
#define IRC_CONTROL_PORT_NUMBER_2 6668
#define CUSEEME_PORT_NUMBER 7648
+#define RTSP_CONTROL_PORT_NUMBER_1 554
+#define RTSP_CONTROL_PORT_NUMBER_2 7070
#define PPTP_CONTROL_PORT_NUMBER 1723
@@ -1112,6 +1118,11 @@ TcpAliasOut(struct ip *pip, int maxpacketsize)
else if (ntohs(tc->th_dport) == IRC_CONTROL_PORT_NUMBER_1
|| ntohs(tc->th_dport) == IRC_CONTROL_PORT_NUMBER_2)
AliasHandleIrcOut(pip, link, maxpacketsize);
+ else if (ntohs(tc->th_dport) == RTSP_CONTROL_PORT_NUMBER_1
+ || ntohs(tc->th_sport) == RTSP_CONTROL_PORT_NUMBER_1
+ || ntohs(tc->th_dport) == RTSP_CONTROL_PORT_NUMBER_2
+ || ntohs(tc->th_sport) == RTSP_CONTROL_PORT_NUMBER_2)
+ AliasHandleRtspOut(pip, link, maxpacketsize);
else if (ntohs(tc->th_dport) == PPTP_CONTROL_PORT_NUMBER
|| ntohs(tc->th_sport) == PPTP_CONTROL_PORT_NUMBER)
AliasHandlePptpOut(pip, link);
@@ -1236,6 +1247,7 @@ FragmentOut(struct ip *pip)
PacketAliasFragmentIn()
PacketAliasIn()
PacketAliasOut()
+ PacketUnaliasOut()
(prototypes in alias.h)
*/
@@ -1465,3 +1477,124 @@ PacketAliasOut(char *ptr, /* valid IP packet */
SetDefaultAliasAddress(addr_save);
return(iresult);
}
+
+int
+PacketUnaliasOut(char *ptr, /* valid IP packet */
+ int maxpacketsize /* for error checking */
+ )
+{
+ struct ip *pip;
+ struct icmp *ic;
+ struct udphdr *ud;
+ struct tcphdr *tc;
+ struct alias_link *link;
+ int iresult = PKT_ALIAS_IGNORED;
+
+ pip = (struct ip *) ptr;
+
+ /* Defense against mangled packets */
+ if (ntohs(pip->ip_len) > maxpacketsize
+ || (pip->ip_hl<<2) > maxpacketsize)
+ return(iresult);
+
+ ud = (struct udphdr *) ((char *) pip + (pip->ip_hl << 2));
+ tc = (struct tcphdr *) ud;
+ ic = (struct icmp *) ud;
+
+ /* Find a link */
+ if (pip->ip_p == IPPROTO_UDP)
+ link = QueryUdpTcpIn(pip->ip_dst, pip->ip_src,
+ ud->uh_dport, ud->uh_sport,
+ IPPROTO_UDP);
+ else if (pip->ip_p == IPPROTO_TCP)
+ link = QueryUdpTcpIn(pip->ip_dst, pip->ip_src,
+ tc->th_dport, tc->th_sport,
+ IPPROTO_TCP);
+ else if (pip->ip_p == IPPROTO_ICMP)
+ link = FindIcmpIn(pip->ip_dst, pip->ip_src, ic->icmp_id);
+ else
+ link = NULL;
+
+ /* Change it from an aliased packet to an unaliased packet */
+ if (link != NULL)
+ {
+ if (pip->ip_p == IPPROTO_UDP || pip->ip_p == IPPROTO_TCP)
+ {
+ u_short *sptr;
+ int accumulate;
+ struct in_addr original_address;
+ u_short original_port;
+
+ original_address = GetOriginalAddress(link);
+ original_port = GetOriginalPort(link);
+
+ /* Adjust TCP/UDP checksum */
+ sptr = (u_short *) &(pip->ip_src);
+ accumulate = *sptr++;
+ accumulate += *sptr;
+ sptr = (u_short *) &original_address;
+ accumulate -= *sptr++;
+ accumulate -= *sptr;
+
+ if (pip->ip_p == IPPROTO_UDP) {
+ accumulate += ud->uh_sport;
+ accumulate -= original_port;
+ ADJUST_CHECKSUM(accumulate, ud->uh_sum)
+ } else {
+ accumulate += tc->th_sport;
+ accumulate -= original_port;
+ ADJUST_CHECKSUM(accumulate, tc->th_sum)
+ }
+
+ /* Adjust IP checksum */
+ DifferentialChecksum(&pip->ip_sum,
+ (u_short *) &original_address,
+ (u_short *) &pip->ip_src,
+ 2);
+
+ /* Un-alias source address and port number */
+ pip->ip_src = original_address;
+ if (pip->ip_p == IPPROTO_UDP)
+ ud->uh_sport = original_port;
+ else
+ tc->th_sport = original_port;
+
+ iresult = PKT_ALIAS_OK;
+
+ } else if (pip->ip_p == IPPROTO_ICMP) {
+
+ u_short *sptr;
+ int accumulate;
+ struct in_addr original_address;
+ u_short original_id;
+
+ original_address = GetOriginalAddress(link);
+ original_id = GetOriginalPort(link);
+
+ /* Adjust ICMP checksum */
+ sptr = (u_short *) &(pip->ip_src);
+ accumulate = *sptr++;
+ accumulate += *sptr;
+ sptr = (u_short *) &original_address;
+ accumulate -= *sptr++;
+ accumulate -= *sptr;
+ accumulate += ic->icmp_id;
+ accumulate -= original_id;
+ ADJUST_CHECKSUM(accumulate, ic->icmp_cksum)
+
+ /* Adjust IP checksum */
+ DifferentialChecksum(&pip->ip_sum,
+ (u_short *) &original_address,
+ (u_short *) &pip->ip_src,
+ 2);
+
+ /* Un-alias source address and port number */
+ pip->ip_src = original_address;
+ ic->icmp_id = original_id;
+
+ iresult = PKT_ALIAS_OK;
+ }
+ }
+ return(iresult);
+
+}
diff --git a/lib/libalias/alias.h b/lib/libalias/alias.h
index 61f759f..8785999 100644
--- a/lib/libalias/alias.h
+++ b/lib/libalias/alias.h
@@ -44,6 +44,9 @@ struct alias_link;
extern int
PacketAliasOut(char *, int maxpacketsize);
+ extern int
+ PacketUnaliasOut(char *, int maxpacketsize);
+
/* Port and Address Redirection */
extern struct alias_link *
PacketAliasRedirectPort(struct in_addr, u_short,
diff --git a/lib/libalias/alias_db.c b/lib/libalias/alias_db.c
index f8baa71..8cf7da5 100644
--- a/lib/libalias/alias_db.c
+++ b/lib/libalias/alias_db.c
@@ -103,6 +103,16 @@
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.
$FreeBSD$
@@ -500,6 +510,9 @@ Link creation and deletion:
Link search:
FindLinkOut() - find link for outgoing packets
FindLinkIn() - find link for incoming packets
+
+Port search:
+ FindNewPortGroup() - find an available group of ports
*/
/* Local prototypes */
@@ -531,11 +544,14 @@ FindLinkIn(struct in_addr, struct in_addr, u_short, u_short, int, int);
#define ALIAS_PORT_BASE 0x08000
#define ALIAS_PORT_MASK 0x07fff
+#define ALIAS_PORT_MASK_EVEN 0x07ffe
#define GET_NEW_PORT_MAX_ATTEMPTS 20
#define GET_ALIAS_PORT -1
#define GET_ALIAS_ID GET_ALIAS_PORT
+#define FIND_EVEN_ALIAS_BASE 1
+
/* GetNewPort() allocates port numbers. Note that if a port number
is already in use, that does not mean that it cannot be used by
another link concurrently. This is because GetNewPort() looks for
@@ -704,6 +720,102 @@ GetSocket(u_short port_net, int *sockfd, int link_type)
}
+/* FindNewPortGroup() returns a base port number for an available
+ range of contiguous port numbers. Note that if a port number
+ is already in use, that does not mean that it cannot be used by
+ another link concurrently. This is because FindNewPortGroup()
+ looks for unused triplets: (dest addr, dest port, alias port). */
+
+int
+FindNewPortGroup(struct in_addr dst_addr,
+ struct in_addr alias_addr,
+ u_short src_port,
+ u_short dst_port,
+ u_short port_count,
+ u_char proto,
+ u_char align)
+{
+ int i, j;
+ int max_trials;
+ u_short port_sys;
+ int link_type;
+
+ /*
+ * Get link_type from protocol
+ */
+
+ switch (proto)
+ {
+ case IPPROTO_UDP:
+ link_type = LINK_UDP;
+ break;
+ case IPPROTO_TCP:
+ link_type = LINK_TCP;
+ break;
+ default:
+ return (0);
+ break;
+ }
+
+ /*
+ * The aliasing port is automatically selected
+ * by one of two methods below:
+ */
+ max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
+
+ if (packetAliasMode & PKT_ALIAS_SAME_PORTS) {
+ /*
+ * When the ALIAS_SAME_PORTS option is
+ * chosen, the first try will be the
+ * actual source port. If this is already
+ * in use, the remainder of the trials
+ * will be random.
+ */
+ port_sys = ntohs(src_port);
+
+ } else {
+
+ /* First trial and all subsequent are random. */
+ if (align == FIND_EVEN_ALIAS_BASE)
+ port_sys = random() & ALIAS_PORT_MASK_EVEN;
+ else
+ port_sys = random() & ALIAS_PORT_MASK;
+
+ port_sys += ALIAS_PORT_BASE;
+ }
+
+/* Port number search */
+ for (i = 0; i < max_trials; i++) {
+
+ struct alias_link *search_result;
+
+ for (j = 0; j < port_count; j++)
+ if (0 != (search_result = FindLinkIn(dst_addr, alias_addr,
+ dst_port, htons(port_sys + j),
+ link_type, 0)))
+ break;
+
+ /* Found a good range, return base */
+ if (j == port_count)
+ return (htons(port_sys));
+
+ /* Find a new base to try */
+ if (align == FIND_EVEN_ALIAS_BASE)
+ port_sys = random() & ALIAS_PORT_MASK_EVEN;
+ else
+ port_sys = random() & ALIAS_PORT_MASK;
+
+ port_sys += ALIAS_PORT_BASE;
+ }
+
+#ifdef DEBUG
+ fprintf(stderr, "PacketAlias/FindNewPortGroup(): ");
+ fprintf(stderr, "could not find free port(s)\n");
+#endif
+
+ return(0);
+}
+
static void
CleanupAliasData(void)
{
@@ -1600,6 +1712,107 @@ FindPptpOut(struct in_addr src_addr,
}
+struct alias_link *
+QueryUdpTcpIn(struct in_addr dst_addr,
+ struct in_addr alias_addr,
+ u_short dst_port,
+ u_short alias_port,
+ u_char proto)
+{
+ int link_type;
+ struct alias_link *link;
+
+ switch (proto)
+ {
+ case IPPROTO_UDP:
+ link_type = LINK_UDP;
+ break;
+ case IPPROTO_TCP:
+ link_type = LINK_TCP;
+ break;
+ default:
+ return NULL;
+ break;
+ }
+
+ link = FindLinkIn(dst_addr, alias_addr,
+ dst_port, alias_port,
+ link_type, 0);
+
+ return(link);
+}
+
+
+struct alias_link *
+QueryUdpTcpOut(struct in_addr src_addr,
+ struct in_addr dst_addr,
+ u_short src_port,
+ u_short dst_port,
+ u_char proto)
+{
+ int link_type;
+ struct alias_link *link;
+
+ switch (proto)
+ {
+ case IPPROTO_UDP:
+ link_type = LINK_UDP;
+ break;
+ case IPPROTO_TCP:
+ link_type = LINK_TCP;
+ break;
+ default:
+ return NULL;
+ break;
+ }
+
+ link = FindLinkOut(src_addr, dst_addr,
+ src_port, dst_port,
+ link_type, 0);
+
+ return(link);
+}
+
+
+struct alias_link *
+FindRtspOut(struct in_addr src_addr,
+ struct in_addr dst_addr,
+ u_short src_port,
+ u_short alias_port,
+ u_char proto)
+{
+ int link_type;
+ struct alias_link *link;
+
+ switch (proto)
+ {
+ case IPPROTO_UDP:
+ link_type = LINK_UDP;
+ break;
+ case IPPROTO_TCP:
+ link_type = LINK_TCP;
+ break;
+ default:
+ return NULL;
+ break;
+ }
+
+ link = FindLinkOut(src_addr, dst_addr, src_port, 0, link_type, 1);
+
+ if (link == NULL)
+ {
+ struct in_addr alias_addr;
+
+ alias_addr = FindAliasAddress(src_addr);
+ link = AddLink(src_addr, dst_addr, alias_addr,
+ src_port, 0, alias_port,
+ link_type);
+ }
+
+ return(link);
+}
+
+
struct in_addr
FindOriginalAddress(struct in_addr alias_addr)
{
diff --git a/lib/libalias/alias_local.h b/lib/libalias/alias_local.h
index 439c9ea..f916d21 100644
--- a/lib/libalias/alias_local.h
+++ b/lib/libalias/alias_local.h
@@ -113,6 +113,15 @@ FindPptpIn(struct in_addr, struct in_addr, u_short);
struct alias_link *
FindPptpOut(struct in_addr, struct in_addr, u_short);
+struct alias_link *
+QueryUdpTcpIn (struct in_addr, struct in_addr, u_short, u_short, u_char);
+
+struct alias_link *
+QueryUdpTcpOut(struct in_addr, struct in_addr, u_short, u_short, u_char);
+
+struct alias_link *
+FindRtspOut(struct in_addr, struct in_addr, u_short, u_short, u_char);
+
struct in_addr
FindOriginalAddress(struct in_addr);
@@ -120,6 +129,8 @@ struct in_addr
FindAliasAddress(struct in_addr);
/* External data access/modification */
+int FindNewPortGroup(struct in_addr, struct in_addr,
+ u_short, u_short, u_short, u_char, u_char);
void GetFragmentAddr(struct alias_link *, struct in_addr *);
void SetFragmentAddr(struct alias_link *, struct in_addr);
void GetFragmentPtr(struct alias_link *, char **);
@@ -165,6 +176,9 @@ void AliasHandleFtpOut(struct ip *, struct alias_link *, int);
/* IRC routines */
void AliasHandleIrcOut(struct ip *, struct alias_link *, int);
+/* RTSP routines */
+void AliasHandleRtspOut(struct ip *, struct alias_link *, int);
+
/* PPTP routines */
int PptpGetCallID(struct ip *, u_short *);
void PptpSetCallID(struct ip *, u_short);
diff --git a/lib/libalias/alias_smedia.c b/lib/libalias/alias_smedia.c
new file mode 100644
index 0000000..2b9ca5f
--- /dev/null
+++ b/lib/libalias/alias_smedia.c
@@ -0,0 +1,427 @@
+/*
+ * alias_smedia.c
+ *
+ * Copyright (c) 2000 Whistle Communications, Inc.
+ * All rights reserved.
+ *
+ * Subject to the following obligations and disclaimer of warranty, use and
+ * redistribution of this software, in source or object code forms, with or
+ * without modifications are expressly permitted by Whistle Communications;
+ * provided, however, that:
+ * 1. Any and all reproductions of the source or object code must include the
+ * copyright notice above and the following disclaimer of warranties; and
+ * 2. No rights are granted, in any manner or form, to use Whistle
+ * Communications, Inc. trademarks, including the mark "WHISTLE
+ * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+ * such appears in the above copyright notice or in the software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+ * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+ * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+ * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+ * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+ * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+ * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+ * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Copyright (c) 2000 Junichi SATOH <junichi@astec.co.jp>
+ * <junichi@junichi.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Authors: Erik Salander <erik@whistle.com>
+ * Junichi SATOH <junichi@astec.co.jp>
+ * <junichi@junichi.org>
+ *
+ * $FreeBSD$
+ */
+
+/*
+ Alias_smedia.c is meant to contain the aliasing code for streaming media
+ protocols. It performs special processing for RSTP sessions under TCP.
+ Specifically, when a SETUP request is sent by a client, or a 200 reply
+ is sent by a server, it is intercepted and modified. The address is
+ changed to the gateway machine and an aliasing port is used.
+
+ More specifically, the "client_port" configuration parameter is
+ parsed for SETUP requests. The "server_port" configuration parameter is
+ parsed for 200 replies eminating from a server. This is intended to handle
+ the unicast case.
+
+ RTSP also allows a redirection of a stream to another client by using the
+ "destination" configuration parameter. The destination config parm would
+ indicate a different IP address. This function is NOT supported by the
+ RTSP translation code below.
+
+ The RTSP multicast functions without any address translation intervention.
+
+ For this routine to work, the SETUP/200 must fit entirely
+ into a single TCP packet. This is typically the case, but exceptions
+ can easily be envisioned under the actual specifications.
+
+ Probably the most troubling aspect of the approach taken here is
+ that the new SETUP/200 will typically be a different length, and
+ this causes a certain amount of bookkeeping to keep track of the
+ changes of sequence and acknowledgment numbers, since the client
+ machine is totally unaware of the modification to the TCP stream.
+
+ Initial version: May, 2000 (eds)
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+
+#include "alias_local.h"
+
+#define RTSP_CONTROL_PORT_NUMBER_1 554
+#define RTSP_CONTROL_PORT_NUMBER_2 7070
+#define RTSP_PORT_GROUP 2
+
+#define ISDIGIT(a) (((a) >= '0') && ((a) <= '9'))
+
+int search_string(char *data, int dlen, char *search_str)
+{
+ int i, j, k;
+ int search_str_len;
+
+ search_str_len = strlen(search_str);
+ for (i = 0; i < dlen - search_str_len; i++) {
+ for (j = i, k = 0; j < dlen - search_str_len; j++, k++) {
+ if (data[j] != search_str[k] &&
+ data[j] != search_str[k] - ('a' - 'A')) {
+ break;
+ }
+ if (k == search_str_len - 1) {
+ return j + 1;
+ }
+ }
+ }
+ return -1;
+}
+
+int alias_rtsp_out(struct ip *pip,
+ struct alias_link *link,
+ char *data,
+ char *port_str)
+{
+ int hlen, tlen, dlen;
+ struct tcphdr *tc;
+ int i, j, pos, state, port_dlen, new_dlen, delta;
+ u_short p[2], new_len;
+ u_short sport, eport, base_port;
+ u_short salias = 0, ealias = 0, base_alias = 0;
+ char *transport_str = "transport:";
+ char newdata[2048], *port_data, *port_newdata, stemp[80];
+ int links_created = 0, pkt_updated = 0;
+ struct alias_link *rtsp_link = NULL;
+ struct in_addr null_addr;
+
+ /* Calculate data length of TCP packet */
+ tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
+ hlen = (pip->ip_hl + tc->th_off) << 2;
+ tlen = ntohs(pip->ip_len);
+ dlen = tlen - hlen;
+
+ /* Find keyword, "Transport: " */
+ pos = search_string(data, dlen, transport_str);
+ if (pos < 0) {
+ return -1;
+ }
+ port_data = data + pos;
+ port_dlen = dlen - pos;
+
+ memcpy(newdata, data, pos);
+ port_newdata = newdata + pos;
+
+ while (port_dlen > strlen(port_str)) {
+ /* Find keyword, appropriate port string */
+ pos = search_string(port_data, port_dlen, port_str);
+ if (pos < 0) {
+ break;
+ }
+
+ memcpy (port_newdata, port_data, pos + 1);
+ port_newdata += (pos + 1);
+
+ p[0] = p[1] = 0;
+ sport = eport = 0;
+ state = 0;
+ for (i = pos; i < port_dlen; i++) {
+ switch(state) {
+ case 0:
+ if (port_data[i] == '=') {
+ state++;
+ }
+ break;
+ case 1:
+ if (ISDIGIT(port_data[i])) {
+ p[0] = p[0] * 10 + port_data[i] - '0';
+ } else {
+ if (port_data[i] == ';') {
+ state = 3;
+ }
+ if (port_data[i] == '-') {
+ state++;
+ }
+ }
+ break;
+ case 2:
+ if (ISDIGIT(port_data[i])) {
+ p[1] = p[1] * 10 + port_data[i] - '0';
+ } else {
+ state++;
+ }
+ break;
+ case 3:
+ base_port = p[0];
+ sport = htons(p[0]);
+ eport = htons(p[1]);
+
+ if (!links_created) {
+
+ links_created = 1;
+ /* Find an even numbered port number base that
+ satisfies the contiguous number of ports we need */
+ null_addr.s_addr = 0;
+ if (0 == (salias = FindNewPortGroup(null_addr,
+ FindAliasAddress(pip->ip_src),
+ sport, 0,
+ RTSP_PORT_GROUP,
+ IPPROTO_UDP, 1))) {
+#ifdef DEBUG
+ fprintf(stderr,
+ "PacketAlias/RTSP: Cannot find contiguous RTSP data ports\n");
+#endif
+ } else {
+
+ base_alias = ntohs(salias);
+ for (j = 0; j < RTSP_PORT_GROUP; j++) {
+ /* Establish link to port found in RTSP packet */
+ rtsp_link = FindRtspOut(GetOriginalAddress(link), null_addr,
+ htons(base_port + j), htons(base_alias + j),
+ IPPROTO_UDP);
+ if (rtsp_link != NULL) {
+#ifndef NO_FW_PUNCH
+ /* Punch hole in firewall */
+ PunchFWHole(rtsp_link);
+#endif
+ } else {
+#ifdef DEBUG
+ fprintf(stderr,
+ "PacketAlias/RTSP: Cannot allocate RTSP data ports\n");
+#endif
+ break;
+ }
+ }
+ }
+ ealias = htons(base_alias + (RTSP_PORT_GROUP - 1));
+ }
+
+ if (salias && rtsp_link) {
+
+ pkt_updated = 1;
+
+ /* Copy into IP packet */
+ sprintf(stemp, "%d", ntohs(salias));
+ memcpy(port_newdata, stemp, strlen(stemp));
+ port_newdata += strlen(stemp);
+
+ if (eport != 0) {
+ *port_newdata = '-';
+ port_newdata++;
+
+ /* Copy into IP packet */
+ sprintf(stemp, "%d", ntohs(ealias));
+ memcpy(port_newdata, stemp, strlen(stemp));
+ port_newdata += strlen(stemp);
+ }
+
+ *port_newdata = ';';
+ port_newdata++;
+ }
+ state++;
+ break;
+ }
+ if (state > 3) {
+ break;
+ }
+ }
+ port_data += i;
+ port_dlen -= i;
+ }
+
+ if (!pkt_updated)
+ return -1;
+
+ memcpy (port_newdata, port_data, port_dlen);
+ port_newdata += port_dlen;
+ *port_newdata = '\0';
+
+ /* Create new packet */
+ new_dlen = port_newdata - newdata;
+ memcpy (data, newdata, new_dlen);
+
+ SetAckModified(link);
+ delta = GetDeltaSeqOut(pip, link);
+ AddSeq(pip, link, delta + new_dlen - dlen);
+
+ new_len = htons(hlen + new_dlen);
+ DifferentialChecksum(&pip->ip_sum,
+ &new_len,
+ &pip->ip_len,
+ 1);
+ pip->ip_len = new_len;
+
+ tc->th_sum = 0;
+ tc->th_sum = TcpChecksum(pip);
+
+ return 0;
+}
+
+/* Support the protocol used by early versions of RealPlayer */
+
+int alias_pna_out(struct ip *pip,
+ struct alias_link *link,
+ char *data,
+ int dlen)
+{
+ struct alias_link *pna_links;
+ u_short msg_id, msg_len;
+ char *work;
+ u_short alias_port, port;
+ struct tcphdr *tc;
+
+ work = data;
+ work += 5;
+ while (work + 4 < data + dlen) {
+ memcpy(&msg_id, work, 2);
+ work += 2;
+ memcpy(&msg_len, work, 2);
+ work += 2;
+ if (ntohs(msg_id) == 0) {
+ /* end of options */
+ return 0;
+ }
+ if ((ntohs(msg_id) == 1) || (ntohs(msg_id) == 7)) {
+ memcpy((char*)&port, (char*)work, 2);
+ pna_links = FindUdpTcpOut(pip->ip_src, GetDestAddress(link),
+ port, 0, IPPROTO_UDP);
+ if (pna_links != NULL) {
+#ifndef NO_FW_PUNCH
+ /* Punch hole in firewall */
+ PunchFWHole(pna_links);
+#endif
+ tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
+ alias_port = GetAliasPort(pna_links);
+ memcpy((char*)work, (char*)&alias_port, 2);
+
+ /* Compute TCP checksum for revised packet */
+ tc->th_sum = 0;
+ tc->th_sum = TcpChecksum(pip);
+ }
+ }
+ work += ntohs(msg_len);
+ }
+
+ return 0;
+}
+
+void
+AliasHandleRtspOut(struct ip *pip, struct alias_link *link, int maxpacketsize)
+{
+ int hlen, tlen, dlen;
+ struct tcphdr *tc;
+ char *data, *setup = "SETUP", *pna = "PNA", *str200 = "200", *okstr = "OK";
+ char *client_port_str = "client_port", *server_port_str = "server_port";
+ int i, parseOk;
+
+ tc = (struct tcphdr *)((char *)pip + (pip->ip_hl << 2));
+ hlen = (pip->ip_hl + tc->th_off) << 2;
+ tlen = ntohs(pip->ip_len);
+ dlen = tlen - hlen;
+
+ data = (char*)pip;
+ data += hlen;
+
+ /* When aliasing a client, check for the SETUP request */
+ if ((ntohs(tc->th_dport) == RTSP_CONTROL_PORT_NUMBER_1) ||
+ (ntohs(tc->th_dport) == RTSP_CONTROL_PORT_NUMBER_2)) {
+
+ if (dlen >= strlen(setup)) {
+ if (memcmp(data, setup, strlen(setup)) == 0) {
+ alias_rtsp_out(pip, link, data, client_port_str);
+ return;
+ }
+ }
+ if (dlen >= strlen(pna)) {
+ if (memcmp(data, pna, strlen(pna)) == 0) {
+ alias_pna_out(pip, link, data, dlen);
+ }
+ }
+
+ } else {
+
+ /* When aliasing a server, check for the 200 reply
+ Accomodate varying number of blanks between 200 & OK */
+
+ if (dlen >= strlen(str200)) {
+
+ for (parseOk = 0, i = 0;
+ i <= dlen - strlen(str200);
+ i++) {
+ if (memcmp(&data[i], str200, strlen(str200)) == 0) {
+ parseOk = 1;
+ break;
+ }
+ }
+ if (parseOk) {
+
+ i += strlen(str200); /* skip string found */
+ while(data[i] == ' ') /* skip blank(s) */
+ i++;
+
+ if ((dlen - i) >= strlen(okstr)) {
+
+ if (memcmp(&data[i], okstr, strlen(okstr)) == 0)
+ alias_rtsp_out(pip, link, data, server_port_str);
+
+ }
+ }
+ }
+ }
+}
diff --git a/lib/libalias/libalias.3 b/lib/libalias/libalias.3
index 4c06d98..0090387 100644
--- a/lib/libalias/libalias.3
+++ b/lib/libalias/libalias.3
@@ -808,6 +808,25 @@ If the checksum is valid,
.Fn PacketAliasInternetChecksum
will return zero.
.Ed
+.Pp
+.Ft int
+.Fn PacketUnaliasOut "char *buffer" "int maxpacketsize"
+.Bd -ragged -offset indent
+An outgoing packet, which has already been aliased, has its private address/port
+information restored by this function.
+The IP packet is pointed to by
+.Fa buffer ,
+and
+.Fa maxpacketsize
+is provided for error checking purposes.
+This function can be used if an already-aliased packet needs to have its
+original IP header restored for further processing (eg. logging).
+.Ed
+.Sh BUGS
+PPTP aliasing does not work when more than one internal client
+connects to the same external server at the same time, because
+PPTP requires a single TCP control connection to be established
+between any two IP addresses.
.Sh AUTHORS
.An Charles Mott Aq cmott@scientech.com ,
versions 1.0 - 1.8, 2.0 - 2.4.
@@ -816,7 +835,9 @@ versions 1.8b, 1.9 and 2.5.
Added IRC DCC support as well as contributing a number of architectural
improvements; added the firewall bypass for FTP/IRC DCC.
.An Erik Salander Aq erik@whistle.com
-added support for PPTP.
+added support for PPTP and RTSP.
+.An Junichi Satoh Aq junichi@junichi.org
+added support for RTSP/PNA.
.Sh ACKNOWLEDGMENTS
Listed below, in approximate chronological order, are individuals who
have provided valuable comments and/or debugging assistance.
diff --git a/sys/netinet/libalias/HISTORY b/sys/netinet/libalias/HISTORY
index 8760d92..c5bca59 100644
--- a/sys/netinet/libalias/HISTORY
+++ b/sys/netinet/libalias/HISTORY
@@ -139,3 +139,7 @@ Version 3.1: May, 2000 (Erik Salander, erik@whistle.com)
- Added support to alias 227 replies, allows aliasing for
FTP servers in passive mode.
- Added support for PPTP aliasing.
+
+Version 3.2: July, 2000 (Erik Salander, erik@whistle.com and
+ Junichi Satoh, junichi@junichi.org)
+ - Added support for streaming media (RTSP and PNA) aliasing.
diff --git a/sys/netinet/libalias/Makefile b/sys/netinet/libalias/Makefile
index 2ee0675..14ace0f 100644
--- a/sys/netinet/libalias/Makefile
+++ b/sys/netinet/libalias/Makefile
@@ -5,7 +5,8 @@ SHLIB_MAJOR= 4
SHLIB_MINOR= 0
CFLAGS+= -Wall -I${.CURDIR}
SRCS= alias.c alias_cuseeme.c alias_db.c alias_ftp.c alias_irc.c \
- alias_nbt.c alias_pptp.c alias_proxy.c alias_util.c
+ alias_nbt.c alias_pptp.c alias_proxy.c alias_smedia.c \
+ alias_util.c
INCS= alias.h
MAN3= libalias.3
diff --git a/sys/netinet/libalias/alias.c b/sys/netinet/libalias/alias.c
index e4770fe..d70efb8 100644
--- a/sys/netinet/libalias/alias.c
+++ b/sys/netinet/libalias/alias.c
@@ -76,9 +76,13 @@
Version 2.3 Dec 1998 (dillon)
- Major bounds checking additions, see FreeBSD/CVS
- Version 3.1 May, 2000 (eds)
+ Version 3.1 May, 2000 (salander)
- Added hooks to handle PPTP.
+ Version 3.2 July, 2000 (salander and satoh)
+ - Added PacketUnaliasOut routine.
+ - Added hooks to handle RTSP/RTP.
+
See HISTORY file for additional revisions.
$FreeBSD$
@@ -102,6 +106,8 @@
#define IRC_CONTROL_PORT_NUMBER_1 6667
#define IRC_CONTROL_PORT_NUMBER_2 6668
#define CUSEEME_PORT_NUMBER 7648
+#define RTSP_CONTROL_PORT_NUMBER_1 554
+#define RTSP_CONTROL_PORT_NUMBER_2 7070
#define PPTP_CONTROL_PORT_NUMBER 1723
@@ -1112,6 +1118,11 @@ TcpAliasOut(struct ip *pip, int maxpacketsize)
else if (ntohs(tc->th_dport) == IRC_CONTROL_PORT_NUMBER_1
|| ntohs(tc->th_dport) == IRC_CONTROL_PORT_NUMBER_2)
AliasHandleIrcOut(pip, link, maxpacketsize);
+ else if (ntohs(tc->th_dport) == RTSP_CONTROL_PORT_NUMBER_1
+ || ntohs(tc->th_sport) == RTSP_CONTROL_PORT_NUMBER_1
+ || ntohs(tc->th_dport) == RTSP_CONTROL_PORT_NUMBER_2
+ || ntohs(tc->th_sport) == RTSP_CONTROL_PORT_NUMBER_2)
+ AliasHandleRtspOut(pip, link, maxpacketsize);
else if (ntohs(tc->th_dport) == PPTP_CONTROL_PORT_NUMBER
|| ntohs(tc->th_sport) == PPTP_CONTROL_PORT_NUMBER)
AliasHandlePptpOut(pip, link);
@@ -1236,6 +1247,7 @@ FragmentOut(struct ip *pip)
PacketAliasFragmentIn()
PacketAliasIn()
PacketAliasOut()
+ PacketUnaliasOut()
(prototypes in alias.h)
*/
@@ -1465,3 +1477,124 @@ PacketAliasOut(char *ptr, /* valid IP packet */
SetDefaultAliasAddress(addr_save);
return(iresult);
}
+
+int
+PacketUnaliasOut(char *ptr, /* valid IP packet */
+ int maxpacketsize /* for error checking */
+ )
+{
+ struct ip *pip;
+ struct icmp *ic;
+ struct udphdr *ud;
+ struct tcphdr *tc;
+ struct alias_link *link;
+ int iresult = PKT_ALIAS_IGNORED;
+
+ pip = (struct ip *) ptr;
+
+ /* Defense against mangled packets */
+ if (ntohs(pip->ip_len) > maxpacketsize
+ || (pip->ip_hl<<2) > maxpacketsize)
+ return(iresult);
+
+ ud = (struct udphdr *) ((char *) pip + (pip->ip_hl << 2));
+ tc = (struct tcphdr *) ud;
+ ic = (struct icmp *) ud;
+
+ /* Find a link */
+ if (pip->ip_p == IPPROTO_UDP)
+ link = QueryUdpTcpIn(pip->ip_dst, pip->ip_src,
+ ud->uh_dport, ud->uh_sport,
+ IPPROTO_UDP);
+ else if (pip->ip_p == IPPROTO_TCP)
+ link = QueryUdpTcpIn(pip->ip_dst, pip->ip_src,
+ tc->th_dport, tc->th_sport,
+ IPPROTO_TCP);
+ else if (pip->ip_p == IPPROTO_ICMP)
+ link = FindIcmpIn(pip->ip_dst, pip->ip_src, ic->icmp_id);
+ else
+ link = NULL;
+
+ /* Change it from an aliased packet to an unaliased packet */
+ if (link != NULL)
+ {
+ if (pip->ip_p == IPPROTO_UDP || pip->ip_p == IPPROTO_TCP)
+ {
+ u_short *sptr;
+ int accumulate;
+ struct in_addr original_address;
+ u_short original_port;
+
+ original_address = GetOriginalAddress(link);
+ original_port = GetOriginalPort(link);
+
+ /* Adjust TCP/UDP checksum */
+ sptr = (u_short *) &(pip->ip_src);
+ accumulate = *sptr++;
+ accumulate += *sptr;
+ sptr = (u_short *) &original_address;
+ accumulate -= *sptr++;
+ accumulate -= *sptr;
+
+ if (pip->ip_p == IPPROTO_UDP) {
+ accumulate += ud->uh_sport;
+ accumulate -= original_port;
+ ADJUST_CHECKSUM(accumulate, ud->uh_sum)
+ } else {
+ accumulate += tc->th_sport;
+ accumulate -= original_port;
+ ADJUST_CHECKSUM(accumulate, tc->th_sum)
+ }
+
+ /* Adjust IP checksum */
+ DifferentialChecksum(&pip->ip_sum,
+ (u_short *) &original_address,
+ (u_short *) &pip->ip_src,
+ 2);
+
+ /* Un-alias source address and port number */
+ pip->ip_src = original_address;
+ if (pip->ip_p == IPPROTO_UDP)
+ ud->uh_sport = original_port;
+ else
+ tc->th_sport = original_port;
+
+ iresult = PKT_ALIAS_OK;
+
+ } else if (pip->ip_p == IPPROTO_ICMP) {
+
+ u_short *sptr;
+ int accumulate;
+ struct in_addr original_address;
+ u_short original_id;
+
+ original_address = GetOriginalAddress(link);
+ original_id = GetOriginalPort(link);
+
+ /* Adjust ICMP checksum */
+ sptr = (u_short *) &(pip->ip_src);
+ accumulate = *sptr++;
+ accumulate += *sptr;
+ sptr = (u_short *) &original_address;
+ accumulate -= *sptr++;
+ accumulate -= *sptr;
+ accumulate += ic->icmp_id;
+ accumulate -= original_id;
+ ADJUST_CHECKSUM(accumulate, ic->icmp_cksum)
+
+ /* Adjust IP checksum */
+ DifferentialChecksum(&pip->ip_sum,
+ (u_short *) &original_address,
+ (u_short *) &pip->ip_src,
+ 2);
+
+ /* Un-alias source address and port number */
+ pip->ip_src = original_address;
+ ic->icmp_id = original_id;
+
+ iresult = PKT_ALIAS_OK;
+ }
+ }
+ return(iresult);
+
+}
diff --git a/sys/netinet/libalias/alias.h b/sys/netinet/libalias/alias.h
index 61f759f..8785999 100644
--- a/sys/netinet/libalias/alias.h
+++ b/sys/netinet/libalias/alias.h
@@ -44,6 +44,9 @@ struct alias_link;
extern int
PacketAliasOut(char *, int maxpacketsize);
+ extern int
+ PacketUnaliasOut(char *, int maxpacketsize);
+
/* Port and Address Redirection */
extern struct alias_link *
PacketAliasRedirectPort(struct in_addr, u_short,
diff --git a/sys/netinet/libalias/alias_db.c b/sys/netinet/libalias/alias_db.c
index f8baa71..8cf7da5 100644
--- a/sys/netinet/libalias/alias_db.c
+++ b/sys/netinet/libalias/alias_db.c
@@ -103,6 +103,16 @@
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.
$FreeBSD$
@@ -500,6 +510,9 @@ Link creation and deletion:
Link search:
FindLinkOut() - find link for outgoing packets
FindLinkIn() - find link for incoming packets
+
+Port search:
+ FindNewPortGroup() - find an available group of ports
*/
/* Local prototypes */
@@ -531,11 +544,14 @@ FindLinkIn(struct in_addr, struct in_addr, u_short, u_short, int, int);
#define ALIAS_PORT_BASE 0x08000
#define ALIAS_PORT_MASK 0x07fff
+#define ALIAS_PORT_MASK_EVEN 0x07ffe
#define GET_NEW_PORT_MAX_ATTEMPTS 20
#define GET_ALIAS_PORT -1
#define GET_ALIAS_ID GET_ALIAS_PORT
+#define FIND_EVEN_ALIAS_BASE 1
+
/* GetNewPort() allocates port numbers. Note that if a port number
is already in use, that does not mean that it cannot be used by
another link concurrently. This is because GetNewPort() looks for
@@ -704,6 +720,102 @@ GetSocket(u_short port_net, int *sockfd, int link_type)
}
+/* FindNewPortGroup() returns a base port number for an available
+ range of contiguous port numbers. Note that if a port number
+ is already in use, that does not mean that it cannot be used by
+ another link concurrently. This is because FindNewPortGroup()
+ looks for unused triplets: (dest addr, dest port, alias port). */
+
+int
+FindNewPortGroup(struct in_addr dst_addr,
+ struct in_addr alias_addr,
+ u_short src_port,
+ u_short dst_port,
+ u_short port_count,
+ u_char proto,
+ u_char align)
+{
+ int i, j;
+ int max_trials;
+ u_short port_sys;
+ int link_type;
+
+ /*
+ * Get link_type from protocol
+ */
+
+ switch (proto)
+ {
+ case IPPROTO_UDP:
+ link_type = LINK_UDP;
+ break;
+ case IPPROTO_TCP:
+ link_type = LINK_TCP;
+ break;
+ default:
+ return (0);
+ break;
+ }
+
+ /*
+ * The aliasing port is automatically selected
+ * by one of two methods below:
+ */
+ max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
+
+ if (packetAliasMode & PKT_ALIAS_SAME_PORTS) {
+ /*
+ * When the ALIAS_SAME_PORTS option is
+ * chosen, the first try will be the
+ * actual source port. If this is already
+ * in use, the remainder of the trials
+ * will be random.
+ */
+ port_sys = ntohs(src_port);
+
+ } else {
+
+ /* First trial and all subsequent are random. */
+ if (align == FIND_EVEN_ALIAS_BASE)
+ port_sys = random() & ALIAS_PORT_MASK_EVEN;
+ else
+ port_sys = random() & ALIAS_PORT_MASK;
+
+ port_sys += ALIAS_PORT_BASE;
+ }
+
+/* Port number search */
+ for (i = 0; i < max_trials; i++) {
+
+ struct alias_link *search_result;
+
+ for (j = 0; j < port_count; j++)
+ if (0 != (search_result = FindLinkIn(dst_addr, alias_addr,
+ dst_port, htons(port_sys + j),
+ link_type, 0)))
+ break;
+
+ /* Found a good range, return base */
+ if (j == port_count)
+ return (htons(port_sys));
+
+ /* Find a new base to try */
+ if (align == FIND_EVEN_ALIAS_BASE)
+ port_sys = random() & ALIAS_PORT_MASK_EVEN;
+ else
+ port_sys = random() & ALIAS_PORT_MASK;
+
+ port_sys += ALIAS_PORT_BASE;
+ }
+
+#ifdef DEBUG
+ fprintf(stderr, "PacketAlias/FindNewPortGroup(): ");
+ fprintf(stderr, "could not find free port(s)\n");
+#endif
+
+ return(0);
+}
+
static void
CleanupAliasData(void)
{
@@ -1600,6 +1712,107 @@ FindPptpOut(struct in_addr src_addr,
}
+struct alias_link *
+QueryUdpTcpIn(struct in_addr dst_addr,
+ struct in_addr alias_addr,
+ u_short dst_port,
+ u_short alias_port,
+ u_char proto)
+{
+ int link_type;
+ struct alias_link *link;
+
+ switch (proto)
+ {
+ case IPPROTO_UDP:
+ link_type = LINK_UDP;
+ break;
+ case IPPROTO_TCP:
+ link_type = LINK_TCP;
+ break;
+ default:
+ return NULL;
+ break;
+ }
+
+ link = FindLinkIn(dst_addr, alias_addr,
+ dst_port, alias_port,
+ link_type, 0);
+
+ return(link);
+}
+
+
+struct alias_link *
+QueryUdpTcpOut(struct in_addr src_addr,
+ struct in_addr dst_addr,
+ u_short src_port,
+ u_short dst_port,
+ u_char proto)
+{
+ int link_type;
+ struct alias_link *link;
+
+ switch (proto)
+ {
+ case IPPROTO_UDP:
+ link_type = LINK_UDP;
+ break;
+ case IPPROTO_TCP:
+ link_type = LINK_TCP;
+ break;
+ default:
+ return NULL;
+ break;
+ }
+
+ link = FindLinkOut(src_addr, dst_addr,
+ src_port, dst_port,
+ link_type, 0);
+
+ return(link);
+}
+
+
+struct alias_link *
+FindRtspOut(struct in_addr src_addr,
+ struct in_addr dst_addr,
+ u_short src_port,
+ u_short alias_port,
+ u_char proto)
+{
+ int link_type;
+ struct alias_link *link;
+
+ switch (proto)
+ {
+ case IPPROTO_UDP:
+ link_type = LINK_UDP;
+ break;
+ case IPPROTO_TCP:
+ link_type = LINK_TCP;
+ break;
+ default:
+ return NULL;
+ break;
+ }
+
+ link = FindLinkOut(src_addr, dst_addr, src_port, 0, link_type, 1);
+
+ if (link == NULL)
+ {
+ struct in_addr alias_addr;
+
+ alias_addr = FindAliasAddress(src_addr);
+ link = AddLink(src_addr, dst_addr, alias_addr,
+ src_port, 0, alias_port,
+ link_type);
+ }
+
+ return(link);
+}
+
+
struct in_addr
FindOriginalAddress(struct in_addr alias_addr)
{
diff --git a/sys/netinet/libalias/alias_local.h b/sys/netinet/libalias/alias_local.h
index 439c9ea..f916d21 100644
--- a/sys/netinet/libalias/alias_local.h
+++ b/sys/netinet/libalias/alias_local.h
@@ -113,6 +113,15 @@ FindPptpIn(struct in_addr, struct in_addr, u_short);
struct alias_link *
FindPptpOut(struct in_addr, struct in_addr, u_short);
+struct alias_link *
+QueryUdpTcpIn (struct in_addr, struct in_addr, u_short, u_short, u_char);
+
+struct alias_link *
+QueryUdpTcpOut(struct in_addr, struct in_addr, u_short, u_short, u_char);
+
+struct alias_link *
+FindRtspOut(struct in_addr, struct in_addr, u_short, u_short, u_char);
+
struct in_addr
FindOriginalAddress(struct in_addr);
@@ -120,6 +129,8 @@ struct in_addr
FindAliasAddress(struct in_addr);
/* External data access/modification */
+int FindNewPortGroup(struct in_addr, struct in_addr,
+ u_short, u_short, u_short, u_char, u_char);
void GetFragmentAddr(struct alias_link *, struct in_addr *);
void SetFragmentAddr(struct alias_link *, struct in_addr);
void GetFragmentPtr(struct alias_link *, char **);
@@ -165,6 +176,9 @@ void AliasHandleFtpOut(struct ip *, struct alias_link *, int);
/* IRC routines */
void AliasHandleIrcOut(struct ip *, struct alias_link *, int);
+/* RTSP routines */
+void AliasHandleRtspOut(struct ip *, struct alias_link *, int);
+
/* PPTP routines */
int PptpGetCallID(struct ip *, u_short *);
void PptpSetCallID(struct ip *, u_short);
diff --git a/sys/netinet/libalias/alias_smedia.c b/sys/netinet/libalias/alias_smedia.c
new file mode 100644
index 0000000..2b9ca5f
--- /dev/null
+++ b/sys/netinet/libalias/alias_smedia.c
@@ -0,0 +1,427 @@
+/*
+ * alias_smedia.c
+ *
+ * Copyright (c) 2000 Whistle Communications, Inc.
+ * All rights reserved.
+ *
+ * Subject to the following obligations and disclaimer of warranty, use and
+ * redistribution of this software, in source or object code forms, with or
+ * without modifications are expressly permitted by Whistle Communications;
+ * provided, however, that:
+ * 1. Any and all reproductions of the source or object code must include the
+ * copyright notice above and the following disclaimer of warranties; and
+ * 2. No rights are granted, in any manner or form, to use Whistle
+ * Communications, Inc. trademarks, including the mark "WHISTLE
+ * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+ * such appears in the above copyright notice or in the software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+ * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+ * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+ * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+ * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+ * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+ * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+ * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Copyright (c) 2000 Junichi SATOH <junichi@astec.co.jp>
+ * <junichi@junichi.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Authors: Erik Salander <erik@whistle.com>
+ * Junichi SATOH <junichi@astec.co.jp>
+ * <junichi@junichi.org>
+ *
+ * $FreeBSD$
+ */
+
+/*
+ Alias_smedia.c is meant to contain the aliasing code for streaming media
+ protocols. It performs special processing for RSTP sessions under TCP.
+ Specifically, when a SETUP request is sent by a client, or a 200 reply
+ is sent by a server, it is intercepted and modified. The address is
+ changed to the gateway machine and an aliasing port is used.
+
+ More specifically, the "client_port" configuration parameter is
+ parsed for SETUP requests. The "server_port" configuration parameter is
+ parsed for 200 replies eminating from a server. This is intended to handle
+ the unicast case.
+
+ RTSP also allows a redirection of a stream to another client by using the
+ "destination" configuration parameter. The destination config parm would
+ indicate a different IP address. This function is NOT supported by the
+ RTSP translation code below.
+
+ The RTSP multicast functions without any address translation intervention.
+
+ For this routine to work, the SETUP/200 must fit entirely
+ into a single TCP packet. This is typically the case, but exceptions
+ can easily be envisioned under the actual specifications.
+
+ Probably the most troubling aspect of the approach taken here is
+ that the new SETUP/200 will typically be a different length, and
+ this causes a certain amount of bookkeeping to keep track of the
+ changes of sequence and acknowledgment numbers, since the client
+ machine is totally unaware of the modification to the TCP stream.
+
+ Initial version: May, 2000 (eds)
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+
+#include "alias_local.h"
+
+#define RTSP_CONTROL_PORT_NUMBER_1 554
+#define RTSP_CONTROL_PORT_NUMBER_2 7070
+#define RTSP_PORT_GROUP 2
+
+#define ISDIGIT(a) (((a) >= '0') && ((a) <= '9'))
+
+int search_string(char *data, int dlen, char *search_str)
+{
+ int i, j, k;
+ int search_str_len;
+
+ search_str_len = strlen(search_str);
+ for (i = 0; i < dlen - search_str_len; i++) {
+ for (j = i, k = 0; j < dlen - search_str_len; j++, k++) {
+ if (data[j] != search_str[k] &&
+ data[j] != search_str[k] - ('a' - 'A')) {
+ break;
+ }
+ if (k == search_str_len - 1) {
+ return j + 1;
+ }
+ }
+ }
+ return -1;
+}
+
+int alias_rtsp_out(struct ip *pip,
+ struct alias_link *link,
+ char *data,
+ char *port_str)
+{
+ int hlen, tlen, dlen;
+ struct tcphdr *tc;
+ int i, j, pos, state, port_dlen, new_dlen, delta;
+ u_short p[2], new_len;
+ u_short sport, eport, base_port;
+ u_short salias = 0, ealias = 0, base_alias = 0;
+ char *transport_str = "transport:";
+ char newdata[2048], *port_data, *port_newdata, stemp[80];
+ int links_created = 0, pkt_updated = 0;
+ struct alias_link *rtsp_link = NULL;
+ struct in_addr null_addr;
+
+ /* Calculate data length of TCP packet */
+ tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
+ hlen = (pip->ip_hl + tc->th_off) << 2;
+ tlen = ntohs(pip->ip_len);
+ dlen = tlen - hlen;
+
+ /* Find keyword, "Transport: " */
+ pos = search_string(data, dlen, transport_str);
+ if (pos < 0) {
+ return -1;
+ }
+ port_data = data + pos;
+ port_dlen = dlen - pos;
+
+ memcpy(newdata, data, pos);
+ port_newdata = newdata + pos;
+
+ while (port_dlen > strlen(port_str)) {
+ /* Find keyword, appropriate port string */
+ pos = search_string(port_data, port_dlen, port_str);
+ if (pos < 0) {
+ break;
+ }
+
+ memcpy (port_newdata, port_data, pos + 1);
+ port_newdata += (pos + 1);
+
+ p[0] = p[1] = 0;
+ sport = eport = 0;
+ state = 0;
+ for (i = pos; i < port_dlen; i++) {
+ switch(state) {
+ case 0:
+ if (port_data[i] == '=') {
+ state++;
+ }
+ break;
+ case 1:
+ if (ISDIGIT(port_data[i])) {
+ p[0] = p[0] * 10 + port_data[i] - '0';
+ } else {
+ if (port_data[i] == ';') {
+ state = 3;
+ }
+ if (port_data[i] == '-') {
+ state++;
+ }
+ }
+ break;
+ case 2:
+ if (ISDIGIT(port_data[i])) {
+ p[1] = p[1] * 10 + port_data[i] - '0';
+ } else {
+ state++;
+ }
+ break;
+ case 3:
+ base_port = p[0];
+ sport = htons(p[0]);
+ eport = htons(p[1]);
+
+ if (!links_created) {
+
+ links_created = 1;
+ /* Find an even numbered port number base that
+ satisfies the contiguous number of ports we need */
+ null_addr.s_addr = 0;
+ if (0 == (salias = FindNewPortGroup(null_addr,
+ FindAliasAddress(pip->ip_src),
+ sport, 0,
+ RTSP_PORT_GROUP,
+ IPPROTO_UDP, 1))) {
+#ifdef DEBUG
+ fprintf(stderr,
+ "PacketAlias/RTSP: Cannot find contiguous RTSP data ports\n");
+#endif
+ } else {
+
+ base_alias = ntohs(salias);
+ for (j = 0; j < RTSP_PORT_GROUP; j++) {
+ /* Establish link to port found in RTSP packet */
+ rtsp_link = FindRtspOut(GetOriginalAddress(link), null_addr,
+ htons(base_port + j), htons(base_alias + j),
+ IPPROTO_UDP);
+ if (rtsp_link != NULL) {
+#ifndef NO_FW_PUNCH
+ /* Punch hole in firewall */
+ PunchFWHole(rtsp_link);
+#endif
+ } else {
+#ifdef DEBUG
+ fprintf(stderr,
+ "PacketAlias/RTSP: Cannot allocate RTSP data ports\n");
+#endif
+ break;
+ }
+ }
+ }
+ ealias = htons(base_alias + (RTSP_PORT_GROUP - 1));
+ }
+
+ if (salias && rtsp_link) {
+
+ pkt_updated = 1;
+
+ /* Copy into IP packet */
+ sprintf(stemp, "%d", ntohs(salias));
+ memcpy(port_newdata, stemp, strlen(stemp));
+ port_newdata += strlen(stemp);
+
+ if (eport != 0) {
+ *port_newdata = '-';
+ port_newdata++;
+
+ /* Copy into IP packet */
+ sprintf(stemp, "%d", ntohs(ealias));
+ memcpy(port_newdata, stemp, strlen(stemp));
+ port_newdata += strlen(stemp);
+ }
+
+ *port_newdata = ';';
+ port_newdata++;
+ }
+ state++;
+ break;
+ }
+ if (state > 3) {
+ break;
+ }
+ }
+ port_data += i;
+ port_dlen -= i;
+ }
+
+ if (!pkt_updated)
+ return -1;
+
+ memcpy (port_newdata, port_data, port_dlen);
+ port_newdata += port_dlen;
+ *port_newdata = '\0';
+
+ /* Create new packet */
+ new_dlen = port_newdata - newdata;
+ memcpy (data, newdata, new_dlen);
+
+ SetAckModified(link);
+ delta = GetDeltaSeqOut(pip, link);
+ AddSeq(pip, link, delta + new_dlen - dlen);
+
+ new_len = htons(hlen + new_dlen);
+ DifferentialChecksum(&pip->ip_sum,
+ &new_len,
+ &pip->ip_len,
+ 1);
+ pip->ip_len = new_len;
+
+ tc->th_sum = 0;
+ tc->th_sum = TcpChecksum(pip);
+
+ return 0;
+}
+
+/* Support the protocol used by early versions of RealPlayer */
+
+int alias_pna_out(struct ip *pip,
+ struct alias_link *link,
+ char *data,
+ int dlen)
+{
+ struct alias_link *pna_links;
+ u_short msg_id, msg_len;
+ char *work;
+ u_short alias_port, port;
+ struct tcphdr *tc;
+
+ work = data;
+ work += 5;
+ while (work + 4 < data + dlen) {
+ memcpy(&msg_id, work, 2);
+ work += 2;
+ memcpy(&msg_len, work, 2);
+ work += 2;
+ if (ntohs(msg_id) == 0) {
+ /* end of options */
+ return 0;
+ }
+ if ((ntohs(msg_id) == 1) || (ntohs(msg_id) == 7)) {
+ memcpy((char*)&port, (char*)work, 2);
+ pna_links = FindUdpTcpOut(pip->ip_src, GetDestAddress(link),
+ port, 0, IPPROTO_UDP);
+ if (pna_links != NULL) {
+#ifndef NO_FW_PUNCH
+ /* Punch hole in firewall */
+ PunchFWHole(pna_links);
+#endif
+ tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
+ alias_port = GetAliasPort(pna_links);
+ memcpy((char*)work, (char*)&alias_port, 2);
+
+ /* Compute TCP checksum for revised packet */
+ tc->th_sum = 0;
+ tc->th_sum = TcpChecksum(pip);
+ }
+ }
+ work += ntohs(msg_len);
+ }
+
+ return 0;
+}
+
+void
+AliasHandleRtspOut(struct ip *pip, struct alias_link *link, int maxpacketsize)
+{
+ int hlen, tlen, dlen;
+ struct tcphdr *tc;
+ char *data, *setup = "SETUP", *pna = "PNA", *str200 = "200", *okstr = "OK";
+ char *client_port_str = "client_port", *server_port_str = "server_port";
+ int i, parseOk;
+
+ tc = (struct tcphdr *)((char *)pip + (pip->ip_hl << 2));
+ hlen = (pip->ip_hl + tc->th_off) << 2;
+ tlen = ntohs(pip->ip_len);
+ dlen = tlen - hlen;
+
+ data = (char*)pip;
+ data += hlen;
+
+ /* When aliasing a client, check for the SETUP request */
+ if ((ntohs(tc->th_dport) == RTSP_CONTROL_PORT_NUMBER_1) ||
+ (ntohs(tc->th_dport) == RTSP_CONTROL_PORT_NUMBER_2)) {
+
+ if (dlen >= strlen(setup)) {
+ if (memcmp(data, setup, strlen(setup)) == 0) {
+ alias_rtsp_out(pip, link, data, client_port_str);
+ return;
+ }
+ }
+ if (dlen >= strlen(pna)) {
+ if (memcmp(data, pna, strlen(pna)) == 0) {
+ alias_pna_out(pip, link, data, dlen);
+ }
+ }
+
+ } else {
+
+ /* When aliasing a server, check for the 200 reply
+ Accomodate varying number of blanks between 200 & OK */
+
+ if (dlen >= strlen(str200)) {
+
+ for (parseOk = 0, i = 0;
+ i <= dlen - strlen(str200);
+ i++) {
+ if (memcmp(&data[i], str200, strlen(str200)) == 0) {
+ parseOk = 1;
+ break;
+ }
+ }
+ if (parseOk) {
+
+ i += strlen(str200); /* skip string found */
+ while(data[i] == ' ') /* skip blank(s) */
+ i++;
+
+ if ((dlen - i) >= strlen(okstr)) {
+
+ if (memcmp(&data[i], okstr, strlen(okstr)) == 0)
+ alias_rtsp_out(pip, link, data, server_port_str);
+
+ }
+ }
+ }
+ }
+}
diff --git a/sys/netinet/libalias/libalias.3 b/sys/netinet/libalias/libalias.3
index 4c06d98..0090387 100644
--- a/sys/netinet/libalias/libalias.3
+++ b/sys/netinet/libalias/libalias.3
@@ -808,6 +808,25 @@ If the checksum is valid,
.Fn PacketAliasInternetChecksum
will return zero.
.Ed
+.Pp
+.Ft int
+.Fn PacketUnaliasOut "char *buffer" "int maxpacketsize"
+.Bd -ragged -offset indent
+An outgoing packet, which has already been aliased, has its private address/port
+information restored by this function.
+The IP packet is pointed to by
+.Fa buffer ,
+and
+.Fa maxpacketsize
+is provided for error checking purposes.
+This function can be used if an already-aliased packet needs to have its
+original IP header restored for further processing (eg. logging).
+.Ed
+.Sh BUGS
+PPTP aliasing does not work when more than one internal client
+connects to the same external server at the same time, because
+PPTP requires a single TCP control connection to be established
+between any two IP addresses.
.Sh AUTHORS
.An Charles Mott Aq cmott@scientech.com ,
versions 1.0 - 1.8, 2.0 - 2.4.
@@ -816,7 +835,9 @@ versions 1.8b, 1.9 and 2.5.
Added IRC DCC support as well as contributing a number of architectural
improvements; added the firewall bypass for FTP/IRC DCC.
.An Erik Salander Aq erik@whistle.com
-added support for PPTP.
+added support for PPTP and RTSP.
+.An Junichi Satoh Aq junichi@junichi.org
+added support for RTSP/PNA.
.Sh ACKNOWLEDGMENTS
Listed below, in approximate chronological order, are individuals who
have provided valuable comments and/or debugging assistance.
OpenPOWER on IntegriCloud