alias_smedia.c revision 63899
1331722Seadler/* 2156952Sume * alias_smedia.c 3156952Sume * 4156952Sume * Copyright (c) 2000 Whistle Communications, Inc. 5156952Sume * All rights reserved. 6156952Sume * 7156952Sume * Subject to the following obligations and disclaimer of warranty, use and 8156952Sume * redistribution of this software, in source or object code forms, with or 9156952Sume * without modifications are expressly permitted by Whistle Communications; 10156952Sume * provided, however, that: 11156952Sume * 1. Any and all reproductions of the source or object code must include the 12156952Sume * copyright notice above and the following disclaimer of warranties; and 13156952Sume * 2. No rights are granted, in any manner or form, to use Whistle 14156952Sume * Communications, Inc. trademarks, including the mark "WHISTLE 15156952Sume * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 16156952Sume * such appears in the above copyright notice or in the software. 17156952Sume * 18156952Sume * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 19156952Sume * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 20156952Sume * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 21156952Sume * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 22156952Sume * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 23156952Sume * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 24156952Sume * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 25156952Sume * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 26156952Sume * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 27156952Sume * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 28156952Sume * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 29156952Sume * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 30156952Sume * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 31156952Sume * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 32156952Sume * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 33156952Sume * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 34156952Sume * OF SUCH DAMAGE. 35156952Sume * 36156952Sume * Copyright (c) 2000 Junichi SATOH <junichi@astec.co.jp> 37156952Sume * <junichi@junichi.org> 38156952Sume * All rights reserved. 39156952Sume * 40156952Sume * Redistribution and use in source and binary forms, with or without 41156952Sume * modification, are permitted provided that the following conditions 42156952Sume * are met: 43156952Sume * 1. Redistributions of source code must retain the above copyright 44156952Sume * notice, this list of conditions and the following disclaimer. 45156952Sume * 2. Redistributions in binary form must reproduce the above copyright 46156952Sume * notice, this list of conditions and the following disclaimer in the 47156952Sume * documentation and/or other materials provided with the distribution. 48156952Sume * 49269867Sume * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 50156952Sume * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 51156956Sume * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 52156956Sume * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 53156952Sume * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 54156952Sume * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 55156952Sume * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 56156956Sume * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 57156952Sume * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 58156952Sume * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 59156952Sume * SUCH DAMAGE. 60156952Sume * 61156952Sume * Authors: Erik Salander <erik@whistle.com> 62156952Sume * Junichi SATOH <junichi@astec.co.jp> 63156952Sume * <junichi@junichi.org> 64156952Sume * 65156952Sume * $FreeBSD: head/sys/netinet/libalias/alias_smedia.c 63899 2000-07-26 23:15:46Z archie $ 66156952Sume */ 67156956Sume 68156952Sume/* 69156952Sume Alias_smedia.c is meant to contain the aliasing code for streaming media 70156952Sume protocols. It performs special processing for RSTP sessions under TCP. 71156952Sume Specifically, when a SETUP request is sent by a client, or a 200 reply 72156952Sume is sent by a server, it is intercepted and modified. The address is 73170244Sume changed to the gateway machine and an aliasing port is used. 74170244Sume 75170244Sume More specifically, the "client_port" configuration parameter is 76170244Sume parsed for SETUP requests. The "server_port" configuration parameter is 77156952Sume parsed for 200 replies eminating from a server. This is intended to handle 78298120Spfg the unicast case. 79156952Sume 80156952Sume RTSP also allows a redirection of a stream to another client by using the 81156952Sume "destination" configuration parameter. The destination config parm would 82156952Sume indicate a different IP address. This function is NOT supported by the 83170244Sume RTSP translation code below. 84156952Sume 85156952Sume The RTSP multicast functions without any address translation intervention. 86156952Sume 87156952Sume For this routine to work, the SETUP/200 must fit entirely 88156952Sume into a single TCP packet. This is typically the case, but exceptions 89156952Sume can easily be envisioned under the actual specifications. 90156952Sume 91156952Sume Probably the most troubling aspect of the approach taken here is 92156952Sume that the new SETUP/200 will typically be a different length, and 93156952Sume this causes a certain amount of bookkeeping to keep track of the 94156952Sume changes of sequence and acknowledgment numbers, since the client 95156952Sume machine is totally unaware of the modification to the TCP stream. 96156952Sume 97156952Sume Initial version: May, 2000 (eds) 98156952Sume*/ 99156952Sume 100156952Sume#include <stdio.h> 101156952Sume#include <string.h> 102156952Sume#include <sys/types.h> 103156952Sume#include <netinet/in_systm.h> 104156952Sume#include <netinet/in.h> 105156952Sume#include <netinet/ip.h> 106156952Sume#include <netinet/tcp.h> 107156952Sume#include <netinet/udp.h> 108156952Sume 109156956Sume#include "alias_local.h" 110156952Sume 111156952Sume#define RTSP_CONTROL_PORT_NUMBER_1 554 112170244Sume#define RTSP_CONTROL_PORT_NUMBER_2 7070 113156952Sume#define RTSP_PORT_GROUP 2 114156952Sume 115156952Sume#define ISDIGIT(a) (((a) >= '0') && ((a) <= '9')) 116156952Sume 117156952Sumeint search_string(char *data, int dlen, char *search_str) 118156952Sume{ 119156952Sume int i, j, k; 120156952Sume int search_str_len; 121156952Sume 122156952Sume search_str_len = strlen(search_str); 123156952Sume for (i = 0; i < dlen - search_str_len; i++) { 124170244Sume for (j = i, k = 0; j < dlen - search_str_len; j++, k++) { 125170244Sume if (data[j] != search_str[k] && 126 data[j] != search_str[k] - ('a' - 'A')) { 127 break; 128 } 129 if (k == search_str_len - 1) { 130 return j + 1; 131 } 132 } 133 } 134 return -1; 135} 136 137int alias_rtsp_out(struct ip *pip, 138 struct alias_link *link, 139 char *data, 140 char *port_str) 141{ 142 int hlen, tlen, dlen; 143 struct tcphdr *tc; 144 int i, j, pos, state, port_dlen, new_dlen, delta; 145 u_short p[2], new_len; 146 u_short sport, eport, base_port; 147 u_short salias = 0, ealias = 0, base_alias = 0; 148 char *transport_str = "transport:"; 149 char newdata[2048], *port_data, *port_newdata, stemp[80]; 150 int links_created = 0, pkt_updated = 0; 151 struct alias_link *rtsp_link = NULL; 152 struct in_addr null_addr; 153 154 /* Calculate data length of TCP packet */ 155 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 156 hlen = (pip->ip_hl + tc->th_off) << 2; 157 tlen = ntohs(pip->ip_len); 158 dlen = tlen - hlen; 159 160 /* Find keyword, "Transport: " */ 161 pos = search_string(data, dlen, transport_str); 162 if (pos < 0) { 163 return -1; 164 } 165 port_data = data + pos; 166 port_dlen = dlen - pos; 167 168 memcpy(newdata, data, pos); 169 port_newdata = newdata + pos; 170 171 while (port_dlen > strlen(port_str)) { 172 /* Find keyword, appropriate port string */ 173 pos = search_string(port_data, port_dlen, port_str); 174 if (pos < 0) { 175 break; 176 } 177 178 memcpy (port_newdata, port_data, pos + 1); 179 port_newdata += (pos + 1); 180 181 p[0] = p[1] = 0; 182 sport = eport = 0; 183 state = 0; 184 for (i = pos; i < port_dlen; i++) { 185 switch(state) { 186 case 0: 187 if (port_data[i] == '=') { 188 state++; 189 } 190 break; 191 case 1: 192 if (ISDIGIT(port_data[i])) { 193 p[0] = p[0] * 10 + port_data[i] - '0'; 194 } else { 195 if (port_data[i] == ';') { 196 state = 3; 197 } 198 if (port_data[i] == '-') { 199 state++; 200 } 201 } 202 break; 203 case 2: 204 if (ISDIGIT(port_data[i])) { 205 p[1] = p[1] * 10 + port_data[i] - '0'; 206 } else { 207 state++; 208 } 209 break; 210 case 3: 211 base_port = p[0]; 212 sport = htons(p[0]); 213 eport = htons(p[1]); 214 215 if (!links_created) { 216 217 links_created = 1; 218 /* Find an even numbered port number base that 219 satisfies the contiguous number of ports we need */ 220 null_addr.s_addr = 0; 221 if (0 == (salias = FindNewPortGroup(null_addr, 222 FindAliasAddress(pip->ip_src), 223 sport, 0, 224 RTSP_PORT_GROUP, 225 IPPROTO_UDP, 1))) { 226#ifdef DEBUG 227 fprintf(stderr, 228 "PacketAlias/RTSP: Cannot find contiguous RTSP data ports\n"); 229#endif 230 } else { 231 232 base_alias = ntohs(salias); 233 for (j = 0; j < RTSP_PORT_GROUP; j++) { 234 /* Establish link to port found in RTSP packet */ 235 rtsp_link = FindRtspOut(GetOriginalAddress(link), null_addr, 236 htons(base_port + j), htons(base_alias + j), 237 IPPROTO_UDP); 238 if (rtsp_link != NULL) { 239#ifndef NO_FW_PUNCH 240 /* Punch hole in firewall */ 241 PunchFWHole(rtsp_link); 242#endif 243 } else { 244#ifdef DEBUG 245 fprintf(stderr, 246 "PacketAlias/RTSP: Cannot allocate RTSP data ports\n"); 247#endif 248 break; 249 } 250 } 251 } 252 ealias = htons(base_alias + (RTSP_PORT_GROUP - 1)); 253 } 254 255 if (salias && rtsp_link) { 256 257 pkt_updated = 1; 258 259 /* Copy into IP packet */ 260 sprintf(stemp, "%d", ntohs(salias)); 261 memcpy(port_newdata, stemp, strlen(stemp)); 262 port_newdata += strlen(stemp); 263 264 if (eport != 0) { 265 *port_newdata = '-'; 266 port_newdata++; 267 268 /* Copy into IP packet */ 269 sprintf(stemp, "%d", ntohs(ealias)); 270 memcpy(port_newdata, stemp, strlen(stemp)); 271 port_newdata += strlen(stemp); 272 } 273 274 *port_newdata = ';'; 275 port_newdata++; 276 } 277 state++; 278 break; 279 } 280 if (state > 3) { 281 break; 282 } 283 } 284 port_data += i; 285 port_dlen -= i; 286 } 287 288 if (!pkt_updated) 289 return -1; 290 291 memcpy (port_newdata, port_data, port_dlen); 292 port_newdata += port_dlen; 293 *port_newdata = '\0'; 294 295 /* Create new packet */ 296 new_dlen = port_newdata - newdata; 297 memcpy (data, newdata, new_dlen); 298 299 SetAckModified(link); 300 delta = GetDeltaSeqOut(pip, link); 301 AddSeq(pip, link, delta + new_dlen - dlen); 302 303 new_len = htons(hlen + new_dlen); 304 DifferentialChecksum(&pip->ip_sum, 305 &new_len, 306 &pip->ip_len, 307 1); 308 pip->ip_len = new_len; 309 310 tc->th_sum = 0; 311 tc->th_sum = TcpChecksum(pip); 312 313 return 0; 314} 315 316/* Support the protocol used by early versions of RealPlayer */ 317 318int alias_pna_out(struct ip *pip, 319 struct alias_link *link, 320 char *data, 321 int dlen) 322{ 323 struct alias_link *pna_links; 324 u_short msg_id, msg_len; 325 char *work; 326 u_short alias_port, port; 327 struct tcphdr *tc; 328 329 work = data; 330 work += 5; 331 while (work + 4 < data + dlen) { 332 memcpy(&msg_id, work, 2); 333 work += 2; 334 memcpy(&msg_len, work, 2); 335 work += 2; 336 if (ntohs(msg_id) == 0) { 337 /* end of options */ 338 return 0; 339 } 340 if ((ntohs(msg_id) == 1) || (ntohs(msg_id) == 7)) { 341 memcpy((char*)&port, (char*)work, 2); 342 pna_links = FindUdpTcpOut(pip->ip_src, GetDestAddress(link), 343 port, 0, IPPROTO_UDP); 344 if (pna_links != NULL) { 345#ifndef NO_FW_PUNCH 346 /* Punch hole in firewall */ 347 PunchFWHole(pna_links); 348#endif 349 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 350 alias_port = GetAliasPort(pna_links); 351 memcpy((char*)work, (char*)&alias_port, 2); 352 353 /* Compute TCP checksum for revised packet */ 354 tc->th_sum = 0; 355 tc->th_sum = TcpChecksum(pip); 356 } 357 } 358 work += ntohs(msg_len); 359 } 360 361 return 0; 362} 363 364void 365AliasHandleRtspOut(struct ip *pip, struct alias_link *link, int maxpacketsize) 366{ 367 int hlen, tlen, dlen; 368 struct tcphdr *tc; 369 char *data, *setup = "SETUP", *pna = "PNA", *str200 = "200", *okstr = "OK"; 370 char *client_port_str = "client_port", *server_port_str = "server_port"; 371 int i, parseOk; 372 373 tc = (struct tcphdr *)((char *)pip + (pip->ip_hl << 2)); 374 hlen = (pip->ip_hl + tc->th_off) << 2; 375 tlen = ntohs(pip->ip_len); 376 dlen = tlen - hlen; 377 378 data = (char*)pip; 379 data += hlen; 380 381 /* When aliasing a client, check for the SETUP request */ 382 if ((ntohs(tc->th_dport) == RTSP_CONTROL_PORT_NUMBER_1) || 383 (ntohs(tc->th_dport) == RTSP_CONTROL_PORT_NUMBER_2)) { 384 385 if (dlen >= strlen(setup)) { 386 if (memcmp(data, setup, strlen(setup)) == 0) { 387 alias_rtsp_out(pip, link, data, client_port_str); 388 return; 389 } 390 } 391 if (dlen >= strlen(pna)) { 392 if (memcmp(data, pna, strlen(pna)) == 0) { 393 alias_pna_out(pip, link, data, dlen); 394 } 395 } 396 397 } else { 398 399 /* When aliasing a server, check for the 200 reply 400 Accomodate varying number of blanks between 200 & OK */ 401 402 if (dlen >= strlen(str200)) { 403 404 for (parseOk = 0, i = 0; 405 i <= dlen - strlen(str200); 406 i++) { 407 if (memcmp(&data[i], str200, strlen(str200)) == 0) { 408 parseOk = 1; 409 break; 410 } 411 } 412 if (parseOk) { 413 414 i += strlen(str200); /* skip string found */ 415 while(data[i] == ' ') /* skip blank(s) */ 416 i++; 417 418 if ((dlen - i) >= strlen(okstr)) { 419 420 if (memcmp(&data[i], okstr, strlen(okstr)) == 0) 421 alias_rtsp_out(pip, link, data, server_port_str); 422 423 } 424 } 425 } 426 } 427} 428