The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netinet/libalias/alias_smedia.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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
  121 #include <netinet/libalias/alias.h>
  122 #include <netinet/libalias/alias_local.h>
  123 #include <netinet/libalias/alias_mod.h>
  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 
  133 static void
  134 AliasHandleRtspOut(struct libalias *, struct ip *, struct alias_link *,
  135     int maxpacketsize);
  136 static int
  137 fingerprint(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 
  153 static int
  154 protohandler(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 
  163 struct proto_handler handlers[] = {
  164         {
  165           .pri = 100,
  166           .dir = OUT,
  167           .proto = TCP|UDP,
  168           .fingerprint = &fingerprint,
  169           .protohandler = &protohandler
  170         },
  171         { EOH }
  172 };
  173 
  174 static int
  175 mod_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
  195 static
  196 #endif
  197 moduledata_t alias_mod = {
  198        "alias_smedia", mod_handler, NULL
  199 };
  200 
  201 #ifdef _KERNEL
  202 DECLARE_MODULE(alias_smedia, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
  203 MODULE_VERSION(alias_smedia, 1);
  204 MODULE_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) >= '') && ((a) <= '9'))
  212 
  213 static int
  214 search_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 
  232 static int
  233 alias_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] - '';
  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] - '';
  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,
  316                                             RTSP_PORT_GROUP,
  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),
  332                                                             IPPROTO_UDP);
  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 = (TH_RES1 >> 8);
  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 
  416 static int
  417 alias_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 = (TH_RES1 >> 8);
  455 #else
  456                                 tc->th_sum = TcpChecksum(pip);
  457 #endif
  458                         }
  459                 }
  460                 work += ntohs(msg_len);
  461         }
  462 
  463         return (0);
  464 }
  465 
  466 static void
  467 AliasHandleRtspOut(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 }

Cache object: f98915baf145e260306e3522a2365fd5


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.