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$");
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>
103162674Spiso#include <sys/systm.h>
104162674Spiso#include <sys/kernel.h>
105162674Spiso#include <sys/module.h>
106145921Sglebius#else
107162674Spiso#include <errno.h>
108145921Sglebius#include <sys/types.h>
10963899Sarchie#include <stdio.h>
11063899Sarchie#include <string.h>
111145921Sglebius#endif
112145921Sglebius
11363899Sarchie#include <netinet/in_systm.h>
11463899Sarchie#include <netinet/in.h>
11563899Sarchie#include <netinet/ip.h>
11663899Sarchie#include <netinet/tcp.h>
11763899Sarchie
118145921Sglebius#ifdef _KERNEL
119145932Sglebius#include <netinet/libalias/alias.h>
120145921Sglebius#include <netinet/libalias/alias_local.h>
121162674Spiso#include <netinet/libalias/alias_mod.h>
122145921Sglebius#else
12363899Sarchie#include "alias_local.h"
124162674Spiso#include "alias_mod.h"
125145921Sglebius#endif
12663899Sarchie
12799207Sbrian#define RTSP_CONTROL_PORT_NUMBER_1 554
12899207Sbrian#define RTSP_CONTROL_PORT_NUMBER_2 7070
129162674Spiso#define TFTP_PORT_NUMBER 69
130162674Spiso
131162674Spisostatic void
132162674SpisoAliasHandleRtspOut(struct libalias *, struct ip *, struct alias_link *,
133162674Spiso		  int maxpacketsize);
134259858Sglebiusstatic int
135190841Spisofingerprint(struct libalias *la, struct alias_data *ah)
136162674Spiso{
137162674Spiso
138164075Smarcus	if (ah->dport != NULL && ah->aport != NULL && ah->sport != NULL &&
139164075Smarcus            ntohs(*ah->dport) == TFTP_PORT_NUMBER)
140164075Smarcus		return (0);
141259858Sglebius	if (ah->dport == NULL || ah->sport == NULL || ah->lnk == NULL ||
142162674Spiso	    ah->maxpktsize == 0)
143162674Spiso		return (-1);
144162674Spiso	if (ntohs(*ah->dport) == RTSP_CONTROL_PORT_NUMBER_1
145162674Spiso	    || ntohs(*ah->sport) == RTSP_CONTROL_PORT_NUMBER_1
146162674Spiso	    || ntohs(*ah->dport) == RTSP_CONTROL_PORT_NUMBER_2
147164075Smarcus	    || ntohs(*ah->sport) == RTSP_CONTROL_PORT_NUMBER_2)
148162674Spiso		return (0);
149162674Spiso	return (-1);
150162674Spiso}
151162674Spiso
152259858Sglebiusstatic int
153162674Spisoprotohandler(struct libalias *la, struct ip *pip, struct alias_data *ah)
154162674Spiso{
155162674Spiso
156162674Spiso	if (ntohs(*ah->dport) == TFTP_PORT_NUMBER)
157162674Spiso		FindRtspOut(la, pip->ip_src, pip->ip_dst,
158162674Spiso 			    *ah->sport, *ah->aport, IPPROTO_UDP);
159162674Spiso	else AliasHandleRtspOut(la, pip, ah->lnk, ah->maxpktsize);
160162674Spiso	return (0);
161162674Spiso}
162162674Spiso
163162674Spisostruct proto_handler handlers[] = {
164259858Sglebius	{
165259858Sglebius	  .pri = 100,
166259858Sglebius	  .dir = OUT,
167162674Spiso	  .proto = TCP|UDP,
168259858Sglebius	  .fingerprint = &fingerprint,
169162674Spiso	  .protohandler = &protohandler
170259858Sglebius	},
171162674Spiso	{ EOH }
172162674Spiso};
173162674Spiso
174162674Spisostatic int
175162674Spisomod_handler(module_t mod, int type, void *data)
176162674Spiso{
177162674Spiso	int error;
178162674Spiso
179162674Spiso	switch (type) {
180162674Spiso	case MOD_LOAD:
181162674Spiso		error = 0;
182162674Spiso		LibAliasAttachHandlers(handlers);
183162674Spiso		break;
184162674Spiso	case MOD_UNLOAD:
185162674Spiso		error = 0;
186162674Spiso		LibAliasDetachHandlers(handlers);
187162674Spiso		break;
188162674Spiso	default:
189162674Spiso		error = EINVAL;
190162674Spiso	}
191162674Spiso	return (error);
192162674Spiso}
193162674Spiso
194162674Spiso#ifdef _KERNEL
195259858Sglebiusstatic
196162674Spiso#endif
197162674Spisomoduledata_t alias_mod = {
198162674Spiso       "alias_smedia", mod_handler, NULL
199162674Spiso};
200162674Spiso
201162674Spiso#ifdef	_KERNEL
202162674SpisoDECLARE_MODULE(alias_smedia, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
203162674SpisoMODULE_VERSION(alias_smedia, 1);
204162674SpisoMODULE_DEPEND(alias_smedia, libalias, 1, 1, 1);
205162674Spiso#endif
206162674Spiso
207162674Spiso#define RTSP_CONTROL_PORT_NUMBER_1 554
208162674Spiso#define RTSP_CONTROL_PORT_NUMBER_2 7070
20963899Sarchie#define RTSP_PORT_GROUP            2
21063899Sarchie
21163899Sarchie#define ISDIGIT(a) (((a) >= '0') && ((a) <= '9'))
21263899Sarchie
21365892Srustatic int
21471796Sbriansearch_string(char *data, int dlen, const char *search_str)
21563899Sarchie{
216127094Sdes	int i, j, k;
217127094Sdes	int search_str_len;
21863899Sarchie
219127094Sdes	search_str_len = strlen(search_str);
220127094Sdes	for (i = 0; i < dlen - search_str_len; i++) {
221127094Sdes		for (j = i, k = 0; j < dlen - search_str_len; j++, k++) {
222127094Sdes			if (data[j] != search_str[k] &&
223127094Sdes			    data[j] != search_str[k] - ('a' - 'A')) {
224127094Sdes				break;
225127094Sdes			}
226127094Sdes			if (k == search_str_len - 1) {
227131613Sdes				return (j + 1);
228127094Sdes			}
229127094Sdes		}
23063899Sarchie	}
231131613Sdes	return (-1);
23263899Sarchie}
23363899Sarchie
23465892Srustatic int
235124621Sphkalias_rtsp_out(struct libalias *la, struct ip *pip,
236131614Sdes    struct alias_link *lnk,
237127094Sdes    char *data,
238127094Sdes    const char *port_str)
23963899Sarchie{
240127094Sdes	int hlen, tlen, dlen;
241127094Sdes	struct tcphdr *tc;
242127094Sdes	int i, j, pos, state, port_dlen, new_dlen, delta;
243127094Sdes	u_short p[2], new_len;
244127094Sdes	u_short sport, eport, base_port;
245127094Sdes	u_short salias = 0, ealias = 0, base_alias = 0;
246127094Sdes	const char *transport_str = "transport:";
247127094Sdes	char newdata[2048], *port_data, *port_newdata, stemp[80];
248127094Sdes	int links_created = 0, pkt_updated = 0;
249131614Sdes	struct alias_link *rtsp_lnk = NULL;
250127094Sdes	struct in_addr null_addr;
25163899Sarchie
252127094Sdes	/* Calculate data length of TCP packet */
253131699Sdes	tc = (struct tcphdr *)ip_next(pip);
254127094Sdes	hlen = (pip->ip_hl + tc->th_off) << 2;
255127094Sdes	tlen = ntohs(pip->ip_len);
256127094Sdes	dlen = tlen - hlen;
25763899Sarchie
258127094Sdes	/* Find keyword, "Transport: " */
259127094Sdes	pos = search_string(data, dlen, transport_str);
26063899Sarchie	if (pos < 0) {
261131613Sdes		return (-1);
26263899Sarchie	}
263127094Sdes	port_data = data + pos;
264127094Sdes	port_dlen = dlen - pos;
26563899Sarchie
266127094Sdes	memcpy(newdata, data, pos);
267127094Sdes	port_newdata = newdata + pos;
26863899Sarchie
269131614Sdes	while (port_dlen > (int)strlen(port_str)) {
270127094Sdes		/* Find keyword, appropriate port string */
271127094Sdes		pos = search_string(port_data, port_dlen, port_str);
272127094Sdes		if (pos < 0) {
273127094Sdes			break;
27463899Sarchie		}
275127094Sdes		memcpy(port_newdata, port_data, pos + 1);
276127094Sdes		port_newdata += (pos + 1);
27763899Sarchie
278127094Sdes		p[0] = p[1] = 0;
279127094Sdes		sport = eport = 0;
280127094Sdes		state = 0;
281127094Sdes		for (i = pos; i < port_dlen; i++) {
282127094Sdes			switch (state) {
283127094Sdes			case 0:
284127094Sdes				if (port_data[i] == '=') {
285127094Sdes					state++;
286127094Sdes				}
287127094Sdes				break;
288127094Sdes			case 1:
289127094Sdes				if (ISDIGIT(port_data[i])) {
290127094Sdes					p[0] = p[0] * 10 + port_data[i] - '0';
291127094Sdes				} else {
292127094Sdes					if (port_data[i] == ';') {
293127094Sdes						state = 3;
294127094Sdes					}
295127094Sdes					if (port_data[i] == '-') {
296127094Sdes						state++;
297127094Sdes					}
298127094Sdes				}
299127094Sdes				break;
300127094Sdes			case 2:
301127094Sdes				if (ISDIGIT(port_data[i])) {
302127094Sdes					p[1] = p[1] * 10 + port_data[i] - '0';
303127094Sdes				} else {
304127094Sdes					state++;
305127094Sdes				}
306127094Sdes				break;
307127094Sdes			case 3:
308127094Sdes				base_port = p[0];
309127094Sdes				sport = htons(p[0]);
310127094Sdes				eport = htons(p[1]);
31163899Sarchie
312127094Sdes				if (!links_created) {
313127094Sdes
314127094Sdes					links_created = 1;
315127094Sdes					/*
316127094Sdes					 * Find an even numbered port
317127094Sdes					 * number base that satisfies the
318127094Sdes					 * contiguous number of ports we
319127094Sdes					 * need
320127094Sdes					 */
321127094Sdes					null_addr.s_addr = 0;
322127094Sdes					if (0 == (salias = FindNewPortGroup(la, null_addr,
323127094Sdes					    FindAliasAddress(la, pip->ip_src),
324127094Sdes					    sport, 0,
325127094Sdes					    RTSP_PORT_GROUP,
326127094Sdes					    IPPROTO_UDP, 1))) {
327145961Sglebius#ifdef LIBALIAS_DEBUG
328127094Sdes						fprintf(stderr,
329127094Sdes						    "PacketAlias/RTSP: Cannot find contiguous RTSP data ports\n");
33063899Sarchie#endif
331127094Sdes					} else {
33263899Sarchie
333127094Sdes						base_alias = ntohs(salias);
334127094Sdes						for (j = 0; j < RTSP_PORT_GROUP; j++) {
335127094Sdes							/*
336127094Sdes							 * Establish link
337127094Sdes							 * to port found in
338127094Sdes							 * RTSP packet
339127094Sdes							 */
340131614Sdes							rtsp_lnk = FindRtspOut(la, GetOriginalAddress(lnk), null_addr,
341127094Sdes							    htons(base_port + j), htons(base_alias + j),
342127094Sdes							    IPPROTO_UDP);
343131614Sdes							if (rtsp_lnk != NULL) {
34463899Sarchie#ifndef NO_FW_PUNCH
345127094Sdes								/*
346127094Sdes								 * Punch
347127094Sdes								 * hole in
348127094Sdes								 * firewall
349127094Sdes								 */
350131614Sdes								PunchFWHole(rtsp_lnk);
35163899Sarchie#endif
352127094Sdes							} else {
353145961Sglebius#ifdef LIBALIAS_DEBUG
354127094Sdes								fprintf(stderr,
355127094Sdes								    "PacketAlias/RTSP: Cannot allocate RTSP data ports\n");
35663899Sarchie#endif
357127094Sdes								break;
358127094Sdes							}
359127094Sdes						}
360127094Sdes					}
361127094Sdes					ealias = htons(base_alias + (RTSP_PORT_GROUP - 1));
362127094Sdes				}
363131614Sdes				if (salias && rtsp_lnk) {
36463899Sarchie
365127094Sdes					pkt_updated = 1;
36663899Sarchie
367127094Sdes					/* Copy into IP packet */
368127094Sdes					sprintf(stemp, "%d", ntohs(salias));
369127094Sdes					memcpy(port_newdata, stemp, strlen(stemp));
370127094Sdes					port_newdata += strlen(stemp);
37163899Sarchie
372127094Sdes					if (eport != 0) {
373127094Sdes						*port_newdata = '-';
374127094Sdes						port_newdata++;
37563899Sarchie
376127094Sdes						/* Copy into IP packet */
377127094Sdes						sprintf(stemp, "%d", ntohs(ealias));
378127094Sdes						memcpy(port_newdata, stemp, strlen(stemp));
379127094Sdes						port_newdata += strlen(stemp);
380127094Sdes					}
381127094Sdes					*port_newdata = ';';
382127094Sdes					port_newdata++;
383127094Sdes				}
384127094Sdes				state++;
385127094Sdes				break;
386127094Sdes			}
387127094Sdes			if (state > 3) {
388127094Sdes				break;
389127094Sdes			}
39063899Sarchie		}
391127094Sdes		port_data += i;
392127094Sdes		port_dlen -= i;
39363899Sarchie	}
39463899Sarchie
395127094Sdes	if (!pkt_updated)
396131613Sdes		return (-1);
39763899Sarchie
398127094Sdes	memcpy(port_newdata, port_data, port_dlen);
399127094Sdes	port_newdata += port_dlen;
400127094Sdes	*port_newdata = '\0';
40163899Sarchie
402127094Sdes	/* Create new packet */
403127094Sdes	new_dlen = port_newdata - newdata;
404127094Sdes	memcpy(data, newdata, new_dlen);
40563899Sarchie
406131614Sdes	SetAckModified(lnk);
407176884Spiso	tc = (struct tcphdr *)ip_next(pip);
408176884Spiso	delta = GetDeltaSeqOut(tc->th_seq, lnk);
409259858Sglebius	AddSeq(lnk, delta + new_dlen - dlen, pip->ip_hl, pip->ip_len,
410176884Spiso	    tc->th_seq, tc->th_off);
41163899Sarchie
412127094Sdes	new_len = htons(hlen + new_dlen);
413127094Sdes	DifferentialChecksum(&pip->ip_sum,
414127094Sdes	    &new_len,
415127094Sdes	    &pip->ip_len,
416127094Sdes	    1);
417127094Sdes	pip->ip_len = new_len;
41863899Sarchie
419127094Sdes	tc->th_sum = 0;
420147623Sglebius#ifdef _KERNEL
421147623Sglebius	tc->th_x2 = 1;
422147623Sglebius#else
423127094Sdes	tc->th_sum = TcpChecksum(pip);
424147623Sglebius#endif
425131613Sdes	return (0);
42663899Sarchie}
42763899Sarchie
42863899Sarchie/* Support the protocol used by early versions of RealPlayer */
42963899Sarchie
43065892Srustatic int
431124621Sphkalias_pna_out(struct libalias *la, struct ip *pip,
432131614Sdes    struct alias_link *lnk,
433127094Sdes    char *data,
434127094Sdes    int dlen)
43563899Sarchie{
436127094Sdes	struct alias_link *pna_links;
437127094Sdes	u_short msg_id, msg_len;
438127094Sdes	char *work;
439127094Sdes	u_short alias_port, port;
440127094Sdes	struct tcphdr *tc;
44163899Sarchie
442127094Sdes	work = data;
443127094Sdes	work += 5;
444127094Sdes	while (work + 4 < data + dlen) {
445127094Sdes		memcpy(&msg_id, work, 2);
446127094Sdes		work += 2;
447127094Sdes		memcpy(&msg_len, work, 2);
448127094Sdes		work += 2;
449127094Sdes		if (ntohs(msg_id) == 0) {
450127094Sdes			/* end of options */
451131613Sdes			return (0);
452127094Sdes		}
453127094Sdes		if ((ntohs(msg_id) == 1) || (ntohs(msg_id) == 7)) {
454127094Sdes			memcpy(&port, work, 2);
455131614Sdes			pna_links = FindUdpTcpOut(la, pip->ip_src, GetDestAddress(lnk),
456127094Sdes			    port, 0, IPPROTO_UDP, 1);
457127094Sdes			if (pna_links != NULL) {
45863899Sarchie#ifndef NO_FW_PUNCH
459127094Sdes				/* Punch hole in firewall */
460127094Sdes				PunchFWHole(pna_links);
46163899Sarchie#endif
462131699Sdes				tc = (struct tcphdr *)ip_next(pip);
463127094Sdes				alias_port = GetAliasPort(pna_links);
464127094Sdes				memcpy(work, &alias_port, 2);
46563899Sarchie
466127094Sdes				/* Compute TCP checksum for revised packet */
467127094Sdes				tc->th_sum = 0;
468147623Sglebius#ifdef _KERNEL
469147623Sglebius				tc->th_x2 = 1;
470147623Sglebius#else
471127094Sdes				tc->th_sum = TcpChecksum(pip);
472147623Sglebius#endif
473127094Sdes			}
474127094Sdes		}
475127094Sdes		work += ntohs(msg_len);
47663899Sarchie	}
47799207Sbrian
478131613Sdes	return (0);
47963899Sarchie}
48063899Sarchie
481162674Spisostatic void
482131614SdesAliasHandleRtspOut(struct libalias *la, struct ip *pip, struct alias_link *lnk, int maxpacketsize)
48363899Sarchie{
484127094Sdes	int hlen, tlen, dlen;
485127094Sdes	struct tcphdr *tc;
486127094Sdes	char *data;
487127094Sdes	const char *setup = "SETUP", *pna = "PNA", *str200 = "200";
488127094Sdes	const char *okstr = "OK", *client_port_str = "client_port";
489127094Sdes	const char *server_port_str = "server_port";
490127094Sdes	int i, parseOk;
49163899Sarchie
492131614Sdes	(void)maxpacketsize;
493131614Sdes
494131699Sdes	tc = (struct tcphdr *)ip_next(pip);
495127094Sdes	hlen = (pip->ip_hl + tc->th_off) << 2;
496127094Sdes	tlen = ntohs(pip->ip_len);
497127094Sdes	dlen = tlen - hlen;
49863899Sarchie
499127094Sdes	data = (char *)pip;
500127094Sdes	data += hlen;
50163899Sarchie
502127094Sdes	/* When aliasing a client, check for the SETUP request */
503127094Sdes	if ((ntohs(tc->th_dport) == RTSP_CONTROL_PORT_NUMBER_1) ||
504127094Sdes	    (ntohs(tc->th_dport) == RTSP_CONTROL_PORT_NUMBER_2)) {
50563899Sarchie
506131614Sdes		if (dlen >= (int)strlen(setup)) {
507127094Sdes			if (memcmp(data, setup, strlen(setup)) == 0) {
508131614Sdes				alias_rtsp_out(la, pip, lnk, data, client_port_str);
509127094Sdes				return;
510127094Sdes			}
511127094Sdes		}
512131614Sdes		if (dlen >= (int)strlen(pna)) {
513127094Sdes			if (memcmp(data, pna, strlen(pna)) == 0) {
514131614Sdes				alias_pna_out(la, pip, lnk, data, dlen);
515127094Sdes			}
516127094Sdes		}
517127094Sdes	} else {
51863899Sarchie
519127094Sdes		/*
520127094Sdes		 * When aliasing a server, check for the 200 reply
521298995Spfg		 * Accommodate varying number of blanks between 200 & OK
522127094Sdes		 */
52363899Sarchie
524131614Sdes		if (dlen >= (int)strlen(str200)) {
52563899Sarchie
526127094Sdes			for (parseOk = 0, i = 0;
527131614Sdes			    i <= dlen - (int)strlen(str200);
528127094Sdes			    i++) {
529127094Sdes				if (memcmp(&data[i], str200, strlen(str200)) == 0) {
530127094Sdes					parseOk = 1;
531127094Sdes					break;
532127094Sdes				}
533127094Sdes			}
534127094Sdes			if (parseOk) {
53563899Sarchie
536127094Sdes				i += strlen(str200);	/* skip string found */
537127094Sdes				while (data[i] == ' ')	/* skip blank(s) */
538127094Sdes					i++;
53963899Sarchie
540131614Sdes				if ((dlen - i) >= (int)strlen(okstr)) {
54199207Sbrian
542127094Sdes					if (memcmp(&data[i], okstr, strlen(okstr)) == 0)
543131614Sdes						alias_rtsp_out(la, pip, lnk, data, server_port_str);
54463899Sarchie
545127094Sdes				}
546127094Sdes			}
547127094Sdes		}
548127094Sdes	}
54963899Sarchie}
550