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_netbsd.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_fil_netbsd.c,v 1.3.2.11 2004/11/12 05:58:46 jmc Exp $       */
    2 
    3 /*
    4  * Copyright (C) 1993-2003 by Darren Reed.
    5  *
    6  * See the IPFILTER.LICENCE file for details on licencing.
    7  */
    8 #if !defined(lint)
    9 static const char sccsid[] = "@(#)ip_fil.c      2.41 6/5/96 (C) 1993-2000 Darren Reed";
   10 static const char rcsid[] = "@(#)Id: ip_fil_netbsd.c,v 2.55.2.12 2004/07/06 11:15:50 darrenr Exp";
   11 #endif
   12 
   13 #if defined(KERNEL) || defined(_KERNEL)
   14 # undef KERNEL
   15 # undef _KERNEL
   16 # define        KERNEL  1
   17 # define        _KERNEL 1
   18 #endif
   19 #include <sys/param.h>
   20 #if (NetBSD >= 199905) && !defined(IPFILTER_LKM) && defined(_KERNEL)
   21 # include "opt_ipfilter_log.h"
   22 # include "opt_pfil_hooks.h"
   23 # include "opt_ipsec.h"
   24 #endif
   25 #include <sys/errno.h>
   26 #include <sys/types.h>
   27 #include <sys/file.h>
   28 #include <sys/ioctl.h>
   29 #include <sys/time.h>
   30 #include <sys/systm.h>
   31 #if (NetBSD > 199609)
   32 # include <sys/dirent.h>
   33 #else
   34 # include <sys/dir.h>
   35 #endif
   36 #include <sys/mbuf.h>
   37 #include <sys/protosw.h>
   38 #include <sys/socket.h>
   39 
   40 #include <net/if.h>
   41 #include <net/route.h>
   42 #include <netinet/in.h>
   43 #include <netinet/in_var.h>
   44 #include <netinet/in_systm.h>
   45 #include <netinet/ip.h>
   46 #include <netinet/ip_var.h>
   47 #include <netinet/tcp.h>
   48 #include <netinet/udp.h>
   49 #include <netinet/tcpip.h>
   50 #include <netinet/ip_icmp.h>
   51 #include "netinet/ip_compat.h"
   52 #ifdef USE_INET6
   53 # include <netinet/icmp6.h>
   54 # if (__NetBSD_Version__ >= 106000000)
   55 #  include <netinet6/nd6.h>
   56 # endif
   57 #endif
   58 #include "netinet/ip_fil.h"
   59 #include "netinet/ip_nat.h"
   60 #include "netinet/ip_frag.h"
   61 #include "netinet/ip_state.h"
   62 #include "netinet/ip_proxy.h"
   63 #include "netinet/ip_auth.h"
   64 #ifdef  IPFILTER_SYNC
   65 #include "netinet/ip_sync.h"
   66 #endif
   67 #ifdef  IPFILTER_SCAN
   68 #include "netinet/ip_scan.h"
   69 #endif
   70 #include "netinet/ip_pool.h"
   71 #include <sys/md5.h>
   72 #include <sys/kernel.h>
   73 extern  int     ip_optcopy __P((struct ip *, struct ip *));
   74 
   75 #ifdef IPFILTER_M_IPFILTER
   76 MALLOC_DEFINE(M_IPFILTER, "IP Filter", "IP Filter packet filter data structures");
   77 #endif
   78 
   79 #if __NetBSD_Version__ >= 105009999
   80 # define        csuminfo        csum_flags
   81 #endif
   82 
   83 extern  struct  protosw inetsw[];
   84 
   85 static  int     (*fr_savep) __P((ip_t *, int, void *, int, struct mbuf **));
   86 static  int     fr_send_ip __P((fr_info_t *, mb_t *, mb_t **));
   87 #ifdef KMUTEX_T
   88 extern  ipfmutex_t      ipf_rw;
   89 extern  ipfrwlock_t     ipf_mutex;
   90 #endif
   91 #ifdef USE_INET6
   92 static int ipfr_fastroute6 __P((struct mbuf *, struct mbuf **,
   93                                 fr_info_t *, frdest_t *));
   94 #endif
   95 
   96 #if (__NetBSD_Version__ >= 104040000)
   97 # include <sys/callout.h>
   98 struct callout fr_slowtimer_ch;
   99 #endif
  100 
  101 #include <sys/conf.h>
  102 #if defined(NETBSD_PF)
  103 # include <net/pfil.h>
  104 /*
  105  * We provide the fr_checkp name just to minimize changes later.
  106  */
  107 int (*fr_checkp) __P((ip_t *ip, int hlen, void *ifp, int out, mb_t **mp));
  108 #endif /* NETBSD_PF */
  109 
  110 #if (__NetBSD_Version__ >= 106080000) && defined(_KERNEL)
  111 const struct cdevsw ipl_cdevsw = {
  112         iplopen, iplclose, iplread, nowrite, iplioctl,
  113         nostop, notty, nopoll, nommap,
  114 };
  115 #endif
  116 
  117 
  118 
  119 #if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 105110000)
  120 # include <net/pfil.h>
  121 
  122 static int fr_check_wrapper(void *, struct mbuf **, struct ifnet *, int );
  123 
  124 static int fr_check_wrapper(arg, mp, ifp, dir)
  125 void *arg;
  126 struct mbuf **mp;
  127 struct ifnet *ifp;
  128 int dir;
  129 {
  130         struct ip *ip;
  131         int rv, hlen;
  132         int error;
  133 
  134         /*
  135          * ensure that mbufs are writable beforehand
  136          * as it's assumed by ipf code.
  137          * XXX inefficient
  138          */
  139         error = m_makewritable(mp, 0, M_COPYALL, M_DONTWAIT);
  140         if (error) {
  141                 m_freem(*mp);
  142                 *mp = NULL;
  143                 return error;
  144         }
  145 
  146 #if defined(M_CSUM_TCPv4)
  147         /*
  148          * If the packet is out-bound, we can't delay checksums
  149          * here.  For in-bound, the checksum has already been
  150          * validated.
  151          */
  152         if (dir == PFIL_OUT) {
  153                 if ((*mp)->m_pkthdr.csum_flags & (M_CSUM_TCPv4|M_CSUM_UDPv4)) {
  154                         in_delayed_cksum(*mp);
  155                         (*mp)->m_pkthdr.csum_flags &=
  156                             ~(M_CSUM_TCPv4|M_CSUM_UDPv4);
  157                 }
  158         }
  159 #endif /* M_CSUM_TCPv4 */
  160 
  161         ip = mtod(*mp, struct ip *);
  162         hlen = ip->ip_hl << 2;
  163 
  164         /*
  165          * We get the packet with all fields in network byte
  166          * order.  We expect ip_len and ip_off to be in host
  167          * order.  We frob them, call the filter, then frob
  168          * them back.
  169          *
  170          * Note, we don't need to update the checksum, because
  171          * it has already been verified.
  172          */
  173         NTOHS(ip->ip_len);
  174         NTOHS(ip->ip_off);
  175 
  176         rv = fr_check(ip, hlen, ifp, (dir == PFIL_OUT), mp);
  177 
  178         if (rv == 0 && *mp != NULL) {
  179                 ip = mtod(*mp, struct ip *);
  180                 HTONS(ip->ip_len);
  181                 HTONS(ip->ip_off);
  182         }
  183 
  184         return (rv);
  185 }
  186 
  187 # ifdef USE_INET6
  188 #  include <netinet/ip6.h>
  189 
  190 static int fr_check_wrapper6(void *, struct mbuf **, struct ifnet *, int );
  191 
  192 static int fr_check_wrapper6(arg, mp, ifp, dir)
  193 void *arg;
  194 struct mbuf **mp;
  195 struct ifnet *ifp;
  196 int dir;
  197 {
  198         int error;
  199         
  200         /*
  201          * ensure that mbufs are writable beforehand
  202          * as it's assumed by ipf code.
  203          * XXX inefficient
  204          */
  205         error = m_makewritable(mp, 0, M_COPYALL, M_DONTWAIT);
  206         if (error) {
  207                 m_freem(*mp);
  208                 *mp = NULL;
  209                 return error;
  210         }
  211 
  212         return (fr_check(mtod(*mp, struct ip *), sizeof(struct ip6_hdr),
  213             ifp, (dir == PFIL_OUT), mp));
  214 }
  215 # endif
  216 #endif /* __NetBSD_Version >= 105110000 */
  217 
  218 
  219 #if     defined(IPFILTER_LKM)
  220 int iplidentify(s)
  221 char *s;
  222 {
  223         if (strcmp(s, "ipl") == 0)
  224                 return 1;
  225         return 0;
  226 }
  227 #endif /* IPFILTER_LKM */
  228 
  229 
  230 /*
  231  * Try to detect the case when compiling for NetBSD with pseudo-device
  232  */
  233 #if defined(PFIL_HOOKS)
  234 void
  235 ipfilterattach(count)
  236 int count;
  237 {
  238 # if 0
  239         if (iplattach() != 0)
  240                 printf("IP Filter failed to attach\n");
  241 # endif
  242 }
  243 #endif
  244 
  245 
  246 int iplattach()
  247 {
  248         int s;
  249 #if defined(NETBSD_PF) && (__NetBSD_Version__ >= 104200000)
  250         int error = 0;
  251 # if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 105110000)
  252         struct pfil_head *ph_inet;
  253 #  ifdef USE_INET6
  254         struct pfil_head *ph_inet6;
  255 #  endif
  256 # endif
  257 #endif
  258 
  259         SPL_NET(s);
  260         if ((fr_running > 0) || (fr_checkp == fr_check)) {
  261                 printf("IP Filter: already initialized\n");
  262                 SPL_X(s);
  263                 return EBUSY;
  264         }
  265 
  266         if (fr_initialise() < 0) {
  267                 SPL_X(s);
  268                 return EIO;
  269         }
  270 
  271 #ifdef NETBSD_PF
  272 # if (__NetBSD_Version__ >= 104200000)
  273 #  if __NetBSD_Version__ >= 105110000
  274         ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
  275 #   ifdef USE_INET6
  276         ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
  277 #   endif
  278         if (ph_inet == NULL
  279 #   ifdef USE_INET6
  280             && ph_inet6 == NULL
  281 #   endif
  282            ) {
  283                 printf("pfil_head_get failed\n");
  284                 return ENODEV;
  285         }
  286 
  287         if (ph_inet != NULL)
  288                 error = pfil_add_hook((void *)fr_check_wrapper, NULL,
  289                                       PFIL_IN|PFIL_OUT, ph_inet);
  290         else
  291                 error = 0;
  292 # else
  293         error = pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT,
  294                               &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
  295 # endif
  296         if (error) {
  297 #  ifdef USE_INET6
  298                 goto pfil_error;
  299 #  else
  300                 fr_deinitialise();
  301                 SPL_X(s);
  302                 return error;
  303 #  endif
  304         }
  305 # else
  306         pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT);
  307 # endif
  308 # ifdef USE_INET6
  309 #  if __NetBSD_Version__ >= 105110000
  310         if (ph_inet6 != NULL)
  311                 error = pfil_add_hook((void *)fr_check_wrapper6, NULL,
  312                                       PFIL_IN|PFIL_OUT, ph_inet6);
  313         else
  314                 error = 0;
  315         if (error) {
  316                 pfil_remove_hook((void *)fr_check_wrapper6, NULL,
  317                                  PFIL_IN|PFIL_OUT, ph_inet6);
  318 #  else
  319         error = pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT,
  320                               &inetsw[ip_protox[IPPROTO_IPV6]].pr_pfh);
  321         if (error) {
  322                 pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT,
  323                                  &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
  324 #  endif
  325 pfil_error:
  326                 fr_deinitialise();
  327                 SPL_X(s);
  328                 return error;
  329         }
  330 # endif
  331 #endif
  332 
  333         bzero((char *)frcache, sizeof(frcache));
  334         fr_savep = fr_checkp;
  335         fr_checkp = fr_check;
  336 
  337         if (fr_control_forwarding & 1)
  338                 ipforwarding = 1;
  339 
  340         SPL_X(s);
  341 
  342 #if (__NetBSD_Version__ >= 104010000)
  343         callout_init(&fr_slowtimer_ch);
  344         callout_reset(&fr_slowtimer_ch, (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT,
  345                      fr_slowtimer, NULL);
  346 #else
  347         timeout(fr_slowtimer, NULL, (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT);
  348 #endif
  349         return 0;
  350 }
  351 
  352 
  353 /*
  354  * Disable the filter by removing the hooks from the IP input/output
  355  * stream.
  356  */
  357 int ipldetach()
  358 {
  359         int s;
  360 #if defined(NETBSD_PF) && (__NetBSD_Version__ >= 104200000)
  361         int error = 0;
  362 # if __NetBSD_Version__ >= 105150000
  363         struct pfil_head *ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
  364 #  ifdef USE_INET6
  365         struct pfil_head *ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
  366 #  endif
  367 # endif
  368 #endif
  369 
  370         SPL_NET(s);
  371 
  372 #if (__NetBSD_Version__ >= 104010000)
  373         callout_stop(&fr_slowtimer_ch);
  374 #else
  375         untimeout(fr_slowtimer, NULL);
  376 #endif /* NetBSD */
  377 
  378         fr_checkp = fr_savep;
  379         (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE);
  380         (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE);
  381 
  382         if (fr_control_forwarding & 2)
  383                 ipforwarding = 0;
  384 
  385 #ifdef NETBSD_PF
  386 # if (__NetBSD_Version__ >= 104200000)
  387 #  if __NetBSD_Version__ >= 105110000
  388         if (ph_inet != NULL)
  389                 error = pfil_remove_hook((void *)fr_check_wrapper, NULL,
  390                                          PFIL_IN|PFIL_OUT, ph_inet);
  391         else
  392                 error = 0;
  393 #  else
  394         error = pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT,
  395                                  &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
  396 #  endif
  397         if (error)
  398                 return error;
  399 # else
  400         pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT);
  401 # endif
  402 # ifdef USE_INET6
  403 #  if __NetBSD_Version__ >= 105110000
  404         if (ph_inet6 != NULL)
  405                 error = pfil_remove_hook((void *)fr_check_wrapper6, NULL,
  406                                          PFIL_IN|PFIL_OUT, ph_inet6);
  407         else
  408                 error = 0;
  409 #  else
  410         error = pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT,
  411                                  &inetsw[ip_protox[IPPROTO_IPV6]].pr_pfh);
  412 #  endif
  413         if (error)
  414                 return error;
  415 # endif
  416 #endif
  417         fr_deinitialise();
  418 
  419         SPL_X(s);
  420         return 0;
  421 }
  422 
  423 
  424 /*
  425  * Filter ioctl interface.
  426  */
  427 int iplioctl(dev, cmd, data, mode
  428 #if (NetBSD >= 199511)
  429 , p)
  430 struct proc *p;
  431 #else
  432 )
  433 #endif
  434 dev_t dev;
  435 u_long cmd;
  436 caddr_t data;
  437 int mode;
  438 {
  439         int s;
  440         int error = 0, unit = 0, tmp;
  441         friostat_t fio;
  442 
  443         if ((securelevel >= 2) && (mode & FWRITE))
  444                 return EPERM;
  445 
  446         unit = GET_MINOR(dev);
  447         if ((IPL_LOGMAX < unit) || (unit < 0))
  448                 return ENXIO;
  449 
  450         if (fr_running <= 0) {
  451                 if (unit != IPL_LOGIPF)
  452                         return EIO;
  453                 if (cmd != SIOCIPFGETNEXT && cmd != SIOCIPFGET &&
  454                     cmd != SIOCIPFSET && cmd != SIOCFRENB &&
  455                     cmd != SIOCGETFS && cmd != SIOCGETFF)
  456                         return EIO;
  457         }
  458 
  459         SPL_NET(s);
  460 
  461         error = fr_ioctlswitch(unit, data, cmd, mode);
  462         if (error != -1) {
  463                 SPL_X(s);
  464                 return error;
  465         }
  466         error = 0;
  467 
  468         switch (cmd)
  469         {
  470         case FIONREAD :
  471 #ifdef IPFILTER_LOG
  472                 BCOPYOUT(&iplused[IPL_LOGIPF], (caddr_t)data,
  473                          sizeof(iplused[IPL_LOGIPF]));
  474 #endif
  475                 break;
  476         case SIOCFRENB :
  477                 if (!(mode & FWRITE))
  478                         error = EPERM;
  479                 else {
  480                         BCOPYIN(data, &tmp, sizeof(tmp));
  481                         if (tmp) {
  482                                 if (fr_running > 0)
  483                                         error = 0;
  484                                 else
  485                                         error = iplattach();
  486                                 if (error == 0)
  487                                         fr_running = 1;
  488                                 else
  489                                         (void) ipldetach();
  490                         } else {
  491                                 error = ipldetach();
  492                                 if (error == 0)
  493                                         fr_running = -1;
  494                         }
  495                 }
  496                 break;
  497         case SIOCIPFSET :
  498                 if (!(mode & FWRITE)) {
  499                         error = EPERM;
  500                         break;
  501                 }
  502         case SIOCIPFGETNEXT :
  503         case SIOCIPFGET :
  504                 error = fr_ipftune(cmd, data);
  505                 break;
  506         case SIOCSETFF :
  507                 if (!(mode & FWRITE))
  508                         error = EPERM;
  509                 else
  510                         BCOPYIN(data, &fr_flags, sizeof(fr_flags));
  511                 break;
  512         case SIOCGETFF :
  513                 BCOPYOUT(&fr_flags, data, sizeof(fr_flags));
  514                 break;
  515         case SIOCFUNCL :
  516                 error = fr_resolvefunc(data);
  517                 break;
  518         case SIOCINAFR :
  519         case SIOCRMAFR :
  520         case SIOCADAFR :
  521         case SIOCZRLST :
  522                 if (!(mode & FWRITE))
  523                         error = EPERM;
  524                 else
  525                         error = frrequest(unit, cmd, data, fr_active, 1);
  526                 break;
  527         case SIOCINIFR :
  528         case SIOCRMIFR :
  529         case SIOCADIFR :
  530                 if (!(mode & FWRITE))
  531                         error = EPERM;
  532                 else
  533                         error = frrequest(unit, cmd, data, 1 - fr_active, 1);
  534                 break;
  535         case SIOCSWAPA :
  536                 if (!(mode & FWRITE))
  537                         error = EPERM;
  538                 else {
  539                         bzero((char *)frcache, sizeof(frcache[0]) * 2);
  540                         *(u_int *)data = fr_active;
  541                         fr_active = 1 - fr_active;
  542                 }
  543                 break;
  544         case SIOCGETFS :
  545                 fr_getstat(&fio);
  546                 error = fr_outobj(data, &fio, IPFOBJ_IPFSTAT);
  547                 break;
  548         case SIOCFRZST :
  549                 if (!(mode & FWRITE))
  550                         error = EPERM;
  551                 else
  552                         error = fr_zerostats(data);
  553                 break;
  554         case SIOCIPFFL :
  555                 if (!(mode & FWRITE))
  556                         error = EPERM;
  557                 else {
  558                         BCOPYIN(data, &tmp, sizeof(tmp));
  559                         tmp = frflush(unit, 4, tmp);
  560                         BCOPYOUT(&tmp, data, sizeof(tmp));
  561                 }
  562                 break;
  563 #ifdef USE_INET6
  564         case SIOCIPFL6 :
  565                 if (!(mode & FWRITE))
  566                         error = EPERM;
  567                 else {
  568                         BCOPYIN(data, &tmp, sizeof(tmp));
  569                         tmp = frflush(unit, 6, tmp);
  570                         BCOPYOUT(&tmp, data, sizeof(tmp));
  571                 }
  572                 break;
  573 #endif
  574         case SIOCSTLCK :
  575                 BCOPYIN(data, &tmp, sizeof(tmp));
  576                 fr_state_lock = tmp;
  577                 fr_nat_lock = tmp;
  578                 fr_frag_lock = tmp;
  579                 fr_auth_lock = tmp;
  580                 break;
  581 #ifdef IPFILTER_LOG
  582         case SIOCIPFFB :
  583                 if (!(mode & FWRITE))
  584                         error = EPERM;
  585                 else
  586                         *(int *)data = ipflog_clear(unit);
  587                 break;
  588 #endif /* IPFILTER_LOG */
  589         case SIOCGFRST :
  590                 error = fr_outobj(data, fr_fragstats(), IPFOBJ_FRAGSTAT);
  591                 break;
  592         case SIOCFRSYN :
  593                 if (!(mode & FWRITE))
  594                         error = EPERM;
  595                 else {
  596                         frsync();
  597                 }
  598                 break;
  599         default :
  600                 error = EINVAL;
  601                 break;
  602         }
  603         SPL_X(s);
  604         return error;
  605 }
  606 
  607 
  608 void fr_forgetifp(ifp)
  609 void *ifp;
  610 {
  611         register frentry_t *f;
  612 
  613         WRITE_ENTER(&ipf_mutex);
  614         for (f = ipacct[0][fr_active]; (f != NULL); f = f->fr_next)
  615                 if (f->fr_ifa == ifp)
  616                         f->fr_ifa = (void *)-1;
  617         for (f = ipacct[1][fr_active]; (f != NULL); f = f->fr_next)
  618                 if (f->fr_ifa == ifp)
  619                         f->fr_ifa = (void *)-1;
  620         for (f = ipfilter[0][fr_active]; (f != NULL); f = f->fr_next)
  621                 if (f->fr_ifa == ifp)
  622                         f->fr_ifa = (void *)-1;
  623         for (f = ipfilter[1][fr_active]; (f != NULL); f = f->fr_next)
  624                 if (f->fr_ifa == ifp)
  625                         f->fr_ifa = (void *)-1;
  626 #ifdef USE_INET6
  627         for (f = ipacct6[0][fr_active]; (f != NULL); f = f->fr_next)
  628                 if (f->fr_ifa == ifp)
  629                         f->fr_ifa = (void *)-1;
  630         for (f = ipacct6[1][fr_active]; (f != NULL); f = f->fr_next)
  631                 if (f->fr_ifa == ifp)
  632                         f->fr_ifa = (void *)-1;
  633         for (f = ipfilter6[0][fr_active]; (f != NULL); f = f->fr_next)
  634                 if (f->fr_ifa == ifp)
  635                         f->fr_ifa = (void *)-1;
  636         for (f = ipfilter6[1][fr_active]; (f != NULL); f = f->fr_next)
  637                 if (f->fr_ifa == ifp)
  638                         f->fr_ifa = (void *)-1;
  639 #endif
  640         RWLOCK_EXIT(&ipf_mutex);
  641         fr_natsync(ifp);
  642 }
  643 
  644 
  645 /*
  646  * routines below for saving IP headers to buffer
  647  */
  648 int iplopen(dev, flags
  649 #if (NetBSD >= 199511)
  650 , devtype, p)
  651 int devtype;
  652 struct proc *p;
  653 #else
  654 )
  655 #endif
  656 dev_t dev;
  657 int flags;
  658 {
  659         u_int min = GET_MINOR(dev);
  660 
  661         if (IPL_LOGMAX < min)
  662                 min = ENXIO;
  663         else
  664                 min = 0;
  665         return min;
  666 }
  667 
  668 
  669 int iplclose(dev, flags
  670 #if (NetBSD >= 199511)
  671 , devtype, p)
  672 int devtype;
  673 struct proc *p;
  674 #else
  675 )
  676 #endif
  677 dev_t dev;
  678 int flags;
  679 {
  680         u_int   min = GET_MINOR(dev);
  681 
  682         if (IPL_LOGMAX < min)
  683                 min = ENXIO;
  684         else
  685                 min = 0;
  686         return min;
  687 }
  688 
  689 /*
  690  * iplread/ipllog
  691  * both of these must operate with at least splnet() lest they be
  692  * called during packet processing and cause an inconsistancy to appear in
  693  * the filter lists.
  694  */
  695 #if (BSD >= 199306)
  696 int iplread(dev, uio, ioflag)
  697 int ioflag;
  698 #else
  699 int iplread(dev, uio)
  700 #endif
  701 dev_t dev;
  702 register struct uio *uio;
  703 {
  704 #ifdef IPFILTER_LOG
  705         return ipflog_read(GET_MINOR(dev), uio);
  706 #else
  707         return ENXIO;
  708 #endif
  709 }
  710 
  711 
  712 /*
  713  * fr_send_reset - this could conceivably be a call to tcp_respond(), but that
  714  * requires a large amount of setting up and isn't any more efficient.
  715  */
  716 int fr_send_reset(fin)
  717 fr_info_t *fin;
  718 {
  719         struct tcphdr *tcp, *tcp2;
  720         int tlen = 0, hlen;
  721         struct mbuf *m;
  722 #ifdef USE_INET6
  723         ip6_t *ip6;
  724 #endif
  725         ip_t *ip;
  726 
  727         tcp = fin->fin_dp;
  728         if (tcp->th_flags & TH_RST)
  729                 return -1;              /* feedback loop */
  730 
  731 #ifndef IPFILTER_CKSUM
  732         if (fr_checkl4sum(fin) == -1)
  733                 return -1;
  734 #endif
  735 
  736         tlen = fin->fin_dlen - (TCP_OFF(tcp) << 2) +
  737                         ((tcp->th_flags & TH_SYN) ? 1 : 0) +
  738                         ((tcp->th_flags & TH_FIN) ? 1 : 0);
  739 
  740 #ifdef USE_INET6
  741         hlen = (fin->fin_v == 6) ? sizeof(ip6_t) : sizeof(ip_t);
  742 #else
  743         hlen = sizeof(ip_t);
  744 #endif
  745 #ifdef MGETHDR
  746         MGETHDR(m, M_DONTWAIT, MT_HEADER);
  747 #else
  748         MGET(m, M_DONTWAIT, MT_HEADER);
  749 #endif
  750         if (m == NULL)
  751                 return -1;
  752         if (sizeof(*tcp2) + hlen > MHLEN) {
  753                 MCLGET(m, M_DONTWAIT);
  754                 if (m == NULL)
  755                         return -1;
  756                 if ((m->m_flags & M_EXT) == 0) {
  757                         FREE_MB_T(m);
  758                         return -1;
  759                 }
  760         }
  761 
  762         m->m_len = sizeof(*tcp2) + hlen;
  763         m->m_data += max_linkhdr;
  764         m->m_pkthdr.len = m->m_len;
  765         m->m_pkthdr.rcvif = (struct ifnet *)0;
  766         ip = mtod(m, struct ip *);
  767 #ifdef USE_INET6
  768         ip6 = (ip6_t *)ip;
  769 #endif
  770         bzero((char *)ip, sizeof(*tcp2) + hlen);
  771         tcp2 = (struct tcphdr *)((char *)ip + hlen);
  772         tcp2->th_sport = tcp->th_dport;
  773         tcp2->th_dport = tcp->th_sport;
  774 
  775         if (tcp->th_flags & TH_ACK) {
  776                 tcp2->th_seq = tcp->th_ack;
  777                 tcp2->th_flags = TH_RST;
  778                 tcp2->th_ack = 0;
  779         } else {
  780                 tcp2->th_seq = 0;
  781                 tcp2->th_ack = ntohl(tcp->th_seq);
  782                 tcp2->th_ack += tlen;
  783                 tcp2->th_ack = htonl(tcp2->th_ack);
  784                 tcp2->th_flags = TH_RST|TH_ACK;
  785         }
  786         tcp2->th_x2 = 0;
  787         TCP_OFF_A(tcp2, sizeof(*tcp2) >> 2);
  788         tcp2->th_win = tcp->th_win;
  789         tcp2->th_sum = 0;
  790         tcp2->th_urp = 0;
  791 
  792 #ifdef USE_INET6
  793         if (fin->fin_v == 6) {
  794                 ip6->ip6_flow = 0;
  795                 ip6->ip6_plen = htons(sizeof(struct tcphdr));
  796                 ip6->ip6_nxt = IPPROTO_TCP;
  797                 ip6->ip6_hlim = 0;
  798                 ip6->ip6_src = fin->fin_dst6;
  799                 ip6->ip6_dst = fin->fin_src6;
  800                 tcp2->th_sum = in6_cksum(m, IPPROTO_TCP,
  801                                          sizeof(*ip6), sizeof(*tcp2));
  802                 return fr_send_ip(fin, m, &m);
  803         }
  804 #endif
  805         ip->ip_p = IPPROTO_TCP;
  806         ip->ip_len = htons(sizeof(struct tcphdr));
  807         ip->ip_src.s_addr = fin->fin_daddr;
  808         ip->ip_dst.s_addr = fin->fin_saddr;
  809         tcp2->th_sum = in_cksum(m, hlen + sizeof(*tcp2));
  810         ip->ip_len = hlen + sizeof(*tcp2);
  811         return fr_send_ip(fin, m, &m);
  812 }
  813 
  814 
  815 static int fr_send_ip(fin, m, mpp)
  816 fr_info_t *fin;
  817 mb_t *m, **mpp;
  818 {
  819         fr_info_t fnew;
  820         ip_t *ip, *oip;
  821         int hlen;
  822 
  823         ip = mtod(m, ip_t *);
  824         bzero((char *)&fnew, sizeof(fnew));
  825 
  826         IP_V_A(ip, fin->fin_v);
  827         switch (fin->fin_v)
  828         {
  829         case 4 :
  830                 fnew.fin_v = 4;
  831                 oip = fin->fin_ip;
  832                 IP_HL_A(ip, sizeof(*oip) >> 2);
  833                 ip->ip_tos = oip->ip_tos;
  834                 ip->ip_id = fr_nextipid(fin);
  835                 ip->ip_off = ip_mtudisc ? IP_DF : 0;
  836                 ip->ip_ttl = ip_defttl;
  837                 ip->ip_sum = 0;
  838                 hlen = sizeof(*oip);
  839                 break;
  840 #ifdef USE_INET6
  841         case 6 :
  842         {
  843                 ip6_t *ip6 = (ip6_t *)ip;
  844 
  845                 ip6->ip6_vfc = 0x60;
  846                 ip6->ip6_hlim = IPDEFTTL;
  847 
  848                 fnew.fin_v = 6;
  849                 hlen = sizeof(*ip6);
  850                 break;
  851         }
  852 #endif
  853         default :
  854                 return EINVAL;
  855         }
  856 #ifdef IPSEC
  857         m->m_pkthdr.rcvif = NULL;
  858 #endif
  859 
  860         fnew.fin_ifp = fin->fin_ifp;
  861         fnew.fin_flx = FI_NOCKSUM;
  862         fnew.fin_m = m;
  863         fnew.fin_ip = ip;
  864         fnew.fin_mp = mpp;
  865         fnew.fin_hlen = hlen;
  866         fnew.fin_dp = (char *)ip + hlen;
  867         (void) fr_makefrip(hlen, ip, &fnew);
  868 
  869         return fr_fastroute(m, mpp, &fnew, NULL);
  870 }
  871 
  872 
  873 int fr_send_icmp_err(type, fin, dst)
  874 int type;
  875 fr_info_t *fin;
  876 int dst;
  877 {
  878         int err, hlen, xtra, iclen, ohlen, avail, code;
  879         struct in_addr dst4;
  880         struct icmp *icmp;
  881         struct mbuf *m;
  882         void *ifp;
  883 #ifdef USE_INET6
  884         ip6_t *ip6, *ip62;
  885         struct in6_addr dst6;
  886 #endif
  887         ip_t *ip, *ip2;
  888 
  889         if ((type < 0) || (type > ICMP_MAXTYPE))
  890                 return -1;
  891 
  892         code = fin->fin_icode;
  893 #ifdef USE_INET6
  894         if ((code < 0) || (code > sizeof(icmptoicmp6unreach)/sizeof(int)))
  895                 return -1;
  896 #endif
  897 
  898 #ifndef IPFILTER_CKSUM
  899         if (fr_checkl4sum(fin) == -1)
  900                 return -1;
  901 #endif
  902 #ifdef MGETHDR
  903         MGETHDR(m, M_DONTWAIT, MT_HEADER);
  904 #else
  905         MGET(m, M_DONTWAIT, MT_HEADER);
  906 #endif
  907         if (m == NULL)
  908                 return -1;
  909         avail = MHLEN;
  910 
  911 
  912         xtra = 0;
  913         hlen = 0;
  914         ohlen = 0;
  915         ifp = fin->fin_ifp;
  916         if (fin->fin_v == 4) {
  917                 if ((fin->fin_p == IPPROTO_ICMP) &&
  918                     !(fin->fin_flx & FI_SHORT))
  919                         switch (ntohs(fin->fin_data[0]) >> 8)
  920                         {
  921                         case ICMP_ECHO :
  922                         case ICMP_TSTAMP :
  923                         case ICMP_IREQ :
  924                         case ICMP_MASKREQ :
  925                                 break;
  926                         default :
  927                                 return 0;
  928                         }
  929 
  930                 if (dst == 0) {
  931                         if (fr_ifpaddr(4, FRI_NORMAL, ifp,
  932                                        &dst4, NULL) == -1) {
  933                                 FREE_MB_T(m);
  934                                 return -1;
  935                         }
  936                 } else
  937                         dst4.s_addr = fin->fin_daddr;
  938 
  939                 hlen = sizeof(ip_t);
  940                 ohlen = fin->fin_hlen;
  941                 if (fin->fin_hlen < fin->fin_plen)
  942                         xtra = MIN(fin->fin_dlen, 8);
  943                 else
  944                         xtra = 0;
  945         }
  946 
  947 #ifdef USE_INET6
  948         else if (fin->fin_v == 6) {
  949                 hlen = sizeof(ip6_t);
  950                 ohlen = sizeof(ip6_t);
  951                 type = icmptoicmp6types[type];
  952                 if (type == ICMP6_DST_UNREACH)
  953                         code = icmptoicmp6unreach[code];
  954 
  955                 if (hlen + sizeof(*icmp) + max_linkhdr +
  956                     fin->fin_plen > avail) {
  957                         MCLGET(m, M_DONTWAIT);
  958                         if (m == NULL)
  959                                 return -1;
  960                         if ((m->m_flags & M_EXT) == 0) {
  961                                 FREE_MB_T(m);
  962                                 return -1;
  963                         }
  964                         avail = MCLBYTES;
  965                 }
  966                 xtra = MIN(fin->fin_plen,
  967                            avail - hlen - sizeof(*icmp) - max_linkhdr);
  968                 if (dst == 0) {
  969                         if (fr_ifpaddr(6, FRI_NORMAL, ifp,
  970                                        (struct in_addr *)&dst6, NULL) == -1) {
  971                                 FREE_MB_T(m);
  972                                 return -1;
  973                         }
  974                 } else
  975                         dst6 = fin->fin_dst6;
  976         }
  977 #endif
  978         else
  979                 return -1;
  980 
  981         iclen = hlen + sizeof(*icmp) + xtra;
  982         avail -= (max_linkhdr + iclen);
  983         m->m_data += max_linkhdr;
  984         m->m_pkthdr.rcvif = (struct ifnet *)0;
  985         if (xtra > avail)
  986                 xtra = avail;
  987         iclen += xtra;
  988         m->m_pkthdr.len = iclen;
  989         if (avail < 0) {
  990                 FREE_MB_T(m);
  991                 return -1;
  992         }
  993         m->m_len = iclen;
  994         ip = mtod(m, ip_t *);
  995         icmp = (struct icmp *)((char *)ip + hlen);
  996         ip2 = (ip_t *)&icmp->icmp_ip;
  997 
  998         icmp->icmp_type = type;
  999         icmp->icmp_code = fin->fin_icode;
 1000         icmp->icmp_cksum = 0;
 1001 #ifdef icmp_nextmtu
 1002         if (type == ICMP_UNREACH &&
 1003             fin->fin_icode == ICMP_UNREACH_NEEDFRAG && ifp)
 1004                 icmp->icmp_nextmtu = htons(((struct ifnet *)ifp)->if_mtu);
 1005 #endif
 1006 
 1007         bcopy((char *)fin->fin_ip, (char *)ip2, ohlen);
 1008 
 1009 #if defined(M_CSUM_IPv4)
 1010         /*
 1011          * Clear any in-bound checksum flags for this packet.
 1012          */
 1013         m->m_pkthdr.csuminfo = 0;
 1014 #endif /* __NetBSD__ && M_CSUM_IPv4 */
 1015 
 1016 #ifdef USE_INET6
 1017         ip6 = (ip6_t *)ip;
 1018         if (fin->fin_v == 6) {
 1019                 ip62 = (ip6_t *)ip2;
 1020 
 1021                 ip6->ip6_flow = 0;
 1022                 ip6->ip6_plen = htons(iclen - hlen);
 1023                 ip6->ip6_nxt = IPPROTO_ICMPV6;
 1024                 ip6->ip6_hlim = 0;
 1025                 ip6->ip6_src = dst6;
 1026                 ip6->ip6_dst = fin->fin_src6;
 1027                 if (xtra > 0)
 1028                         bcopy((char *)fin->fin_ip + ohlen,
 1029                               (char *)&icmp->icmp_ip + ohlen, xtra);
 1030                 icmp->icmp_cksum = in6_cksum(m, IPPROTO_ICMPV6,
 1031                                              sizeof(*ip6), iclen - hlen);
 1032         } else
 1033 #endif
 1034         {
 1035                 ip->ip_p = IPPROTO_ICMP;
 1036                 ip->ip_src.s_addr = dst4.s_addr;
 1037                 ip->ip_dst.s_addr = fin->fin_saddr;
 1038 
 1039                 if (xtra > 0)
 1040                         bcopy((char *)fin->fin_ip + ohlen,
 1041                               (char *)&icmp->icmp_ip + ohlen, xtra);
 1042                 icmp->icmp_cksum = ipf_cksum((u_short *)icmp,
 1043                                              sizeof(*icmp) + 8);
 1044                 ip->ip_len = iclen;
 1045                 ip->ip_p = IPPROTO_ICMP;
 1046         }
 1047         err = fr_send_ip(fin, m, &m);
 1048         return err;
 1049 }
 1050 
 1051 
 1052 int fr_fastroute(m0, mpp, fin, fdp)
 1053 mb_t *m0, **mpp;
 1054 fr_info_t *fin;
 1055 frdest_t *fdp;
 1056 {
 1057         register struct ip *ip, *mhip;
 1058         register struct mbuf *m = m0;
 1059         register struct route *ro;
 1060         int len, off, error = 0, hlen, code;
 1061         struct ifnet *ifp, *sifp;
 1062         struct sockaddr_in *dst;
 1063         struct route iproute;
 1064         u_short ip_off;
 1065         frentry_t *fr;
 1066 
 1067 #ifdef USE_INET6
 1068         if (fin->fin_v == 6) {
 1069                 error = ipfr_fastroute6(m0, mpp, fin, fdp);
 1070                 if ((error != 0) && (*mpp != NULL)) {
 1071                         FREE_MB_T(*mpp);
 1072                         *mpp = NULL;
 1073                 }
 1074                 return error;
 1075         }
 1076 #endif
 1077 
 1078         hlen = fin->fin_hlen;
 1079         ip = mtod(m0, struct ip *);
 1080 
 1081 #if defined(M_CSUM_IPv4)
 1082         /*
 1083          * Clear any in-bound checksum flags for this packet.
 1084          */
 1085         m0->m_pkthdr.csuminfo = 0;
 1086 #endif /* __NetBSD__ && M_CSUM_IPv4 */
 1087 
 1088         /*
 1089          * Route packet.
 1090          */
 1091         ro = &iproute;
 1092         bzero((caddr_t)ro, sizeof (*ro));
 1093         dst = (struct sockaddr_in *)&ro->ro_dst;
 1094         dst->sin_family = AF_INET;
 1095         dst->sin_addr = ip->ip_dst;
 1096 
 1097         fr = fin->fin_fr;
 1098         if (fdp != NULL)
 1099                 ifp = fdp->fd_ifp;
 1100         else
 1101                 ifp = fin->fin_ifp;
 1102 
 1103         if ((ifp == NULL) && (!fr || !(fr->fr_flags & FR_FASTROUTE))) {
 1104                 error = -2;
 1105                 goto bad;
 1106         }
 1107 
 1108         /*
 1109          * In case we're here due to "to <if>" being used with "keep state",
 1110          * check that we're going in the correct direction.
 1111          */
 1112         if ((fr != NULL) && (fin->fin_rev != 0)) {
 1113                 if ((ifp != NULL) && (fdp == &fr->fr_tif))
 1114                         return 0;
 1115         } else if (fdp != NULL) {
 1116                 if (fdp->fd_ip.s_addr != 0)
 1117                         dst->sin_addr = fdp->fd_ip;
 1118         }
 1119 
 1120         dst->sin_len = sizeof(*dst);
 1121         rtalloc(ro);
 1122 
 1123         if ((ifp == NULL) && (ro->ro_rt != NULL))
 1124                 ifp = ro->ro_rt->rt_ifp;
 1125 
 1126         if ((ro->ro_rt == NULL) || (ifp == NULL)) {
 1127                 if (in_localaddr(ip->ip_dst))
 1128                         error = EHOSTUNREACH;
 1129                 else
 1130                         error = ENETUNREACH;
 1131                 goto bad;
 1132         }
 1133         if (ro->ro_rt->rt_flags & RTF_GATEWAY)
 1134                 dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway;
 1135         if (ro->ro_rt)
 1136                 ro->ro_rt->rt_use++;
 1137 
 1138         /*
 1139          * For input packets which are being "fastrouted", they won't
 1140          * go back through output filtering and miss their chance to get
 1141          * NAT'd and counted.
 1142          */
 1143         if (fin->fin_out == 0) {
 1144                 sifp = fin->fin_ifp;
 1145                 fin->fin_ifp = ifp;
 1146                 fin->fin_out = 1;
 1147                 (void) fr_acctpkt(fin, NULL);
 1148                 fin->fin_fr = NULL;
 1149                 if (!fr || !(fr->fr_flags & FR_RETMASK)) {
 1150                         u_32_t pass;
 1151 
 1152                         (void) fr_checkstate(fin, &pass);
 1153                 }
 1154 
 1155                 switch (fr_checknatout(fin, NULL))
 1156                 {
 1157                 case 0 :
 1158                         break;
 1159                 case 1 :
 1160                         ip->ip_sum = 0;
 1161                         break;
 1162                 case -1 :
 1163                         error = -1;
 1164                         goto done;
 1165                         break;
 1166                 }
 1167 
 1168                 fin->fin_ifp = sifp;
 1169                 fin->fin_out = 0;
 1170         } else
 1171                 ip->ip_sum = 0;
 1172         /*
 1173          * If small enough for interface, can just send directly.
 1174          */
 1175         if (ip->ip_len <= ifp->if_mtu) {
 1176                 ip->ip_len = htons(ip->ip_len);
 1177                 ip->ip_off = htons(ip->ip_off);
 1178 #if defined(M_CSUM_IPv4)
 1179                 if (ifp->if_capabilities & IFCAP_CSUM_IPv4)
 1180                         m->m_pkthdr.csuminfo |= M_CSUM_IPv4;
 1181                 else if (ip->ip_sum == 0)
 1182                         ip->ip_sum = in_cksum(m, hlen);
 1183 #else
 1184                 if (!ip->ip_sum)
 1185                         ip->ip_sum = in_cksum(m, hlen);
 1186 #endif /* M_CSUM_IPv4 */
 1187                 error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst,
 1188                                           ro->ro_rt);
 1189                 goto done;
 1190         }
 1191         /*
 1192          * Too large for interface; fragment if possible.
 1193          * Must be able to put at least 8 bytes per fragment.
 1194          */
 1195         ip_off = ip->ip_off;
 1196         if (ip_off & IP_DF) {
 1197                 error = EMSGSIZE;
 1198                 goto bad;
 1199         }
 1200         len = (ifp->if_mtu - hlen) &~ 7;
 1201         if (len < 8) {
 1202                 error = EMSGSIZE;
 1203                 goto bad;
 1204         }
 1205 
 1206     {
 1207         int mhlen, firstlen = len;
 1208         struct mbuf **mnext = &m->m_act;
 1209 
 1210         /*
 1211          * Loop through length of segment after first fragment,
 1212          * make new header and copy data of each part and link onto chain.
 1213          */
 1214         m0 = m;
 1215         mhlen = sizeof (struct ip);
 1216         for (off = hlen + len; off < ip->ip_len; off += len) {
 1217 #ifdef MGETHDR
 1218                 MGETHDR(m, M_DONTWAIT, MT_HEADER);
 1219 #else
 1220                 MGET(m, M_DONTWAIT, MT_HEADER);
 1221 #endif
 1222                 if (m == 0) {
 1223                         m = m0;
 1224                         error = ENOBUFS;
 1225                         goto bad;
 1226                 }
 1227                 m->m_data += max_linkhdr;
 1228                 mhip = mtod(m, struct ip *);
 1229                 bcopy((char *)ip, (char *)mhip, sizeof(*ip));
 1230                 if (hlen > sizeof (struct ip)) {
 1231                         mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
 1232                         IP_HL_A(mhip, mhlen >> 2);
 1233                 }
 1234                 m->m_len = mhlen;
 1235                 mhip->ip_off = ((off - hlen) >> 3) + ip_off;
 1236                 if (off + len >= ip->ip_len)
 1237                         len = ip->ip_len - off;
 1238                 else
 1239                         mhip->ip_off |= IP_MF;
 1240                 mhip->ip_len = htons((u_short)(len + mhlen));
 1241                 m->m_next = m_copy(m0, off, len);
 1242                 if (m->m_next == 0) {
 1243                         error = ENOBUFS;        /* ??? */
 1244                         goto sendorfree;
 1245                 }
 1246                 m->m_pkthdr.len = mhlen + len;
 1247                 m->m_pkthdr.rcvif = NULL;
 1248                 mhip->ip_off = htons((u_short)mhip->ip_off);
 1249                 mhip->ip_sum = 0;
 1250                 mhip->ip_sum = in_cksum(m, mhlen);
 1251                 *mnext = m;
 1252                 mnext = &m->m_act;
 1253         }
 1254         /*
 1255          * Update first fragment by trimming what's been copied out
 1256          * and updating header, then send each fragment (in order).
 1257          */
 1258         m_adj(m0, hlen + firstlen - ip->ip_len);
 1259         ip->ip_len = htons((u_short)(hlen + firstlen));
 1260         ip->ip_off = htons((u_short)IP_MF);
 1261         ip->ip_sum = 0;
 1262         ip->ip_sum = in_cksum(m0, hlen);
 1263 sendorfree:
 1264         for (m = m0; m; m = m0) {
 1265                 m0 = m->m_act;
 1266                 m->m_act = 0;
 1267                 if (error == 0)
 1268                         error = (*ifp->if_output)(ifp, m,
 1269                             (struct sockaddr *)dst, ro->ro_rt);
 1270                 else
 1271                         FREE_MB_T(m);
 1272         }
 1273     }   
 1274 done:
 1275         if (!error)
 1276                 fr_frouteok[0]++;
 1277         else
 1278                 fr_frouteok[1]++;
 1279 
 1280         if (ro->ro_rt) {
 1281                 RTFREE(ro->ro_rt);
 1282         }
 1283         *mpp = NULL;
 1284         return error;
 1285 bad:
 1286         if (error == EMSGSIZE) {
 1287                 sifp = fin->fin_ifp;
 1288                 code = fin->fin_icode;
 1289                 fin->fin_icode = ICMP_UNREACH_NEEDFRAG;
 1290                 fin->fin_ifp = ifp;
 1291                 (void) fr_send_icmp_err(ICMP_UNREACH, fin, 1);
 1292                 fin->fin_ifp = sifp;
 1293                 fin->fin_icode = code;
 1294         }
 1295         FREE_MB_T(m);
 1296         goto done;
 1297 }
 1298 
 1299 
 1300 #if defined(USE_INET6)
 1301 /*
 1302  * This is the IPv6 specific fastroute code.  It doesn't clean up the mbuf's
 1303  * or ensure that it is an IPv6 packet that is being forwarded, those are
 1304  * expected to be done by the called (ipfr_fastroute).
 1305  */
 1306 static int ipfr_fastroute6(m0, mpp, fin, fdp)
 1307 struct mbuf *m0, **mpp;
 1308 fr_info_t *fin;
 1309 frdest_t *fdp;
 1310 {
 1311         struct route_in6 ip6route;
 1312         struct sockaddr_in6 *dst6;
 1313         struct route_in6 *ro;
 1314         struct ifnet *ifp;
 1315         frentry_t *fr;
 1316         u_long mtu;
 1317         int error;
 1318 
 1319         ro = &ip6route;
 1320         fr = fin->fin_fr;
 1321         bzero((caddr_t)ro, sizeof(*ro));
 1322         dst6 = (struct sockaddr_in6 *)&ro->ro_dst;
 1323         dst6->sin6_family = AF_INET6;
 1324         dst6->sin6_len = sizeof(struct sockaddr_in6);
 1325         dst6->sin6_addr = fin->fin_fi.fi_dst.in6;
 1326 
 1327         if (fdp != NULL)
 1328                 ifp = fdp->fd_ifp;
 1329         else
 1330                 ifp = fin->fin_ifp;
 1331 
 1332         if ((fr != NULL) && (fin->fin_rev != 0)) {
 1333                 if ((ifp != NULL) && (fdp == &fr->fr_tif))
 1334                         return 0;
 1335         } else if (fdp != NULL) {
 1336                 if (IP6_NOTZERO(&fdp->fd_ip6))
 1337                         dst6->sin6_addr = fdp->fd_ip6.in6;
 1338         }
 1339 
 1340         rtalloc((struct route *)ro);
 1341 
 1342         if ((ifp == NULL) && (ro->ro_rt != NULL))
 1343                 ifp = ro->ro_rt->rt_ifp;
 1344 
 1345         if ((ro->ro_rt == NULL) || (ifp == NULL)) {
 1346                 error = EHOSTUNREACH;
 1347                 goto bad;
 1348         }
 1349 
 1350         /* KAME */
 1351         if (IN6_IS_ADDR_LINKLOCAL(&dst6->sin6_addr))
 1352                 dst6->sin6_addr.s6_addr16[1] = htons(ifp->if_index);
 1353 
 1354         {
 1355 #if (__NetBSD_Version__ >= 106010000)
 1356                 struct in6_addr finaldst = fin->fin_dst6;
 1357                 int frag;
 1358 #endif
 1359                 if (ro->ro_rt->rt_flags & RTF_GATEWAY)
 1360                         dst6 = (struct sockaddr_in6 *)ro->ro_rt->rt_gateway;
 1361                 ro->ro_rt->rt_use++;
 1362 
 1363 #if (__NetBSD_Version__ <= 106009999)
 1364                 mtu = nd_ifinfo[ifp->if_index].linkmtu;
 1365 #else
 1366                 /* Determine path MTU. */
 1367                 error = ip6_getpmtu(ro, ro, ifp, &finaldst, &mtu, &frag);
 1368 #endif
 1369                 if ((error == 0) && (m0->m_pkthdr.len <= mtu)) {
 1370                         *mpp = NULL;
 1371                         error = nd6_output(ifp, fin->fin_ifp, m0,
 1372                                                    dst6, ro->ro_rt);
 1373                 } else {
 1374                         error = EMSGSIZE;
 1375                 }
 1376         }
 1377 bad:
 1378         if (ro->ro_rt != NULL) {
 1379                 RTFREE(ro->ro_rt);
 1380         }
 1381         return error;
 1382 }
 1383 #endif
 1384 
 1385 
 1386 int fr_verifysrc(fin)
 1387 fr_info_t *fin;
 1388 {
 1389         struct sockaddr_in *dst;
 1390         struct route iproute;
 1391 
 1392         bzero((char *)&iproute, sizeof(iproute));
 1393         dst = (struct sockaddr_in *)&iproute.ro_dst;
 1394         dst->sin_len = sizeof(*dst);
 1395         dst->sin_family = AF_INET;
 1396         dst->sin_addr = fin->fin_src;
 1397         rtalloc(&iproute);
 1398         if (iproute.ro_rt == NULL)
 1399                 return 0;
 1400         return (fin->fin_ifp == iproute.ro_rt->rt_ifp);
 1401 }
 1402 
 1403 
 1404 /*
 1405  * return the first IP Address associated with an interface
 1406  */
 1407 int fr_ifpaddr(v, atype, ifptr, inp, inpmask)
 1408 int v, atype;
 1409 void *ifptr;
 1410 struct in_addr *inp, *inpmask;
 1411 {
 1412 #ifdef USE_INET6
 1413         struct in6_addr *inp6 = NULL;
 1414 #endif
 1415         struct sockaddr *sock, *mask;
 1416         struct sockaddr_in *sin;
 1417         struct ifaddr *ifa;
 1418         struct ifnet *ifp;
 1419 
 1420         if ((ifptr == NULL) || (ifptr == (void *)-1))
 1421                 return -1;
 1422 
 1423         ifp = ifptr;
 1424         mask = NULL;
 1425 
 1426         if (v == 4)
 1427                 inp->s_addr = 0;
 1428 #ifdef USE_INET6
 1429         else if (v == 6)
 1430                 bzero((char *)inp, sizeof(struct in6_addr));
 1431 #endif
 1432 
 1433         ifa = ifp->if_addrlist.tqh_first;
 1434         sock = ifa->ifa_addr;
 1435         while (sock != NULL && ifa != NULL) {
 1436                 sin = (struct sockaddr_in *)sock;
 1437                 if ((v == 4) && (sin->sin_family == AF_INET))
 1438                         break;
 1439 #ifdef USE_INET6
 1440                 if ((v == 6) && (sin->sin_family == AF_INET6)) {
 1441                         inp6 = &((struct sockaddr_in6 *)sin)->sin6_addr;
 1442                         if (!IN6_IS_ADDR_LINKLOCAL(inp6) &&
 1443                             !IN6_IS_ADDR_LOOPBACK(inp6))
 1444                                 break;
 1445                 }
 1446 #endif
 1447                 ifa = ifa->ifa_list.tqe_next;
 1448                 if (ifa != NULL)
 1449                         sock = ifa->ifa_addr;
 1450         }
 1451         if (ifa == NULL || sock == NULL)
 1452                 return -1;
 1453 
 1454         mask = ifa->ifa_netmask;
 1455         if (atype == FRI_BROADCAST)
 1456                 sock = ifa->ifa_broadaddr;
 1457         else if (atype == FRI_PEERADDR)
 1458                 sock = ifa->ifa_dstaddr;
 1459 
 1460 #ifdef USE_INET6
 1461         if (v == 6)
 1462                 return fr_ifpfillv6addr(atype, (struct sockaddr_in6 *)sock,
 1463                                         (struct sockaddr_in6 *)mask,
 1464                                         inp, inpmask);
 1465 #endif
 1466         return fr_ifpfillv4addr(atype, (struct sockaddr_in *)sock,
 1467                                 (struct sockaddr_in *)mask, inp, inpmask);
 1468 }
 1469 
 1470 
 1471 u_32_t fr_newisn(fin)
 1472 fr_info_t *fin;
 1473 {
 1474         u_32_t newiss;
 1475 #if __NetBSD_Version >= 105190000       /* 1.5T */
 1476         size_t asz;
 1477         
 1478 
 1479         if (fin->fin_v == 4)
 1480                 asz = sizeof(struct in_addr);
 1481         else if (fin->fin_v == 6)
 1482                 asz = sizeof(fin->fin_src);
 1483         newiss = tcp_new_iss1((void *)&fin->fin_src, (void *)&fin->fin_dst,
 1484                               fin->fin_sport, fin->fin_dport, asz);
 1485 #else
 1486         static int iss_seq_off = 0;
 1487         u_char hash[16];
 1488         MD5_CTX ctx;
 1489 
 1490         /*
 1491          * Compute the base value of the ISS.  It is a hash
 1492          * of (saddr, sport, daddr, dport, secret).
 1493          */
 1494         MD5Init(&ctx);
 1495 
 1496         MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src,
 1497                   sizeof(fin->fin_fi.fi_src));
 1498         MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst,
 1499                   sizeof(fin->fin_fi.fi_dst));
 1500         MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat));
 1501 
 1502         MD5Update(&ctx, ipf_iss_secret, sizeof(ipf_iss_secret));
 1503 
 1504         MD5Final(hash, &ctx);
 1505 
 1506         memcpy(&newiss, hash, sizeof(newiss));
 1507 
 1508         /*
 1509          * Now increment our "timer", and add it in to
 1510          * the computed value.
 1511          *
 1512          * XXX Use `addin'?
 1513          * XXX TCP_ISSINCR too large to use?
 1514          */
 1515         iss_seq_off += 0x00010000;
 1516         newiss += iss_seq_off;
 1517 #endif
 1518         return newiss;
 1519 }
 1520 
 1521 
 1522 /* ------------------------------------------------------------------------ */
 1523 /* Function:    fr_nextipid                                                 */
 1524 /* Returns:     int - 0 == success, -1 == error (packet should be droppped) */
 1525 /* Parameters:  fin(I) - pointer to packet information                      */
 1526 /*                                                                          */
 1527 /* Returns the next IPv4 ID to use for this packet.                         */
 1528 /* ------------------------------------------------------------------------ */
 1529 u_short fr_nextipid(fin)
 1530 fr_info_t *fin;
 1531 {
 1532         static u_short ipid = 0;
 1533         u_short id;
 1534 
 1535         MUTEX_ENTER(&ipf_rw);
 1536         id = ipid++;
 1537         MUTEX_EXIT(&ipf_rw);
 1538 
 1539         return id;
 1540 }
 1541 
 1542 
 1543 INLINE void fr_checkv4sum(fin)
 1544 fr_info_t *fin;
 1545 {
 1546 #ifdef M_CSUM_TCP_UDP_BAD
 1547         int manual, pflag, cflags, active;
 1548         mb_t *m;
 1549 
 1550         if ((fin->fin_flx & FI_NOCKSUM) != 0)
 1551                 return;
 1552 
 1553         manual = 0;
 1554         m = fin->fin_m;
 1555         if (m == NULL) {
 1556                 manual = 1;
 1557                 goto skipauto;
 1558         }
 1559 
 1560         switch (fin->fin_p)
 1561         {
 1562         case IPPROTO_UDP :
 1563                 pflag = M_CSUM_UDPv4;
 1564                 break;
 1565         case IPPROTO_TCP :
 1566                 pflag = M_CSUM_TCPv4;
 1567                 break;
 1568         default :
 1569                 pflag = 0;
 1570                 manual = 1;
 1571                 break;
 1572         }
 1573 
 1574         active = ((struct ifnet *)fin->fin_ifp)->if_csum_flags_rx & pflag;
 1575         active |= M_CSUM_TCP_UDP_BAD | M_CSUM_DATA;
 1576         cflags = m->m_pkthdr.csum_flags & active;
 1577 
 1578         if (pflag != 0) {
 1579                 if (cflags == (pflag | M_CSUM_TCP_UDP_BAD)) {
 1580                         fin->fin_flx |= FI_BAD;
 1581                 } else if (cflags == (pflag | M_CSUM_DATA)) {
 1582                         if ((m->m_pkthdr.csum_data ^ 0xffff) != 0)
 1583                                 fin->fin_flx |= FI_BAD;
 1584                 } else if (cflags == pflag) {
 1585                         ;
 1586                 } else {
 1587                         manual = 1;
 1588                 }
 1589         }
 1590 skipauto:
 1591 # ifdef IPFILTER_CKSUM
 1592         if (manual != 0)
 1593                 if (fr_checkl4sum(fin) == -1)
 1594                         fin->fin_flx |= FI_BAD;
 1595 # else
 1596         ;
 1597 # endif
 1598 #else
 1599 # ifdef IPFILTER_CKSUM
 1600         if (fr_checkl4sum(fin) == -1)
 1601                 fin->fin_flx |= FI_BAD;
 1602 # endif
 1603 #endif
 1604 }
 1605 
 1606 
 1607 #ifdef USE_INET6
 1608 INLINE void fr_checkv6sum(fin)
 1609 fr_info_t *fin;
 1610 {
 1611 # ifdef M_CSUM_TCP_UDP_BAD
 1612         int manual, pflag, cflags, active;
 1613         mb_t *m;
 1614 
 1615         if ((fin->fin_flx & FI_NOCKSUM) != 0)
 1616                 return;
 1617 
 1618         manual = 0;
 1619         m = fin->fin_m;
 1620 
 1621         switch (fin->fin_p)
 1622         {
 1623         case IPPROTO_UDP :
 1624                 pflag = M_CSUM_UDPv6;
 1625                 break;
 1626         case IPPROTO_TCP :
 1627                 pflag = M_CSUM_TCPv6;
 1628                 break;
 1629         default :
 1630                 pflag = 0;
 1631                 manual = 1;
 1632                 break;
 1633         }
 1634 
 1635         active = ((struct ifnet *)fin->fin_ifp)->if_csum_flags_rx & pflag;
 1636         active |= M_CSUM_TCP_UDP_BAD | M_CSUM_DATA;
 1637         cflags = m->m_pkthdr.csum_flags & active;
 1638 
 1639         if (pflag != 0) {
 1640                 if (cflags == (pflag | M_CSUM_TCP_UDP_BAD)) {
 1641                         fin->fin_flx |= FI_BAD;
 1642                 } else if (cflags == (pflag | M_CSUM_DATA)) {
 1643                         if ((m->m_pkthdr.csum_data ^ 0xffff) != 0)
 1644                                 fin->fin_flx |= FI_BAD;
 1645                 } else if (cflags == pflag) {
 1646                         ;
 1647                 } else {
 1648                         manual = 1;
 1649                 }
 1650         }
 1651 #  ifdef IPFILTER_CKSUM
 1652         if (manual != 0)
 1653                 if (fr_checkl4sum(fin) == -1)
 1654                         fin->fin_flx |= FI_BAD;
 1655 #  endif
 1656 # else
 1657 #  ifdef IPFILTER_CKSUM
 1658         if (fr_checkl4sum(fin) == -1)
 1659                 fin->fin_flx |= FI_BAD;
 1660 #  endif
 1661 # endif
 1662 }
 1663 #endif /* USE_INET6 */
 1664 
 1665 
 1666 size_t mbufchainlen(m0)
 1667 struct mbuf *m0;
 1668 {
 1669         size_t len;
 1670 
 1671         if ((m0->m_flags & M_PKTHDR) != 0) {
 1672                 len = m0->m_pkthdr.len;
 1673         } else {
 1674                 struct mbuf *m;
 1675 
 1676                 for (m = m0, len = 0; m != NULL; m = m->m_next)
 1677                         len += m->m_len;
 1678         }
 1679         return len;
 1680 }

Cache object: 2c7af8930dca01f5c2403f11e837ff57


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