Deleted Added
full compact
alias_smedia.c (190841) alias_smedia.c (259858)
1/*
2 * alias_smedia.c
3 *
4 * Copyright (c) 2000 Whistle Communications, Inc.
5 * All rights reserved.
6 *
7 * Subject to the following obligations and disclaimer of warranty, use and
8 * redistribution of this software, in source or object code forms, with or
9 * without modifications are expressly permitted by Whistle Communications;
10 * provided, however, that:
11 * 1. Any and all reproductions of the source or object code must include the
12 * copyright notice above and the following disclaimer of warranties; and
13 * 2. No rights are granted, in any manner or form, to use Whistle
14 * Communications, Inc. trademarks, including the mark "WHISTLE
15 * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
16 * such appears in the above copyright notice or in the software.
17 *
18 * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
19 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
20 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
21 * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
23 * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
24 * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
25 * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
26 * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
27 * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
28 * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
29 * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33 * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
34 * OF SUCH DAMAGE.
35 *
36 * Copyright (c) 2000 Junichi SATOH <junichi@astec.co.jp>
37 * <junichi@junichi.org>
38 * All rights reserved.
39 *
40 * Redistribution and use in source and binary forms, with or without
41 * modification, are permitted provided that the following conditions
42 * are met:
43 * 1. Redistributions of source code must retain the above copyright
44 * notice, this list of conditions and the following disclaimer.
45 * 2. Redistributions in binary form must reproduce the above copyright
46 * notice, this list of conditions and the following disclaimer in the
47 * documentation and/or other materials provided with the distribution.
48 *
49 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 * SUCH DAMAGE.
60 *
61 * Authors: Erik Salander <erik@whistle.com>
62 * Junichi SATOH <junichi@astec.co.jp>
63 * <junichi@junichi.org>
64 */
65
66#include <sys/cdefs.h>
1/*
2 * alias_smedia.c
3 *
4 * Copyright (c) 2000 Whistle Communications, Inc.
5 * All rights reserved.
6 *
7 * Subject to the following obligations and disclaimer of warranty, use and
8 * redistribution of this software, in source or object code forms, with or
9 * without modifications are expressly permitted by Whistle Communications;
10 * provided, however, that:
11 * 1. Any and all reproductions of the source or object code must include the
12 * copyright notice above and the following disclaimer of warranties; and
13 * 2. No rights are granted, in any manner or form, to use Whistle
14 * Communications, Inc. trademarks, including the mark "WHISTLE
15 * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
16 * such appears in the above copyright notice or in the software.
17 *
18 * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
19 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
20 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
21 * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
23 * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
24 * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
25 * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
26 * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
27 * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
28 * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
29 * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33 * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
34 * OF SUCH DAMAGE.
35 *
36 * Copyright (c) 2000 Junichi SATOH <junichi@astec.co.jp>
37 * <junichi@junichi.org>
38 * All rights reserved.
39 *
40 * Redistribution and use in source and binary forms, with or without
41 * modification, are permitted provided that the following conditions
42 * are met:
43 * 1. Redistributions of source code must retain the above copyright
44 * notice, this list of conditions and the following disclaimer.
45 * 2. Redistributions in binary form must reproduce the above copyright
46 * notice, this list of conditions and the following disclaimer in the
47 * documentation and/or other materials provided with the distribution.
48 *
49 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 * SUCH DAMAGE.
60 *
61 * Authors: Erik Salander <erik@whistle.com>
62 * Junichi SATOH <junichi@astec.co.jp>
63 * <junichi@junichi.org>
64 */
65
66#include <sys/cdefs.h>
67__FBSDID("$FreeBSD: head/sys/netinet/libalias/alias_smedia.c 190841 2009-04-08 11:56:49Z piso $");
67__FBSDID("$FreeBSD: head/sys/netinet/libalias/alias_smedia.c 259858 2013-12-25 02:06:57Z glebius $");
68
69/*
70 Alias_smedia.c is meant to contain the aliasing code for streaming media
71 protocols. It performs special processing for RSTP sessions under TCP.
72 Specifically, when a SETUP request is sent by a client, or a 200 reply
73 is sent by a server, it is intercepted and modified. The address is
74 changed to the gateway machine and an aliasing port is used.
75
76 More specifically, the "client_port" configuration parameter is
77 parsed for SETUP requests. The "server_port" configuration parameter is
78 parsed for 200 replies eminating from a server. This is intended to handle
79 the unicast case.
80
81 RTSP also allows a redirection of a stream to another client by using the
82 "destination" configuration parameter. The destination config parm would
83 indicate a different IP address. This function is NOT supported by the
84 RTSP translation code below.
85
86 The RTSP multicast functions without any address translation intervention.
87
88 For this routine to work, the SETUP/200 must fit entirely
89 into a single TCP packet. This is typically the case, but exceptions
90 can easily be envisioned under the actual specifications.
91
92 Probably the most troubling aspect of the approach taken here is
93 that the new SETUP/200 will typically be a different length, and
94 this causes a certain amount of bookkeeping to keep track of the
95 changes of sequence and acknowledgment numbers, since the client
96 machine is totally unaware of the modification to the TCP stream.
97
98 Initial version: May, 2000 (eds)
99*/
100
101#ifdef _KERNEL
102#include <sys/param.h>
103#include <sys/systm.h>
104#include <sys/kernel.h>
105#include <sys/module.h>
106#else
107#include <errno.h>
108#include <sys/types.h>
109#include <stdio.h>
110#include <string.h>
111#endif
112
113#include <netinet/in_systm.h>
114#include <netinet/in.h>
115#include <netinet/ip.h>
116#include <netinet/tcp.h>
117
118#ifdef _KERNEL
119#include <netinet/libalias/alias.h>
120#include <netinet/libalias/alias_local.h>
121#include <netinet/libalias/alias_mod.h>
122#else
123#include "alias_local.h"
124#include "alias_mod.h"
125#endif
126
127#define RTSP_CONTROL_PORT_NUMBER_1 554
128#define RTSP_CONTROL_PORT_NUMBER_2 7070
129#define TFTP_PORT_NUMBER 69
130
131static void
132AliasHandleRtspOut(struct libalias *, struct ip *, struct alias_link *,
133 int maxpacketsize);
68
69/*
70 Alias_smedia.c is meant to contain the aliasing code for streaming media
71 protocols. It performs special processing for RSTP sessions under TCP.
72 Specifically, when a SETUP request is sent by a client, or a 200 reply
73 is sent by a server, it is intercepted and modified. The address is
74 changed to the gateway machine and an aliasing port is used.
75
76 More specifically, the "client_port" configuration parameter is
77 parsed for SETUP requests. The "server_port" configuration parameter is
78 parsed for 200 replies eminating from a server. This is intended to handle
79 the unicast case.
80
81 RTSP also allows a redirection of a stream to another client by using the
82 "destination" configuration parameter. The destination config parm would
83 indicate a different IP address. This function is NOT supported by the
84 RTSP translation code below.
85
86 The RTSP multicast functions without any address translation intervention.
87
88 For this routine to work, the SETUP/200 must fit entirely
89 into a single TCP packet. This is typically the case, but exceptions
90 can easily be envisioned under the actual specifications.
91
92 Probably the most troubling aspect of the approach taken here is
93 that the new SETUP/200 will typically be a different length, and
94 this causes a certain amount of bookkeeping to keep track of the
95 changes of sequence and acknowledgment numbers, since the client
96 machine is totally unaware of the modification to the TCP stream.
97
98 Initial version: May, 2000 (eds)
99*/
100
101#ifdef _KERNEL
102#include <sys/param.h>
103#include <sys/systm.h>
104#include <sys/kernel.h>
105#include <sys/module.h>
106#else
107#include <errno.h>
108#include <sys/types.h>
109#include <stdio.h>
110#include <string.h>
111#endif
112
113#include <netinet/in_systm.h>
114#include <netinet/in.h>
115#include <netinet/ip.h>
116#include <netinet/tcp.h>
117
118#ifdef _KERNEL
119#include <netinet/libalias/alias.h>
120#include <netinet/libalias/alias_local.h>
121#include <netinet/libalias/alias_mod.h>
122#else
123#include "alias_local.h"
124#include "alias_mod.h"
125#endif
126
127#define RTSP_CONTROL_PORT_NUMBER_1 554
128#define RTSP_CONTROL_PORT_NUMBER_2 7070
129#define TFTP_PORT_NUMBER 69
130
131static void
132AliasHandleRtspOut(struct libalias *, struct ip *, struct alias_link *,
133 int maxpacketsize);
134static int
134static int
135fingerprint(struct libalias *la, struct alias_data *ah)
136{
137
138 if (ah->dport != NULL && ah->aport != NULL && ah->sport != NULL &&
139 ntohs(*ah->dport) == TFTP_PORT_NUMBER)
140 return (0);
135fingerprint(struct libalias *la, struct alias_data *ah)
136{
137
138 if (ah->dport != NULL && ah->aport != NULL && ah->sport != NULL &&
139 ntohs(*ah->dport) == TFTP_PORT_NUMBER)
140 return (0);
141 if (ah->dport == NULL || ah->sport == NULL || ah->lnk == NULL ||
141 if (ah->dport == NULL || ah->sport == NULL || ah->lnk == NULL ||
142 ah->maxpktsize == 0)
143 return (-1);
144 if (ntohs(*ah->dport) == RTSP_CONTROL_PORT_NUMBER_1
145 || ntohs(*ah->sport) == RTSP_CONTROL_PORT_NUMBER_1
146 || ntohs(*ah->dport) == RTSP_CONTROL_PORT_NUMBER_2
147 || ntohs(*ah->sport) == RTSP_CONTROL_PORT_NUMBER_2)
148 return (0);
149 return (-1);
150}
151
142 ah->maxpktsize == 0)
143 return (-1);
144 if (ntohs(*ah->dport) == RTSP_CONTROL_PORT_NUMBER_1
145 || ntohs(*ah->sport) == RTSP_CONTROL_PORT_NUMBER_1
146 || ntohs(*ah->dport) == RTSP_CONTROL_PORT_NUMBER_2
147 || ntohs(*ah->sport) == RTSP_CONTROL_PORT_NUMBER_2)
148 return (0);
149 return (-1);
150}
151
152static int
152static int
153protohandler(struct libalias *la, struct ip *pip, struct alias_data *ah)
154{
155
156 if (ntohs(*ah->dport) == TFTP_PORT_NUMBER)
157 FindRtspOut(la, pip->ip_src, pip->ip_dst,
158 *ah->sport, *ah->aport, IPPROTO_UDP);
159 else AliasHandleRtspOut(la, pip, ah->lnk, ah->maxpktsize);
160 return (0);
161}
162
163struct proto_handler handlers[] = {
153protohandler(struct libalias *la, struct ip *pip, struct alias_data *ah)
154{
155
156 if (ntohs(*ah->dport) == TFTP_PORT_NUMBER)
157 FindRtspOut(la, pip->ip_src, pip->ip_dst,
158 *ah->sport, *ah->aport, IPPROTO_UDP);
159 else AliasHandleRtspOut(la, pip, ah->lnk, ah->maxpktsize);
160 return (0);
161}
162
163struct proto_handler handlers[] = {
164 {
165 .pri = 100,
166 .dir = OUT,
164 {
165 .pri = 100,
166 .dir = OUT,
167 .proto = TCP|UDP,
167 .proto = TCP|UDP,
168 .fingerprint = &fingerprint,
168 .fingerprint = &fingerprint,
169 .protohandler = &protohandler
169 .protohandler = &protohandler
170 },
170 },
171 { EOH }
172};
173
174static int
175mod_handler(module_t mod, int type, void *data)
176{
177 int error;
178
179 switch (type) {
180 case MOD_LOAD:
181 error = 0;
182 LibAliasAttachHandlers(handlers);
183 break;
184 case MOD_UNLOAD:
185 error = 0;
186 LibAliasDetachHandlers(handlers);
187 break;
188 default:
189 error = EINVAL;
190 }
191 return (error);
192}
193
194#ifdef _KERNEL
171 { EOH }
172};
173
174static int
175mod_handler(module_t mod, int type, void *data)
176{
177 int error;
178
179 switch (type) {
180 case MOD_LOAD:
181 error = 0;
182 LibAliasAttachHandlers(handlers);
183 break;
184 case MOD_UNLOAD:
185 error = 0;
186 LibAliasDetachHandlers(handlers);
187 break;
188 default:
189 error = EINVAL;
190 }
191 return (error);
192}
193
194#ifdef _KERNEL
195static
195static
196#endif
197moduledata_t alias_mod = {
198 "alias_smedia", mod_handler, NULL
199};
200
201#ifdef _KERNEL
202DECLARE_MODULE(alias_smedia, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
203MODULE_VERSION(alias_smedia, 1);
204MODULE_DEPEND(alias_smedia, libalias, 1, 1, 1);
205#endif
206
207#define RTSP_CONTROL_PORT_NUMBER_1 554
208#define RTSP_CONTROL_PORT_NUMBER_2 7070
209#define RTSP_PORT_GROUP 2
210
211#define ISDIGIT(a) (((a) >= '0') && ((a) <= '9'))
212
213static int
214search_string(char *data, int dlen, const char *search_str)
215{
216 int i, j, k;
217 int search_str_len;
218
219 search_str_len = strlen(search_str);
220 for (i = 0; i < dlen - search_str_len; i++) {
221 for (j = i, k = 0; j < dlen - search_str_len; j++, k++) {
222 if (data[j] != search_str[k] &&
223 data[j] != search_str[k] - ('a' - 'A')) {
224 break;
225 }
226 if (k == search_str_len - 1) {
227 return (j + 1);
228 }
229 }
230 }
231 return (-1);
232}
233
234static int
235alias_rtsp_out(struct libalias *la, struct ip *pip,
236 struct alias_link *lnk,
237 char *data,
238 const char *port_str)
239{
240 int hlen, tlen, dlen;
241 struct tcphdr *tc;
242 int i, j, pos, state, port_dlen, new_dlen, delta;
243 u_short p[2], new_len;
244 u_short sport, eport, base_port;
245 u_short salias = 0, ealias = 0, base_alias = 0;
246 const char *transport_str = "transport:";
247 char newdata[2048], *port_data, *port_newdata, stemp[80];
248 int links_created = 0, pkt_updated = 0;
249 struct alias_link *rtsp_lnk = NULL;
250 struct in_addr null_addr;
251
252 /* Calculate data length of TCP packet */
253 tc = (struct tcphdr *)ip_next(pip);
254 hlen = (pip->ip_hl + tc->th_off) << 2;
255 tlen = ntohs(pip->ip_len);
256 dlen = tlen - hlen;
257
258 /* Find keyword, "Transport: " */
259 pos = search_string(data, dlen, transport_str);
260 if (pos < 0) {
261 return (-1);
262 }
263 port_data = data + pos;
264 port_dlen = dlen - pos;
265
266 memcpy(newdata, data, pos);
267 port_newdata = newdata + pos;
268
269 while (port_dlen > (int)strlen(port_str)) {
270 /* Find keyword, appropriate port string */
271 pos = search_string(port_data, port_dlen, port_str);
272 if (pos < 0) {
273 break;
274 }
275 memcpy(port_newdata, port_data, pos + 1);
276 port_newdata += (pos + 1);
277
278 p[0] = p[1] = 0;
279 sport = eport = 0;
280 state = 0;
281 for (i = pos; i < port_dlen; i++) {
282 switch (state) {
283 case 0:
284 if (port_data[i] == '=') {
285 state++;
286 }
287 break;
288 case 1:
289 if (ISDIGIT(port_data[i])) {
290 p[0] = p[0] * 10 + port_data[i] - '0';
291 } else {
292 if (port_data[i] == ';') {
293 state = 3;
294 }
295 if (port_data[i] == '-') {
296 state++;
297 }
298 }
299 break;
300 case 2:
301 if (ISDIGIT(port_data[i])) {
302 p[1] = p[1] * 10 + port_data[i] - '0';
303 } else {
304 state++;
305 }
306 break;
307 case 3:
308 base_port = p[0];
309 sport = htons(p[0]);
310 eport = htons(p[1]);
311
312 if (!links_created) {
313
314 links_created = 1;
315 /*
316 * Find an even numbered port
317 * number base that satisfies the
318 * contiguous number of ports we
319 * need
320 */
321 null_addr.s_addr = 0;
322 if (0 == (salias = FindNewPortGroup(la, null_addr,
323 FindAliasAddress(la, pip->ip_src),
324 sport, 0,
325 RTSP_PORT_GROUP,
326 IPPROTO_UDP, 1))) {
327#ifdef LIBALIAS_DEBUG
328 fprintf(stderr,
329 "PacketAlias/RTSP: Cannot find contiguous RTSP data ports\n");
330#endif
331 } else {
332
333 base_alias = ntohs(salias);
334 for (j = 0; j < RTSP_PORT_GROUP; j++) {
335 /*
336 * Establish link
337 * to port found in
338 * RTSP packet
339 */
340 rtsp_lnk = FindRtspOut(la, GetOriginalAddress(lnk), null_addr,
341 htons(base_port + j), htons(base_alias + j),
342 IPPROTO_UDP);
343 if (rtsp_lnk != NULL) {
344#ifndef NO_FW_PUNCH
345 /*
346 * Punch
347 * hole in
348 * firewall
349 */
350 PunchFWHole(rtsp_lnk);
351#endif
352 } else {
353#ifdef LIBALIAS_DEBUG
354 fprintf(stderr,
355 "PacketAlias/RTSP: Cannot allocate RTSP data ports\n");
356#endif
357 break;
358 }
359 }
360 }
361 ealias = htons(base_alias + (RTSP_PORT_GROUP - 1));
362 }
363 if (salias && rtsp_lnk) {
364
365 pkt_updated = 1;
366
367 /* Copy into IP packet */
368 sprintf(stemp, "%d", ntohs(salias));
369 memcpy(port_newdata, stemp, strlen(stemp));
370 port_newdata += strlen(stemp);
371
372 if (eport != 0) {
373 *port_newdata = '-';
374 port_newdata++;
375
376 /* Copy into IP packet */
377 sprintf(stemp, "%d", ntohs(ealias));
378 memcpy(port_newdata, stemp, strlen(stemp));
379 port_newdata += strlen(stemp);
380 }
381 *port_newdata = ';';
382 port_newdata++;
383 }
384 state++;
385 break;
386 }
387 if (state > 3) {
388 break;
389 }
390 }
391 port_data += i;
392 port_dlen -= i;
393 }
394
395 if (!pkt_updated)
396 return (-1);
397
398 memcpy(port_newdata, port_data, port_dlen);
399 port_newdata += port_dlen;
400 *port_newdata = '\0';
401
402 /* Create new packet */
403 new_dlen = port_newdata - newdata;
404 memcpy(data, newdata, new_dlen);
405
406 SetAckModified(lnk);
407 tc = (struct tcphdr *)ip_next(pip);
408 delta = GetDeltaSeqOut(tc->th_seq, lnk);
196#endif
197moduledata_t alias_mod = {
198 "alias_smedia", mod_handler, NULL
199};
200
201#ifdef _KERNEL
202DECLARE_MODULE(alias_smedia, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
203MODULE_VERSION(alias_smedia, 1);
204MODULE_DEPEND(alias_smedia, libalias, 1, 1, 1);
205#endif
206
207#define RTSP_CONTROL_PORT_NUMBER_1 554
208#define RTSP_CONTROL_PORT_NUMBER_2 7070
209#define RTSP_PORT_GROUP 2
210
211#define ISDIGIT(a) (((a) >= '0') && ((a) <= '9'))
212
213static int
214search_string(char *data, int dlen, const char *search_str)
215{
216 int i, j, k;
217 int search_str_len;
218
219 search_str_len = strlen(search_str);
220 for (i = 0; i < dlen - search_str_len; i++) {
221 for (j = i, k = 0; j < dlen - search_str_len; j++, k++) {
222 if (data[j] != search_str[k] &&
223 data[j] != search_str[k] - ('a' - 'A')) {
224 break;
225 }
226 if (k == search_str_len - 1) {
227 return (j + 1);
228 }
229 }
230 }
231 return (-1);
232}
233
234static int
235alias_rtsp_out(struct libalias *la, struct ip *pip,
236 struct alias_link *lnk,
237 char *data,
238 const char *port_str)
239{
240 int hlen, tlen, dlen;
241 struct tcphdr *tc;
242 int i, j, pos, state, port_dlen, new_dlen, delta;
243 u_short p[2], new_len;
244 u_short sport, eport, base_port;
245 u_short salias = 0, ealias = 0, base_alias = 0;
246 const char *transport_str = "transport:";
247 char newdata[2048], *port_data, *port_newdata, stemp[80];
248 int links_created = 0, pkt_updated = 0;
249 struct alias_link *rtsp_lnk = NULL;
250 struct in_addr null_addr;
251
252 /* Calculate data length of TCP packet */
253 tc = (struct tcphdr *)ip_next(pip);
254 hlen = (pip->ip_hl + tc->th_off) << 2;
255 tlen = ntohs(pip->ip_len);
256 dlen = tlen - hlen;
257
258 /* Find keyword, "Transport: " */
259 pos = search_string(data, dlen, transport_str);
260 if (pos < 0) {
261 return (-1);
262 }
263 port_data = data + pos;
264 port_dlen = dlen - pos;
265
266 memcpy(newdata, data, pos);
267 port_newdata = newdata + pos;
268
269 while (port_dlen > (int)strlen(port_str)) {
270 /* Find keyword, appropriate port string */
271 pos = search_string(port_data, port_dlen, port_str);
272 if (pos < 0) {
273 break;
274 }
275 memcpy(port_newdata, port_data, pos + 1);
276 port_newdata += (pos + 1);
277
278 p[0] = p[1] = 0;
279 sport = eport = 0;
280 state = 0;
281 for (i = pos; i < port_dlen; i++) {
282 switch (state) {
283 case 0:
284 if (port_data[i] == '=') {
285 state++;
286 }
287 break;
288 case 1:
289 if (ISDIGIT(port_data[i])) {
290 p[0] = p[0] * 10 + port_data[i] - '0';
291 } else {
292 if (port_data[i] == ';') {
293 state = 3;
294 }
295 if (port_data[i] == '-') {
296 state++;
297 }
298 }
299 break;
300 case 2:
301 if (ISDIGIT(port_data[i])) {
302 p[1] = p[1] * 10 + port_data[i] - '0';
303 } else {
304 state++;
305 }
306 break;
307 case 3:
308 base_port = p[0];
309 sport = htons(p[0]);
310 eport = htons(p[1]);
311
312 if (!links_created) {
313
314 links_created = 1;
315 /*
316 * Find an even numbered port
317 * number base that satisfies the
318 * contiguous number of ports we
319 * need
320 */
321 null_addr.s_addr = 0;
322 if (0 == (salias = FindNewPortGroup(la, null_addr,
323 FindAliasAddress(la, pip->ip_src),
324 sport, 0,
325 RTSP_PORT_GROUP,
326 IPPROTO_UDP, 1))) {
327#ifdef LIBALIAS_DEBUG
328 fprintf(stderr,
329 "PacketAlias/RTSP: Cannot find contiguous RTSP data ports\n");
330#endif
331 } else {
332
333 base_alias = ntohs(salias);
334 for (j = 0; j < RTSP_PORT_GROUP; j++) {
335 /*
336 * Establish link
337 * to port found in
338 * RTSP packet
339 */
340 rtsp_lnk = FindRtspOut(la, GetOriginalAddress(lnk), null_addr,
341 htons(base_port + j), htons(base_alias + j),
342 IPPROTO_UDP);
343 if (rtsp_lnk != NULL) {
344#ifndef NO_FW_PUNCH
345 /*
346 * Punch
347 * hole in
348 * firewall
349 */
350 PunchFWHole(rtsp_lnk);
351#endif
352 } else {
353#ifdef LIBALIAS_DEBUG
354 fprintf(stderr,
355 "PacketAlias/RTSP: Cannot allocate RTSP data ports\n");
356#endif
357 break;
358 }
359 }
360 }
361 ealias = htons(base_alias + (RTSP_PORT_GROUP - 1));
362 }
363 if (salias && rtsp_lnk) {
364
365 pkt_updated = 1;
366
367 /* Copy into IP packet */
368 sprintf(stemp, "%d", ntohs(salias));
369 memcpy(port_newdata, stemp, strlen(stemp));
370 port_newdata += strlen(stemp);
371
372 if (eport != 0) {
373 *port_newdata = '-';
374 port_newdata++;
375
376 /* Copy into IP packet */
377 sprintf(stemp, "%d", ntohs(ealias));
378 memcpy(port_newdata, stemp, strlen(stemp));
379 port_newdata += strlen(stemp);
380 }
381 *port_newdata = ';';
382 port_newdata++;
383 }
384 state++;
385 break;
386 }
387 if (state > 3) {
388 break;
389 }
390 }
391 port_data += i;
392 port_dlen -= i;
393 }
394
395 if (!pkt_updated)
396 return (-1);
397
398 memcpy(port_newdata, port_data, port_dlen);
399 port_newdata += port_dlen;
400 *port_newdata = '\0';
401
402 /* Create new packet */
403 new_dlen = port_newdata - newdata;
404 memcpy(data, newdata, new_dlen);
405
406 SetAckModified(lnk);
407 tc = (struct tcphdr *)ip_next(pip);
408 delta = GetDeltaSeqOut(tc->th_seq, lnk);
409 AddSeq(lnk, delta + new_dlen - dlen, pip->ip_hl, pip->ip_len,
409 AddSeq(lnk, delta + new_dlen - dlen, pip->ip_hl, pip->ip_len,
410 tc->th_seq, tc->th_off);
411
412 new_len = htons(hlen + new_dlen);
413 DifferentialChecksum(&pip->ip_sum,
414 &new_len,
415 &pip->ip_len,
416 1);
417 pip->ip_len = new_len;
418
419 tc->th_sum = 0;
420#ifdef _KERNEL
421 tc->th_x2 = 1;
422#else
423 tc->th_sum = TcpChecksum(pip);
424#endif
425 return (0);
426}
427
428/* Support the protocol used by early versions of RealPlayer */
429
430static int
431alias_pna_out(struct libalias *la, struct ip *pip,
432 struct alias_link *lnk,
433 char *data,
434 int dlen)
435{
436 struct alias_link *pna_links;
437 u_short msg_id, msg_len;
438 char *work;
439 u_short alias_port, port;
440 struct tcphdr *tc;
441
442 work = data;
443 work += 5;
444 while (work + 4 < data + dlen) {
445 memcpy(&msg_id, work, 2);
446 work += 2;
447 memcpy(&msg_len, work, 2);
448 work += 2;
449 if (ntohs(msg_id) == 0) {
450 /* end of options */
451 return (0);
452 }
453 if ((ntohs(msg_id) == 1) || (ntohs(msg_id) == 7)) {
454 memcpy(&port, work, 2);
455 pna_links = FindUdpTcpOut(la, pip->ip_src, GetDestAddress(lnk),
456 port, 0, IPPROTO_UDP, 1);
457 if (pna_links != NULL) {
458#ifndef NO_FW_PUNCH
459 /* Punch hole in firewall */
460 PunchFWHole(pna_links);
461#endif
462 tc = (struct tcphdr *)ip_next(pip);
463 alias_port = GetAliasPort(pna_links);
464 memcpy(work, &alias_port, 2);
465
466 /* Compute TCP checksum for revised packet */
467 tc->th_sum = 0;
468#ifdef _KERNEL
469 tc->th_x2 = 1;
470#else
471 tc->th_sum = TcpChecksum(pip);
472#endif
473 }
474 }
475 work += ntohs(msg_len);
476 }
477
478 return (0);
479}
480
481static void
482AliasHandleRtspOut(struct libalias *la, struct ip *pip, struct alias_link *lnk, int maxpacketsize)
483{
484 int hlen, tlen, dlen;
485 struct tcphdr *tc;
486 char *data;
487 const char *setup = "SETUP", *pna = "PNA", *str200 = "200";
488 const char *okstr = "OK", *client_port_str = "client_port";
489 const char *server_port_str = "server_port";
490 int i, parseOk;
491
492 (void)maxpacketsize;
493
494 tc = (struct tcphdr *)ip_next(pip);
495 hlen = (pip->ip_hl + tc->th_off) << 2;
496 tlen = ntohs(pip->ip_len);
497 dlen = tlen - hlen;
498
499 data = (char *)pip;
500 data += hlen;
501
502 /* When aliasing a client, check for the SETUP request */
503 if ((ntohs(tc->th_dport) == RTSP_CONTROL_PORT_NUMBER_1) ||
504 (ntohs(tc->th_dport) == RTSP_CONTROL_PORT_NUMBER_2)) {
505
506 if (dlen >= (int)strlen(setup)) {
507 if (memcmp(data, setup, strlen(setup)) == 0) {
508 alias_rtsp_out(la, pip, lnk, data, client_port_str);
509 return;
510 }
511 }
512 if (dlen >= (int)strlen(pna)) {
513 if (memcmp(data, pna, strlen(pna)) == 0) {
514 alias_pna_out(la, pip, lnk, data, dlen);
515 }
516 }
517 } else {
518
519 /*
520 * When aliasing a server, check for the 200 reply
521 * Accomodate varying number of blanks between 200 & OK
522 */
523
524 if (dlen >= (int)strlen(str200)) {
525
526 for (parseOk = 0, i = 0;
527 i <= dlen - (int)strlen(str200);
528 i++) {
529 if (memcmp(&data[i], str200, strlen(str200)) == 0) {
530 parseOk = 1;
531 break;
532 }
533 }
534 if (parseOk) {
535
536 i += strlen(str200); /* skip string found */
537 while (data[i] == ' ') /* skip blank(s) */
538 i++;
539
540 if ((dlen - i) >= (int)strlen(okstr)) {
541
542 if (memcmp(&data[i], okstr, strlen(okstr)) == 0)
543 alias_rtsp_out(la, pip, lnk, data, server_port_str);
544
545 }
546 }
547 }
548 }
549}
410 tc->th_seq, tc->th_off);
411
412 new_len = htons(hlen + new_dlen);
413 DifferentialChecksum(&pip->ip_sum,
414 &new_len,
415 &pip->ip_len,
416 1);
417 pip->ip_len = new_len;
418
419 tc->th_sum = 0;
420#ifdef _KERNEL
421 tc->th_x2 = 1;
422#else
423 tc->th_sum = TcpChecksum(pip);
424#endif
425 return (0);
426}
427
428/* Support the protocol used by early versions of RealPlayer */
429
430static int
431alias_pna_out(struct libalias *la, struct ip *pip,
432 struct alias_link *lnk,
433 char *data,
434 int dlen)
435{
436 struct alias_link *pna_links;
437 u_short msg_id, msg_len;
438 char *work;
439 u_short alias_port, port;
440 struct tcphdr *tc;
441
442 work = data;
443 work += 5;
444 while (work + 4 < data + dlen) {
445 memcpy(&msg_id, work, 2);
446 work += 2;
447 memcpy(&msg_len, work, 2);
448 work += 2;
449 if (ntohs(msg_id) == 0) {
450 /* end of options */
451 return (0);
452 }
453 if ((ntohs(msg_id) == 1) || (ntohs(msg_id) == 7)) {
454 memcpy(&port, work, 2);
455 pna_links = FindUdpTcpOut(la, pip->ip_src, GetDestAddress(lnk),
456 port, 0, IPPROTO_UDP, 1);
457 if (pna_links != NULL) {
458#ifndef NO_FW_PUNCH
459 /* Punch hole in firewall */
460 PunchFWHole(pna_links);
461#endif
462 tc = (struct tcphdr *)ip_next(pip);
463 alias_port = GetAliasPort(pna_links);
464 memcpy(work, &alias_port, 2);
465
466 /* Compute TCP checksum for revised packet */
467 tc->th_sum = 0;
468#ifdef _KERNEL
469 tc->th_x2 = 1;
470#else
471 tc->th_sum = TcpChecksum(pip);
472#endif
473 }
474 }
475 work += ntohs(msg_len);
476 }
477
478 return (0);
479}
480
481static void
482AliasHandleRtspOut(struct libalias *la, struct ip *pip, struct alias_link *lnk, int maxpacketsize)
483{
484 int hlen, tlen, dlen;
485 struct tcphdr *tc;
486 char *data;
487 const char *setup = "SETUP", *pna = "PNA", *str200 = "200";
488 const char *okstr = "OK", *client_port_str = "client_port";
489 const char *server_port_str = "server_port";
490 int i, parseOk;
491
492 (void)maxpacketsize;
493
494 tc = (struct tcphdr *)ip_next(pip);
495 hlen = (pip->ip_hl + tc->th_off) << 2;
496 tlen = ntohs(pip->ip_len);
497 dlen = tlen - hlen;
498
499 data = (char *)pip;
500 data += hlen;
501
502 /* When aliasing a client, check for the SETUP request */
503 if ((ntohs(tc->th_dport) == RTSP_CONTROL_PORT_NUMBER_1) ||
504 (ntohs(tc->th_dport) == RTSP_CONTROL_PORT_NUMBER_2)) {
505
506 if (dlen >= (int)strlen(setup)) {
507 if (memcmp(data, setup, strlen(setup)) == 0) {
508 alias_rtsp_out(la, pip, lnk, data, client_port_str);
509 return;
510 }
511 }
512 if (dlen >= (int)strlen(pna)) {
513 if (memcmp(data, pna, strlen(pna)) == 0) {
514 alias_pna_out(la, pip, lnk, data, dlen);
515 }
516 }
517 } else {
518
519 /*
520 * When aliasing a server, check for the 200 reply
521 * Accomodate varying number of blanks between 200 & OK
522 */
523
524 if (dlen >= (int)strlen(str200)) {
525
526 for (parseOk = 0, i = 0;
527 i <= dlen - (int)strlen(str200);
528 i++) {
529 if (memcmp(&data[i], str200, strlen(str200)) == 0) {
530 parseOk = 1;
531 break;
532 }
533 }
534 if (parseOk) {
535
536 i += strlen(str200); /* skip string found */
537 while (data[i] == ' ') /* skip blank(s) */
538 i++;
539
540 if ((dlen - i) >= (int)strlen(okstr)) {
541
542 if (memcmp(&data[i], okstr, strlen(okstr)) == 0)
543 alias_rtsp_out(la, pip, lnk, data, server_port_str);
544
545 }
546 }
547 }
548 }
549}