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/netpfil/ipfilter/netinet/ip_irc_pxy.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  * Copyright (C) 2012 by Darren Reed.
    3  *
    4  * See the IPFILTER.LICENCE file for details on licencing.
    5  *
    6  * $Id$
    7  */
    8 
    9 #define IPF_IRC_PROXY
   10 
   11 #define IPF_IRCBUFSZ    96      /* This *MUST* be >= 64! */
   12 
   13 
   14 void ipf_p_irc_main_load(void);
   15 void ipf_p_irc_main_unload(void);
   16 int ipf_p_irc_new(void *, fr_info_t *, ap_session_t *, nat_t *);
   17 int ipf_p_irc_out(void *, fr_info_t *, ap_session_t *, nat_t *);
   18 int ipf_p_irc_send(fr_info_t *, nat_t *);
   19 int ipf_p_irc_complete(ircinfo_t *, char *, size_t);
   20 u_short ipf_irc_atoi(char **);
   21 
   22 static  frentry_t       ircnatfr;
   23 
   24 int     irc_proxy_init = 0;
   25 
   26 
   27 /*
   28  * Initialize local structures.
   29  */
   30 void
   31 ipf_p_irc_main_load(void)
   32 {
   33         bzero((char *)&ircnatfr, sizeof(ircnatfr));
   34         ircnatfr.fr_ref = 1;
   35         ircnatfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE;
   36         MUTEX_INIT(&ircnatfr.fr_lock, "IRC proxy rule lock");
   37         irc_proxy_init = 1;
   38 }
   39 
   40 
   41 void
   42 ipf_p_irc_main_unload(void)
   43 {
   44         if (irc_proxy_init == 1) {
   45                 MUTEX_DESTROY(&ircnatfr.fr_lock);
   46                 irc_proxy_init = 0;
   47         }
   48 }
   49 
   50 
   51 const char *ipf_p_irc_dcctypes[] = {
   52         "CHAT ",        /* CHAT chat ipnumber portnumber */
   53         "SEND ",        /* SEND filename ipnumber portnumber */
   54         "MOVE ",
   55         "TSEND ",
   56         "SCHAT ",
   57         NULL,
   58 };
   59 
   60 
   61 /*
   62  * :A PRIVMSG B :^ADCC CHAT chat 0 0^A\r\n
   63  * PRIVMSG B ^ADCC CHAT chat 0 0^A\r\n
   64  */
   65 
   66 
   67 int
   68 ipf_p_irc_complete(ircinfo_t *ircp, char *buf, size_t len)
   69 {
   70         register char *s, c;
   71         register size_t i;
   72         u_32_t l;
   73         int j, k;
   74 
   75         ircp->irc_ipnum = 0;
   76         ircp->irc_port = 0;
   77 
   78         if (len < 31)
   79                 return (0);
   80         s = buf;
   81         c = *s++;
   82         i = len - 1;
   83 
   84         if ((c != ':') && (c != 'P'))
   85                 return (0);
   86 
   87         if (c == ':') {
   88                 /*
   89                  * Loosely check that the source is a nickname of some sort
   90                  */
   91                 s++;
   92                 c = *s;
   93                 ircp->irc_snick = s;
   94                 if (!ISALPHA(c))
   95                         return (0);
   96                 i--;
   97                 for (c = *s; !ISSPACE(c) && (i > 0); i--)
   98                         c = *s++;
   99                 if (i < 31)
  100                         return (0);
  101                 if (c != 'P')
  102                         return (0);
  103         } else
  104                 ircp->irc_snick = NULL;
  105 
  106         /*
  107          * Check command string
  108          */
  109         if (strncmp(s, "PRIVMSG ", 8))
  110                 return (0);
  111         i -= 8;
  112         s += 8;
  113         c = *s;
  114         ircp->irc_dnick = s;
  115 
  116         /*
  117          * Loosely check that the destination is a nickname of some sort
  118          */
  119         if (!ISALPHA(c))
  120                 return (0);
  121         for (; !ISSPACE(c) && (i > 0); i--)
  122                 c = *s++;
  123         if (i < 20)
  124                 return (0);
  125         s++,
  126         i--;
  127 
  128         /*
  129          * Look for a ^A to start the DCC
  130          */
  131         c = *s;
  132         if (c == ':') {
  133                 s++;
  134                 c = *s;
  135         }
  136 
  137         if (strncmp(s, "\001DCC ", 4))
  138                 return (0);
  139 
  140         i -= 4;
  141         s += 4;
  142 
  143         /*
  144          * Check for a recognised DCC command
  145          */
  146         for (j = 0, k = 0; ipf_p_irc_dcctypes[j]; j++) {
  147                 k = MIN(strlen(ipf_p_irc_dcctypes[j]), i);
  148                 if (!strncmp(ipf_p_irc_dcctypes[j], s, k))
  149                         break;
  150         }
  151         if (!ipf_p_irc_dcctypes[j])
  152                 return (0);
  153 
  154         ircp->irc_type = s;
  155         i -= k;
  156         s += k;
  157 
  158         if (i < 11)
  159                 return (0);
  160 
  161         /*
  162          * Check for the arg
  163          */
  164         c = *s;
  165         if (ISSPACE(c))
  166                 return (0);
  167         ircp->irc_arg = s;
  168         for (; (c != ' ') && (c != '\001') && (i > 0); i--)
  169                 c = *s++;
  170 
  171         if (c == '\001')        /* In reality a ^A can quote another ^A...*/
  172                 return (0);
  173 
  174         if (i < 5)
  175                 return (0);
  176 
  177         s++;
  178         i--;
  179         c = *s;
  180         if (!ISDIGIT(c))
  181                 return (0);
  182         ircp->irc_addr = s;
  183         /*
  184          * Get the IP#
  185          */
  186         for (l = 0; ISDIGIT(c) && (i > 0); i--) {
  187                 l *= 10;
  188                 l += c - '';
  189                 c = *s++;
  190         }
  191 
  192         if (i < 4)
  193                 return (0);
  194 
  195         if (c != ' ')
  196                 return (0);
  197 
  198         ircp->irc_ipnum = l;
  199         s++;
  200         i--;
  201         c = *s;
  202         if (!ISDIGIT(c))
  203                 return (0);
  204         /*
  205          * Get the port#
  206          */
  207         for (l = 0; ISDIGIT(c) && (i > 0); i--) {
  208                 l *= 10;
  209                 l += c - '';
  210                 c = *s++;
  211         }
  212         if (i < 3)
  213                 return (0);
  214         if (strncmp(s, "\001\r\n", 3))
  215                 return (0);
  216         s += 3;
  217         ircp->irc_len = s - buf;
  218         ircp->irc_port = l;
  219         return (1);
  220 }
  221 
  222 
  223 int
  224 ipf_p_irc_new(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat)
  225 {
  226         ircinfo_t *irc;
  227 
  228         if (fin->fin_v != 4)
  229                 return (-1);
  230 
  231         KMALLOC(irc, ircinfo_t *);
  232         if (irc == NULL)
  233                 return (-1);
  234 
  235         nat = nat;      /* LINT */
  236 
  237         aps->aps_data = irc;
  238         aps->aps_psiz = sizeof(ircinfo_t);
  239 
  240         bzero((char *)irc, sizeof(*irc));
  241         return (0);
  242 }
  243 
  244 
  245 int
  246 ipf_p_irc_send(fr_info_t *fin, nat_t *nat)
  247 {
  248         char ctcpbuf[IPF_IRCBUFSZ], newbuf[IPF_IRCBUFSZ];
  249         tcphdr_t *tcp, tcph, *tcp2 = &tcph;
  250         int off, inc = 0, i, dlen;
  251         ipf_main_softc_t *softc;
  252         size_t nlen = 0, olen;
  253         struct in_addr swip;
  254         u_short a5, sp;
  255         ircinfo_t *irc;
  256         fr_info_t fi;
  257         nat_t *nat2;
  258         u_int a1;
  259         ip_t *ip;
  260         mb_t *m;
  261 #if SOLARIS
  262         mb_t *m1;
  263 #endif
  264         softc = fin->fin_main_soft;
  265 
  266         m = fin->fin_m;
  267         ip = fin->fin_ip;
  268         tcp = (tcphdr_t *)fin->fin_dp;
  269         bzero(ctcpbuf, sizeof(ctcpbuf));
  270         off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff;
  271 
  272         dlen = MSGDSIZE(m) - off;
  273         if (dlen <= 0)
  274                 return (0);
  275         COPYDATA(m, off, MIN(sizeof(ctcpbuf), dlen), ctcpbuf);
  276 
  277         if (dlen <= 0)
  278                 return (0);
  279         ctcpbuf[sizeof(ctcpbuf) - 1] = '\0';
  280         *newbuf = '\0';
  281 
  282         irc = nat->nat_aps->aps_data;
  283         if (ipf_p_irc_complete(irc, ctcpbuf, dlen) == 0)
  284                 return (0);
  285 
  286         /*
  287          * check that IP address in the DCC reply is the same as the
  288          * sender of the command - prevents use for port scanning.
  289          */
  290         if (irc->irc_ipnum != ntohl(nat->nat_osrcaddr))
  291                 return (0);
  292 
  293         a5 = irc->irc_port;
  294 
  295         /*
  296          * Calculate new address parts for the DCC command
  297          */
  298         a1 = ntohl(ip->ip_src.s_addr);
  299         olen = irc->irc_len;
  300         i = irc->irc_addr - ctcpbuf;
  301         i++;
  302         (void) strncpy(newbuf, ctcpbuf, i);
  303         /* DO NOT change these! */
  304         (void) snprintf(newbuf, sizeof(newbuf), "%u %u\001\r\n", a1, a5);
  305 
  306         nlen = strlen(newbuf);
  307         inc = nlen - olen;
  308 
  309         if ((inc + fin->fin_plen) > 65535)
  310                 return (0);
  311 
  312 #if SOLARIS
  313         for (m1 = m; m1->b_cont; m1 = m1->b_cont)
  314                 ;
  315         if ((inc > 0) && (m1->b_datap->db_lim - m1->b_wptr < inc)) {
  316                 mblk_t *nm;
  317 
  318                 /* alloc enough to keep same trailer space for lower driver */
  319                 nm = allocb(nlen, BPRI_MED);
  320                 PANIC((!nm),("ipf_p_irc_out: allocb failed"));
  321 
  322                 nm->b_band = m1->b_band;
  323                 nm->b_wptr += nlen;
  324 
  325                 m1->b_wptr -= olen;
  326                 PANIC((m1->b_wptr < m1->b_rptr),
  327                       ("ipf_p_irc_out: cannot handle fragmented data block"));
  328 
  329                 linkb(m1, nm);
  330         } else {
  331 # if SOLARIS && defined(ICK_VALID)
  332                 if (m1->b_datap->db_struiolim == m1->b_wptr)
  333                         m1->b_datap->db_struiolim += inc;
  334                 m1->b_datap->db_struioflag &= ~STRUIO_IP;
  335 # endif
  336                 m1->b_wptr += inc;
  337         }
  338 #else
  339         if (inc < 0)
  340                 m_adj(m, inc);
  341         /* the mbuf chain will be extended if necessary by m_copyback() */
  342 #endif
  343         COPYBACK(m, off, nlen, newbuf);
  344         fin->fin_flx |= FI_DOCKSUM;
  345 
  346         if (inc != 0) {
  347 #if SOLARIS
  348                 register u_32_t sum1, sum2;
  349 
  350                 sum1 = fin->fin_plen;
  351                 sum2 = fin->fin_plen + inc;
  352 
  353                 /* Because ~1 == -2, We really need ~1 == -1 */
  354                 if (sum1 > sum2)
  355                         sum2--;
  356                 sum2 -= sum1;
  357                 sum2 = (sum2 & 0xffff) + (sum2 >> 16);
  358 
  359                 ipf_fix_outcksum(0, &ip->ip_sum, sum2, 0);
  360 #endif
  361                 fin->fin_plen += inc;
  362                 ip->ip_len = htons(fin->fin_plen);
  363                 fin->fin_dlen += inc;
  364         }
  365 
  366         /*
  367          * Add skeleton NAT entry for connection which will come back the
  368          * other way.
  369          */
  370         sp = htons(a5);
  371         /*
  372          * Don't allow the PORT command to specify a port < 1024 due to
  373          * security crap.
  374          */
  375         if (ntohs(sp) < 1024)
  376                 return (0);
  377 
  378         /*
  379          * The server may not make the connection back from port 20, but
  380          * it is the most likely so use it here to check for a conflicting
  381          * mapping.
  382          */
  383         bcopy((caddr_t)fin, (caddr_t)&fi, sizeof(fi));
  384         fi.fin_data[0] = sp;
  385         fi.fin_data[1] = fin->fin_data[1];
  386         nat2 = ipf_nat_outlookup(fin, IPN_TCP, nat->nat_pr[1], nat->nat_nsrcip,
  387                              ip->ip_dst);
  388         if (nat2 == NULL) {
  389 #ifdef USE_MUTEXES
  390                 ipf_nat_softc_t *softn = softc->ipf_nat_soft;
  391 #endif
  392 
  393                 bcopy((caddr_t)fin, (caddr_t)&fi, sizeof(fi));
  394                 bzero((char *)tcp2, sizeof(*tcp2));
  395                 tcp2->th_win = htons(8192);
  396                 tcp2->th_sport = sp;
  397                 tcp2->th_dport = 0; /* XXX - don't specify remote port */
  398                 fi.fin_data[0] = ntohs(sp);
  399                 fi.fin_data[1] = 0;
  400                 fi.fin_dp = (char *)tcp2;
  401                 fi.fin_fr = &ircnatfr;
  402                 fi.fin_dlen = sizeof(*tcp2);
  403                 fi.fin_plen = fi.fin_hlen + sizeof(*tcp2);
  404                 swip = ip->ip_src;
  405                 ip->ip_src = nat->nat_nsrcip;
  406                 MUTEX_ENTER(&softn->ipf_nat_new);
  407                 nat2 = ipf_nat_add(&fi, nat->nat_ptr, NULL,
  408                                NAT_SLAVE|IPN_TCP|SI_W_DPORT, NAT_OUTBOUND);
  409                 MUTEX_EXIT(&softn->ipf_nat_new);
  410                 if (nat2 != NULL) {
  411                         (void) ipf_nat_proto(&fi, nat2, 0);
  412                         MUTEX_ENTER(&nat2->nat_lock);
  413                         ipf_nat_update(&fi, nat2);
  414                         MUTEX_EXIT(&nat2->nat_lock);
  415 
  416                         (void) ipf_state_add(softc, &fi, NULL, SI_W_DPORT);
  417                 }
  418                 ip->ip_src = swip;
  419         }
  420         return (inc);
  421 }
  422 
  423 
  424 int
  425 ipf_p_irc_out(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat)
  426 {
  427         aps = aps;      /* LINT */
  428         return (ipf_p_irc_send(fin, nat));
  429 }

Cache object: 4b9b7fd1a5b479eec134e7159d772855


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