]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netinet/libalias/alias_smedia.c
This commit was generated by cvs2svn to compensate for changes in r145510,
[FreeBSD/FreeBSD.git] / sys / netinet / libalias / alias_smedia.c
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$");
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 #include <stdio.h>
102 #include <string.h>
103 #include <sys/types.h>
104 #include <netinet/in_systm.h>
105 #include <netinet/in.h>
106 #include <netinet/ip.h>
107 #include <netinet/tcp.h>
108 #include <netinet/udp.h>
109
110 #include "alias_local.h"
111
112 #define RTSP_CONTROL_PORT_NUMBER_1 554
113 #define RTSP_CONTROL_PORT_NUMBER_2 7070
114 #define RTSP_PORT_GROUP            2
115
116 #define ISDIGIT(a) (((a) >= '0') && ((a) <= '9'))
117
118 static int
119 search_string(char *data, int dlen, const char *search_str)
120 {
121         int i, j, k;
122         int search_str_len;
123
124         search_str_len = strlen(search_str);
125         for (i = 0; i < dlen - search_str_len; i++) {
126                 for (j = i, k = 0; j < dlen - search_str_len; j++, k++) {
127                         if (data[j] != search_str[k] &&
128                             data[j] != search_str[k] - ('a' - 'A')) {
129                                 break;
130                         }
131                         if (k == search_str_len - 1) {
132                                 return (j + 1);
133                         }
134                 }
135         }
136         return (-1);
137 }
138
139 static int
140 alias_rtsp_out(struct libalias *la, struct ip *pip,
141     struct alias_link *lnk,
142     char *data,
143     const char *port_str)
144 {
145         int hlen, tlen, dlen;
146         struct tcphdr *tc;
147         int i, j, pos, state, port_dlen, new_dlen, delta;
148         u_short p[2], new_len;
149         u_short sport, eport, base_port;
150         u_short salias = 0, ealias = 0, base_alias = 0;
151         const char *transport_str = "transport:";
152         char newdata[2048], *port_data, *port_newdata, stemp[80];
153         int links_created = 0, pkt_updated = 0;
154         struct alias_link *rtsp_lnk = NULL;
155         struct in_addr null_addr;
156
157         /* Calculate data length of TCP packet */
158         tc = (struct tcphdr *)ip_next(pip);
159         hlen = (pip->ip_hl + tc->th_off) << 2;
160         tlen = ntohs(pip->ip_len);
161         dlen = tlen - hlen;
162
163         /* Find keyword, "Transport: " */
164         pos = search_string(data, dlen, transport_str);
165         if (pos < 0) {
166                 return (-1);
167         }
168         port_data = data + pos;
169         port_dlen = dlen - pos;
170
171         memcpy(newdata, data, pos);
172         port_newdata = newdata + pos;
173
174         while (port_dlen > (int)strlen(port_str)) {
175                 /* Find keyword, appropriate port string */
176                 pos = search_string(port_data, port_dlen, port_str);
177                 if (pos < 0) {
178                         break;
179                 }
180                 memcpy(port_newdata, port_data, pos + 1);
181                 port_newdata += (pos + 1);
182
183                 p[0] = p[1] = 0;
184                 sport = eport = 0;
185                 state = 0;
186                 for (i = pos; i < port_dlen; i++) {
187                         switch (state) {
188                         case 0:
189                                 if (port_data[i] == '=') {
190                                         state++;
191                                 }
192                                 break;
193                         case 1:
194                                 if (ISDIGIT(port_data[i])) {
195                                         p[0] = p[0] * 10 + port_data[i] - '0';
196                                 } else {
197                                         if (port_data[i] == ';') {
198                                                 state = 3;
199                                         }
200                                         if (port_data[i] == '-') {
201                                                 state++;
202                                         }
203                                 }
204                                 break;
205                         case 2:
206                                 if (ISDIGIT(port_data[i])) {
207                                         p[1] = p[1] * 10 + port_data[i] - '0';
208                                 } else {
209                                         state++;
210                                 }
211                                 break;
212                         case 3:
213                                 base_port = p[0];
214                                 sport = htons(p[0]);
215                                 eport = htons(p[1]);
216
217                                 if (!links_created) {
218
219                                         links_created = 1;
220                                         /*
221                                          * Find an even numbered port
222                                          * number base that satisfies the
223                                          * contiguous number of ports we
224                                          * need
225                                          */
226                                         null_addr.s_addr = 0;
227                                         if (0 == (salias = FindNewPortGroup(la, null_addr,
228                                             FindAliasAddress(la, pip->ip_src),
229                                             sport, 0,
230                                             RTSP_PORT_GROUP,
231                                             IPPROTO_UDP, 1))) {
232 #ifdef DEBUG
233                                                 fprintf(stderr,
234                                                     "PacketAlias/RTSP: Cannot find contiguous RTSP data ports\n");
235 #endif
236                                         } else {
237
238                                                 base_alias = ntohs(salias);
239                                                 for (j = 0; j < RTSP_PORT_GROUP; j++) {
240                                                         /*
241                                                          * Establish link
242                                                          * to port found in
243                                                          * RTSP packet
244                                                          */
245                                                         rtsp_lnk = FindRtspOut(la, GetOriginalAddress(lnk), null_addr,
246                                                             htons(base_port + j), htons(base_alias + j),
247                                                             IPPROTO_UDP);
248                                                         if (rtsp_lnk != NULL) {
249 #ifndef NO_FW_PUNCH
250                                                                 /*
251                                                                  * Punch
252                                                                  * hole in
253                                                                  * firewall
254                                                                  */
255                                                                 PunchFWHole(rtsp_lnk);
256 #endif
257                                                         } else {
258 #ifdef DEBUG
259                                                                 fprintf(stderr,
260                                                                     "PacketAlias/RTSP: Cannot allocate RTSP data ports\n");
261 #endif
262                                                                 break;
263                                                         }
264                                                 }
265                                         }
266                                         ealias = htons(base_alias + (RTSP_PORT_GROUP - 1));
267                                 }
268                                 if (salias && rtsp_lnk) {
269
270                                         pkt_updated = 1;
271
272                                         /* Copy into IP packet */
273                                         sprintf(stemp, "%d", ntohs(salias));
274                                         memcpy(port_newdata, stemp, strlen(stemp));
275                                         port_newdata += strlen(stemp);
276
277                                         if (eport != 0) {
278                                                 *port_newdata = '-';
279                                                 port_newdata++;
280
281                                                 /* Copy into IP packet */
282                                                 sprintf(stemp, "%d", ntohs(ealias));
283                                                 memcpy(port_newdata, stemp, strlen(stemp));
284                                                 port_newdata += strlen(stemp);
285                                         }
286                                         *port_newdata = ';';
287                                         port_newdata++;
288                                 }
289                                 state++;
290                                 break;
291                         }
292                         if (state > 3) {
293                                 break;
294                         }
295                 }
296                 port_data += i;
297                 port_dlen -= i;
298         }
299
300         if (!pkt_updated)
301                 return (-1);
302
303         memcpy(port_newdata, port_data, port_dlen);
304         port_newdata += port_dlen;
305         *port_newdata = '\0';
306
307         /* Create new packet */
308         new_dlen = port_newdata - newdata;
309         memcpy(data, newdata, new_dlen);
310
311         SetAckModified(lnk);
312         delta = GetDeltaSeqOut(pip, lnk);
313         AddSeq(pip, lnk, delta + new_dlen - dlen);
314
315         new_len = htons(hlen + new_dlen);
316         DifferentialChecksum(&pip->ip_sum,
317             &new_len,
318             &pip->ip_len,
319             1);
320         pip->ip_len = new_len;
321
322         tc->th_sum = 0;
323         tc->th_sum = TcpChecksum(pip);
324
325         return (0);
326 }
327
328 /* Support the protocol used by early versions of RealPlayer */
329
330 static int
331 alias_pna_out(struct libalias *la, struct ip *pip,
332     struct alias_link *lnk,
333     char *data,
334     int dlen)
335 {
336         struct alias_link *pna_links;
337         u_short msg_id, msg_len;
338         char *work;
339         u_short alias_port, port;
340         struct tcphdr *tc;
341
342         work = data;
343         work += 5;
344         while (work + 4 < data + dlen) {
345                 memcpy(&msg_id, work, 2);
346                 work += 2;
347                 memcpy(&msg_len, work, 2);
348                 work += 2;
349                 if (ntohs(msg_id) == 0) {
350                         /* end of options */
351                         return (0);
352                 }
353                 if ((ntohs(msg_id) == 1) || (ntohs(msg_id) == 7)) {
354                         memcpy(&port, work, 2);
355                         pna_links = FindUdpTcpOut(la, pip->ip_src, GetDestAddress(lnk),
356                             port, 0, IPPROTO_UDP, 1);
357                         if (pna_links != NULL) {
358 #ifndef NO_FW_PUNCH
359                                 /* Punch hole in firewall */
360                                 PunchFWHole(pna_links);
361 #endif
362                                 tc = (struct tcphdr *)ip_next(pip);
363                                 alias_port = GetAliasPort(pna_links);
364                                 memcpy(work, &alias_port, 2);
365
366                                 /* Compute TCP checksum for revised packet */
367                                 tc->th_sum = 0;
368                                 tc->th_sum = TcpChecksum(pip);
369                         }
370                 }
371                 work += ntohs(msg_len);
372         }
373
374         return (0);
375 }
376
377 void
378 AliasHandleRtspOut(struct libalias *la, struct ip *pip, struct alias_link *lnk, int maxpacketsize)
379 {
380         int hlen, tlen, dlen;
381         struct tcphdr *tc;
382         char *data;
383         const char *setup = "SETUP", *pna = "PNA", *str200 = "200";
384         const char *okstr = "OK", *client_port_str = "client_port";
385         const char *server_port_str = "server_port";
386         int i, parseOk;
387
388         (void)maxpacketsize;
389
390         tc = (struct tcphdr *)ip_next(pip);
391         hlen = (pip->ip_hl + tc->th_off) << 2;
392         tlen = ntohs(pip->ip_len);
393         dlen = tlen - hlen;
394
395         data = (char *)pip;
396         data += hlen;
397
398         /* When aliasing a client, check for the SETUP request */
399         if ((ntohs(tc->th_dport) == RTSP_CONTROL_PORT_NUMBER_1) ||
400             (ntohs(tc->th_dport) == RTSP_CONTROL_PORT_NUMBER_2)) {
401
402                 if (dlen >= (int)strlen(setup)) {
403                         if (memcmp(data, setup, strlen(setup)) == 0) {
404                                 alias_rtsp_out(la, pip, lnk, data, client_port_str);
405                                 return;
406                         }
407                 }
408                 if (dlen >= (int)strlen(pna)) {
409                         if (memcmp(data, pna, strlen(pna)) == 0) {
410                                 alias_pna_out(la, pip, lnk, data, dlen);
411                         }
412                 }
413         } else {
414
415                 /*
416                  * When aliasing a server, check for the 200 reply
417                  * Accomodate varying number of blanks between 200 & OK
418                  */
419
420                 if (dlen >= (int)strlen(str200)) {
421
422                         for (parseOk = 0, i = 0;
423                             i <= dlen - (int)strlen(str200);
424                             i++) {
425                                 if (memcmp(&data[i], str200, strlen(str200)) == 0) {
426                                         parseOk = 1;
427                                         break;
428                                 }
429                         }
430                         if (parseOk) {
431
432                                 i += strlen(str200);    /* skip string found */
433                                 while (data[i] == ' ')  /* skip blank(s) */
434                                         i++;
435
436                                 if ((dlen - i) >= (int)strlen(okstr)) {
437
438                                         if (memcmp(&data[i], okstr, strlen(okstr)) == 0)
439                                                 alias_rtsp_out(la, pip, lnk, data, server_port_str);
440
441                                 }
442                         }
443                 }
444         }
445 }