4 * Copyright (c) 2000 Whistle Communications, Inc.
7 * Subject to the following obligations and disclaimer of warranty, use and
8 * redistribution of this software, in source or object code forms, with or
9 * without modifications are expressly permitted by Whistle Communications;
10 * provided, however, that:
11 * 1. Any and all reproductions of the source or object code must include the
12 * copyright notice above and the following disclaimer of warranties; and
13 * 2. No rights are granted, in any manner or form, to use Whistle
14 * Communications, Inc. trademarks, including the mark "WHISTLE
15 * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
16 * such appears in the above copyright notice or in the software.
18 * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
19 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
20 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
21 * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
23 * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
24 * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
25 * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
26 * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
27 * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
28 * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
29 * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33 * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
36 * Copyright (c) 2000 Junichi SATOH <junichi@astec.co.jp>
37 * <junichi@junichi.org>
38 * All rights reserved.
40 * Redistribution and use in source and binary forms, with or without
41 * modification, are permitted provided that the following conditions
43 * 1. Redistributions of source code must retain the above copyright
44 * notice, this list of conditions and the following disclaimer.
45 * 2. Redistributions in binary form must reproduce the above copyright
46 * notice, this list of conditions and the following disclaimer in the
47 * documentation and/or other materials provided with the distribution.
49 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61 * Authors: Erik Salander <erik@whistle.com>
62 * Junichi SATOH <junichi@astec.co.jp>
63 * <junichi@junichi.org>
65 * $FreeBSD: src/lib/libalias/alias_smedia.c,v 1.1.2.4 2001/03/05 03:48:00 kris Exp $
69 Alias_smedia.c is meant to contain the aliasing code for streaming media
70 protocols. It performs special processing for RSTP sessions under TCP.
71 Specifically, when a SETUP request is sent by a client, or a 200 reply
72 is sent by a server, it is intercepted and modified. The address is
73 changed to the gateway machine and an aliasing port is used.
75 More specifically, the "client_port" configuration parameter is
76 parsed for SETUP requests. The "server_port" configuration parameter is
77 parsed for 200 replies eminating from a server. This is intended to handle
80 RTSP also allows a redirection of a stream to another client by using the
81 "destination" configuration parameter. The destination config parm would
82 indicate a different IP address. This function is NOT supported by the
83 RTSP translation code below.
85 The RTSP multicast functions without any address translation intervention.
87 For this routine to work, the SETUP/200 must fit entirely
88 into a single TCP packet. This is typically the case, but exceptions
89 can easily be envisioned under the actual specifications.
91 Probably the most troubling aspect of the approach taken here is
92 that the new SETUP/200 will typically be a different length, and
93 this causes a certain amount of bookkeeping to keep track of the
94 changes of sequence and acknowledgment numbers, since the client
95 machine is totally unaware of the modification to the TCP stream.
97 Initial version: May, 2000 (eds)
102 #include <sys/types.h>
103 #include <netinet/in_systm.h>
104 #include <netinet/in.h>
105 #include <netinet/ip.h>
106 #include <netinet/tcp.h>
107 #include <netinet/udp.h>
109 #include "alias_local.h"
111 #define RTSP_CONTROL_PORT_NUMBER_1 554
112 #define RTSP_CONTROL_PORT_NUMBER_2 7070
113 #define RTSP_PORT_GROUP 2
115 #define ISDIGIT(a) (((a) >= '0') && ((a) <= '9'))
118 search_string(char *data, int dlen, const char *search_str)
123 search_str_len = strlen(search_str);
124 for (i = 0; i < dlen - search_str_len; i++) {
125 for (j = i, k = 0; j < dlen - search_str_len; j++, k++) {
126 if (data[j] != search_str[k] &&
127 data[j] != search_str[k] - ('a' - 'A')) {
130 if (k == search_str_len - 1) {
139 alias_rtsp_out(struct ip *pip,
140 struct alias_link *link,
142 const char *port_str)
144 int hlen, tlen, dlen;
146 int i, j, pos, state, port_dlen, new_dlen, delta;
147 u_short p[2], new_len;
148 u_short sport, eport, base_port;
149 u_short salias = 0, ealias = 0, base_alias = 0;
150 const char *transport_str = "transport:";
151 char newdata[2048], *port_data, *port_newdata, stemp[80];
152 int links_created = 0, pkt_updated = 0;
153 struct alias_link *rtsp_link = NULL;
154 struct in_addr null_addr;
156 /* Calculate data length of TCP packet */
157 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
158 hlen = (pip->ip_hl + tc->th_off) << 2;
159 tlen = ntohs(pip->ip_len);
162 /* Find keyword, "Transport: " */
163 pos = search_string(data, dlen, transport_str);
167 port_data = data + pos;
168 port_dlen = dlen - pos;
170 memcpy(newdata, data, pos);
171 port_newdata = newdata + pos;
173 while (port_dlen > strlen(port_str)) {
174 /* Find keyword, appropriate port string */
175 pos = search_string(port_data, port_dlen, port_str);
180 memcpy (port_newdata, port_data, pos + 1);
181 port_newdata += (pos + 1);
186 for (i = pos; i < port_dlen; i++) {
189 if (port_data[i] == '=') {
194 if (ISDIGIT(port_data[i])) {
195 p[0] = p[0] * 10 + port_data[i] - '0';
197 if (port_data[i] == ';') {
200 if (port_data[i] == '-') {
206 if (ISDIGIT(port_data[i])) {
207 p[1] = p[1] * 10 + port_data[i] - '0';
217 if (!links_created) {
220 /* Find an even numbered port number base that
221 satisfies the contiguous number of ports we need */
222 null_addr.s_addr = 0;
223 if (0 == (salias = FindNewPortGroup(null_addr,
224 FindAliasAddress(pip->ip_src),
230 "PacketAlias/RTSP: Cannot find contiguous RTSP data ports\n");
234 base_alias = ntohs(salias);
235 for (j = 0; j < RTSP_PORT_GROUP; j++) {
236 /* Establish link to port found in RTSP packet */
237 rtsp_link = FindRtspOut(GetOriginalAddress(link), null_addr,
238 htons(base_port + j), htons(base_alias + j),
240 if (rtsp_link != NULL) {
242 /* Punch hole in firewall */
243 PunchFWHole(rtsp_link);
248 "PacketAlias/RTSP: Cannot allocate RTSP data ports\n");
254 ealias = htons(base_alias + (RTSP_PORT_GROUP - 1));
257 if (salias && rtsp_link) {
261 /* Copy into IP packet */
262 sprintf(stemp, "%d", ntohs(salias));
263 memcpy(port_newdata, stemp, strlen(stemp));
264 port_newdata += strlen(stemp);
270 /* Copy into IP packet */
271 sprintf(stemp, "%d", ntohs(ealias));
272 memcpy(port_newdata, stemp, strlen(stemp));
273 port_newdata += strlen(stemp);
293 memcpy (port_newdata, port_data, port_dlen);
294 port_newdata += port_dlen;
295 *port_newdata = '\0';
297 /* Create new packet */
298 new_dlen = port_newdata - newdata;
299 memcpy (data, newdata, new_dlen);
301 SetAckModified(link);
302 delta = GetDeltaSeqOut(pip, link);
303 AddSeq(pip, link, delta + new_dlen - dlen);
305 new_len = htons(hlen + new_dlen);
306 DifferentialChecksum(&pip->ip_sum,
310 pip->ip_len = new_len;
313 tc->th_sum = TcpChecksum(pip);
318 /* Support the protocol used by early versions of RealPlayer */
321 alias_pna_out(struct ip *pip,
322 struct alias_link *link,
326 struct alias_link *pna_links;
327 u_short msg_id, msg_len;
329 u_short alias_port, port;
334 while (work + 4 < data + dlen) {
335 memcpy(&msg_id, work, 2);
337 memcpy(&msg_len, work, 2);
339 if (ntohs(msg_id) == 0) {
343 if ((ntohs(msg_id) == 1) || (ntohs(msg_id) == 7)) {
344 memcpy(&port, work, 2);
345 pna_links = FindUdpTcpOut(pip->ip_src, GetDestAddress(link),
346 port, 0, IPPROTO_UDP, 1);
347 if (pna_links != NULL) {
349 /* Punch hole in firewall */
350 PunchFWHole(pna_links);
352 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
353 alias_port = GetAliasPort(pna_links);
354 memcpy(work, &alias_port, 2);
356 /* Compute TCP checksum for revised packet */
358 tc->th_sum = TcpChecksum(pip);
361 work += ntohs(msg_len);
368 AliasHandleRtspOut(struct ip *pip, struct alias_link *link, int maxpacketsize)
370 int hlen, tlen, dlen;
373 const char *setup = "SETUP", *pna = "PNA", *str200 = "200";
374 const char *okstr = "OK", *client_port_str = "client_port";
375 const char *server_port_str = "server_port";
378 tc = (struct tcphdr *)((char *)pip + (pip->ip_hl << 2));
379 hlen = (pip->ip_hl + tc->th_off) << 2;
380 tlen = ntohs(pip->ip_len);
386 /* When aliasing a client, check for the SETUP request */
387 if ((ntohs(tc->th_dport) == RTSP_CONTROL_PORT_NUMBER_1) ||
388 (ntohs(tc->th_dport) == RTSP_CONTROL_PORT_NUMBER_2)) {
390 if (dlen >= strlen(setup)) {
391 if (memcmp(data, setup, strlen(setup)) == 0) {
392 alias_rtsp_out(pip, link, data, client_port_str);
396 if (dlen >= strlen(pna)) {
397 if (memcmp(data, pna, strlen(pna)) == 0) {
398 alias_pna_out(pip, link, data, dlen);
404 /* When aliasing a server, check for the 200 reply
405 Accomodate varying number of blanks between 200 & OK */
407 if (dlen >= strlen(str200)) {
409 for (parseOk = 0, i = 0;
410 i <= dlen - strlen(str200);
412 if (memcmp(&data[i], str200, strlen(str200)) == 0) {
419 i += strlen(str200); /* skip string found */
420 while(data[i] == ' ') /* skip blank(s) */
423 if ((dlen - i) >= strlen(okstr)) {
425 if (memcmp(&data[i], okstr, strlen(okstr)) == 0)
426 alias_rtsp_out(pip, link, data, server_port_str);