4 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD AND BSD-2-Clause
6 * Copyright (c) 2000 Whistle Communications, Inc.
9 * Subject to the following obligations and disclaimer of warranty, use and
10 * redistribution of this software, in source or object code forms, with or
11 * without modifications are expressly permitted by Whistle Communications;
12 * provided, however, that:
13 * 1. Any and all reproductions of the source or object code must include the
14 * copyright notice above and the following disclaimer of warranties; and
15 * 2. No rights are granted, in any manner or form, to use Whistle
16 * Communications, Inc. trademarks, including the mark "WHISTLE
17 * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
18 * such appears in the above copyright notice or in the software.
20 * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
21 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
22 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
23 * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
24 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
25 * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
26 * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
27 * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
28 * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
29 * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
30 * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
31 * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
32 * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35 * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
38 * Copyright (c) 2000 Junichi SATOH <junichi@astec.co.jp>
39 * <junichi@junichi.org>
40 * All rights reserved.
42 * Redistribution and use in source and binary forms, with or without
43 * modification, are permitted provided that the following conditions
45 * 1. Redistributions of source code must retain the above copyright
46 * notice, this list of conditions and the following disclaimer.
47 * 2. Redistributions in binary form must reproduce the above copyright
48 * notice, this list of conditions and the following disclaimer in the
49 * documentation and/or other materials provided with the distribution.
51 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63 * Authors: Erik Salander <erik@whistle.com>
64 * Junichi SATOH <junichi@astec.co.jp>
65 * <junichi@junichi.org>
68 #include <sys/cdefs.h>
69 __FBSDID("$FreeBSD$");
72 Alias_smedia.c is meant to contain the aliasing code for streaming media
73 protocols. It performs special processing for RSTP sessions under TCP.
74 Specifically, when a SETUP request is sent by a client, or a 200 reply
75 is sent by a server, it is intercepted and modified. The address is
76 changed to the gateway machine and an aliasing port is used.
78 More specifically, the "client_port" configuration parameter is
79 parsed for SETUP requests. The "server_port" configuration parameter is
80 parsed for 200 replies eminating from a server. This is intended to handle
83 RTSP also allows a redirection of a stream to another client by using the
84 "destination" configuration parameter. The destination config parm would
85 indicate a different IP address. This function is NOT supported by the
86 RTSP translation code below.
88 The RTSP multicast functions without any address translation intervention.
90 For this routine to work, the SETUP/200 must fit entirely
91 into a single TCP packet. This is typically the case, but exceptions
92 can easily be envisioned under the actual specifications.
94 Probably the most troubling aspect of the approach taken here is
95 that the new SETUP/200 will typically be a different length, and
96 this causes a certain amount of bookkeeping to keep track of the
97 changes of sequence and acknowledgment numbers, since the client
98 machine is totally unaware of the modification to the TCP stream.
100 Initial version: May, 2000 (eds)
104 #include <sys/param.h>
105 #include <sys/systm.h>
106 #include <sys/kernel.h>
107 #include <sys/module.h>
110 #include <sys/types.h>
115 #include <netinet/in_systm.h>
116 #include <netinet/in.h>
117 #include <netinet/ip.h>
118 #include <netinet/tcp.h>
121 #include <netinet/libalias/alias.h>
122 #include <netinet/libalias/alias_local.h>
123 #include <netinet/libalias/alias_mod.h>
125 #include "alias_local.h"
126 #include "alias_mod.h"
129 #define RTSP_CONTROL_PORT_NUMBER_1 554
130 #define RTSP_CONTROL_PORT_NUMBER_2 7070
131 #define TFTP_PORT_NUMBER 69
134 AliasHandleRtspOut(struct libalias *, struct ip *, struct alias_link *,
137 fingerprint(struct libalias *la, struct alias_data *ah)
140 if (ah->dport != NULL && ah->aport != NULL && ah->sport != NULL &&
141 ntohs(*ah->dport) == TFTP_PORT_NUMBER)
143 if (ah->dport == NULL || ah->sport == NULL || ah->lnk == NULL ||
146 if (ntohs(*ah->dport) == RTSP_CONTROL_PORT_NUMBER_1
147 || ntohs(*ah->sport) == RTSP_CONTROL_PORT_NUMBER_1
148 || ntohs(*ah->dport) == RTSP_CONTROL_PORT_NUMBER_2
149 || ntohs(*ah->sport) == RTSP_CONTROL_PORT_NUMBER_2)
155 protohandler(struct libalias *la, struct ip *pip, struct alias_data *ah)
158 if (ntohs(*ah->dport) == TFTP_PORT_NUMBER)
159 FindRtspOut(la, pip->ip_src, pip->ip_dst,
160 *ah->sport, *ah->aport, IPPROTO_UDP);
161 else AliasHandleRtspOut(la, pip, ah->lnk, ah->maxpktsize);
165 struct proto_handler handlers[] = {
170 .fingerprint = &fingerprint,
171 .protohandler = &protohandler
177 mod_handler(module_t mod, int type, void *data)
184 LibAliasAttachHandlers(handlers);
188 LibAliasDetachHandlers(handlers);
199 moduledata_t alias_mod = {
200 "alias_smedia", mod_handler, NULL
204 DECLARE_MODULE(alias_smedia, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
205 MODULE_VERSION(alias_smedia, 1);
206 MODULE_DEPEND(alias_smedia, libalias, 1, 1, 1);
209 #define RTSP_CONTROL_PORT_NUMBER_1 554
210 #define RTSP_CONTROL_PORT_NUMBER_2 7070
211 #define RTSP_PORT_GROUP 2
213 #define ISDIGIT(a) (((a) >= '0') && ((a) <= '9'))
216 search_string(char *data, int dlen, const char *search_str)
221 search_str_len = strlen(search_str);
222 for (i = 0; i < dlen - search_str_len; i++) {
223 for (j = i, k = 0; j < dlen - search_str_len; j++, k++) {
224 if (data[j] != search_str[k] &&
225 data[j] != search_str[k] - ('a' - 'A')) {
228 if (k == search_str_len - 1) {
237 alias_rtsp_out(struct libalias *la, struct ip *pip,
238 struct alias_link *lnk,
240 const char *port_str)
242 int hlen, tlen, dlen;
244 int i, j, pos, state, port_dlen, new_dlen, delta;
245 u_short p[2], new_len;
246 u_short sport, eport, base_port;
247 u_short salias = 0, ealias = 0, base_alias = 0;
248 const char *transport_str = "transport:";
249 char newdata[2048], *port_data, *port_newdata, stemp[80];
250 int links_created = 0, pkt_updated = 0;
251 struct alias_link *rtsp_lnk = NULL;
252 struct in_addr null_addr;
254 /* Calculate data length of TCP packet */
255 tc = (struct tcphdr *)ip_next(pip);
256 hlen = (pip->ip_hl + tc->th_off) << 2;
257 tlen = ntohs(pip->ip_len);
260 /* Find keyword, "Transport: " */
261 pos = search_string(data, dlen, transport_str);
265 port_data = data + pos;
266 port_dlen = dlen - pos;
268 memcpy(newdata, data, pos);
269 port_newdata = newdata + pos;
271 while (port_dlen > (int)strlen(port_str)) {
272 /* Find keyword, appropriate port string */
273 pos = search_string(port_data, port_dlen, port_str);
277 memcpy(port_newdata, port_data, pos + 1);
278 port_newdata += (pos + 1);
283 for (i = pos; i < port_dlen; i++) {
286 if (port_data[i] == '=') {
291 if (ISDIGIT(port_data[i])) {
292 p[0] = p[0] * 10 + port_data[i] - '0';
294 if (port_data[i] == ';') {
297 if (port_data[i] == '-') {
303 if (ISDIGIT(port_data[i])) {
304 p[1] = p[1] * 10 + port_data[i] - '0';
314 if (!links_created) {
318 * Find an even numbered port
319 * number base that satisfies the
320 * contiguous number of ports we
323 null_addr.s_addr = 0;
324 if (0 == (salias = FindNewPortGroup(la, null_addr,
325 FindAliasAddress(la, pip->ip_src),
329 #ifdef LIBALIAS_DEBUG
331 "PacketAlias/RTSP: Cannot find contiguous RTSP data ports\n");
335 base_alias = ntohs(salias);
336 for (j = 0; j < RTSP_PORT_GROUP; j++) {
342 rtsp_lnk = FindRtspOut(la, GetOriginalAddress(lnk), null_addr,
343 htons(base_port + j), htons(base_alias + j),
345 if (rtsp_lnk != NULL) {
352 PunchFWHole(rtsp_lnk);
355 #ifdef LIBALIAS_DEBUG
357 "PacketAlias/RTSP: Cannot allocate RTSP data ports\n");
363 ealias = htons(base_alias + (RTSP_PORT_GROUP - 1));
365 if (salias && rtsp_lnk) {
369 /* Copy into IP packet */
370 sprintf(stemp, "%d", ntohs(salias));
371 memcpy(port_newdata, stemp, strlen(stemp));
372 port_newdata += strlen(stemp);
378 /* Copy into IP packet */
379 sprintf(stemp, "%d", ntohs(ealias));
380 memcpy(port_newdata, stemp, strlen(stemp));
381 port_newdata += strlen(stemp);
400 memcpy(port_newdata, port_data, port_dlen);
401 port_newdata += port_dlen;
402 *port_newdata = '\0';
404 /* Create new packet */
405 new_dlen = port_newdata - newdata;
406 memcpy(data, newdata, new_dlen);
409 tc = (struct tcphdr *)ip_next(pip);
410 delta = GetDeltaSeqOut(tc->th_seq, lnk);
411 AddSeq(lnk, delta + new_dlen - dlen, pip->ip_hl, pip->ip_len,
412 tc->th_seq, tc->th_off);
414 new_len = htons(hlen + new_dlen);
415 DifferentialChecksum(&pip->ip_sum,
419 pip->ip_len = new_len;
425 tc->th_sum = TcpChecksum(pip);
430 /* Support the protocol used by early versions of RealPlayer */
433 alias_pna_out(struct libalias *la, struct ip *pip,
434 struct alias_link *lnk,
438 struct alias_link *pna_links;
439 u_short msg_id, msg_len;
441 u_short alias_port, port;
446 while (work + 4 < data + dlen) {
447 memcpy(&msg_id, work, 2);
449 memcpy(&msg_len, work, 2);
451 if (ntohs(msg_id) == 0) {
455 if ((ntohs(msg_id) == 1) || (ntohs(msg_id) == 7)) {
456 memcpy(&port, work, 2);
457 pna_links = FindUdpTcpOut(la, pip->ip_src, GetDestAddress(lnk),
458 port, 0, IPPROTO_UDP, 1);
459 if (pna_links != NULL) {
461 /* Punch hole in firewall */
462 PunchFWHole(pna_links);
464 tc = (struct tcphdr *)ip_next(pip);
465 alias_port = GetAliasPort(pna_links);
466 memcpy(work, &alias_port, 2);
468 /* Compute TCP checksum for revised packet */
473 tc->th_sum = TcpChecksum(pip);
477 work += ntohs(msg_len);
484 AliasHandleRtspOut(struct libalias *la, struct ip *pip, struct alias_link *lnk, int maxpacketsize)
486 int hlen, tlen, dlen;
489 const char *setup = "SETUP", *pna = "PNA", *str200 = "200";
490 const char *okstr = "OK", *client_port_str = "client_port";
491 const char *server_port_str = "server_port";
496 tc = (struct tcphdr *)ip_next(pip);
497 hlen = (pip->ip_hl + tc->th_off) << 2;
498 tlen = ntohs(pip->ip_len);
504 /* When aliasing a client, check for the SETUP request */
505 if ((ntohs(tc->th_dport) == RTSP_CONTROL_PORT_NUMBER_1) ||
506 (ntohs(tc->th_dport) == RTSP_CONTROL_PORT_NUMBER_2)) {
508 if (dlen >= (int)strlen(setup)) {
509 if (memcmp(data, setup, strlen(setup)) == 0) {
510 alias_rtsp_out(la, pip, lnk, data, client_port_str);
514 if (dlen >= (int)strlen(pna)) {
515 if (memcmp(data, pna, strlen(pna)) == 0) {
516 alias_pna_out(la, pip, lnk, data, dlen);
522 * When aliasing a server, check for the 200 reply
523 * Accommodate varying number of blanks between 200 & OK
526 if (dlen >= (int)strlen(str200)) {
528 for (parseOk = 0, i = 0;
529 i <= dlen - (int)strlen(str200);
531 if (memcmp(&data[i], str200, strlen(str200)) == 0) {
538 i += strlen(str200); /* skip string found */
539 while (data[i] == ' ') /* skip blank(s) */
542 if ((dlen - i) >= (int)strlen(okstr)) {
544 if (memcmp(&data[i], okstr, strlen(okstr)) == 0)
545 alias_rtsp_out(la, pip, lnk, data, server_port_str);