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_scan.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 #if defined(KERNEL) || defined(_KERNEL)
    7 # undef KERNEL
    8 # undef _KERNEL
    9 # define        KERNEL  1
   10 # define        _KERNEL 1
   11 #endif
   12 #include <sys/param.h>
   13 #include <sys/types.h>
   14 #include <sys/time.h>
   15 #include <sys/errno.h>
   16 #if !defined(_KERNEL)
   17 # include <stdlib.h>
   18 # include <string.h>
   19 # define _KERNEL
   20 # include <sys/uio.h>
   21 # undef _KERNEL
   22 #else
   23 # include <sys/systm.h>
   24 # if !defined(__SVR4)
   25 #  include <sys/mbuf.h>
   26 # endif
   27 #endif
   28 #include <sys/socket.h>
   29 # include <sys/ioccom.h>
   30 #ifdef __FreeBSD__
   31 # include <sys/filio.h>
   32 # include <sys/malloc.h>
   33 #else
   34 # include <sys/ioctl.h>
   35 #endif
   36 
   37 #include <netinet/in.h>
   38 #include <netinet/in_systm.h>
   39 #include <netinet/ip.h>
   40 #include <netinet/tcp.h>
   41 
   42 #include <net/if.h>
   43 
   44 
   45 #include "netinet/ip_compat.h"
   46 #include "netinet/ip_fil.h"
   47 #include "netinet/ip_state.h"
   48 #include "netinet/ip_scan.h"
   49 /* END OF INCLUDES */
   50 
   51 #if !defined(lint)
   52 static const char sccsid[] = "@(#)ip_state.c    1.8 6/5/96 (C) 1993-2000 Darren Reed";
   53 static const char rcsid[] = "@(#)$Id$";
   54 #endif
   55 
   56 #ifdef  IPFILTER_SCAN   /* endif at bottom of file */
   57 
   58 
   59 ipscan_t        *ipf_scan_list = NULL,
   60                 *ipf_scan_tail = NULL;
   61 ipscanstat_t    ipf_scan_stat;
   62 # ifdef USE_MUTEXES
   63 ipfrwlock_t     ipf_scan_rwlock;
   64 # endif
   65 
   66 # ifndef isalpha
   67 #  define       isalpha(x)      (((x) >= 'A' && 'Z' >= (x)) || \
   68                                  ((x) >= 'a' && 'z' >= (x)))
   69 # endif
   70 
   71 
   72 int ipf_scan_add(caddr_t);
   73 int ipf_scan_remove(caddr_t);
   74 struct ipscan *ipf_scan_lookup(char *);
   75 int ipf_scan_matchstr(sinfo_t *, char *, int);
   76 int ipf_scan_matchisc(ipscan_t *, ipstate_t *, int, int, int *);
   77 int ipf_scan_match(ipstate_t *);
   78 
   79 static int      ipf_scan_inited = 0;
   80 
   81 
   82 int
   83 ipf_scan_init(void)
   84 {
   85         RWLOCK_INIT(&ipf_scan_rwlock, "ip scan rwlock");
   86         ipf_scan_inited = 1;
   87         return (0);
   88 }
   89 
   90 
   91 void
   92 ipf_scan_unload(ipf_main_softc_t *arg)
   93 {
   94         if (ipf_scan_inited == 1) {
   95                 RW_DESTROY(&ipf_scan_rwlock);
   96                 ipf_scan_inited = 0;
   97         }
   98 }
   99 
  100 
  101 int
  102 ipf_scan_add(caddr_t data)
  103 {
  104         ipscan_t *i, *isc;
  105         int err;
  106 
  107         KMALLOC(isc, ipscan_t *);
  108         if (!isc) {
  109                 ipf_interror = 90001;
  110                 return (ENOMEM);
  111         }
  112 
  113         err = copyinptr(data, isc, sizeof(*isc));
  114         if (err) {
  115                 KFREE(isc);
  116                 return (err);
  117         }
  118 
  119         WRITE_ENTER(&ipf_scan_rwlock);
  120 
  121         i = ipf_scan_lookup(isc->ipsc_tag);
  122         if (i != NULL) {
  123                 RWLOCK_EXIT(&ipf_scan_rwlock);
  124                 KFREE(isc);
  125                 ipf_interror = 90002;
  126                 return (EEXIST);
  127         }
  128 
  129         if (ipf_scan_tail) {
  130                 ipf_scan_tail->ipsc_next = isc;
  131                 isc->ipsc_pnext = &ipf_scan_tail->ipsc_next;
  132                 ipf_scan_tail = isc;
  133         } else {
  134                 ipf_scan_list = isc;
  135                 ipf_scan_tail = isc;
  136                 isc->ipsc_pnext = &ipf_scan_list;
  137         }
  138         isc->ipsc_next = NULL;
  139 
  140         isc->ipsc_hits = 0;
  141         isc->ipsc_fref = 0;
  142         isc->ipsc_sref = 0;
  143         isc->ipsc_active = 0;
  144 
  145         ipf_scan_stat.iscs_entries++;
  146         RWLOCK_EXIT(&ipf_scan_rwlock);
  147         return (0);
  148 }
  149 
  150 
  151 int
  152 ipf_scan_remove(caddr_t data)
  153 {
  154         ipscan_t isc, *i;
  155         int err;
  156 
  157         err = copyinptr(data, &isc, sizeof(isc));
  158         if (err)
  159                 return (err);
  160 
  161         WRITE_ENTER(&ipf_scan_rwlock);
  162 
  163         i = ipf_scan_lookup(isc.ipsc_tag);
  164         if (i == NULL)
  165                 err = ENOENT;
  166         else {
  167                 if (i->ipsc_fref) {
  168                         RWLOCK_EXIT(&ipf_scan_rwlock);
  169                         ipf_interror = 90003;
  170                         return (EBUSY);
  171                 }
  172 
  173                 *i->ipsc_pnext = i->ipsc_next;
  174                 if (i->ipsc_next)
  175                         i->ipsc_next->ipsc_pnext = i->ipsc_pnext;
  176                 else {
  177                         if (i->ipsc_pnext == &ipf_scan_list)
  178                                 ipf_scan_tail = NULL;
  179                         else
  180                                 ipf_scan_tail = *(*i->ipsc_pnext)->ipsc_pnext;
  181                 }
  182 
  183                 ipf_scan_stat.iscs_entries--;
  184                 KFREE(i);
  185         }
  186         RWLOCK_EXIT(&ipf_scan_rwlock);
  187         return (err);
  188 }
  189 
  190 
  191 struct ipscan *
  192 ipf_scan_lookup(char *tag)
  193 {
  194         ipscan_t *i;
  195 
  196         for (i = ipf_scan_list; i; i = i->ipsc_next)
  197                 if (!strcmp(i->ipsc_tag, tag))
  198                         return (i);
  199         return (NULL);
  200 }
  201 
  202 
  203 int
  204 ipf_scan_attachfr(struct frentry *fr)
  205 {
  206         ipscan_t *i;
  207 
  208         if (fr->fr_isctag != -1) {
  209                 READ_ENTER(&ipf_scan_rwlock);
  210                 i = ipf_scan_lookup(fr->fr_isctag + fr->fr_names);
  211                 if (i != NULL) {
  212                         ATOMIC_INC32(i->ipsc_fref);
  213                 }
  214                 RWLOCK_EXIT(&ipf_scan_rwlock);
  215                 if (i == NULL) {
  216                         ipf_interror = 90004;
  217                         return (ENOENT);
  218                 }
  219                 fr->fr_isc = i;
  220         }
  221         return (0);
  222 }
  223 
  224 
  225 int
  226 ipf_scan_attachis(struct ipstate *is)
  227 {
  228         frentry_t *fr;
  229         ipscan_t *i;
  230 
  231         READ_ENTER(&ipf_scan_rwlock);
  232         fr = is->is_rule;
  233         if (fr != NULL) {
  234                 i = fr->fr_isc;
  235                 if ((i != NULL) && (i != (ipscan_t *)-1)) {
  236                         is->is_isc = i;
  237                         ATOMIC_INC32(i->ipsc_sref);
  238                         if (i->ipsc_clen)
  239                                 is->is_flags |= IS_SC_CLIENT;
  240                         else
  241                                 is->is_flags |= IS_SC_MATCHC;
  242                         if (i->ipsc_slen)
  243                                 is->is_flags |= IS_SC_SERVER;
  244                         else
  245                                 is->is_flags |= IS_SC_MATCHS;
  246                 }
  247         }
  248         RWLOCK_EXIT(&ipf_scan_rwlock);
  249         return (0);
  250 }
  251 
  252 
  253 int
  254 ipf_scan_detachfr(struct frentry *fr)
  255 {
  256         ipscan_t *i;
  257 
  258         i = fr->fr_isc;
  259         if (i != NULL) {
  260                 ATOMIC_DEC32(i->ipsc_fref);
  261         }
  262         return (0);
  263 }
  264 
  265 
  266 int
  267 ipf_scan_detachis(is)
  268         struct ipstate *is;
  269 {
  270         ipscan_t *i;
  271 
  272         READ_ENTER(&ipf_scan_rwlock);
  273         if ((i = is->is_isc) && (i != (ipscan_t *)-1)) {
  274                 ATOMIC_DEC32(i->ipsc_sref);
  275                 is->is_isc = NULL;
  276                 is->is_flags &= ~(IS_SC_CLIENT|IS_SC_SERVER);
  277         }
  278         RWLOCK_EXIT(&ipf_scan_rwlock);
  279         return (0);
  280 }
  281 
  282 
  283 /*
  284  * 'string' compare for scanning
  285  */
  286 int
  287 ipf_scan_matchstr(sinfo_t *sp, char *str, int n)
  288 {
  289         char *s, *t, *up;
  290         int i = n;
  291 
  292         if (i > sp->s_len)
  293                 i = sp->s_len;
  294         up = str;
  295 
  296         for (s = sp->s_txt, t = sp->s_msk; i; i--, s++, t++, up++)
  297                 switch ((int)*t)
  298                 {
  299                 case '.' :
  300                         if (*s != *up)
  301                                 return (1);
  302                         break;
  303                 case '?' :
  304                         if (!ISALPHA(*up) || ((*s & 0x5f) != (*up & 0x5f)))
  305                                 return (1);
  306                         break;
  307                 case '*' :
  308                         break;
  309                 }
  310         return (0);
  311 }
  312 
  313 
  314 /*
  315  * Returns 3 if both server and client match, 2 if just server,
  316  * 1 if just client
  317  */
  318 int
  319 ipf_scan_matchisc(ipscan_t *isc, ipstate_t *is, int cl, int sl, int maxm[2])
  320 {
  321         int i, j, k, n, ret = 0, flags;
  322 
  323         flags = is->is_flags;
  324 
  325         /*
  326          * If we've already matched more than what is on offer, then
  327          * assume we have a better match already and forget this one.
  328          */
  329         if (maxm != NULL) {
  330                 if (isc->ipsc_clen < maxm[0])
  331                         return (0);
  332                 if (isc->ipsc_slen < maxm[1])
  333                         return (0);
  334                 j = maxm[0];
  335                 k = maxm[1];
  336         } else {
  337                 j = 0;
  338                 k = 0;
  339         }
  340 
  341         if (!isc->ipsc_clen)
  342                 ret = 1;
  343         else if (((flags & (IS_SC_MATCHC|IS_SC_CLIENT)) == IS_SC_CLIENT) &&
  344                  cl && isc->ipsc_clen) {
  345                 i = 0;
  346                 n = MIN(cl, isc->ipsc_clen);
  347                 if ((n > 0) && (!maxm || (n >= maxm[1]))) {
  348                         if (!ipf_scan_matchstr(&isc->ipsc_cl,
  349                                                is->is_sbuf[0], n)) {
  350                                 i++;
  351                                 ret |= 1;
  352                                 if (n > j)
  353                                         j = n;
  354                         }
  355                 }
  356         }
  357 
  358         if (!isc->ipsc_slen)
  359                 ret |= 2;
  360         else if (((flags & (IS_SC_MATCHS|IS_SC_SERVER)) == IS_SC_SERVER) &&
  361                  sl && isc->ipsc_slen) {
  362                 i = 0;
  363                 n = MIN(cl, isc->ipsc_slen);
  364                 if ((n > 0) && (!maxm || (n >= maxm[1]))) {
  365                         if (!ipf_scan_matchstr(&isc->ipsc_sl,
  366                                                is->is_sbuf[1], n)) {
  367                                 i++;
  368                                 ret |= 2;
  369                                 if (n > k)
  370                                         k = n;
  371                         }
  372                 }
  373         }
  374 
  375         if (maxm && (ret == 3)) {
  376                 maxm[0] = j;
  377                 maxm[1] = k;
  378         }
  379         return (ret);
  380 }
  381 
  382 
  383 int
  384 ipf_scan_match(ipstate_t *is)
  385 {
  386         int i, j, k, n, cl, sl, maxm[2];
  387         ipscan_t *isc, *lm;
  388         tcpdata_t *t;
  389 
  390         for (cl = 0, n = is->is_smsk[0]; n & 1; n >>= 1)
  391                 cl++;
  392         for (sl = 0, n = is->is_smsk[1]; n & 1; n >>= 1)
  393                 sl++;
  394 
  395         j = 0;
  396         isc = is->is_isc;
  397         if (isc != NULL) {
  398                 /*
  399                  * Known object to scan for.
  400                  */
  401                 i = ipf_scan_matchisc(isc, is, cl, sl, NULL);
  402                 if (i & 1) {
  403                         is->is_flags |= IS_SC_MATCHC;
  404                         is->is_flags &= ~IS_SC_CLIENT;
  405                 } else if (cl >= isc->ipsc_clen)
  406                         is->is_flags &= ~IS_SC_CLIENT;
  407                 if (i & 2) {
  408                         is->is_flags |= IS_SC_MATCHS;
  409                         is->is_flags &= ~IS_SC_SERVER;
  410                 } else if (sl >= isc->ipsc_slen)
  411                         is->is_flags &= ~IS_SC_SERVER;
  412         } else {
  413                 i = 0;
  414                 lm = NULL;
  415                 maxm[0] = 0;
  416                 maxm[1] = 0;
  417                 for (k = 0, isc = ipf_scan_list; isc; isc = isc->ipsc_next) {
  418                         i = ipf_scan_matchisc(isc, is, cl, sl, maxm);
  419                         if (i) {
  420                                 /*
  421                                  * We only want to remember the best match
  422                                  * and the number of times we get a best
  423                                  * match.
  424                                  */
  425                                 if ((j == 3) && (i < 3))
  426                                         continue;
  427                                 if ((i == 3) && (j != 3))
  428                                         k = 1;
  429                                 else
  430                                         k++;
  431                                 j = i;
  432                                 lm = isc;
  433                         }
  434                 }
  435                 if (k == 1)
  436                         isc = lm;
  437                 if (isc == NULL)
  438                         return (0);
  439 
  440                 /*
  441                  * No matches or partial matches, so reset the respective
  442                  * search flag.
  443                  */
  444                 if (!(j & 1))
  445                         is->is_flags &= ~IS_SC_CLIENT;
  446 
  447                 if (!(j & 2))
  448                         is->is_flags &= ~IS_SC_SERVER;
  449 
  450                 /*
  451                  * If we found the best match, then set flags appropriately.
  452                  */
  453                 if ((j == 3) && (k == 1)) {
  454                         is->is_flags &= ~(IS_SC_SERVER|IS_SC_CLIENT);
  455                         is->is_flags |= (IS_SC_MATCHS|IS_SC_MATCHC);
  456                 }
  457         }
  458 
  459         /*
  460          * If the acknowledged side of a connection has moved past the data in
  461          * which we are interested, then reset respective flag.
  462          */
  463         t = &is->is_tcp.ts_data[0];
  464         if (t->td_end > is->is_s0[0] + 15)
  465                 is->is_flags &= ~IS_SC_CLIENT;
  466 
  467         t = &is->is_tcp.ts_data[1];
  468         if (t->td_end > is->is_s0[1] + 15)
  469                 is->is_flags &= ~IS_SC_SERVER;
  470 
  471         /*
  472          * Matching complete ?
  473          */
  474         j = ISC_A_NONE;
  475         if ((is->is_flags & IS_SC_MATCHALL) == IS_SC_MATCHALL) {
  476                 j = isc->ipsc_action;
  477                 ipf_scan_stat.iscs_acted++;
  478         } else if ((is->is_isc != NULL) &&
  479                    ((is->is_flags & IS_SC_MATCHALL) != IS_SC_MATCHALL) &&
  480                    !(is->is_flags & (IS_SC_CLIENT|IS_SC_SERVER))) {
  481                 /*
  482                  * Matching failed...
  483                  */
  484                 j = isc->ipsc_else;
  485                 ipf_scan_stat.iscs_else++;
  486         }
  487 
  488         switch (j)
  489         {
  490         case  ISC_A_CLOSE :
  491                 /*
  492                  * If as a result of a successful match we are to
  493                  * close a connection, change the "keep state" info.
  494                  * to block packets and generate TCP RST's.
  495                  */
  496                 is->is_pass &= ~FR_RETICMP;
  497                 is->is_pass |= FR_RETRST;
  498                 break;
  499         default :
  500                 break;
  501         }
  502 
  503         return (i);
  504 }
  505 
  506 
  507 /*
  508  * check if a packet matches what we're scanning for
  509  */
  510 int
  511 ipf_scan_packet(fr_info_t *fin, ipstate_t *is)
  512 {
  513         int i, j, rv, dlen, off, thoff;
  514         u_32_t seq, s0;
  515         tcphdr_t *tcp;
  516 
  517         rv = !IP6_EQ(&fin->fin_fi.fi_src, &is->is_src);
  518         tcp = fin->fin_dp;
  519         seq = ntohl(tcp->th_seq);
  520 
  521         if (!is->is_s0[rv])
  522                 return (1);
  523 
  524         /*
  525          * check if this packet has more data that falls within the first
  526          * 16 bytes sent in either direction.
  527          */
  528         s0 = is->is_s0[rv];
  529         off = seq - s0;
  530         if ((off > 15) || (off < 0))
  531                 return (1);
  532         thoff = TCP_OFF(tcp) << 2;
  533         dlen = fin->fin_dlen - thoff;
  534         if (dlen <= 0)
  535                 return (1);
  536         if (dlen > 16)
  537                 dlen = 16;
  538         if (off + dlen > 16)
  539                 dlen = 16 - off;
  540 
  541         j = 0xffff >> (16 - dlen);
  542         i = (0xffff & j) << off;
  543 #ifdef _KERNEL
  544         COPYDATA(*(mb_t **)fin->fin_mp, fin->fin_plen - fin->fin_dlen + thoff,
  545                  dlen, (caddr_t)is->is_sbuf[rv] + off);
  546 #endif
  547         is->is_smsk[rv] |= i;
  548         for (j = 0, i = is->is_smsk[rv]; i & 1; i >>= 1)
  549                 j++;
  550         if (j == 0)
  551                 return (1);
  552 
  553         (void) ipf_scan_match(is);
  554 #if 0
  555         /*
  556          * There is the potential here for plain text passwords to get
  557          * buffered and stored for some time...
  558          */
  559         if (!(is->is_flags & IS_SC_CLIENT))
  560                 bzero(is->is_sbuf[0], sizeof(is->is_sbuf[0]));
  561         if (!(is->is_flags & IS_SC_SERVER))
  562                 bzero(is->is_sbuf[1], sizeof(is->is_sbuf[1]));
  563 #endif
  564         return (0);
  565 }
  566 
  567 
  568 int
  569 ipf_scan_ioctl(caddr_t data, ioctlcmd_t cmd, int mode, int uid, void *ctx)
  570 {
  571         ipscanstat_t ipscs;
  572         int err = 0;
  573 
  574         switch (cmd)
  575         {
  576         case SIOCADSCA :
  577                 err = ipf_scan_add(data);
  578                 break;
  579         case SIOCRMSCA :
  580                 err = ipf_scan_remove(data);
  581                 break;
  582         case SIOCGSCST :
  583                 bcopy((char *)&ipf_scan_stat, (char *)&ipscs, sizeof(ipscs));
  584                 ipscs.iscs_list = ipf_scan_list;
  585                 err = BCOPYOUT(&ipscs, data, sizeof(ipscs));
  586                 if (err != 0) {
  587                         ipf_interror = 90005;
  588                         err = EFAULT;
  589                 }
  590                 break;
  591         default :
  592                 err = EINVAL;
  593                 break;
  594         }
  595 
  596         return (err);
  597 }
  598 #endif  /* IPFILTER_SCAN */

Cache object: e5ea22acd820cb95bf3422a962147ecb


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