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_irc.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  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2001 Charles Mott <cm@linktel.net>
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD$");
   31 
   32 /* Alias_irc.c intercepts packages contain IRC CTCP commands, and
   33         changes DCC commands to export a port on the aliasing host instead
   34         of an aliased host.
   35 
   36     For this routine to work, the DCC command must fit entirely into a
   37     single TCP packet.  This will usually happen, but is not
   38     guaranteed.
   39 
   40          The interception is likely to change the length of the packet.
   41          The handling of this is copied more-or-less verbatim from
   42          ftp_alias.c
   43 
   44          Initial version: Eivind Eklund <perhaps@yes.no> (ee) 97-01-29
   45 
   46          Version 2.1:  May, 1997 (cjm)
   47              Very minor changes to conform with
   48              local/global/function naming conventions
   49              within the packet alising module.
   50 */
   51 
   52 /* Includes */
   53 #ifdef _KERNEL
   54 #include <sys/param.h>
   55 #include <sys/ctype.h>
   56 #include <sys/limits.h>
   57 #include <sys/systm.h>
   58 #include <sys/kernel.h>
   59 #include <sys/module.h>
   60 #else
   61 #include <ctype.h>
   62 #include <errno.h>
   63 #include <sys/types.h>
   64 #include <stdio.h>
   65 #include <stdlib.h>
   66 #include <string.h>
   67 #include <limits.h>
   68 #endif
   69 
   70 #include <netinet/in_systm.h>
   71 #include <netinet/in.h>
   72 #include <netinet/ip.h>
   73 #include <netinet/tcp.h>
   74 
   75 #ifdef _KERNEL
   76 #include <netinet/libalias/alias.h>
   77 #include <netinet/libalias/alias_local.h>
   78 #include <netinet/libalias/alias_mod.h>
   79 #else
   80 #include "alias_local.h"
   81 #include "alias_mod.h"
   82 #endif
   83 
   84 #define IRC_CONTROL_PORT_NUMBER_1 6667
   85 #define IRC_CONTROL_PORT_NUMBER_2 6668
   86 
   87 #define PKTSIZE (IP_MAXPACKET + 1)
   88 char *newpacket;
   89 
   90 /* Local defines */
   91 #define DBprintf(a)
   92 
   93 static void
   94 AliasHandleIrcOut(struct libalias *, struct ip *, struct alias_link *,
   95     int maxpacketsize);
   96 
   97 static int
   98 fingerprint(struct libalias *la, struct alias_data *ah)
   99 {
  100         if (ah->dport == NULL || ah->lnk == NULL || ah->maxpktsize == 0)
  101                 return (-1);
  102         if (ntohs(*ah->dport) == IRC_CONTROL_PORT_NUMBER_1
  103             || ntohs(*ah->dport) == IRC_CONTROL_PORT_NUMBER_2)
  104                 return (0);
  105         return (-1);
  106 }
  107 
  108 static int
  109 protohandler(struct libalias *la, struct ip *pip, struct alias_data *ah)
  110 {
  111         newpacket = malloc(PKTSIZE);
  112         if (newpacket) {
  113                 AliasHandleIrcOut(la, pip, ah->lnk, ah->maxpktsize);
  114                 free(newpacket);
  115         }
  116         return (0);
  117 }
  118 
  119 struct proto_handler handlers[] = {
  120         {
  121           .pri = 90,
  122           .dir = OUT,
  123           .proto = TCP,
  124           .fingerprint = &fingerprint,
  125           .protohandler = &protohandler
  126         },
  127         { EOH }
  128 };
  129 
  130 static int
  131 mod_handler(module_t mod, int type, void *data)
  132 {
  133         int error;
  134 
  135         switch (type) {
  136         case MOD_LOAD:
  137                 error = 0;
  138                 LibAliasAttachHandlers(handlers);
  139                 break;
  140         case MOD_UNLOAD:
  141                 error = 0;
  142                 LibAliasDetachHandlers(handlers);
  143                 break;
  144         default:
  145                 error = EINVAL;
  146         }
  147         return (error);
  148 }
  149 
  150 #ifdef _KERNEL
  151 static
  152 #endif
  153 moduledata_t alias_mod = {
  154        "alias_irc", mod_handler, NULL
  155 };
  156 
  157 /* Kernel module definition. */
  158 #ifdef _KERNEL
  159 DECLARE_MODULE(alias_irc, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
  160 MODULE_VERSION(alias_irc, 1);
  161 MODULE_DEPEND(alias_irc, libalias, 1, 1, 1);
  162 #endif
  163 
  164 static void
  165 AliasHandleIrcOut(struct libalias *la,
  166     struct ip *pip,             /* IP packet to examine */
  167     struct alias_link *lnk,     /* Which link are we on? */
  168     int maxsize                 /* Maximum size of IP packet including
  169                                  * headers */
  170 )
  171 {
  172         int hlen, tlen, dlen;
  173         struct in_addr true_addr;
  174         u_short true_port;
  175         char *sptr;
  176         struct tcphdr *tc;
  177         int i;                  /* Iterator through the source */
  178 
  179         /* Calculate data length of TCP packet */
  180         tc = (struct tcphdr *)ip_next(pip);
  181         hlen = (pip->ip_hl + tc->th_off) << 2;
  182         tlen = ntohs(pip->ip_len);
  183         dlen = tlen - hlen;
  184 
  185         /*
  186          * Return if data length is too short - assume an entire PRIVMSG in
  187          * each packet.
  188          */
  189         if (dlen < (int)sizeof(":A!a@n.n PRIVMSG A :aDCC 1 1a") - 1)
  190                 return;
  191 
  192         /* Place string pointer at beginning of data */
  193         sptr = (char *)pip;
  194         sptr += hlen;
  195         maxsize -= hlen;        /* We're interested in maximum size of
  196                                  * data, not packet */
  197 
  198         /* Search for a CTCP command [Note 1] */
  199         for (i = 0; i < dlen; i++) {
  200                 if (sptr[i] == '\001')
  201                         goto lFOUND_CTCP;
  202         }
  203         return;                 /* No CTCP commands in  */
  204         /* Handle CTCP commands - the buffer may have to be copied */
  205         lFOUND_CTCP:
  206         {
  207                 unsigned int copyat = i;
  208                 unsigned int iCopy = 0; /* How much data have we written to
  209                                          * copy-back string? */
  210                 unsigned long org_addr; /* Original IP address */
  211                 unsigned short org_port;        /* Original source port
  212                                                  * address */
  213 
  214         lCTCP_START:
  215                 if (i >= dlen || iCopy >= PKTSIZE)
  216                         goto lPACKET_DONE;
  217                 newpacket[iCopy++] = sptr[i++]; /* Copy the CTCP start
  218                                                  * character */
  219                 /* Start of a CTCP */
  220                 if (i + 4 >= dlen)      /* Too short for DCC */
  221                         goto lBAD_CTCP;
  222                 if (sptr[i + 0] != 'D')
  223                         goto lBAD_CTCP;
  224                 if (sptr[i + 1] != 'C')
  225                         goto lBAD_CTCP;
  226                 if (sptr[i + 2] != 'C')
  227                         goto lBAD_CTCP;
  228                 if (sptr[i + 3] != ' ')
  229                         goto lBAD_CTCP;
  230                 /* We have a DCC command - handle it! */
  231                 i += 4;         /* Skip "DCC " */
  232                 if (iCopy + 4 > PKTSIZE)
  233                         goto lPACKET_DONE;
  234                 newpacket[iCopy++] = 'D';
  235                 newpacket[iCopy++] = 'C';
  236                 newpacket[iCopy++] = 'C';
  237                 newpacket[iCopy++] = ' ';
  238 
  239                 DBprintf(("Found DCC\n"));
  240                 /*
  241                  * Skip any extra spaces (should not occur according to
  242                  * protocol, but DCC breaks CTCP protocol anyway
  243                  */
  244                 while (sptr[i] == ' ') {
  245                         if (++i >= dlen) {
  246                                 DBprintf(("DCC packet terminated in just spaces\n"));
  247                                 goto lPACKET_DONE;
  248                         }
  249                 }
  250 
  251                 DBprintf(("Transferring command...\n"));
  252                 while (sptr[i] != ' ') {
  253                         newpacket[iCopy++] = sptr[i];
  254                         if (++i >= dlen || iCopy >= PKTSIZE) {
  255                                 DBprintf(("DCC packet terminated during command\n"));
  256                                 goto lPACKET_DONE;
  257                         }
  258                 }
  259                 /* Copy _one_ space */
  260                 if (i + 1 < dlen && iCopy < PKTSIZE)
  261                         newpacket[iCopy++] = sptr[i++];
  262 
  263                 DBprintf(("Done command - removing spaces\n"));
  264                 /*
  265                  * Skip any extra spaces (should not occur according to
  266                  * protocol, but DCC breaks CTCP protocol anyway
  267                  */
  268                 while (sptr[i] == ' ') {
  269                         if (++i >= dlen) {
  270                                 DBprintf(("DCC packet terminated in just spaces (post-command)\n"));
  271                                 goto lPACKET_DONE;
  272                         }
  273                 }
  274 
  275                 DBprintf(("Transferring filename...\n"));
  276                 while (sptr[i] != ' ') {
  277                         newpacket[iCopy++] = sptr[i];
  278                         if (++i >= dlen || iCopy >= PKTSIZE) {
  279                                 DBprintf(("DCC packet terminated during filename\n"));
  280                                 goto lPACKET_DONE;
  281                         }
  282                 }
  283                 /* Copy _one_ space */
  284                 if (i + 1 < dlen && iCopy < PKTSIZE)
  285                         newpacket[iCopy++] = sptr[i++];
  286 
  287                 DBprintf(("Done filename - removing spaces\n"));
  288                 /*
  289                  * Skip any extra spaces (should not occur according to
  290                  * protocol, but DCC breaks CTCP protocol anyway
  291                  */
  292                 while (sptr[i] == ' ') {
  293                         if (++i >= dlen) {
  294                                 DBprintf(("DCC packet terminated in just spaces (post-filename)\n"));
  295                                 goto lPACKET_DONE;
  296                         }
  297                 }
  298 
  299                 DBprintf(("Fetching IP address\n"));
  300                 /* Fetch IP address */
  301                 org_addr = 0;
  302                 while (i < dlen && isdigit(sptr[i])) {
  303                         if (org_addr > ULONG_MAX / 10UL) {      /* Terminate on overflow */
  304                                 DBprintf(("DCC Address overflow (org_addr == 0x%08lx, next char %c\n", org_addr, sptr[i]));
  305                                 goto lBAD_CTCP;
  306                         }
  307                         org_addr *= 10;
  308                         org_addr += sptr[i++] - '';
  309                 }
  310                 DBprintf(("Skipping space\n"));
  311                 if (i + 1 >= dlen || sptr[i] != ' ') {
  312                         DBprintf(("Overflow (%d >= %d) or bad character (%02x) terminating IP address\n", i + 1, dlen, sptr[i]));
  313                         goto lBAD_CTCP;
  314                 }
  315                 /*
  316                  * Skip any extra spaces (should not occur according to
  317                  * protocol, but DCC breaks CTCP protocol anyway, so we
  318                  * might as well play it safe
  319                  */
  320                 while (sptr[i] == ' ') {
  321                         if (++i >= dlen) {
  322                                 DBprintf(("Packet failure - space overflow.\n"));
  323                                 goto lPACKET_DONE;
  324                         }
  325                 }
  326                 DBprintf(("Fetching port number\n"));
  327                 /* Fetch source port */
  328                 org_port = 0;
  329                 while (i < dlen && isdigit(sptr[i])) {
  330                         if (org_port > 6554) {  /* Terminate on overflow
  331                                                  * (65536/10 rounded up */
  332                                 DBprintf(("DCC: port number overflow\n"));
  333                                 goto lBAD_CTCP;
  334                         }
  335                         org_port *= 10;
  336                         org_port += sptr[i++] - '';
  337                 }
  338                 /* Skip illegal addresses (or early termination) */
  339                 if (i >= dlen || (sptr[i] != '\001' && sptr[i] != ' ')) {
  340                         DBprintf(("Bad port termination\n"));
  341                         goto lBAD_CTCP;
  342                 }
  343                 DBprintf(("Got IP %lu and port %u\n", org_addr, (unsigned)org_port));
  344 
  345                 /* We've got the address and port - now alias it */
  346                 {
  347                         struct alias_link *dcc_lnk;
  348                         struct in_addr destaddr;
  349 
  350                         true_port = htons(org_port);
  351                         true_addr.s_addr = htonl(org_addr);
  352                         destaddr.s_addr = 0;
  353 
  354                         /* Sanity/Security checking */
  355                         if (!org_addr || !org_port ||
  356                             pip->ip_src.s_addr != true_addr.s_addr ||
  357                             org_port < IPPORT_RESERVED)
  358                                 goto lBAD_CTCP;
  359 
  360                         /*
  361                          * Steal the FTP_DATA_PORT - it doesn't really
  362                          * matter, and this would probably allow it through
  363                          * at least _some_ firewalls.
  364                          */
  365                         dcc_lnk = FindUdpTcpOut(la, true_addr, destaddr,
  366                             true_port, 0,
  367                             IPPROTO_TCP, 1);
  368                         DBprintf(("Got a DCC link\n"));
  369                         if (dcc_lnk) {
  370                                 struct in_addr alias_address;   /* Address from aliasing */
  371                                 u_short alias_port;     /* Port given by
  372                                                          * aliasing */
  373                                 int n;
  374 
  375 #ifndef NO_FW_PUNCH
  376                                 /* Generate firewall hole as appropriate */
  377                                 PunchFWHole(dcc_lnk);
  378 #endif
  379 
  380                                 alias_address = GetAliasAddress(lnk);
  381                                 n = snprintf(&newpacket[iCopy],
  382                                     PKTSIZE - iCopy,
  383                                     "%lu ", (u_long) htonl(alias_address.s_addr));
  384                                 if (n < 0) {
  385                                         DBprintf(("DCC packet construct failure.\n"));
  386                                         goto lBAD_CTCP;
  387                                 }
  388                                 if ((iCopy += n) >= PKTSIZE) {  /* Truncated/fit exactly
  389                                                                                  * - bad news */
  390                                         DBprintf(("DCC constructed packet overflow.\n"));
  391                                         goto lBAD_CTCP;
  392                                 }
  393                                 alias_port = GetAliasPort(dcc_lnk);
  394                                 n = snprintf(&newpacket[iCopy],
  395                                     PKTSIZE - iCopy,
  396                                     "%u", htons(alias_port));
  397                                 if (n < 0) {
  398                                         DBprintf(("DCC packet construct failure.\n"));
  399                                         goto lBAD_CTCP;
  400                                 }
  401                                 iCopy += n;
  402                                 /*
  403                                  * Done - truncated cases will be taken
  404                                  * care of by lBAD_CTCP
  405                                  */
  406                                 DBprintf(("Aliased IP %lu and port %u\n", alias_address.s_addr, (unsigned)alias_port));
  407                         }
  408                 }
  409                 /*
  410                  * An uninteresting CTCP - state entered right after '\001'
  411                  * has been pushed.  Also used to copy the rest of a DCC,
  412                  * after IP address and port has been handled
  413                  */
  414                 lBAD_CTCP:
  415                 for (; i < dlen && iCopy < PKTSIZE; i++, iCopy++) {
  416                         newpacket[iCopy] = sptr[i];     /* Copy CTCP unchanged */
  417                         if (sptr[i] == '\001') {
  418                                 goto lNORMAL_TEXT;
  419                         }
  420                 }
  421                 goto lPACKET_DONE;
  422                 /* Normal text */
  423                 lNORMAL_TEXT:
  424                 for (; i < dlen && iCopy < PKTSIZE; i++, iCopy++) {
  425                         newpacket[iCopy] = sptr[i];     /* Copy CTCP unchanged */
  426                         if (sptr[i] == '\001') {
  427                                 goto lCTCP_START;
  428                         }
  429                 }
  430                 /* Handle the end of a packet */
  431                 lPACKET_DONE:
  432                 iCopy = iCopy > maxsize - copyat ? maxsize - copyat : iCopy;
  433                 memcpy(sptr + copyat, newpacket, iCopy);
  434 
  435                 /* Save information regarding modified seq and ack numbers */
  436                 {
  437                         int delta;
  438 
  439                         SetAckModified(lnk);
  440                         tc = (struct tcphdr *)ip_next(pip);
  441                         delta = GetDeltaSeqOut(tc->th_seq, lnk);
  442                         AddSeq(lnk, delta + copyat + iCopy - dlen, pip->ip_hl,
  443                             pip->ip_len, tc->th_seq, tc->th_off);
  444                 }
  445 
  446                 /* Revise IP header */
  447                 {
  448                         u_short new_len;
  449 
  450                         new_len = htons(hlen + iCopy + copyat);
  451                         DifferentialChecksum(&pip->ip_sum,
  452                             &new_len,
  453                             &pip->ip_len,
  454                             1);
  455                         pip->ip_len = new_len;
  456                 }
  457 
  458                 /* Compute TCP checksum for revised packet */
  459                 tc->th_sum = 0;
  460 #ifdef _KERNEL
  461                 tc->th_x2 = (TH_RES1 >> 8);
  462 #else
  463                 tc->th_sum = TcpChecksum(pip);
  464 #endif
  465                 return;
  466         }
  467 }
  468 
  469 /* Notes:
  470   [Note 1]
  471   The initial search will most often fail; it could be replaced with a 32-bit specific search.
  472   Such a search would be done for 32-bit unsigned value V:
  473    V ^= 0x01010101;          (Search is for null bytes)
  474    if( ((V-0x01010101)^V) & 0x80808080 ) {
  475      (found a null bytes which was a 01 byte)
  476    }
  477   To assert that the processor is 32-bits, do
  478    extern int ircdccar[32];        (32 bits)
  479    extern int ircdccar[CHAR_BIT*sizeof(unsigned int)];
  480   which will generate a type-error on all but 32-bit machines.
  481 
  482   [Note 2] This routine really ought to be replaced with one that
  483   creates a transparent proxy on the aliasing host, to allow arbitrary
  484   changes in the TCP stream.  This should not be too difficult given
  485   this base;  I (ee) will try to do this some time later.
  486 */

Cache object: 5a3de62a4d894acfdfcdb4301e3791d3


[ 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.