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