alias_smedia.c revision 145961
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 145961 2005-05-06 11:07:49Z glebius $"); 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 101145921Sglebius#ifdef _KERNEL 102145921Sglebius#include <sys/param.h> 103145921Sglebius#include <sys/libkern.h> 104145921Sglebius#else 105145921Sglebius#include <sys/types.h> 10663899Sarchie#include <stdio.h> 10763899Sarchie#include <string.h> 108145921Sglebius#endif 109145921Sglebius 11063899Sarchie#include <netinet/in_systm.h> 11163899Sarchie#include <netinet/in.h> 11263899Sarchie#include <netinet/ip.h> 11363899Sarchie#include <netinet/tcp.h> 11463899Sarchie#include <netinet/udp.h> 11563899Sarchie 116145921Sglebius#ifdef _KERNEL 117145932Sglebius#include <netinet/libalias/alias.h> 118145921Sglebius#include <netinet/libalias/alias_local.h> 119145921Sglebius#else 12063899Sarchie#include "alias_local.h" 121145921Sglebius#endif 12263899Sarchie 12399207Sbrian#define RTSP_CONTROL_PORT_NUMBER_1 554 12499207Sbrian#define RTSP_CONTROL_PORT_NUMBER_2 7070 12563899Sarchie#define RTSP_PORT_GROUP 2 12663899Sarchie 12763899Sarchie#define ISDIGIT(a) (((a) >= '0') && ((a) <= '9')) 12863899Sarchie 12965892Srustatic int 13071796Sbriansearch_string(char *data, int dlen, const char *search_str) 13163899Sarchie{ 132127094Sdes int i, j, k; 133127094Sdes int search_str_len; 13463899Sarchie 135127094Sdes search_str_len = strlen(search_str); 136127094Sdes for (i = 0; i < dlen - search_str_len; i++) { 137127094Sdes for (j = i, k = 0; j < dlen - search_str_len; j++, k++) { 138127094Sdes if (data[j] != search_str[k] && 139127094Sdes data[j] != search_str[k] - ('a' - 'A')) { 140127094Sdes break; 141127094Sdes } 142127094Sdes if (k == search_str_len - 1) { 143131613Sdes return (j + 1); 144127094Sdes } 145127094Sdes } 14663899Sarchie } 147131613Sdes return (-1); 14863899Sarchie} 14963899Sarchie 15065892Srustatic int 151124621Sphkalias_rtsp_out(struct libalias *la, struct ip *pip, 152131614Sdes struct alias_link *lnk, 153127094Sdes char *data, 154127094Sdes const char *port_str) 15563899Sarchie{ 156127094Sdes int hlen, tlen, dlen; 157127094Sdes struct tcphdr *tc; 158127094Sdes int i, j, pos, state, port_dlen, new_dlen, delta; 159127094Sdes u_short p[2], new_len; 160127094Sdes u_short sport, eport, base_port; 161127094Sdes u_short salias = 0, ealias = 0, base_alias = 0; 162127094Sdes const char *transport_str = "transport:"; 163127094Sdes char newdata[2048], *port_data, *port_newdata, stemp[80]; 164127094Sdes int links_created = 0, pkt_updated = 0; 165131614Sdes struct alias_link *rtsp_lnk = NULL; 166127094Sdes struct in_addr null_addr; 16763899Sarchie 168127094Sdes /* Calculate data length of TCP packet */ 169131699Sdes tc = (struct tcphdr *)ip_next(pip); 170127094Sdes hlen = (pip->ip_hl + tc->th_off) << 2; 171127094Sdes tlen = ntohs(pip->ip_len); 172127094Sdes dlen = tlen - hlen; 17363899Sarchie 174127094Sdes /* Find keyword, "Transport: " */ 175127094Sdes pos = search_string(data, dlen, transport_str); 17663899Sarchie if (pos < 0) { 177131613Sdes return (-1); 17863899Sarchie } 179127094Sdes port_data = data + pos; 180127094Sdes port_dlen = dlen - pos; 18163899Sarchie 182127094Sdes memcpy(newdata, data, pos); 183127094Sdes port_newdata = newdata + pos; 18463899Sarchie 185131614Sdes while (port_dlen > (int)strlen(port_str)) { 186127094Sdes /* Find keyword, appropriate port string */ 187127094Sdes pos = search_string(port_data, port_dlen, port_str); 188127094Sdes if (pos < 0) { 189127094Sdes break; 19063899Sarchie } 191127094Sdes memcpy(port_newdata, port_data, pos + 1); 192127094Sdes port_newdata += (pos + 1); 19363899Sarchie 194127094Sdes p[0] = p[1] = 0; 195127094Sdes sport = eport = 0; 196127094Sdes state = 0; 197127094Sdes for (i = pos; i < port_dlen; i++) { 198127094Sdes switch (state) { 199127094Sdes case 0: 200127094Sdes if (port_data[i] == '=') { 201127094Sdes state++; 202127094Sdes } 203127094Sdes break; 204127094Sdes case 1: 205127094Sdes if (ISDIGIT(port_data[i])) { 206127094Sdes p[0] = p[0] * 10 + port_data[i] - '0'; 207127094Sdes } else { 208127094Sdes if (port_data[i] == ';') { 209127094Sdes state = 3; 210127094Sdes } 211127094Sdes if (port_data[i] == '-') { 212127094Sdes state++; 213127094Sdes } 214127094Sdes } 215127094Sdes break; 216127094Sdes case 2: 217127094Sdes if (ISDIGIT(port_data[i])) { 218127094Sdes p[1] = p[1] * 10 + port_data[i] - '0'; 219127094Sdes } else { 220127094Sdes state++; 221127094Sdes } 222127094Sdes break; 223127094Sdes case 3: 224127094Sdes base_port = p[0]; 225127094Sdes sport = htons(p[0]); 226127094Sdes eport = htons(p[1]); 22763899Sarchie 228127094Sdes if (!links_created) { 229127094Sdes 230127094Sdes links_created = 1; 231127094Sdes /* 232127094Sdes * Find an even numbered port 233127094Sdes * number base that satisfies the 234127094Sdes * contiguous number of ports we 235127094Sdes * need 236127094Sdes */ 237127094Sdes null_addr.s_addr = 0; 238127094Sdes if (0 == (salias = FindNewPortGroup(la, null_addr, 239127094Sdes FindAliasAddress(la, pip->ip_src), 240127094Sdes sport, 0, 241127094Sdes RTSP_PORT_GROUP, 242127094Sdes IPPROTO_UDP, 1))) { 243145961Sglebius#ifdef LIBALIAS_DEBUG 244127094Sdes fprintf(stderr, 245127094Sdes "PacketAlias/RTSP: Cannot find contiguous RTSP data ports\n"); 24663899Sarchie#endif 247127094Sdes } else { 24863899Sarchie 249127094Sdes base_alias = ntohs(salias); 250127094Sdes for (j = 0; j < RTSP_PORT_GROUP; j++) { 251127094Sdes /* 252127094Sdes * Establish link 253127094Sdes * to port found in 254127094Sdes * RTSP packet 255127094Sdes */ 256131614Sdes rtsp_lnk = FindRtspOut(la, GetOriginalAddress(lnk), null_addr, 257127094Sdes htons(base_port + j), htons(base_alias + j), 258127094Sdes IPPROTO_UDP); 259131614Sdes if (rtsp_lnk != NULL) { 26063899Sarchie#ifndef NO_FW_PUNCH 261127094Sdes /* 262127094Sdes * Punch 263127094Sdes * hole in 264127094Sdes * firewall 265127094Sdes */ 266131614Sdes PunchFWHole(rtsp_lnk); 26763899Sarchie#endif 268127094Sdes } else { 269145961Sglebius#ifdef LIBALIAS_DEBUG 270127094Sdes fprintf(stderr, 271127094Sdes "PacketAlias/RTSP: Cannot allocate RTSP data ports\n"); 27263899Sarchie#endif 273127094Sdes break; 274127094Sdes } 275127094Sdes } 276127094Sdes } 277127094Sdes ealias = htons(base_alias + (RTSP_PORT_GROUP - 1)); 278127094Sdes } 279131614Sdes if (salias && rtsp_lnk) { 28063899Sarchie 281127094Sdes pkt_updated = 1; 28263899Sarchie 283127094Sdes /* Copy into IP packet */ 284127094Sdes sprintf(stemp, "%d", ntohs(salias)); 285127094Sdes memcpy(port_newdata, stemp, strlen(stemp)); 286127094Sdes port_newdata += strlen(stemp); 28763899Sarchie 288127094Sdes if (eport != 0) { 289127094Sdes *port_newdata = '-'; 290127094Sdes port_newdata++; 29163899Sarchie 292127094Sdes /* Copy into IP packet */ 293127094Sdes sprintf(stemp, "%d", ntohs(ealias)); 294127094Sdes memcpy(port_newdata, stemp, strlen(stemp)); 295127094Sdes port_newdata += strlen(stemp); 296127094Sdes } 297127094Sdes *port_newdata = ';'; 298127094Sdes port_newdata++; 299127094Sdes } 300127094Sdes state++; 301127094Sdes break; 302127094Sdes } 303127094Sdes if (state > 3) { 304127094Sdes break; 305127094Sdes } 30663899Sarchie } 307127094Sdes port_data += i; 308127094Sdes port_dlen -= i; 30963899Sarchie } 31063899Sarchie 311127094Sdes if (!pkt_updated) 312131613Sdes return (-1); 31363899Sarchie 314127094Sdes memcpy(port_newdata, port_data, port_dlen); 315127094Sdes port_newdata += port_dlen; 316127094Sdes *port_newdata = '\0'; 31763899Sarchie 318127094Sdes /* Create new packet */ 319127094Sdes new_dlen = port_newdata - newdata; 320127094Sdes memcpy(data, newdata, new_dlen); 32163899Sarchie 322131614Sdes SetAckModified(lnk); 323131614Sdes delta = GetDeltaSeqOut(pip, lnk); 324131614Sdes AddSeq(pip, lnk, delta + new_dlen - dlen); 32563899Sarchie 326127094Sdes new_len = htons(hlen + new_dlen); 327127094Sdes DifferentialChecksum(&pip->ip_sum, 328127094Sdes &new_len, 329127094Sdes &pip->ip_len, 330127094Sdes 1); 331127094Sdes pip->ip_len = new_len; 33263899Sarchie 333127094Sdes tc->th_sum = 0; 334127094Sdes tc->th_sum = TcpChecksum(pip); 33563899Sarchie 336131613Sdes return (0); 33763899Sarchie} 33863899Sarchie 33963899Sarchie/* Support the protocol used by early versions of RealPlayer */ 34063899Sarchie 34165892Srustatic int 342124621Sphkalias_pna_out(struct libalias *la, struct ip *pip, 343131614Sdes struct alias_link *lnk, 344127094Sdes char *data, 345127094Sdes int dlen) 34663899Sarchie{ 347127094Sdes struct alias_link *pna_links; 348127094Sdes u_short msg_id, msg_len; 349127094Sdes char *work; 350127094Sdes u_short alias_port, port; 351127094Sdes struct tcphdr *tc; 35263899Sarchie 353127094Sdes work = data; 354127094Sdes work += 5; 355127094Sdes while (work + 4 < data + dlen) { 356127094Sdes memcpy(&msg_id, work, 2); 357127094Sdes work += 2; 358127094Sdes memcpy(&msg_len, work, 2); 359127094Sdes work += 2; 360127094Sdes if (ntohs(msg_id) == 0) { 361127094Sdes /* end of options */ 362131613Sdes return (0); 363127094Sdes } 364127094Sdes if ((ntohs(msg_id) == 1) || (ntohs(msg_id) == 7)) { 365127094Sdes memcpy(&port, work, 2); 366131614Sdes pna_links = FindUdpTcpOut(la, pip->ip_src, GetDestAddress(lnk), 367127094Sdes port, 0, IPPROTO_UDP, 1); 368127094Sdes if (pna_links != NULL) { 36963899Sarchie#ifndef NO_FW_PUNCH 370127094Sdes /* Punch hole in firewall */ 371127094Sdes PunchFWHole(pna_links); 37263899Sarchie#endif 373131699Sdes tc = (struct tcphdr *)ip_next(pip); 374127094Sdes alias_port = GetAliasPort(pna_links); 375127094Sdes memcpy(work, &alias_port, 2); 37663899Sarchie 377127094Sdes /* Compute TCP checksum for revised packet */ 378127094Sdes tc->th_sum = 0; 379127094Sdes tc->th_sum = TcpChecksum(pip); 380127094Sdes } 381127094Sdes } 382127094Sdes work += ntohs(msg_len); 38363899Sarchie } 38499207Sbrian 385131613Sdes return (0); 38663899Sarchie} 38763899Sarchie 38863899Sarchievoid 389131614SdesAliasHandleRtspOut(struct libalias *la, struct ip *pip, struct alias_link *lnk, int maxpacketsize) 39063899Sarchie{ 391127094Sdes int hlen, tlen, dlen; 392127094Sdes struct tcphdr *tc; 393127094Sdes char *data; 394127094Sdes const char *setup = "SETUP", *pna = "PNA", *str200 = "200"; 395127094Sdes const char *okstr = "OK", *client_port_str = "client_port"; 396127094Sdes const char *server_port_str = "server_port"; 397127094Sdes int i, parseOk; 39863899Sarchie 399131614Sdes (void)maxpacketsize; 400131614Sdes 401131699Sdes tc = (struct tcphdr *)ip_next(pip); 402127094Sdes hlen = (pip->ip_hl + tc->th_off) << 2; 403127094Sdes tlen = ntohs(pip->ip_len); 404127094Sdes dlen = tlen - hlen; 40563899Sarchie 406127094Sdes data = (char *)pip; 407127094Sdes data += hlen; 40863899Sarchie 409127094Sdes /* When aliasing a client, check for the SETUP request */ 410127094Sdes if ((ntohs(tc->th_dport) == RTSP_CONTROL_PORT_NUMBER_1) || 411127094Sdes (ntohs(tc->th_dport) == RTSP_CONTROL_PORT_NUMBER_2)) { 41263899Sarchie 413131614Sdes if (dlen >= (int)strlen(setup)) { 414127094Sdes if (memcmp(data, setup, strlen(setup)) == 0) { 415131614Sdes alias_rtsp_out(la, pip, lnk, data, client_port_str); 416127094Sdes return; 417127094Sdes } 418127094Sdes } 419131614Sdes if (dlen >= (int)strlen(pna)) { 420127094Sdes if (memcmp(data, pna, strlen(pna)) == 0) { 421131614Sdes alias_pna_out(la, pip, lnk, data, dlen); 422127094Sdes } 423127094Sdes } 424127094Sdes } else { 42563899Sarchie 426127094Sdes /* 427127094Sdes * When aliasing a server, check for the 200 reply 428127094Sdes * Accomodate varying number of blanks between 200 & OK 429127094Sdes */ 43063899Sarchie 431131614Sdes if (dlen >= (int)strlen(str200)) { 43263899Sarchie 433127094Sdes for (parseOk = 0, i = 0; 434131614Sdes i <= dlen - (int)strlen(str200); 435127094Sdes i++) { 436127094Sdes if (memcmp(&data[i], str200, strlen(str200)) == 0) { 437127094Sdes parseOk = 1; 438127094Sdes break; 439127094Sdes } 440127094Sdes } 441127094Sdes if (parseOk) { 44263899Sarchie 443127094Sdes i += strlen(str200); /* skip string found */ 444127094Sdes while (data[i] == ' ') /* skip blank(s) */ 445127094Sdes i++; 44663899Sarchie 447131614Sdes if ((dlen - i) >= (int)strlen(okstr)) { 44899207Sbrian 449127094Sdes if (memcmp(&data[i], okstr, strlen(okstr)) == 0) 450131614Sdes alias_rtsp_out(la, pip, lnk, data, server_port_str); 45163899Sarchie 452127094Sdes } 453127094Sdes } 454127094Sdes } 455127094Sdes } 45663899Sarchie} 457