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_fil.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) 1993-1997 by Darren Reed.
    3  *
    4  * Redistribution and use in source and binary forms are permitted
    5  * provided that this notice is preserved and due credit is given
    6  * to the original author and the contributors.
    7  */
    8 #if !defined(lint)
    9 static const char sccsid[] = "@(#)ip_fil.c      2.41 6/5/96 (C) 1993-1995 Darren Reed";
   10 static const char rcsid[] = "@(#)$FreeBSD$";
   11 #endif
   12 
   13 #include "opt_ipfilter.h"
   14 
   15 #ifndef SOLARIS
   16 #define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4)))
   17 #endif
   18 
   19 #if defined(KERNEL) && !defined(_KERNEL)
   20 # define        _KERNEL
   21 #endif
   22 #ifdef  __FreeBSD__
   23 # if defined(_KERNEL) && !defined(IPFILTER_LKM)
   24 #  define __FreeBSD_version 300000      /* this will do as a hack */
   25 # else
   26 #  include <osreldate.h>
   27 # endif
   28 #endif
   29 #ifndef _KERNEL
   30 # include <stdio.h>
   31 # include <string.h>
   32 # include <stdlib.h>
   33 # include <ctype.h>
   34 #endif
   35 #include <sys/errno.h>
   36 #include <sys/types.h>
   37 #include <sys/param.h>
   38 #include <sys/file.h>
   39 #if __FreeBSD_version >= 220000 && defined(_KERNEL)
   40 # include <sys/fcntl.h>
   41 # include <sys/filio.h>
   42 #else
   43 # include <sys/ioctl.h>
   44 #endif
   45 #include <sys/time.h>
   46 #ifdef  _KERNEL
   47 # include <sys/systm.h>
   48 #endif
   49 #include <sys/uio.h>
   50 #if !SOLARIS
   51 # if (NetBSD > 199609) || (OpenBSD > 199603) || __FreeBSD_version >= 220000
   52 #  include <sys/dirent.h>
   53 # else
   54 #  include <sys/dir.h>
   55 # endif
   56 # include <sys/mbuf.h>
   57 #else
   58 # include <sys/filio.h>
   59 #endif
   60 #include <sys/protosw.h>
   61 #include <sys/socket.h>
   62 
   63 #include <net/if.h>
   64 #ifdef sun
   65 # include <net/af.h>
   66 #endif
   67 #if __FreeBSD_version >= 300000
   68 # include <net/if_var.h>
   69 # include <sys/malloc.h>
   70 #endif
   71 #ifdef __sgi
   72 #include <sys/debug.h>
   73 # ifdef IFF_DRVRLOCK /* IRIX6 */
   74 #include <sys/hashing.h>
   75 # endif
   76 #endif
   77 #include <net/route.h>
   78 #include <netinet/in.h>
   79 #if !(defined(__sgi) && !defined(IFF_DRVRLOCK)) /* IRIX < 6 */
   80 #include <netinet/in_var.h>
   81 #endif
   82 #include <netinet/in_systm.h>
   83 #include <netinet/ip.h>
   84 #include <netinet/ip_var.h>
   85 #include <netinet/tcp.h>
   86 #include <netinet/udp.h>
   87 #include <netinet/tcpip.h>
   88 #include <netinet/ip_icmp.h>
   89 #ifndef _KERNEL
   90 # include <syslog.h>
   91 #endif
   92 #include "netinet/ip_compat.h"
   93 #include "netinet/ip_fil.h"
   94 #include "netinet/ip_proxy.h"
   95 #include "netinet/ip_nat.h"
   96 #include "netinet/ip_frag.h"
   97 #include "netinet/ip_state.h"
   98 #include "netinet/ip_auth.h"
   99 #ifndef MIN
  100 #define MIN(a,b)        (((a)<(b))?(a):(b))
  101 #endif
  102 #if     !SOLARIS && defined(_KERNEL)
  103 extern  int     ip_optcopy __P((struct ip *, struct ip *));
  104 #endif
  105 
  106 
  107 extern  struct  protosw inetsw[];
  108 
  109 #ifndef _KERNEL
  110 # include "ipt.h"
  111 static  struct  ifnet **ifneta = NULL;
  112 static  int     nifs = 0;
  113 #else
  114 # if    (BSD < 199306) && !defined(__sgi)
  115 static  int     (*fr_saveslowtimo) __P((void));
  116 # else
  117 static  void    (*fr_saveslowtimo) __P((void));
  118 # endif
  119 # if    (BSD < 199306) || defined(__sgi)
  120 extern  int     tcp_ttl;
  121 # endif
  122 #endif
  123 
  124 int     ipl_inited = 0;
  125 int     ipl_unreach = ICMP_UNREACH_FILTER;
  126 u_long  ipl_frouteok[2] = {0, 0};
  127 
  128 static  void    fixskip __P((frentry_t **, frentry_t *, int));
  129 static  void    frzerostats __P((caddr_t));
  130 static  void    frsync __P((void));
  131 #if defined(__NetBSD__) || defined(__OpenBSD__) || (__FreeBSD_version >= 300003)
  132 static  int     frrequest __P((int, u_long, caddr_t, int));
  133 #else
  134 static  int     frrequest __P((int, int, caddr_t, int));
  135 #endif
  136 #ifdef  _KERNEL
  137 static  int     (*fr_savep) __P((ip_t *, int, void *, int, struct mbuf **));
  138 #else
  139 int     ipllog __P((void));
  140 void    init_ifp __P((void));
  141 # ifdef __sgi
  142 static int      no_output __P((struct ifnet *, struct mbuf *,
  143                                struct sockaddr *));
  144 static int      write_output __P((struct ifnet *, struct mbuf *,
  145                                   struct sockaddr *));
  146 # else
  147 static int      no_output __P((struct ifnet *, struct mbuf *,
  148                                struct sockaddr *, struct rtentry *));
  149 static int      write_output __P((struct ifnet *, struct mbuf *,
  150                                   struct sockaddr *, struct rtentry *));
  151 # endif
  152 #endif
  153 
  154 #if (_BSDI_VERSION >= 199510) && defined(_KERNEL)
  155 # include <sys/device.h>
  156 # include <sys/conf.h>
  157 
  158 struct cfdriver iplcd = {
  159         NULL, "ipl", NULL, NULL, DV_DULL, 0
  160 };
  161 
  162 struct devsw iplsw = {
  163         &iplcd,
  164         iplopen, iplclose, iplread, nowrite, iplioctl, noselect, nommap,
  165         nostrat, nodump, nopsize, 0,
  166         nostop
  167 };
  168 #endif /* _BSDI_VERSION >= 199510  && _KERNEL */
  169 
  170 #if defined(__NetBSD__) || defined(__OpenBSD__)  || (_BSDI_VERSION >= 199701)
  171 # include <sys/conf.h>
  172 # if defined(NETBSD_PF)
  173 #  include <net/pfil.h>
  174 /*
  175  * We provide the fr_checkp name just to minimize changes later.
  176  */
  177 int (*fr_checkp) __P((ip_t *ip, int hlen, void *ifp, int out, mb_t **mp));
  178 # endif /* NETBSD_PF */
  179 #endif /* __NetBSD__ */
  180 
  181 #ifdef  _KERNEL
  182 # if    defined(IPFILTER_LKM) && !defined(__sgi)
  183 int iplidentify(s)
  184 char *s;
  185 {
  186         if (strcmp(s, "ipl") == 0)
  187                 return 1;
  188         return 0;
  189 }
  190 # endif /* IPFILTER_LKM */
  191 
  192 
  193 /*
  194  * Try to detect the case when compiling for NetBSD with pseudo-device
  195  */
  196 # if defined(__NetBSD__) && defined(PFIL_HOOKS)
  197 void
  198 ipfilterattach(count)
  199 int count;
  200 {
  201         iplattach();
  202 }
  203 # endif
  204 
  205 
  206 int iplattach()
  207 {
  208         char *defpass;
  209         int s;
  210 # ifdef __sgi
  211         int error;
  212 # endif
  213 
  214         SPL_NET(s);
  215         if (ipl_inited || (fr_checkp == fr_check)) {
  216                 printf("IP Filter: already initialized\n");
  217                 SPL_X(s);
  218                 return EBUSY;
  219         }
  220 
  221 # ifdef NETBSD_PF
  222         pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT);
  223 # endif
  224 
  225 # ifdef __sgi
  226         error = ipfilter_sgi_attach();
  227         if (error) {
  228                 SPL_X(s);
  229                 return error;
  230         }
  231 # endif
  232 
  233         ipl_inited = 1;
  234         bzero((char *)frcache, sizeof(frcache));
  235         bzero((char *)nat_table, sizeof(nat_table));
  236         fr_savep = fr_checkp;
  237         fr_checkp = fr_check;
  238         fr_saveslowtimo = inetsw[0].pr_slowtimo;
  239         inetsw[0].pr_slowtimo = ipfr_slowtimer;
  240 
  241 # ifdef IPFILTER_LOG
  242         ipflog_init();
  243 # endif
  244         SPL_X(s);
  245         if (fr_pass & FR_PASS)
  246                 defpass = "pass";
  247         else if (fr_pass & FR_BLOCK)
  248                 defpass = "block";
  249         else
  250                 defpass = "no-match -> block";
  251 
  252         printf("IP Filter: initialized.  Default = %s all, Logging = %s\n",
  253                 defpass,
  254 # ifdef IPFILTER_LOG
  255                 "enabled");
  256 # else
  257                 "disabled");
  258 # endif
  259         return 0;
  260 }
  261 
  262 
  263 /*
  264  * Disable the filter by removing the hooks from the IP input/output
  265  * stream.
  266  */
  267 int ipldetach()
  268 {
  269         int s, i = FR_INQUE|FR_OUTQUE;
  270 
  271         SPL_NET(s);
  272         if (!ipl_inited)
  273         {
  274                 printf("IP Filter: not initialized\n");
  275                 SPL_X(s);
  276                 return 0;
  277         }
  278 
  279         fr_checkp = fr_savep;
  280         inetsw[0].pr_slowtimo = fr_saveslowtimo;
  281         frflush(IPL_LOGIPF, &i);
  282         ipl_inited = 0;
  283 
  284 # ifdef NETBSD_PF
  285         pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT);
  286 # endif
  287 
  288 # ifdef __sgi
  289         ipfilter_sgi_detach();
  290 # endif
  291 
  292         ipfr_unload();
  293         ip_natunload();
  294         fr_stateunload();
  295         fr_authunload();
  296 
  297         SPL_X(s);
  298         return 0;
  299 }
  300 #endif /* _KERNEL */
  301 
  302 
  303 static  void    frzerostats(data)
  304 caddr_t data;
  305 {
  306         struct  friostat        fio;
  307 
  308         bcopy((char *)frstats, (char *)fio.f_st,
  309                 sizeof(struct filterstats) * 2);
  310         fio.f_fin[0] = ipfilter[0][0];
  311         fio.f_fin[1] = ipfilter[0][1];
  312         fio.f_fout[0] = ipfilter[1][0];
  313         fio.f_fout[1] = ipfilter[1][1];
  314         fio.f_acctin[0] = ipacct[0][0];
  315         fio.f_acctin[1] = ipacct[0][1];
  316         fio.f_acctout[0] = ipacct[1][0];
  317         fio.f_acctout[1] = ipacct[1][1];
  318         fio.f_active = fr_active;
  319         fio.f_froute[0] = ipl_frouteok[0];
  320         fio.f_froute[1] = ipl_frouteok[1];
  321         IWCOPY((caddr_t)&fio, data, sizeof(fio));
  322         bzero((char *)frstats, sizeof(*frstats) * 2);
  323 }
  324 
  325 
  326 /*
  327  * Filter ioctl interface.
  328  */
  329 #ifdef __sgi
  330 int IPL_EXTERN(ioctl)(dev_t dev, int cmd, caddr_t data, int mode
  331 # ifdef _KERNEL
  332         , cred_t *cp, int *rp
  333 # endif
  334 )
  335 #else
  336 int IPL_EXTERN(ioctl)(dev, cmd, data, mode
  337 #if ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || (NetBSD >= 199511) || \
  338      (__FreeBSD_version >= 220000)) && defined(_KERNEL)
  339 , p)
  340 struct proc *p;
  341 #else
  342 )
  343 #endif
  344 dev_t dev;
  345 #if defined(__NetBSD__) || defined(__OpenBSD__) || \
  346     (_BSDI_VERSION >= 199701) || (__FreeBSD_version >= 300003)
  347 u_long cmd;
  348 #else
  349 int cmd;
  350 #endif
  351 caddr_t data;
  352 int mode;
  353 #endif /* __sgi */
  354 {
  355 #if defined(_KERNEL) && !SOLARIS
  356         int s;
  357 #endif
  358         int error = 0, unit = 0, tmp;
  359 
  360 #ifdef  _KERNEL
  361         unit = GET_MINOR(dev);
  362         if ((IPL_LOGMAX < unit) || (unit < 0))
  363                 return ENXIO;
  364 #endif
  365 
  366         SPL_NET(s);
  367 
  368         if (unit == IPL_LOGNAT) {
  369                 error = nat_ioctl(data, cmd, mode);
  370                 SPL_X(s);
  371                 return error;
  372         }
  373         if (unit == IPL_LOGSTATE) {
  374                 error = fr_state_ioctl(data, cmd, mode);
  375                 SPL_X(s);
  376                 return error;
  377         }
  378         switch (cmd) {
  379         case FIONREAD :
  380 #ifdef IPFILTER_LOG
  381                 IWCOPY((caddr_t)&iplused[IPL_LOGIPF], (caddr_t)data,
  382                        sizeof(iplused[IPL_LOGIPF]));
  383 #endif
  384                 break;
  385 #if !defined(IPFILTER_LKM) && defined(_KERNEL)
  386         case SIOCFRENB :
  387         {
  388                 u_int   enable;
  389 
  390                 if (!(mode & FWRITE))
  391                         error = EPERM;
  392                 else {
  393                         IRCOPY(data, (caddr_t)&enable, sizeof(enable));
  394                         if (enable)
  395                                 error = iplattach();
  396                         else
  397                                 error = ipldetach();
  398                 }
  399                 break;
  400         }
  401 #endif
  402         case SIOCSETFF :
  403                 if (!(mode & FWRITE))
  404                         error = EPERM;
  405                 else
  406                         IRCOPY(data, (caddr_t)&fr_flags, sizeof(fr_flags));
  407                 break;
  408         case SIOCGETFF :
  409                 IWCOPY((caddr_t)&fr_flags, data, sizeof(fr_flags));
  410                 break;
  411         case SIOCINAFR :
  412         case SIOCRMAFR :
  413         case SIOCADAFR :
  414         case SIOCZRLST :
  415                 if (!(mode & FWRITE))
  416                         error = EPERM;
  417                 else
  418                         error = frrequest(unit, cmd, data, fr_active);
  419                 break;
  420         case SIOCINIFR :
  421         case SIOCRMIFR :
  422         case SIOCADIFR :
  423                 if (!(mode & FWRITE))
  424                         error = EPERM;
  425                 else
  426                         error = frrequest(unit, cmd, data, 1 - fr_active);
  427                 break;
  428         case SIOCSWAPA :
  429                 if (!(mode & FWRITE))
  430                         error = EPERM;
  431                 else {
  432                         bzero((char *)frcache, sizeof(frcache[0]) * 2);
  433                         *(u_int *)data = fr_active;
  434                         fr_active = 1 - fr_active;
  435                 }
  436                 break;
  437         case SIOCGETFS :
  438         {
  439                 struct  friostat        fio;
  440 
  441                 bcopy((char *)frstats, (char *)fio.f_st,
  442                         sizeof(struct filterstats) * 2);
  443                 fio.f_fin[0] = ipfilter[0][0];
  444                 fio.f_fin[1] = ipfilter[0][1];
  445                 fio.f_fout[0] = ipfilter[1][0];
  446                 fio.f_fout[1] = ipfilter[1][1];
  447                 fio.f_acctin[0] = ipacct[0][0];
  448                 fio.f_acctin[1] = ipacct[0][1];
  449                 fio.f_acctout[0] = ipacct[1][0];
  450                 fio.f_acctout[1] = ipacct[1][1];
  451                 fio.f_auth = ipauth;
  452                 fio.f_active = fr_active;
  453                 fio.f_froute[0] = ipl_frouteok[0];
  454                 fio.f_froute[1] = ipl_frouteok[1];
  455                 IWCOPY((caddr_t)&fio, data, sizeof(fio));
  456                 break;
  457         }
  458         case    SIOCFRZST :
  459                 if (!(mode & FWRITE))
  460                         error = EPERM;
  461                 else
  462                         frzerostats(data);
  463                 break;
  464         case    SIOCIPFFL :
  465                 if (!(mode & FWRITE))
  466                         error = EPERM;
  467                 else {
  468                         IRCOPY(data, (caddr_t)&tmp, sizeof(tmp));
  469                         frflush(unit, &tmp);
  470                         IWCOPY((caddr_t)&tmp, data, sizeof(tmp));
  471                 }
  472                 break;
  473 #ifdef  IPFILTER_LOG
  474         case    SIOCIPFFB :
  475                 if (!(mode & FWRITE))
  476                         error = EPERM;
  477                 else
  478                         *(int *)data = ipflog_clear(unit);
  479                 break;
  480 #endif /* IPFILTER_LOG */
  481         case SIOCGFRST :
  482                 IWCOPY((caddr_t)ipfr_fragstats(), data, sizeof(ipfrstat_t));
  483                 break;
  484         case SIOCAUTHW :
  485         case SIOCAUTHR :
  486                 if (!(mode & FWRITE)) {
  487                         error = EPERM;
  488                         break;
  489                 }
  490         case SIOCATHST :
  491                 error = fr_auth_ioctl(data, cmd, NULL, NULL);
  492                 break;
  493         case SIOCFRSYN :
  494                 if (!(mode & FWRITE))
  495                         error = EPERM;
  496                 else {
  497 #if defined(_KERNEL) && defined(__sgi)
  498                         ipfsync();
  499 #endif
  500                         frsync();
  501                 }
  502                 break;
  503         default :
  504                 error = EINVAL;
  505                 break;
  506         }
  507         SPL_X(s);
  508         return error;
  509 }
  510 
  511 
  512 static void frsync()
  513 {
  514 #ifdef _KERNEL
  515         struct ifnet *ifp;
  516 
  517 # if (__FreeBSD_version >= 300000)
  518         for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next)
  519 # elif defined(__OpenBSD__) || (NetBSD >= 199511)
  520         for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next)
  521 # else
  522         for (ifp = ifnet; ifp; ifp = ifp->if_next)
  523 # endif
  524                 ip_natsync(ifp);
  525 #endif
  526 }
  527 
  528 
  529 static void fixskip(listp, rp, addremove)
  530 frentry_t **listp, *rp;
  531 int addremove;
  532 {
  533         frentry_t *fp;
  534         int rules = 0, rn = 0;
  535 
  536         for (fp = *listp; fp && (fp != rp); fp = fp->fr_next, rules++)
  537                 ;
  538 
  539         if (!fp)
  540                 return;
  541 
  542         for (fp = *listp; fp && (fp != rp); fp = fp->fr_next, rn++)
  543                 if (fp->fr_skip && (rn + fp->fr_skip >= rules))
  544                         fp->fr_skip += addremove;
  545 }
  546 
  547 
  548 static int frrequest(unit, req, data, set)
  549 int unit;
  550 #if defined(__NetBSD__) || defined(__OpenBSD__) || (__FreeBSD_version >= 300003)
  551 u_long req;
  552 #else
  553 int req;
  554 #endif
  555 int set;
  556 caddr_t data;
  557 {
  558         register frentry_t *fp, *f, **fprev;
  559         register frentry_t **ftail;
  560         frentry_t frd;
  561         frdest_t *fdp;
  562         frgroup_t *fg = NULL;
  563         int error = 0, in, group;
  564 
  565         fp = &frd;
  566         IRCOPY(data, (caddr_t)fp, sizeof(*fp));
  567 
  568         /*
  569          * Check that the group number does exist and that if a head group
  570          * has been specified, doesn't exist.
  571          */
  572         if (fp->fr_grhead &&
  573             fr_findgroup(fp->fr_grhead, fp->fr_flags, unit, set, NULL))
  574                 return EEXIST;
  575         if (fp->fr_group &&
  576             !fr_findgroup(fp->fr_group, fp->fr_flags, unit, set, NULL))
  577                 return ESRCH;
  578 
  579         in = (fp->fr_flags & FR_INQUE) ? 0 : 1;
  580 
  581         if (unit == IPL_LOGAUTH)
  582                 ftail = fprev = &ipauth;
  583         else if (fp->fr_flags & FR_ACCOUNT)
  584                 ftail = fprev = &ipacct[in][set];
  585         else if (fp->fr_flags & (FR_OUTQUE|FR_INQUE))
  586                 ftail = fprev = &ipfilter[in][set];
  587         else
  588                 return ESRCH;
  589 
  590         if ((group = fp->fr_group)) {
  591                 if (!(fg = fr_findgroup(group, fp->fr_flags, unit, set, NULL)))
  592                         return ESRCH;
  593                 ftail = fprev = fg->fg_start;
  594         }
  595 
  596         bzero((char *)frcache, sizeof(frcache[0]) * 2);
  597 
  598         if (*fp->fr_ifname) {
  599                 fp->fr_ifa = GETUNIT(fp->fr_ifname);
  600                 if (!fp->fr_ifa)
  601                         fp->fr_ifa = (void *)-1;
  602         }
  603 
  604         fdp = &fp->fr_dif;
  605         fp->fr_flags &= ~FR_DUP;
  606         if (*fdp->fd_ifname) {
  607                 fdp->fd_ifp = GETUNIT(fdp->fd_ifname);
  608                 if (!fdp->fd_ifp)
  609                         fdp->fd_ifp = (struct ifnet *)-1;
  610                 else
  611                         fp->fr_flags |= FR_DUP;
  612         }
  613 
  614         fdp = &fp->fr_tif;
  615         if (*fdp->fd_ifname) {
  616                 fdp->fd_ifp = GETUNIT(fdp->fd_ifname);
  617                 if (!fdp->fd_ifp)
  618                         fdp->fd_ifp = (struct ifnet *)-1;
  619         }
  620 
  621         /*
  622          * Look for a matching filter rule, but don't include the next or
  623          * interface pointer in the comparison (fr_next, fr_ifa).
  624          */
  625         for (; (f = *ftail); ftail = &f->fr_next)
  626                 if (bcmp((char *)&f->fr_ip, (char *)&fp->fr_ip,
  627                          FR_CMPSIZ) == 0)
  628                         break;
  629 
  630         /*
  631          * If zero'ing statistics, copy current to caller and zero.
  632          */
  633         if (req == SIOCZRLST) {
  634                 if (!f)
  635                         return ESRCH;
  636                 IWCOPY((caddr_t)f, data, sizeof(*f));
  637                 f->fr_hits = 0;
  638                 f->fr_bytes = 0;
  639                 return 0;
  640         }
  641 
  642         if (!f) {
  643                 ftail = fprev;
  644                 if (req != SIOCINAFR && req != SIOCINIFR)
  645                         while ((f = *ftail))
  646                                 ftail = &f->fr_next;
  647                 else if (fp->fr_hits)
  648                         while (--fp->fr_hits && (f = *ftail))
  649                                 ftail = &f->fr_next;
  650                 f = NULL;
  651         }
  652 
  653         if (req == SIOCDELFR || req == SIOCRMIFR) {
  654                 if (!f)
  655                         error = ESRCH;
  656                 else {
  657                         if (f->fr_ref > 1)
  658                                 return EBUSY;
  659                         if (fg && fg->fg_head)
  660                                 fg->fg_head->fr_ref--;
  661                         if (unit == IPL_LOGAUTH)
  662                                 return fr_auth_ioctl(data, req, f, ftail);
  663                         if (f->fr_grhead)
  664                                 fr_delgroup(f->fr_grhead, fp->fr_flags, unit,
  665                                             set);
  666                         fixskip(fprev, f, -1);
  667                         *ftail = f->fr_next;
  668                         KFREE(f);
  669                 }
  670         } else {
  671                 if (f)
  672                         error = EEXIST;
  673                 else {
  674                         if (unit == IPL_LOGAUTH)
  675                                 return fr_auth_ioctl(data, req, f, ftail);
  676                         KMALLOC(f, frentry_t *, sizeof(*f));
  677                         if (f != NULL) {
  678                                 if (fg && fg->fg_head)
  679                                         fg->fg_head->fr_ref++;
  680                                 bcopy((char *)fp, (char *)f, sizeof(*f));
  681                                 f->fr_ref = 1;
  682                                 f->fr_hits = 0;
  683                                 f->fr_next = *ftail;
  684                                 *ftail = f;
  685                                 if (req == SIOCINIFR || req == SIOCINAFR)
  686                                         fixskip(fprev, f, 1);
  687                                 f->fr_grp = NULL;
  688                                 if ((group = f->fr_grhead))
  689                                         fg = fr_addgroup(group, f, unit, set);
  690                         } else
  691                                 error = ENOMEM;
  692                 }
  693         }
  694         return (error);
  695 }
  696 
  697 
  698 #ifdef  _KERNEL
  699 /*
  700  * routines below for saving IP headers to buffer
  701  */
  702 #ifdef __sgi
  703 # ifdef _KERNEL
  704 int IPL_EXTERN(open)(dev_t *pdev, int flags, int devtype, cred_t *cp)
  705 # else
  706 int IPL_EXTERN(open)(dev_t dev, int flags)
  707 # endif
  708 #else
  709 int IPL_EXTERN(open)(dev, flags
  710 # if ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || (NetBSD >= 199511) || \
  711      (__FreeBSD_version >= 220000)) && defined(_KERNEL)
  712 , devtype, p)
  713 int devtype;
  714 struct proc *p;
  715 # else
  716 )
  717 # endif
  718 dev_t dev;
  719 int flags;
  720 #endif /* __sgi */
  721 {
  722 #if defined(__sgi) && defined(_KERNEL)
  723         u_int min = geteminor(*pdev);
  724 #else
  725         u_int min = GET_MINOR(dev);
  726 #endif
  727 
  728         if (IPL_LOGMAX < min)
  729                 min = ENXIO;
  730         else
  731                 min = 0;
  732         return min;
  733 }
  734 
  735 
  736 #ifdef __sgi
  737 int IPL_EXTERN(close)(dev_t dev, int flags, int devtype, cred_t *cp)
  738 #else
  739 int IPL_EXTERN(close)(dev, flags
  740 # if ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || (NetBSD >= 199511) || \
  741      (__FreeBSD_version >= 220000)) && defined(_KERNEL)
  742 , devtype, p)
  743 int devtype;
  744 struct proc *p;
  745 # else
  746 )
  747 # endif
  748 dev_t dev;
  749 int flags;
  750 #endif /* __sgi */
  751 {
  752         u_int   min = GET_MINOR(dev);
  753 
  754         if (2 < min)
  755                 min = ENXIO;
  756         else
  757                 min = 0;
  758         return min;
  759 }
  760 
  761 /*
  762  * iplread/ipllog
  763  * both of these must operate with at least splnet() lest they be
  764  * called during packet processing and cause an inconsistancy to appear in
  765  * the filter lists.
  766  */
  767 #ifdef __sgi
  768 int IPL_EXTERN(read)(dev_t dev, uio_t *uio, cred_t *crp)
  769 #else
  770 #  if BSD >= 199306
  771 int IPL_EXTERN(read)(dev, uio, ioflag)
  772 int ioflag;
  773 #  else
  774 int IPL_EXTERN(read)(dev, uio)
  775 #  endif
  776 dev_t dev;
  777 register struct uio *uio;
  778 #endif /* __sgi */
  779 {
  780 #  ifdef IPFILTER_LOG
  781         return ipflog_read(GET_MINOR(dev), uio);
  782 #  else
  783         return ENXIO;
  784 #  endif
  785 }
  786 
  787 
  788 /*
  789  * send_reset - this could conceivably be a call to tcp_respond(), but that
  790  * requires a large amount of setting up and isn't any more efficient.
  791  */
  792 int send_reset(ti)
  793 struct tcpiphdr *ti;
  794 {
  795         struct tcpiphdr *tp;
  796         struct tcphdr *tcp;
  797         struct mbuf *m;
  798         int tlen = 0, err;
  799         ip_t *ip;
  800 # if defined(__FreeBSD_version) && (__FreeBSD_version >= 220000)
  801         struct route ro;
  802 # endif
  803 
  804         if (ti->ti_flags & TH_RST)
  805                 return -1;              /* feedback loop */
  806 # if    (BSD < 199306) || defined(__sgi)
  807         m = m_get(M_DONTWAIT, MT_HEADER);
  808 # else
  809         m = m_gethdr(M_DONTWAIT, MT_HEADER);
  810         m->m_data += max_linkhdr;
  811 # endif
  812         if (m == NULL)
  813                 return -1;
  814 
  815         if (ti->ti_flags & TH_SYN)
  816                 tlen = 1;
  817         m->m_len = sizeof (struct tcpiphdr);
  818 # if    BSD >= 199306
  819         m->m_pkthdr.len = sizeof (struct tcpiphdr);
  820         m->m_pkthdr.rcvif = (struct ifnet *)0;
  821 # endif
  822         bzero(mtod(m, char *), sizeof(struct tcpiphdr));
  823         ip = mtod(m, struct ip *);
  824         tp = mtod(m, struct tcpiphdr *);
  825         tcp = (struct tcphdr *)((char *)ip + sizeof(struct ip));
  826 
  827         ip->ip_src.s_addr = ti->ti_dst.s_addr;
  828         ip->ip_dst.s_addr = ti->ti_src.s_addr;
  829         tcp->th_dport = ti->ti_sport;
  830         tcp->th_sport = ti->ti_dport;
  831         tcp->th_ack = htonl(ntohl(ti->ti_seq) + tlen);
  832         tcp->th_off = sizeof(struct tcphdr) >> 2;
  833         tcp->th_flags = TH_RST|TH_ACK;
  834         tp->ti_pr = ((struct ip *)ti)->ip_p;
  835         tp->ti_len = htons(sizeof(struct tcphdr));
  836         tcp->th_sum = in_cksum(m, sizeof(struct tcpiphdr));
  837 
  838         ip->ip_tos = ((struct ip *)ti)->ip_tos;
  839         ip->ip_p = ((struct ip *)ti)->ip_p;
  840         ip->ip_len = sizeof (struct tcpiphdr);
  841 # if (BSD < 199306) || defined(__sgi)
  842         ip->ip_ttl = tcp_ttl;
  843 # else
  844         ip->ip_ttl = ip_defttl;
  845 # endif
  846 
  847 # if defined(__FreeBSD_version) && (__FreeBSD_version >= 220000)
  848         bzero((char *)&ro, sizeof(ro));
  849         err = ip_output(m, (struct mbuf *)0, &ro, 0, 0);
  850         if (ro.ro_rt)
  851                 RTFREE(ro.ro_rt);
  852 # else
  853         /*
  854          * extra 0 in case of multicast
  855          */
  856         err = ip_output(m, (struct mbuf *)0, 0, 0, 0);
  857 # endif
  858         return err;
  859 }
  860 
  861 
  862 # if !defined(IPFILTER_LKM) && (__FreeBSD_version < 300000) && !defined(__sgi)
  863 #  if   (BSD < 199306)
  864 int iplinit __P((void));
  865 
  866 int
  867 #  else
  868 void iplinit __P((void));
  869 
  870 void
  871 #  endif
  872 iplinit()
  873 {
  874         (void) iplattach();
  875         ip_init();
  876 }
  877 # endif /* ! __NetBSD__ */
  878 
  879 
  880 size_t mbufchainlen(m0)
  881 register struct mbuf *m0;
  882 {
  883         register size_t len = 0;
  884 
  885         for (; m0; m0 = m0->m_next)
  886                 len += m0->m_len;
  887         return len;
  888 }
  889 
  890 
  891 void ipfr_fastroute(m0, fin, fdp)
  892 struct mbuf *m0;
  893 fr_info_t *fin;
  894 frdest_t *fdp;
  895 {
  896         register struct ip *ip, *mhip;
  897         register struct mbuf *m = m0;
  898         register struct route *ro;
  899         struct ifnet *ifp = fdp->fd_ifp;
  900         int len, off, error = 0;
  901         int hlen = fin->fin_hlen;
  902         struct route iproute;
  903         struct sockaddr_in *dst;
  904 
  905         ip = mtod(m0, struct ip *);
  906         /*
  907          * Route packet.
  908          */
  909         ro = &iproute;
  910         bzero((caddr_t)ro, sizeof (*ro));
  911         dst = (struct sockaddr_in *)&ro->ro_dst;
  912         dst->sin_family = AF_INET;
  913         dst->sin_addr = fdp->fd_ip.s_addr ? fdp->fd_ip : ip->ip_dst;
  914 # ifdef __bsdi__
  915         dst->sin_len = sizeof(*dst);
  916 # endif
  917 # if    (BSD >= 199306) && !defined(__NetBSD__) && !defined(__bsdi__) && \
  918         !defined(__OpenBSD__)
  919 # ifdef RTF_CLONING
  920         rtalloc_ign(ro, RTF_CLONING);
  921 #  else
  922         rtalloc_ign(ro, RTF_PRCLONING);
  923 #  endif
  924 # else
  925         rtalloc(ro);
  926 # endif
  927         if (!ifp) {
  928                 if (!(fin->fin_fr->fr_flags & FR_FASTROUTE)) {
  929                         error = -2;
  930                         goto bad;
  931                 }
  932                 if (ro->ro_rt == 0 || (ifp = ro->ro_rt->rt_ifp) == 0) {
  933                         if (in_localaddr(ip->ip_dst))
  934                                 error = EHOSTUNREACH;
  935                         else
  936                                 error = ENETUNREACH;
  937                         goto bad;
  938                 }
  939                 if (ro->ro_rt->rt_flags & RTF_GATEWAY)
  940                         dst = (struct sockaddr_in *)&ro->ro_rt->rt_gateway;
  941         }
  942         if (ro->ro_rt)
  943                 ro->ro_rt->rt_use++;
  944 
  945         /*
  946          * For input packets which are being "fastrouted", they won't
  947          * go back through output filtering and miss their chance to get
  948          * NAT'd.
  949          */
  950         (void) ip_natout(ip, hlen, fin);
  951         if (fin->fin_out)
  952                 ip->ip_sum = 0;
  953         /*
  954          * If small enough for interface, can just send directly.
  955          */
  956         if (ip->ip_len <= ifp->if_mtu) {
  957 # ifndef sparc
  958                 ip->ip_id = htons(ip->ip_id);
  959                 ip->ip_len = htons(ip->ip_len);
  960                 ip->ip_off = htons(ip->ip_off);
  961 # endif
  962                 if (!ip->ip_sum)
  963                         ip->ip_sum = in_cksum(m, hlen);
  964 # if    BSD >= 199306
  965                 error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst,
  966                                           ro->ro_rt);
  967 # else
  968                 error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst);
  969 # endif
  970                 goto done;
  971         }
  972         /*
  973          * Too large for interface; fragment if possible.
  974          * Must be able to put at least 8 bytes per fragment.
  975          */
  976         if (ip->ip_off & IP_DF) {
  977                 error = EMSGSIZE;
  978                 goto bad;
  979         }
  980         len = (ifp->if_mtu - hlen) &~ 7;
  981         if (len < 8) {
  982                 error = EMSGSIZE;
  983                 goto bad;
  984         }
  985 
  986     {
  987         int mhlen, firstlen = len;
  988         struct mbuf **mnext = &m->m_act;
  989 
  990         /*
  991          * Loop through length of segment after first fragment,
  992          * make new header and copy data of each part and link onto chain.
  993          */
  994         m0 = m;
  995         mhlen = sizeof (struct ip);
  996         for (off = hlen + len; off < ip->ip_len; off += len) {
  997                 MGET(m, M_DONTWAIT, MT_HEADER);
  998                 if (m == 0) {
  999                         error = ENOBUFS;
 1000                         goto bad;
 1001                 }
 1002 # if BSD >= 199306
 1003                 m->m_data += max_linkhdr;
 1004 # else
 1005                 m->m_off = MMAXOFF - hlen;
 1006 # endif
 1007                 mhip = mtod(m, struct ip *);
 1008                 bcopy((char *)ip, (char *)mhip, sizeof(*ip));
 1009                 if (hlen > sizeof (struct ip)) {
 1010                         mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
 1011                         mhip->ip_hl = mhlen >> 2;
 1012                 }
 1013                 m->m_len = mhlen;
 1014                 mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF);
 1015                 if (ip->ip_off & IP_MF)
 1016                         mhip->ip_off |= IP_MF;
 1017                 if (off + len >= ip->ip_len)
 1018                         len = ip->ip_len - off;
 1019                 else
 1020                         mhip->ip_off |= IP_MF;
 1021                 mhip->ip_len = htons((u_short)(len + mhlen));
 1022                 m->m_next = m_copy(m0, off, len);
 1023                 if (m->m_next == 0) {
 1024                         error = ENOBUFS;        /* ??? */
 1025                         goto sendorfree;
 1026                 }
 1027 # ifndef sparc
 1028                 mhip->ip_off = htons((u_short)mhip->ip_off);
 1029 # endif
 1030                 mhip->ip_sum = 0;
 1031                 mhip->ip_sum = in_cksum(m, mhlen);
 1032                 *mnext = m;
 1033                 mnext = &m->m_act;
 1034         }
 1035         /*
 1036          * Update first fragment by trimming what's been copied out
 1037          * and updating header, then send each fragment (in order).
 1038          */
 1039         m_adj(m0, hlen + firstlen - ip->ip_len);
 1040         ip->ip_len = htons((u_short)(hlen + firstlen));
 1041         ip->ip_off = htons((u_short)(ip->ip_off | IP_MF));
 1042         ip->ip_sum = 0;
 1043         ip->ip_sum = in_cksum(m0, hlen);
 1044 sendorfree:
 1045         for (m = m0; m; m = m0) {
 1046                 m0 = m->m_act;
 1047                 m->m_act = 0;
 1048                 if (error == 0)
 1049 # if BSD >= 199306
 1050                         error = (*ifp->if_output)(ifp, m,
 1051                             (struct sockaddr *)dst, ro->ro_rt);
 1052 # else
 1053                         error = (*ifp->if_output)(ifp, m,
 1054                             (struct sockaddr *)dst);
 1055 # endif
 1056                 else
 1057                         m_freem(m);
 1058         }
 1059     }   
 1060 done:
 1061         if (!error)
 1062                 ipl_frouteok[0]++;
 1063         else
 1064                 ipl_frouteok[1]++;
 1065 
 1066         if (ro->ro_rt) {
 1067                 RTFREE(ro->ro_rt);
 1068         }
 1069         return;
 1070 bad:
 1071         m_freem(m);
 1072         goto done;
 1073 }
 1074 #else /* #ifdef _KERNEL */
 1075 
 1076 
 1077 #ifdef __sgi
 1078 static int no_output __P((struct ifnet *ifp, struct mbuf *m,
 1079                            struct sockaddr *s))
 1080 #else
 1081 static int no_output __P((struct ifnet *ifp, struct mbuf *m,
 1082                            struct sockaddr *s, struct rtentry *rt))
 1083 #endif
 1084 {
 1085         return 0;
 1086 }
 1087 
 1088 
 1089 # ifdef __STDC__
 1090 #ifdef __sgi
 1091 static int write_output __P((struct ifnet *ifp, struct mbuf *m,
 1092                              struct sockaddr *s))
 1093 #else
 1094 static int write_output __P((struct ifnet *ifp, struct mbuf *m,
 1095                              struct sockaddr *s, struct rtentry *rt))
 1096 #endif
 1097 {
 1098 # if !(defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
 1099         (defined(OpenBSD) && (OpenBSD >= 199603))
 1100         ip_t *ip = (ip_t *)m;
 1101 #  endif
 1102 # else
 1103 static int write_output(ifp, ip)
 1104 struct ifnet *ifp;
 1105 ip_t *ip;
 1106 {
 1107 # endif
 1108         FILE *fp;
 1109         char fname[32];
 1110 
 1111 # if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
 1112         (defined(OpenBSD) && (OpenBSD >= 199603))
 1113         snprintf(fname, sizeof(fname), "/tmp/%s", ifp->if_xname);
 1114         if ((fp = fopen(fname, "a"))) {
 1115                 fclose(fp);
 1116         }
 1117 # else
 1118         snprintf(fname, sizeof(fname), "/tmp/%s%d", ifp->if_name, ifp->if_unit);
 1119         if ((fp = fopen(fname, "a"))) {
 1120                 fwrite((char *)ip, ntohs(ip->ip_len), 1, fp);
 1121                 fclose(fp);
 1122         }
 1123 # endif
 1124         return 0;
 1125 }
 1126 
 1127 
 1128 struct ifnet *get_unit(name)
 1129 char *name;
 1130 {
 1131         struct ifnet *ifp, **ifa;
 1132 # if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
 1133         (defined(OpenBSD) && (OpenBSD >= 199603))
 1134         for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) {
 1135                 if (!strcmp(name, ifp->if_xname))
 1136                         return ifp;
 1137         }
 1138 # else
 1139         char ifname[32], *s;
 1140 
 1141         for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) {
 1142                 (void) snprintf(ifname, sizeof(ifname),
 1143                         "%s%d", ifp->if_name, ifp->if_unit);
 1144                 if (!strcmp(name, ifname))
 1145                         return ifp;
 1146         }
 1147 # endif
 1148 
 1149         if (!ifneta) {
 1150                 ifneta = (struct ifnet **)malloc(sizeof(ifp) * 2);
 1151                 ifneta[1] = NULL;
 1152                 ifneta[0] = (struct ifnet *)calloc(1, sizeof(*ifp));
 1153                 nifs = 1;
 1154         } else {
 1155                 nifs++;
 1156                 ifneta = (struct ifnet **)realloc(ifneta,
 1157                                                   (nifs + 1) * sizeof(*ifa));
 1158                 ifneta[nifs] = NULL;
 1159                 ifneta[nifs - 1] = (struct ifnet *)malloc(sizeof(*ifp));
 1160         }
 1161         ifp = ifneta[nifs - 1];
 1162 
 1163 # if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
 1164         (defined(OpenBSD) && (OpenBSD >= 199603))
 1165         strncpy(ifp->if_xname, name, sizeof(ifp->if_xname));
 1166 # else
 1167         for (s = name; *s && !isdigit(*s); s++)
 1168                 ;
 1169         if (*s && isdigit(*s)) {
 1170                 ifp->if_unit = atoi(s);
 1171                 ifp->if_name = (char *)malloc(s - name + 1);
 1172                 strncpy(ifp->if_name, name, s - name);
 1173                 ifp->if_name[s - name] = '\0';
 1174         } else {
 1175                 ifp->if_name = strdup(name);
 1176                 ifp->if_unit = -1;
 1177         }
 1178 # endif
 1179         ifp->if_output = no_output;
 1180         return ifp;
 1181 }
 1182 
 1183 
 1184 
 1185 void init_ifp()
 1186 {
 1187         FILE *fp;
 1188         struct ifnet *ifp, **ifa;
 1189         char fname[32];
 1190 # if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
 1191         (defined(OpenBSD) && (OpenBSD >= 199603))
 1192         for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) {
 1193                 ifp->if_output = write_output;
 1194                 snprintf(fname, sizeof(fname), "/tmp/%s", ifp->if_xname);
 1195                 if ((fp = fopen(fname, "w")))
 1196                         fclose(fp);
 1197         }
 1198 # else
 1199 
 1200         for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) {
 1201                 ifp->if_output = write_output;
 1202                 snprintf(fname, sizeof(fname),
 1203                     "/tmp/%s%d", ifp->if_name, ifp->if_unit);
 1204                 if ((fp = fopen(fname, "w")))
 1205                         fclose(fp);
 1206         }
 1207 # endif
 1208 }
 1209 
 1210 
 1211 void ipfr_fastroute(ip, fin, fdp)
 1212 ip_t *ip;
 1213 fr_info_t *fin;
 1214 frdest_t *fdp;
 1215 {
 1216         struct ifnet *ifp = fdp->fd_ifp;
 1217 
 1218         if (!ifp)
 1219                 return; /* no routing table out here */
 1220 
 1221         ip->ip_len = htons((u_short)ip->ip_len);
 1222         ip->ip_off = htons((u_short)(ip->ip_off | IP_MF));
 1223         ip->ip_sum = 0;
 1224 #ifdef __sgi
 1225         (*ifp->if_output)(ifp, (void *)ip, NULL);
 1226 #else
 1227         (*ifp->if_output)(ifp, (void *)ip, NULL, 0);
 1228 #endif
 1229 }
 1230 
 1231 
 1232 int ipllog __P((void))
 1233 {
 1234         verbose("l");
 1235         return 0;
 1236 }
 1237 
 1238 
 1239 int send_reset(ip, ifp)
 1240 ip_t *ip;
 1241 struct ifnet *ifp;
 1242 {
 1243         verbose("- TCP RST sent\n");
 1244         return 0;
 1245 }
 1246 
 1247 
 1248 int icmp_error(ip, ifp)
 1249 ip_t *ip;
 1250 struct ifnet *ifp;
 1251 {
 1252         verbose("- TCP RST sent\n");
 1253         return 0;
 1254 }
 1255 #endif /* _KERNEL */

Cache object: 17b1792ac4106e01d2ba216efcbbfd0c


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