2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
25 * Copyright (c) 2000 Whistle Communications, Inc.
26 * All rights reserved.
28 * Subject to the following obligations and disclaimer of warranty, use and
29 * redistribution of this software, in source or object code forms, with or
30 * without modifications are expressly permitted by Whistle Communications;
31 * provided, however, that:
32 * 1. Any and all reproductions of the source or object code must include the
33 * copyright notice above and the following disclaimer of warranties; and
34 * 2. No rights are granted, in any manner or form, to use Whistle
35 * Communications, Inc. trademarks, including the mark "WHISTLE
36 * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
37 * such appears in the above copyright notice or in the software.
39 * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
40 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
41 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
42 * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
43 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
44 * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
45 * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
46 * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
47 * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
48 * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
49 * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
50 * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
51 * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
52 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
53 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
54 * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
57 * Copyright (c) 2000 Junichi SATOH <junichi@astec.co.jp>
58 * <junichi@junichi.org>
59 * All rights reserved.
61 * Redistribution and use in source and binary forms, with or without
62 * modification, are permitted provided that the following conditions
64 * 1. Redistributions of source code must retain the above copyright
65 * notice, this list of conditions and the following disclaimer.
66 * 2. Redistributions in binary form must reproduce the above copyright
67 * notice, this list of conditions and the following disclaimer in the
68 * documentation and/or other materials provided with the distribution.
70 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
71 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
72 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
73 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
74 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
75 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
76 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
77 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
78 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
79 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
82 * Authors: Erik Salander <erik@whistle.com>
83 * Junichi SATOH <junichi@astec.co.jp>
84 * <junichi@junichi.org>
87 * $FreeBSD: src/lib/libalias/alias_smedia.c,v 1.1.2.4 2001/03/05 03:48:00 kris Exp $
91 Alias_smedia.c is meant to contain the aliasing code for streaming media
92 protocols. It performs special processing for RSTP sessions under TCP.
93 Specifically, when a SETUP request is sent by a client, or a 200 reply
94 is sent by a server, it is intercepted and modified. The address is
95 changed to the gateway machine and an aliasing port is used.
97 More specifically, the "client_port" configuration parameter is
98 parsed for SETUP requests. The "server_port" configuration parameter is
99 parsed for 200 replies eminating from a server. This is intended to handle
102 RTSP also allows a redirection of a stream to another client by using the
103 "destination" configuration parameter. The destination config parm would
104 indicate a different IP address. This function is NOT supported by the
105 RTSP translation code below.
107 The RTSP multicast functions without any address translation intervention.
109 For this routine to work, the SETUP/200 must fit entirely
110 into a single TCP packet. This is typically the case, but exceptions
111 can easily be envisioned under the actual specifications.
113 Probably the most troubling aspect of the approach taken here is
114 that the new SETUP/200 will typically be a different length, and
115 this causes a certain amount of bookkeeping to keep track of the
116 changes of sequence and acknowledgment numbers, since the client
117 machine is totally unaware of the modification to the TCP stream.
119 Initial version: May, 2000 (eds)
124 #include <sys/types.h>
125 #include <netinet/in_systm.h>
126 #include <netinet/in.h>
127 #include <netinet/ip.h>
128 #include <netinet/tcp.h>
129 #include <netinet/udp.h>
131 #include "alias_local.h"
133 #define RTSP_CONTROL_PORT_NUMBER_1 554
134 #define RTSP_CONTROL_PORT_NUMBER_2 7070
135 #define RTSP_PORT_GROUP 2
137 #define ISDIGIT(a) (((a) >= '0') && ((a) <= '9'))
140 search_string(char *data
, int dlen
, const char *search_str
)
145 search_str_len
= strlen(search_str
);
146 for (i
= 0; i
< dlen
- search_str_len
; i
++) {
147 for (j
= i
, k
= 0; j
< dlen
- search_str_len
; j
++, k
++) {
148 if (data
[j
] != search_str
[k
] &&
149 data
[j
] != search_str
[k
] - ('a' - 'A')) {
152 if (k
== search_str_len
- 1) {
161 alias_rtsp_out(struct ip
*pip
,
162 struct alias_link
*link
,
164 const char *port_str
)
166 int hlen
, tlen
, dlen
;
168 int i
, j
, pos
, state
, port_dlen
, new_dlen
, delta
;
169 u_short p
[2], new_len
;
170 u_short sport
, eport
, base_port
;
171 u_short salias
= 0, ealias
= 0, base_alias
= 0;
172 const char *transport_str
= "transport:";
173 char newdata
[2048], *port_data
, *port_newdata
, stemp
[80];
174 int links_created
= 0, pkt_updated
= 0;
175 struct alias_link
*rtsp_link
= NULL
;
176 struct in_addr null_addr
;
178 /* Calculate data length of TCP packet */
179 tc
= (struct tcphdr
*) ((char *) pip
+ (pip
->ip_hl
<< 2));
180 hlen
= (pip
->ip_hl
+ tc
->th_off
) << 2;
181 tlen
= ntohs(pip
->ip_len
);
184 /* Find keyword, "Transport: " */
185 pos
= search_string(data
, dlen
, transport_str
);
189 port_data
= data
+ pos
;
190 port_dlen
= dlen
- pos
;
192 memcpy(newdata
, data
, pos
);
193 port_newdata
= newdata
+ pos
;
195 while (port_dlen
> strlen(port_str
)) {
196 /* Find keyword, appropriate port string */
197 pos
= search_string(port_data
, port_dlen
, port_str
);
202 memcpy (port_newdata
, port_data
, pos
+ 1);
203 port_newdata
+= (pos
+ 1);
208 for (i
= pos
; i
< port_dlen
; i
++) {
211 if (port_data
[i
] == '=') {
216 if (ISDIGIT(port_data
[i
])) {
217 p
[0] = p
[0] * 10 + port_data
[i
] - '0';
219 if (port_data
[i
] == ';') {
222 if (port_data
[i
] == '-') {
228 if (ISDIGIT(port_data
[i
])) {
229 p
[1] = p
[1] * 10 + port_data
[i
] - '0';
239 if (!links_created
) {
242 /* Find an even numbered port number base that
243 satisfies the contiguous number of ports we need */
244 null_addr
.s_addr
= 0;
245 if (0 == (salias
= FindNewPortGroup(null_addr
,
246 FindAliasAddress(pip
->ip_src
),
252 "PacketAlias/RTSP: Cannot find contiguous RTSP data ports\n");
256 base_alias
= ntohs(salias
);
257 for (j
= 0; j
< RTSP_PORT_GROUP
; j
++) {
258 /* Establish link to port found in RTSP packet */
259 rtsp_link
= FindRtspOut(GetOriginalAddress(link
), null_addr
,
260 htons(base_port
+ j
), htons(base_alias
+ j
),
262 if (rtsp_link
!= NULL
) {
264 /* Punch hole in firewall */
265 PunchFWHole(rtsp_link
);
270 "PacketAlias/RTSP: Cannot allocate RTSP data ports\n");
276 ealias
= htons(base_alias
+ (RTSP_PORT_GROUP
- 1));
279 if (salias
&& rtsp_link
) {
283 /* Copy into IP packet */
284 sprintf(stemp
, "%d", ntohs(salias
));
285 memcpy(port_newdata
, stemp
, strlen(stemp
));
286 port_newdata
+= strlen(stemp
);
292 /* Copy into IP packet */
293 sprintf(stemp
, "%d", ntohs(ealias
));
294 memcpy(port_newdata
, stemp
, strlen(stemp
));
295 port_newdata
+= strlen(stemp
);
315 memcpy (port_newdata
, port_data
, port_dlen
);
316 port_newdata
+= port_dlen
;
317 *port_newdata
= '\0';
319 /* Create new packet */
320 new_dlen
= port_newdata
- newdata
;
321 memcpy (data
, newdata
, new_dlen
);
323 SetAckModified(link
);
324 delta
= GetDeltaSeqOut(pip
, link
);
325 AddSeq(pip
, link
, delta
+ new_dlen
- dlen
);
327 new_len
= htons(hlen
+ new_dlen
);
328 DifferentialChecksum(&pip
->ip_sum
,
332 pip
->ip_len
= new_len
;
335 tc
->th_sum
= TcpChecksum(pip
);
340 /* Support the protocol used by early versions of RealPlayer */
343 alias_pna_out(struct ip
*pip
,
344 struct alias_link
*link
,
348 struct alias_link
*pna_links
;
349 u_short msg_id
, msg_len
;
351 u_short alias_port
, port
;
356 while (work
+ 4 < data
+ dlen
) {
357 memcpy(&msg_id
, work
, 2);
359 memcpy(&msg_len
, work
, 2);
361 if (ntohs(msg_id
) == 0) {
365 if ((ntohs(msg_id
) == 1) || (ntohs(msg_id
) == 7)) {
366 memcpy(&port
, work
, 2);
367 pna_links
= FindUdpTcpOut(pip
->ip_src
, GetDestAddress(link
),
368 port
, 0, IPPROTO_UDP
, 1);
369 if (pna_links
!= NULL
) {
371 /* Punch hole in firewall */
372 PunchFWHole(pna_links
);
374 tc
= (struct tcphdr
*) ((char *) pip
+ (pip
->ip_hl
<< 2));
375 alias_port
= GetAliasPort(pna_links
);
376 memcpy(work
, &alias_port
, 2);
378 /* Compute TCP checksum for revised packet */
380 tc
->th_sum
= TcpChecksum(pip
);
383 work
+= ntohs(msg_len
);
390 AliasHandleRtspOut(struct ip
*pip
, struct alias_link
*link
, int maxpacketsize
)
392 int hlen
, tlen
, dlen
;
395 const char *setup
= "SETUP", *pna
= "PNA", *str200
= "200";
396 const char *okstr
= "OK", *client_port_str
= "client_port";
397 const char *server_port_str
= "server_port";
400 tc
= (struct tcphdr
*)((char *)pip
+ (pip
->ip_hl
<< 2));
401 hlen
= (pip
->ip_hl
+ tc
->th_off
) << 2;
402 tlen
= ntohs(pip
->ip_len
);
408 /* When aliasing a client, check for the SETUP request */
409 if ((ntohs(tc
->th_dport
) == RTSP_CONTROL_PORT_NUMBER_1
) ||
410 (ntohs(tc
->th_dport
) == RTSP_CONTROL_PORT_NUMBER_2
)) {
412 if (dlen
>= strlen(setup
)) {
413 if (memcmp(data
, setup
, strlen(setup
)) == 0) {
414 alias_rtsp_out(pip
, link
, data
, client_port_str
);
418 if (dlen
>= strlen(pna
)) {
419 if (memcmp(data
, pna
, strlen(pna
)) == 0) {
420 alias_pna_out(pip
, link
, data
, dlen
);
426 /* When aliasing a server, check for the 200 reply
427 Accomodate varying number of blanks between 200 & OK */
429 if (dlen
>= strlen(str200
)) {
431 for (parseOk
= 0, i
= 0;
432 i
<= dlen
- strlen(str200
);
434 if (memcmp(&data
[i
], str200
, strlen(str200
)) == 0) {
441 i
+= strlen(str200
); /* skip string found */
442 while(data
[i
] == ' ') /* skip blank(s) */
445 if ((dlen
- i
) >= strlen(okstr
)) {
447 if (memcmp(&data
[i
], okstr
, strlen(okstr
)) == 0)
448 alias_rtsp_out(pip
, link
, data
, server_port_str
);