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

Cache object: edb89cdf976583f69ef7910923a89a65


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