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>
66 #include <sys/cdefs.h>
67 __FBSDID("$FreeBSD$");
70 Alias_smedia.c is meant to contain the aliasing code for streaming media
71 protocols. It performs special processing for RSTP sessions under TCP.
72 Specifically, when a SETUP request is sent by a client, or a 200 reply
73 is sent by a server, it is intercepted and modified. The address is
74 changed to the gateway machine and an aliasing port is used.
76 More specifically, the "client_port" configuration parameter is
77 parsed for SETUP requests. The "server_port" configuration parameter is
78 parsed for 200 replies eminating from a server. This is intended to handle
81 RTSP also allows a redirection of a stream to another client by using the
82 "destination" configuration parameter. The destination config parm would
83 indicate a different IP address. This function is NOT supported by the
84 RTSP translation code below.
86 The RTSP multicast functions without any address translation intervention.
88 For this routine to work, the SETUP/200 must fit entirely
89 into a single TCP packet. This is typically the case, but exceptions
90 can easily be envisioned under the actual specifications.
92 Probably the most troubling aspect of the approach taken here is
93 that the new SETUP/200 will typically be a different length, and
94 this causes a certain amount of bookkeeping to keep track of the
95 changes of sequence and acknowledgment numbers, since the client
96 machine is totally unaware of the modification to the TCP stream.
98 Initial version: May, 2000 (eds)
102 #include <sys/param.h>
103 #include <sys/systm.h>
104 #include <sys/kernel.h>
105 #include <sys/module.h>
108 #include <sys/types.h>
113 #include <netinet/in_systm.h>
114 #include <netinet/in.h>
115 #include <netinet/ip.h>
116 #include <netinet/tcp.h>
119 #include <netinet/libalias/alias.h>
120 #include <netinet/libalias/alias_local.h>
121 #include <netinet/libalias/alias_mod.h>
123 #include "alias_local.h"
124 #include "alias_mod.h"
127 #define RTSP_CONTROL_PORT_NUMBER_1 554
128 #define RTSP_CONTROL_PORT_NUMBER_2 7070
129 #define TFTP_PORT_NUMBER 69
132 AliasHandleRtspOut(struct libalias *, struct ip *, struct alias_link *,
135 fingerprint(struct libalias *la, struct ip *pip, struct alias_data *ah)
138 if (ah->dport == NULL || ah->sport == NULL || ah->lnk == NULL ||
141 if (ntohs(*ah->dport) == RTSP_CONTROL_PORT_NUMBER_1
142 || ntohs(*ah->sport) == RTSP_CONTROL_PORT_NUMBER_1
143 || ntohs(*ah->dport) == RTSP_CONTROL_PORT_NUMBER_2
144 || ntohs(*ah->sport) == RTSP_CONTROL_PORT_NUMBER_2
145 || ntohs(*ah->dport) == TFTP_PORT_NUMBER)
151 protohandler(struct libalias *la, struct ip *pip, struct alias_data *ah)
154 if (ntohs(*ah->dport) == TFTP_PORT_NUMBER)
155 FindRtspOut(la, pip->ip_src, pip->ip_dst,
156 *ah->sport, *ah->aport, IPPROTO_UDP);
157 else AliasHandleRtspOut(la, pip, ah->lnk, ah->maxpktsize);
161 struct proto_handler handlers[] = {
166 .fingerprint = &fingerprint,
167 .protohandler = &protohandler
173 mod_handler(module_t mod, int type, void *data)
180 LibAliasAttachHandlers(handlers);
184 LibAliasDetachHandlers(handlers);
195 moduledata_t alias_mod = {
196 "alias_smedia", mod_handler, NULL
200 DECLARE_MODULE(alias_smedia, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
201 MODULE_VERSION(alias_smedia, 1);
202 MODULE_DEPEND(alias_smedia, libalias, 1, 1, 1);
205 #define RTSP_CONTROL_PORT_NUMBER_1 554
206 #define RTSP_CONTROL_PORT_NUMBER_2 7070
207 #define RTSP_PORT_GROUP 2
209 #define ISDIGIT(a) (((a) >= '0') && ((a) <= '9'))
212 search_string(char *data, int dlen, const char *search_str)
217 search_str_len = strlen(search_str);
218 for (i = 0; i < dlen - search_str_len; i++) {
219 for (j = i, k = 0; j < dlen - search_str_len; j++, k++) {
220 if (data[j] != search_str[k] &&
221 data[j] != search_str[k] - ('a' - 'A')) {
224 if (k == search_str_len - 1) {
233 alias_rtsp_out(struct libalias *la, struct ip *pip,
234 struct alias_link *lnk,
236 const char *port_str)
238 int hlen, tlen, dlen;
240 int i, j, pos, state, port_dlen, new_dlen, delta;
241 u_short p[2], new_len;
242 u_short sport, eport, base_port;
243 u_short salias = 0, ealias = 0, base_alias = 0;
244 const char *transport_str = "transport:";
245 char newdata[2048], *port_data, *port_newdata, stemp[80];
246 int links_created = 0, pkt_updated = 0;
247 struct alias_link *rtsp_lnk = NULL;
248 struct in_addr null_addr;
250 /* Calculate data length of TCP packet */
251 tc = (struct tcphdr *)ip_next(pip);
252 hlen = (pip->ip_hl + tc->th_off) << 2;
253 tlen = ntohs(pip->ip_len);
256 /* Find keyword, "Transport: " */
257 pos = search_string(data, dlen, transport_str);
261 port_data = data + pos;
262 port_dlen = dlen - pos;
264 memcpy(newdata, data, pos);
265 port_newdata = newdata + pos;
267 while (port_dlen > (int)strlen(port_str)) {
268 /* Find keyword, appropriate port string */
269 pos = search_string(port_data, port_dlen, port_str);
273 memcpy(port_newdata, port_data, pos + 1);
274 port_newdata += (pos + 1);
279 for (i = pos; i < port_dlen; i++) {
282 if (port_data[i] == '=') {
287 if (ISDIGIT(port_data[i])) {
288 p[0] = p[0] * 10 + port_data[i] - '0';
290 if (port_data[i] == ';') {
293 if (port_data[i] == '-') {
299 if (ISDIGIT(port_data[i])) {
300 p[1] = p[1] * 10 + port_data[i] - '0';
310 if (!links_created) {
314 * Find an even numbered port
315 * number base that satisfies the
316 * contiguous number of ports we
319 null_addr.s_addr = 0;
320 if (0 == (salias = FindNewPortGroup(la, null_addr,
321 FindAliasAddress(la, pip->ip_src),
325 #ifdef LIBALIAS_DEBUG
327 "PacketAlias/RTSP: Cannot find contiguous RTSP data ports\n");
331 base_alias = ntohs(salias);
332 for (j = 0; j < RTSP_PORT_GROUP; j++) {
338 rtsp_lnk = FindRtspOut(la, GetOriginalAddress(lnk), null_addr,
339 htons(base_port + j), htons(base_alias + j),
341 if (rtsp_lnk != NULL) {
348 PunchFWHole(rtsp_lnk);
351 #ifdef LIBALIAS_DEBUG
353 "PacketAlias/RTSP: Cannot allocate RTSP data ports\n");
359 ealias = htons(base_alias + (RTSP_PORT_GROUP - 1));
361 if (salias && rtsp_lnk) {
365 /* Copy into IP packet */
366 sprintf(stemp, "%d", ntohs(salias));
367 memcpy(port_newdata, stemp, strlen(stemp));
368 port_newdata += strlen(stemp);
374 /* Copy into IP packet */
375 sprintf(stemp, "%d", ntohs(ealias));
376 memcpy(port_newdata, stemp, strlen(stemp));
377 port_newdata += strlen(stemp);
396 memcpy(port_newdata, port_data, port_dlen);
397 port_newdata += port_dlen;
398 *port_newdata = '\0';
400 /* Create new packet */
401 new_dlen = port_newdata - newdata;
402 memcpy(data, newdata, new_dlen);
405 delta = GetDeltaSeqOut(pip, lnk);
406 AddSeq(pip, lnk, delta + new_dlen - dlen);
408 new_len = htons(hlen + new_dlen);
409 DifferentialChecksum(&pip->ip_sum,
413 pip->ip_len = new_len;
419 tc->th_sum = TcpChecksum(pip);
424 /* Support the protocol used by early versions of RealPlayer */
427 alias_pna_out(struct libalias *la, struct ip *pip,
428 struct alias_link *lnk,
432 struct alias_link *pna_links;
433 u_short msg_id, msg_len;
435 u_short alias_port, port;
440 while (work + 4 < data + dlen) {
441 memcpy(&msg_id, work, 2);
443 memcpy(&msg_len, work, 2);
445 if (ntohs(msg_id) == 0) {
449 if ((ntohs(msg_id) == 1) || (ntohs(msg_id) == 7)) {
450 memcpy(&port, work, 2);
451 pna_links = FindUdpTcpOut(la, pip->ip_src, GetDestAddress(lnk),
452 port, 0, IPPROTO_UDP, 1);
453 if (pna_links != NULL) {
455 /* Punch hole in firewall */
456 PunchFWHole(pna_links);
458 tc = (struct tcphdr *)ip_next(pip);
459 alias_port = GetAliasPort(pna_links);
460 memcpy(work, &alias_port, 2);
462 /* Compute TCP checksum for revised packet */
467 tc->th_sum = TcpChecksum(pip);
471 work += ntohs(msg_len);
478 AliasHandleRtspOut(struct libalias *la, struct ip *pip, struct alias_link *lnk, int maxpacketsize)
480 int hlen, tlen, dlen;
483 const char *setup = "SETUP", *pna = "PNA", *str200 = "200";
484 const char *okstr = "OK", *client_port_str = "client_port";
485 const char *server_port_str = "server_port";
490 tc = (struct tcphdr *)ip_next(pip);
491 hlen = (pip->ip_hl + tc->th_off) << 2;
492 tlen = ntohs(pip->ip_len);
498 /* When aliasing a client, check for the SETUP request */
499 if ((ntohs(tc->th_dport) == RTSP_CONTROL_PORT_NUMBER_1) ||
500 (ntohs(tc->th_dport) == RTSP_CONTROL_PORT_NUMBER_2)) {
502 if (dlen >= (int)strlen(setup)) {
503 if (memcmp(data, setup, strlen(setup)) == 0) {
504 alias_rtsp_out(la, pip, lnk, data, client_port_str);
508 if (dlen >= (int)strlen(pna)) {
509 if (memcmp(data, pna, strlen(pna)) == 0) {
510 alias_pna_out(la, pip, lnk, data, dlen);
516 * When aliasing a server, check for the 200 reply
517 * Accomodate varying number of blanks between 200 & OK
520 if (dlen >= (int)strlen(str200)) {
522 for (parseOk = 0, i = 0;
523 i <= dlen - (int)strlen(str200);
525 if (memcmp(&data[i], str200, strlen(str200)) == 0) {
532 i += strlen(str200); /* skip string found */
533 while (data[i] == ' ') /* skip blank(s) */
536 if ((dlen - i) >= (int)strlen(okstr)) {
538 if (memcmp(&data[i], okstr, strlen(okstr)) == 0)
539 alias_rtsp_out(la, pip, lnk, data, server_port_str);