alias_smedia.c revision 124621
163899Sarchie/* 263899Sarchie * alias_smedia.c 363899Sarchie * 463899Sarchie * Copyright (c) 2000 Whistle Communications, Inc. 563899Sarchie * All rights reserved. 663899Sarchie * 763899Sarchie * Subject to the following obligations and disclaimer of warranty, use and 863899Sarchie * redistribution of this software, in source or object code forms, with or 963899Sarchie * without modifications are expressly permitted by Whistle Communications; 1063899Sarchie * provided, however, that: 1163899Sarchie * 1. Any and all reproductions of the source or object code must include the 1263899Sarchie * copyright notice above and the following disclaimer of warranties; and 1363899Sarchie * 2. No rights are granted, in any manner or form, to use Whistle 1463899Sarchie * Communications, Inc. trademarks, including the mark "WHISTLE 1563899Sarchie * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 1663899Sarchie * such appears in the above copyright notice or in the software. 1763899Sarchie * 1863899Sarchie * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 1963899Sarchie * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 2063899Sarchie * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 2163899Sarchie * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 2263899Sarchie * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 2363899Sarchie * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 2463899Sarchie * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 2563899Sarchie * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 2663899Sarchie * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 2763899Sarchie * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 2863899Sarchie * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 2963899Sarchie * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 3063899Sarchie * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 3163899Sarchie * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3263899Sarchie * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3363899Sarchie * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 3463899Sarchie * OF SUCH DAMAGE. 3563899Sarchie * 3663899Sarchie * Copyright (c) 2000 Junichi SATOH <junichi@astec.co.jp> 3763899Sarchie * <junichi@junichi.org> 3863899Sarchie * All rights reserved. 3963899Sarchie * 4063899Sarchie * Redistribution and use in source and binary forms, with or without 4163899Sarchie * modification, are permitted provided that the following conditions 4263899Sarchie * are met: 4363899Sarchie * 1. Redistributions of source code must retain the above copyright 4463899Sarchie * notice, this list of conditions and the following disclaimer. 4563899Sarchie * 2. Redistributions in binary form must reproduce the above copyright 4663899Sarchie * notice, this list of conditions and the following disclaimer in the 4763899Sarchie * documentation and/or other materials provided with the distribution. 4863899Sarchie * 4963899Sarchie * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 5063899Sarchie * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 5163899Sarchie * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 5263899Sarchie * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 5363899Sarchie * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 5463899Sarchie * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 5563899Sarchie * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 5663899Sarchie * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 5763899Sarchie * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5863899Sarchie * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 5963899Sarchie * SUCH DAMAGE. 6063899Sarchie * 6163899Sarchie * Authors: Erik Salander <erik@whistle.com> 6263899Sarchie * Junichi SATOH <junichi@astec.co.jp> 6363899Sarchie * <junichi@junichi.org> 6463899Sarchie */ 6563899Sarchie 6684195Sdillon#include <sys/cdefs.h> 6784195Sdillon__FBSDID("$FreeBSD: head/sys/netinet/libalias/alias_smedia.c 124621 2004-01-17 10:52:21Z phk $"); 6884195Sdillon 6963899Sarchie/* 7063899Sarchie Alias_smedia.c is meant to contain the aliasing code for streaming media 7163899Sarchie protocols. It performs special processing for RSTP sessions under TCP. 7263899Sarchie Specifically, when a SETUP request is sent by a client, or a 200 reply 7399207Sbrian is sent by a server, it is intercepted and modified. The address is 7463899Sarchie changed to the gateway machine and an aliasing port is used. 7563899Sarchie 7699207Sbrian More specifically, the "client_port" configuration parameter is 7799207Sbrian parsed for SETUP requests. The "server_port" configuration parameter is 7863899Sarchie parsed for 200 replies eminating from a server. This is intended to handle 7963899Sarchie the unicast case. 8063899Sarchie 8163899Sarchie RTSP also allows a redirection of a stream to another client by using the 8263899Sarchie "destination" configuration parameter. The destination config parm would 8399207Sbrian indicate a different IP address. This function is NOT supported by the 8463899Sarchie RTSP translation code below. 8563899Sarchie 8663899Sarchie The RTSP multicast functions without any address translation intervention. 8763899Sarchie 8863899Sarchie For this routine to work, the SETUP/200 must fit entirely 8963899Sarchie into a single TCP packet. This is typically the case, but exceptions 9063899Sarchie can easily be envisioned under the actual specifications. 9163899Sarchie 9263899Sarchie Probably the most troubling aspect of the approach taken here is 9363899Sarchie that the new SETUP/200 will typically be a different length, and 9463899Sarchie this causes a certain amount of bookkeeping to keep track of the 9563899Sarchie changes of sequence and acknowledgment numbers, since the client 9663899Sarchie machine is totally unaware of the modification to the TCP stream. 9763899Sarchie 9899207Sbrian Initial version: May, 2000 (eds) 9963899Sarchie*/ 10063899Sarchie 10163899Sarchie#include <stdio.h> 10263899Sarchie#include <string.h> 10363899Sarchie#include <sys/types.h> 10463899Sarchie#include <netinet/in_systm.h> 10563899Sarchie#include <netinet/in.h> 10663899Sarchie#include <netinet/ip.h> 10763899Sarchie#include <netinet/tcp.h> 10863899Sarchie#include <netinet/udp.h> 10963899Sarchie 11063899Sarchie#include "alias_local.h" 11163899Sarchie 11299207Sbrian#define RTSP_CONTROL_PORT_NUMBER_1 554 11399207Sbrian#define RTSP_CONTROL_PORT_NUMBER_2 7070 11463899Sarchie#define RTSP_PORT_GROUP 2 11563899Sarchie 11663899Sarchie#define ISDIGIT(a) (((a) >= '0') && ((a) <= '9')) 11763899Sarchie 11865892Srustatic int 11971796Sbriansearch_string(char *data, int dlen, const char *search_str) 12063899Sarchie{ 12163899Sarchie int i, j, k; 12263899Sarchie int search_str_len; 12363899Sarchie 12463899Sarchie search_str_len = strlen(search_str); 12563899Sarchie for (i = 0; i < dlen - search_str_len; i++) { 12663899Sarchie for (j = i, k = 0; j < dlen - search_str_len; j++, k++) { 12763899Sarchie if (data[j] != search_str[k] && 12863899Sarchie data[j] != search_str[k] - ('a' - 'A')) { 12963899Sarchie break; 13063899Sarchie } 13163899Sarchie if (k == search_str_len - 1) { 13263899Sarchie return j + 1; 13363899Sarchie } 13463899Sarchie } 13563899Sarchie } 13663899Sarchie return -1; 13763899Sarchie} 13863899Sarchie 13965892Srustatic int 140124621Sphkalias_rtsp_out(struct libalias *la, struct ip *pip, 14163899Sarchie struct alias_link *link, 14263899Sarchie char *data, 14371796Sbrian const char *port_str) 14463899Sarchie{ 14563899Sarchie int hlen, tlen, dlen; 14663899Sarchie struct tcphdr *tc; 14763899Sarchie int i, j, pos, state, port_dlen, new_dlen, delta; 14863899Sarchie u_short p[2], new_len; 14963899Sarchie u_short sport, eport, base_port; 15063899Sarchie u_short salias = 0, ealias = 0, base_alias = 0; 15171796Sbrian const char *transport_str = "transport:"; 15263899Sarchie char newdata[2048], *port_data, *port_newdata, stemp[80]; 15363899Sarchie int links_created = 0, pkt_updated = 0; 15463899Sarchie struct alias_link *rtsp_link = NULL; 15599207Sbrian struct in_addr null_addr; 15663899Sarchie 15763899Sarchie /* Calculate data length of TCP packet */ 15863899Sarchie tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 15963899Sarchie hlen = (pip->ip_hl + tc->th_off) << 2; 16063899Sarchie tlen = ntohs(pip->ip_len); 16163899Sarchie dlen = tlen - hlen; 16263899Sarchie 16363899Sarchie /* Find keyword, "Transport: " */ 16463899Sarchie pos = search_string(data, dlen, transport_str); 16563899Sarchie if (pos < 0) { 16663899Sarchie return -1; 16763899Sarchie } 16863899Sarchie port_data = data + pos; 16963899Sarchie port_dlen = dlen - pos; 17063899Sarchie 17163899Sarchie memcpy(newdata, data, pos); 17263899Sarchie port_newdata = newdata + pos; 17363899Sarchie 17463899Sarchie while (port_dlen > strlen(port_str)) { 17563899Sarchie /* Find keyword, appropriate port string */ 17663899Sarchie pos = search_string(port_data, port_dlen, port_str); 17763899Sarchie if (pos < 0) { 17863899Sarchie break; 17963899Sarchie } 18063899Sarchie 18163899Sarchie memcpy (port_newdata, port_data, pos + 1); 18263899Sarchie port_newdata += (pos + 1); 18363899Sarchie 18463899Sarchie p[0] = p[1] = 0; 18563899Sarchie sport = eport = 0; 18663899Sarchie state = 0; 18763899Sarchie for (i = pos; i < port_dlen; i++) { 18863899Sarchie switch(state) { 18963899Sarchie case 0: 19063899Sarchie if (port_data[i] == '=') { 19163899Sarchie state++; 19263899Sarchie } 19363899Sarchie break; 19463899Sarchie case 1: 19563899Sarchie if (ISDIGIT(port_data[i])) { 19663899Sarchie p[0] = p[0] * 10 + port_data[i] - '0'; 19763899Sarchie } else { 19863899Sarchie if (port_data[i] == ';') { 19963899Sarchie state = 3; 20063899Sarchie } 20163899Sarchie if (port_data[i] == '-') { 20263899Sarchie state++; 20363899Sarchie } 20463899Sarchie } 20563899Sarchie break; 20663899Sarchie case 2: 20763899Sarchie if (ISDIGIT(port_data[i])) { 20863899Sarchie p[1] = p[1] * 10 + port_data[i] - '0'; 20963899Sarchie } else { 21063899Sarchie state++; 21163899Sarchie } 21263899Sarchie break; 21363899Sarchie case 3: 21463899Sarchie base_port = p[0]; 21563899Sarchie sport = htons(p[0]); 21663899Sarchie eport = htons(p[1]); 21763899Sarchie 21863899Sarchie if (!links_created) { 21963899Sarchie 22099207Sbrian links_created = 1; 22163899Sarchie /* Find an even numbered port number base that 22263899Sarchie satisfies the contiguous number of ports we need */ 22363899Sarchie null_addr.s_addr = 0; 224124621Sphk if (0 == (salias = FindNewPortGroup(la, null_addr, 225124621Sphk FindAliasAddress(la, pip->ip_src), 22699207Sbrian sport, 0, 22799207Sbrian RTSP_PORT_GROUP, 22899207Sbrian IPPROTO_UDP, 1))) { 22963899Sarchie#ifdef DEBUG 23063899Sarchie fprintf(stderr, 23163899Sarchie "PacketAlias/RTSP: Cannot find contiguous RTSP data ports\n"); 23263899Sarchie#endif 23363899Sarchie } else { 23463899Sarchie 23563899Sarchie base_alias = ntohs(salias); 23663899Sarchie for (j = 0; j < RTSP_PORT_GROUP; j++) { 23763899Sarchie /* Establish link to port found in RTSP packet */ 238124621Sphk rtsp_link = FindRtspOut(la, GetOriginalAddress(link), null_addr, 23963899Sarchie htons(base_port + j), htons(base_alias + j), 24063899Sarchie IPPROTO_UDP); 24163899Sarchie if (rtsp_link != NULL) { 24263899Sarchie#ifndef NO_FW_PUNCH 24363899Sarchie /* Punch hole in firewall */ 24463899Sarchie PunchFWHole(rtsp_link); 24563899Sarchie#endif 24663899Sarchie } else { 24763899Sarchie#ifdef DEBUG 24863899Sarchie fprintf(stderr, 24963899Sarchie "PacketAlias/RTSP: Cannot allocate RTSP data ports\n"); 25063899Sarchie#endif 25163899Sarchie break; 25263899Sarchie } 25363899Sarchie } 25463899Sarchie } 25563899Sarchie ealias = htons(base_alias + (RTSP_PORT_GROUP - 1)); 25663899Sarchie } 25763899Sarchie 25863899Sarchie if (salias && rtsp_link) { 25963899Sarchie 26063899Sarchie pkt_updated = 1; 26163899Sarchie 26263899Sarchie /* Copy into IP packet */ 26363899Sarchie sprintf(stemp, "%d", ntohs(salias)); 26463899Sarchie memcpy(port_newdata, stemp, strlen(stemp)); 26563899Sarchie port_newdata += strlen(stemp); 26663899Sarchie 26763899Sarchie if (eport != 0) { 26863899Sarchie *port_newdata = '-'; 26963899Sarchie port_newdata++; 27063899Sarchie 27163899Sarchie /* Copy into IP packet */ 27263899Sarchie sprintf(stemp, "%d", ntohs(ealias)); 27363899Sarchie memcpy(port_newdata, stemp, strlen(stemp)); 27463899Sarchie port_newdata += strlen(stemp); 27563899Sarchie } 27663899Sarchie 27763899Sarchie *port_newdata = ';'; 27863899Sarchie port_newdata++; 27963899Sarchie } 28063899Sarchie state++; 28163899Sarchie break; 28263899Sarchie } 28363899Sarchie if (state > 3) { 28463899Sarchie break; 28563899Sarchie } 28663899Sarchie } 28763899Sarchie port_data += i; 28863899Sarchie port_dlen -= i; 28963899Sarchie } 29063899Sarchie 29163899Sarchie if (!pkt_updated) 29263899Sarchie return -1; 29363899Sarchie 29463899Sarchie memcpy (port_newdata, port_data, port_dlen); 29563899Sarchie port_newdata += port_dlen; 29663899Sarchie *port_newdata = '\0'; 29763899Sarchie 29863899Sarchie /* Create new packet */ 29963899Sarchie new_dlen = port_newdata - newdata; 30063899Sarchie memcpy (data, newdata, new_dlen); 30163899Sarchie 30263899Sarchie SetAckModified(link); 30363899Sarchie delta = GetDeltaSeqOut(pip, link); 30463899Sarchie AddSeq(pip, link, delta + new_dlen - dlen); 30563899Sarchie 30663899Sarchie new_len = htons(hlen + new_dlen); 30763899Sarchie DifferentialChecksum(&pip->ip_sum, 30863899Sarchie &new_len, 30963899Sarchie &pip->ip_len, 31063899Sarchie 1); 31163899Sarchie pip->ip_len = new_len; 31263899Sarchie 31363899Sarchie tc->th_sum = 0; 31463899Sarchie tc->th_sum = TcpChecksum(pip); 31563899Sarchie 31663899Sarchie return 0; 31763899Sarchie} 31863899Sarchie 31963899Sarchie/* Support the protocol used by early versions of RealPlayer */ 32063899Sarchie 32165892Srustatic int 322124621Sphkalias_pna_out(struct libalias *la, struct ip *pip, 32363899Sarchie struct alias_link *link, 32463899Sarchie char *data, 32563899Sarchie int dlen) 32663899Sarchie{ 32763899Sarchie struct alias_link *pna_links; 32863899Sarchie u_short msg_id, msg_len; 32963899Sarchie char *work; 33063899Sarchie u_short alias_port, port; 33163899Sarchie struct tcphdr *tc; 33263899Sarchie 33363899Sarchie work = data; 33463899Sarchie work += 5; 33563899Sarchie while (work + 4 < data + dlen) { 33663899Sarchie memcpy(&msg_id, work, 2); 33763899Sarchie work += 2; 33863899Sarchie memcpy(&msg_len, work, 2); 33963899Sarchie work += 2; 34063899Sarchie if (ntohs(msg_id) == 0) { 34163899Sarchie /* end of options */ 34263899Sarchie return 0; 34363899Sarchie } 34463899Sarchie if ((ntohs(msg_id) == 1) || (ntohs(msg_id) == 7)) { 34571796Sbrian memcpy(&port, work, 2); 346124621Sphk pna_links = FindUdpTcpOut(la, pip->ip_src, GetDestAddress(link), 34767980Sru port, 0, IPPROTO_UDP, 1); 34863899Sarchie if (pna_links != NULL) { 34963899Sarchie#ifndef NO_FW_PUNCH 35063899Sarchie /* Punch hole in firewall */ 35163899Sarchie PunchFWHole(pna_links); 35263899Sarchie#endif 35363899Sarchie tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 35463899Sarchie alias_port = GetAliasPort(pna_links); 35571796Sbrian memcpy(work, &alias_port, 2); 35663899Sarchie 35763899Sarchie /* Compute TCP checksum for revised packet */ 35863899Sarchie tc->th_sum = 0; 35963899Sarchie tc->th_sum = TcpChecksum(pip); 36063899Sarchie } 36163899Sarchie } 36263899Sarchie work += ntohs(msg_len); 36363899Sarchie } 36499207Sbrian 36563899Sarchie return 0; 36663899Sarchie} 36763899Sarchie 36863899Sarchievoid 369124621SphkAliasHandleRtspOut(struct libalias *la, struct ip *pip, struct alias_link *link, int maxpacketsize) 37063899Sarchie{ 37163899Sarchie int hlen, tlen, dlen; 37263899Sarchie struct tcphdr *tc; 37371796Sbrian char *data; 37471796Sbrian const char *setup = "SETUP", *pna = "PNA", *str200 = "200"; 37571796Sbrian const char *okstr = "OK", *client_port_str = "client_port"; 37671796Sbrian const char *server_port_str = "server_port"; 37763899Sarchie int i, parseOk; 37863899Sarchie 37963899Sarchie tc = (struct tcphdr *)((char *)pip + (pip->ip_hl << 2)); 38063899Sarchie hlen = (pip->ip_hl + tc->th_off) << 2; 38163899Sarchie tlen = ntohs(pip->ip_len); 38263899Sarchie dlen = tlen - hlen; 38363899Sarchie 38463899Sarchie data = (char*)pip; 38563899Sarchie data += hlen; 38663899Sarchie 38763899Sarchie /* When aliasing a client, check for the SETUP request */ 38899207Sbrian if ((ntohs(tc->th_dport) == RTSP_CONTROL_PORT_NUMBER_1) || 38999207Sbrian (ntohs(tc->th_dport) == RTSP_CONTROL_PORT_NUMBER_2)) { 39063899Sarchie 39163899Sarchie if (dlen >= strlen(setup)) { 39263899Sarchie if (memcmp(data, setup, strlen(setup)) == 0) { 393124621Sphk alias_rtsp_out(la, pip, link, data, client_port_str); 39463899Sarchie return; 39563899Sarchie } 39663899Sarchie } 39763899Sarchie if (dlen >= strlen(pna)) { 39863899Sarchie if (memcmp(data, pna, strlen(pna)) == 0) { 399124621Sphk alias_pna_out(la, pip, link, data, dlen); 40063899Sarchie } 40163899Sarchie } 40263899Sarchie 40363899Sarchie } else { 40463899Sarchie 40563899Sarchie /* When aliasing a server, check for the 200 reply 40663899Sarchie Accomodate varying number of blanks between 200 & OK */ 40763899Sarchie 40863899Sarchie if (dlen >= strlen(str200)) { 40963899Sarchie 41099207Sbrian for (parseOk = 0, i = 0; 41199207Sbrian i <= dlen - strlen(str200); 41263899Sarchie i++) { 41399207Sbrian if (memcmp(&data[i], str200, strlen(str200)) == 0) { 41499207Sbrian parseOk = 1; 41563899Sarchie break; 41663899Sarchie } 41763899Sarchie } 41899207Sbrian if (parseOk) { 41963899Sarchie 42099207Sbrian i += strlen(str200); /* skip string found */ 42163899Sarchie while(data[i] == ' ') /* skip blank(s) */ 42263899Sarchie i++; 42399207Sbrian 42463899Sarchie if ((dlen - i) >= strlen(okstr)) { 42563899Sarchie 42699207Sbrian if (memcmp(&data[i], okstr, strlen(okstr)) == 0) 427124621Sphk alias_rtsp_out(la, pip, link, data, server_port_str); 42863899Sarchie 42963899Sarchie } 43063899Sarchie } 43163899Sarchie } 43263899Sarchie } 43363899Sarchie} 434