]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sys/contrib/ipfilter/netinet/ip_fil_freebsd.c
MFC r341377, r341388 (fixup):
[FreeBSD/stable/10.git] / sys / contrib / ipfilter / netinet / ip_fil_freebsd.c
1 /*      $FreeBSD$       */
2
3 /*
4  * Copyright (C) 2012 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$";
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 #if defined(__FreeBSD_version) && (__FreeBSD_version >= 400000) && \
20     !defined(KLD_MODULE) && !defined(IPFILTER_LKM)
21 # include "opt_inet6.h"
22 #endif
23 #if defined(__FreeBSD_version) && (__FreeBSD_version >= 440000) && \
24     !defined(KLD_MODULE) && !defined(IPFILTER_LKM)
25 # include "opt_random_ip_id.h"
26 #endif
27 #include <sys/param.h>
28 #include <sys/errno.h>
29 #include <sys/types.h>
30 #include <sys/file.h>
31 # include <sys/fcntl.h>
32 # include <sys/filio.h>
33 #include <sys/time.h>
34 #include <sys/systm.h>
35 # include <sys/dirent.h>
36 #if defined(__FreeBSD_version) && (__FreeBSD_version >= 800000)
37 #include <sys/jail.h>
38 #endif
39 # include <sys/mbuf.h>
40 # include <sys/sockopt.h>
41 #if !defined(__hpux)
42 # include <sys/mbuf.h>
43 #endif
44 #include <sys/socket.h>
45 # include <sys/selinfo.h>
46 # include <netinet/tcp_var.h>
47
48 #include <net/if.h>
49 # include <net/if_var.h>
50 #  include <net/netisr.h>
51 #include <net/route.h>
52 #include <netinet/in.h>
53 #include <netinet/in_var.h>
54 #include <netinet/in_systm.h>
55 #include <netinet/ip.h>
56 #include <netinet/ip_var.h>
57 #include <netinet/tcp.h>
58 #if defined(__FreeBSD_version) && (__FreeBSD_version >= 800000)
59 #include <net/vnet.h>
60 #else
61 #define CURVNET_SET(arg)
62 #define CURVNET_RESTORE()
63 #endif
64 #include <netinet/udp.h>
65 #include <netinet/tcpip.h>
66 #include <netinet/ip_icmp.h>
67 #include "netinet/ip_compat.h"
68 #ifdef USE_INET6
69 # include <netinet/icmp6.h>
70 #endif
71 #include "netinet/ip_fil.h"
72 #include "netinet/ip_nat.h"
73 #include "netinet/ip_frag.h"
74 #include "netinet/ip_state.h"
75 #include "netinet/ip_proxy.h"
76 #include "netinet/ip_auth.h"
77 #include "netinet/ip_sync.h"
78 #include "netinet/ip_lookup.h"
79 #include "netinet/ip_dstlist.h"
80 #ifdef  IPFILTER_SCAN
81 #include "netinet/ip_scan.h"
82 #endif
83 #include "netinet/ip_pool.h"
84 # include <sys/malloc.h>
85 #include <sys/kernel.h>
86 #ifdef CSUM_DATA_VALID
87 #include <machine/in_cksum.h>
88 #endif
89 extern  int     ip_optcopy __P((struct ip *, struct ip *));
90
91 # ifdef IPFILTER_M_IPFILTER
92 MALLOC_DEFINE(M_IPFILTER, "ipfilter", "IP Filter packet filter data structures");
93 # endif
94
95
96 static  u_short ipid = 0;
97 static  int     (*ipf_savep) __P((void *, ip_t *, int, void *, int, struct mbuf **));
98 static  int     ipf_send_ip __P((fr_info_t *, mb_t *));
99 static void     ipf_timer_func __P((void *arg));
100 int             ipf_locks_done = 0;
101
102 ipf_main_softc_t ipfmain;
103
104 # include <sys/conf.h>
105 # if defined(NETBSD_PF)
106 #  include <net/pfil.h>
107 # endif /* NETBSD_PF */
108 /*
109  * We provide the ipf_checkp name just to minimize changes later.
110  */
111 int (*ipf_checkp) __P((void *, ip_t *ip, int hlen, void *ifp, int out, mb_t **mp));
112
113
114 static eventhandler_tag ipf_arrivetag, ipf_departtag, ipf_clonetag;
115
116 static void ipf_ifevent(void *arg);
117
118 static void ipf_ifevent(arg)
119         void *arg;
120 {
121         ipf_sync(arg, NULL);
122 }
123
124
125
126 static int
127 ipf_check_wrapper(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir)
128 {
129         struct ip *ip = mtod(*mp, struct ip *);
130         int rv;
131
132         /*
133          * IPFilter expects evreything in network byte order
134          */
135 #if (__FreeBSD_version < 1000019)
136         ip->ip_len = htons(ip->ip_len);
137         ip->ip_off = htons(ip->ip_off);
138 #endif
139         rv = ipf_check(&ipfmain, ip, ip->ip_hl << 2, ifp, (dir == PFIL_OUT),
140                        mp);
141 #if (__FreeBSD_version < 1000019)
142         if ((rv == 0) && (*mp != NULL)) {
143                 ip = mtod(*mp, struct ip *);
144                 ip->ip_len = ntohs(ip->ip_len);
145                 ip->ip_off = ntohs(ip->ip_off);
146         }
147 #endif
148         return rv;
149 }
150
151 # ifdef USE_INET6
152 #  include <netinet/ip6.h>
153
154 static int
155 ipf_check_wrapper6(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir)
156 {
157         return (ipf_check(&ipfmain, mtod(*mp, struct ip *),
158                           sizeof(struct ip6_hdr), ifp, (dir == PFIL_OUT), mp));
159 }
160 # endif
161 #if     defined(IPFILTER_LKM)
162 int ipf_identify(s)
163         char *s;
164 {
165         if (strcmp(s, "ipl") == 0)
166                 return 1;
167         return 0;
168 }
169 #endif /* IPFILTER_LKM */
170
171
172 static void
173 ipf_timer_func(arg)
174         void *arg;
175 {
176         ipf_main_softc_t *softc = arg;
177         SPL_INT(s);
178
179         SPL_NET(s);
180         READ_ENTER(&softc->ipf_global);
181
182         if (softc->ipf_running > 0)
183                 ipf_slowtimer(softc);
184
185         if (softc->ipf_running == -1 || softc->ipf_running == 1) {
186 #if 0
187                 softc->ipf_slow_ch = timeout(ipf_timer_func, softc, hz/2);
188 #endif
189                 callout_init(&softc->ipf_slow_ch, 1);
190                 callout_reset(&softc->ipf_slow_ch,
191                         (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT,
192                         ipf_timer_func, softc);
193         }
194         RWLOCK_EXIT(&softc->ipf_global);
195         SPL_X(s);
196 }
197
198
199 int
200 ipfattach(softc)
201         ipf_main_softc_t *softc;
202 {
203 #ifdef USE_SPL
204         int s;
205 #endif
206
207         SPL_NET(s);
208         if (softc->ipf_running > 0) {
209                 SPL_X(s);
210                 return EBUSY;
211         }
212
213         if (ipf_init_all(softc) < 0) {
214                 SPL_X(s);
215                 return EIO;
216         }
217
218
219         if (ipf_checkp != ipf_check) {
220                 ipf_savep = ipf_checkp;
221                 ipf_checkp = ipf_check;
222         }
223
224         bzero((char *)ipfmain.ipf_selwait, sizeof(ipfmain.ipf_selwait));
225         softc->ipf_running = 1;
226
227         if (softc->ipf_control_forwarding & 1)
228                 V_ipforwarding = 1;
229
230         ipid = 0;
231
232         SPL_X(s);
233 #if 0
234         softc->ipf_slow_ch = timeout(ipf_timer_func, softc,
235                                      (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT);
236 #endif
237         callout_init(&softc->ipf_slow_ch, 1);
238         callout_reset(&softc->ipf_slow_ch, (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT,
239                 ipf_timer_func, softc);
240         return 0;
241 }
242
243
244 /*
245  * Disable the filter by removing the hooks from the IP input/output
246  * stream.
247  */
248 int
249 ipfdetach(softc)
250         ipf_main_softc_t *softc;
251 {
252 #ifdef USE_SPL
253         int s;
254 #endif
255
256         if (softc->ipf_control_forwarding & 2)
257                 V_ipforwarding = 0;
258
259         SPL_NET(s);
260
261 #if 0
262         if (softc->ipf_slow_ch.callout != NULL)
263                 untimeout(ipf_timer_func, softc, softc->ipf_slow_ch);
264         bzero(&softc->ipf_slow, sizeof(softc->ipf_slow));
265 #endif
266         callout_drain(&softc->ipf_slow_ch);
267
268 #ifndef NETBSD_PF
269         if (ipf_checkp != NULL)
270                 ipf_checkp = ipf_savep;
271         ipf_savep = NULL;
272 #endif
273
274         ipf_fini_all(softc);
275
276         softc->ipf_running = -2;
277
278         SPL_X(s);
279
280         return 0;
281 }
282
283
284 /*
285  * Filter ioctl interface.
286  */
287 int
288 ipfioctl(dev, cmd, data, mode, p)
289         struct thread *p;
290 #    define     p_cred  td_ucred
291 #    define     p_uid   td_ucred->cr_ruid
292         struct cdev *dev;
293         ioctlcmd_t cmd;
294         caddr_t data;
295         int mode;
296 {
297         int error = 0, unit = 0;
298         SPL_INT(s);
299
300 #if (BSD >= 199306)
301         if (securelevel_ge(p->p_cred, 3) && (mode & FWRITE))
302         {
303                 ipfmain.ipf_interror = 130001;
304                 return EPERM;
305         }
306 #endif
307
308         unit = GET_MINOR(dev);
309         if ((IPL_LOGMAX < unit) || (unit < 0)) {
310                 ipfmain.ipf_interror = 130002;
311                 return ENXIO;
312         }
313
314         if (ipfmain.ipf_running <= 0) {
315                 if (unit != IPL_LOGIPF && cmd != SIOCIPFINTERROR) {
316                         ipfmain.ipf_interror = 130003;
317                         return EIO;
318                 }
319                 if (cmd != SIOCIPFGETNEXT && cmd != SIOCIPFGET &&
320                     cmd != SIOCIPFSET && cmd != SIOCFRENB &&
321                     cmd != SIOCGETFS && cmd != SIOCGETFF &&
322                     cmd != SIOCIPFINTERROR) {
323                         ipfmain.ipf_interror = 130004;
324                         return EIO;
325                 }
326         }
327
328         SPL_NET(s);
329
330         CURVNET_SET(TD_TO_VNET(p));
331         error = ipf_ioctlswitch(&ipfmain, unit, data, cmd, mode, p->p_uid, p);
332         CURVNET_RESTORE();
333         if (error != -1) {
334                 SPL_X(s);
335                 return error;
336         }
337
338         SPL_X(s);
339
340         return error;
341 }
342
343
344 /*
345  * ipf_send_reset - this could conceivably be a call to tcp_respond(), but that
346  * requires a large amount of setting up and isn't any more efficient.
347  */
348 int
349 ipf_send_reset(fin)
350         fr_info_t *fin;
351 {
352         struct tcphdr *tcp, *tcp2;
353         int tlen = 0, hlen;
354         struct mbuf *m;
355 #ifdef USE_INET6
356         ip6_t *ip6;
357 #endif
358         ip_t *ip;
359
360         tcp = fin->fin_dp;
361         if (tcp->th_flags & TH_RST)
362                 return -1;              /* feedback loop */
363
364         if (ipf_checkl4sum(fin) == -1)
365                 return -1;
366
367         tlen = fin->fin_dlen - (TCP_OFF(tcp) << 2) +
368                         ((tcp->th_flags & TH_SYN) ? 1 : 0) +
369                         ((tcp->th_flags & TH_FIN) ? 1 : 0);
370
371 #ifdef USE_INET6
372         hlen = (fin->fin_v == 6) ? sizeof(ip6_t) : sizeof(ip_t);
373 #else
374         hlen = sizeof(ip_t);
375 #endif
376 #ifdef MGETHDR
377         MGETHDR(m, M_DONTWAIT, MT_HEADER);
378 #else
379         MGET(m, M_DONTWAIT, MT_HEADER);
380 #endif
381         if (m == NULL)
382                 return -1;
383         if (sizeof(*tcp2) + hlen > MLEN) {
384                 MCLGET(m, M_DONTWAIT);
385                 if ((m->m_flags & M_EXT) == 0) {
386                         FREE_MB_T(m);
387                         return -1;
388                 }
389         }
390
391         m->m_len = sizeof(*tcp2) + hlen;
392 #if (BSD >= 199103)
393         m->m_data += max_linkhdr;
394         m->m_pkthdr.len = m->m_len;
395         m->m_pkthdr.rcvif = (struct ifnet *)0;
396 #endif
397         ip = mtod(m, struct ip *);
398         bzero((char *)ip, hlen);
399 #ifdef USE_INET6
400         ip6 = (ip6_t *)ip;
401 #endif
402         tcp2 = (struct tcphdr *)((char *)ip + hlen);
403         tcp2->th_sport = tcp->th_dport;
404         tcp2->th_dport = tcp->th_sport;
405
406         if (tcp->th_flags & TH_ACK) {
407                 tcp2->th_seq = tcp->th_ack;
408                 tcp2->th_flags = TH_RST;
409                 tcp2->th_ack = 0;
410         } else {
411                 tcp2->th_seq = 0;
412                 tcp2->th_ack = ntohl(tcp->th_seq);
413                 tcp2->th_ack += tlen;
414                 tcp2->th_ack = htonl(tcp2->th_ack);
415                 tcp2->th_flags = TH_RST|TH_ACK;
416         }
417         TCP_X2_A(tcp2, 0);
418         TCP_OFF_A(tcp2, sizeof(*tcp2) >> 2);
419         tcp2->th_win = tcp->th_win;
420         tcp2->th_sum = 0;
421         tcp2->th_urp = 0;
422
423 #ifdef USE_INET6
424         if (fin->fin_v == 6) {
425                 ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow;
426                 ip6->ip6_plen = htons(sizeof(struct tcphdr));
427                 ip6->ip6_nxt = IPPROTO_TCP;
428                 ip6->ip6_hlim = 0;
429                 ip6->ip6_src = fin->fin_dst6.in6;
430                 ip6->ip6_dst = fin->fin_src6.in6;
431                 tcp2->th_sum = in6_cksum(m, IPPROTO_TCP,
432                                          sizeof(*ip6), sizeof(*tcp2));
433                 return ipf_send_ip(fin, m);
434         }
435 #endif
436         ip->ip_p = IPPROTO_TCP;
437         ip->ip_len = htons(sizeof(struct tcphdr));
438         ip->ip_src.s_addr = fin->fin_daddr;
439         ip->ip_dst.s_addr = fin->fin_saddr;
440         tcp2->th_sum = in_cksum(m, hlen + sizeof(*tcp2));
441         ip->ip_len = htons(hlen + sizeof(*tcp2));
442         return ipf_send_ip(fin, m);
443 }
444
445
446 /*
447  * ip_len must be in network byte order when called.
448  */
449 static int
450 ipf_send_ip(fin, m)
451         fr_info_t *fin;
452         mb_t *m;
453 {
454         fr_info_t fnew;
455         ip_t *ip, *oip;
456         int hlen;
457
458         ip = mtod(m, ip_t *);
459         bzero((char *)&fnew, sizeof(fnew));
460         fnew.fin_main_soft = fin->fin_main_soft;
461
462         IP_V_A(ip, fin->fin_v);
463         switch (fin->fin_v)
464         {
465         case 4 :
466                 oip = fin->fin_ip;
467                 hlen = sizeof(*oip);
468                 fnew.fin_v = 4;
469                 fnew.fin_p = ip->ip_p;
470                 fnew.fin_plen = ntohs(ip->ip_len);
471                 IP_HL_A(ip, sizeof(*oip) >> 2);
472                 ip->ip_tos = oip->ip_tos;
473                 ip->ip_id = fin->fin_ip->ip_id;
474                 ip->ip_off = htons(V_path_mtu_discovery ? IP_DF : 0);
475                 ip->ip_ttl = V_ip_defttl;
476                 ip->ip_sum = 0;
477                 break;
478 #ifdef USE_INET6
479         case 6 :
480         {
481                 ip6_t *ip6 = (ip6_t *)ip;
482
483                 ip6->ip6_vfc = 0x60;
484                 ip6->ip6_hlim = IPDEFTTL;
485
486                 hlen = sizeof(*ip6);
487                 fnew.fin_p = ip6->ip6_nxt;
488                 fnew.fin_v = 6;
489                 fnew.fin_plen = ntohs(ip6->ip6_plen) + hlen;
490                 break;
491         }
492 #endif
493         default :
494                 return EINVAL;
495         }
496 #ifdef IPSEC
497         m->m_pkthdr.rcvif = NULL;
498 #endif
499
500         fnew.fin_ifp = fin->fin_ifp;
501         fnew.fin_flx = FI_NOCKSUM;
502         fnew.fin_m = m;
503         fnew.fin_ip = ip;
504         fnew.fin_mp = &m;
505         fnew.fin_hlen = hlen;
506         fnew.fin_dp = (char *)ip + hlen;
507         (void) ipf_makefrip(hlen, ip, &fnew);
508
509         return ipf_fastroute(m, &m, &fnew, NULL);
510 }
511
512
513 int
514 ipf_send_icmp_err(type, fin, dst)
515         int type;
516         fr_info_t *fin;
517         int dst;
518 {
519         int err, hlen, xtra, iclen, ohlen, avail, code;
520         struct in_addr dst4;
521         struct icmp *icmp;
522         struct mbuf *m;
523         i6addr_t dst6;
524         void *ifp;
525 #ifdef USE_INET6
526         ip6_t *ip6;
527 #endif
528         ip_t *ip, *ip2;
529
530         if ((type < 0) || (type >= ICMP_MAXTYPE))
531                 return -1;
532
533         code = fin->fin_icode;
534 #ifdef USE_INET6
535         /* See NetBSD ip_fil_netbsd.c r1.4: */
536         if ((code < 0) || (code >= sizeof(icmptoicmp6unreach)/sizeof(int)))
537                 return -1;
538 #endif
539
540         if (ipf_checkl4sum(fin) == -1)
541                 return -1;
542 #ifdef MGETHDR
543         MGETHDR(m, M_DONTWAIT, MT_HEADER);
544 #else
545         MGET(m, M_DONTWAIT, MT_HEADER);
546 #endif
547         if (m == NULL)
548                 return -1;
549         avail = MHLEN;
550
551         xtra = 0;
552         hlen = 0;
553         ohlen = 0;
554         dst4.s_addr = 0;
555         ifp = fin->fin_ifp;
556         if (fin->fin_v == 4) {
557                 if ((fin->fin_p == IPPROTO_ICMP) && !(fin->fin_flx & FI_SHORT))
558                         switch (ntohs(fin->fin_data[0]) >> 8)
559                         {
560                         case ICMP_ECHO :
561                         case ICMP_TSTAMP :
562                         case ICMP_IREQ :
563                         case ICMP_MASKREQ :
564                                 break;
565                         default :
566                                 FREE_MB_T(m);
567                                 return 0;
568                         }
569
570                 if (dst == 0) {
571                         if (ipf_ifpaddr(&ipfmain, 4, FRI_NORMAL, ifp,
572                                         &dst6, NULL) == -1) {
573                                 FREE_MB_T(m);
574                                 return -1;
575                         }
576                         dst4 = dst6.in4;
577                 } else
578                         dst4.s_addr = fin->fin_daddr;
579
580                 hlen = sizeof(ip_t);
581                 ohlen = fin->fin_hlen;
582                 iclen = hlen + offsetof(struct icmp, icmp_ip) + ohlen;
583                 if (fin->fin_hlen < fin->fin_plen)
584                         xtra = MIN(fin->fin_dlen, 8);
585                 else
586                         xtra = 0;
587         }
588
589 #ifdef USE_INET6
590         else if (fin->fin_v == 6) {
591                 hlen = sizeof(ip6_t);
592                 ohlen = sizeof(ip6_t);
593                 iclen = hlen + offsetof(struct icmp, icmp_ip) + ohlen;
594                 type = icmptoicmp6types[type];
595                 if (type == ICMP6_DST_UNREACH)
596                         code = icmptoicmp6unreach[code];
597
598                 if (iclen + max_linkhdr + fin->fin_plen > avail) {
599                         MCLGET(m, M_DONTWAIT);
600                         if ((m->m_flags & M_EXT) == 0) {
601                                 FREE_MB_T(m);
602                                 return -1;
603                         }
604                         avail = MCLBYTES;
605                 }
606                 xtra = MIN(fin->fin_plen, avail - iclen - max_linkhdr);
607                 xtra = MIN(xtra, IPV6_MMTU - iclen);
608                 if (dst == 0) {
609                         if (ipf_ifpaddr(&ipfmain, 6, FRI_NORMAL, ifp,
610                                         &dst6, NULL) == -1) {
611                                 FREE_MB_T(m);
612                                 return -1;
613                         }
614                 } else
615                         dst6 = fin->fin_dst6;
616         }
617 #endif
618         else {
619                 FREE_MB_T(m);
620                 return -1;
621         }
622
623         avail -= (max_linkhdr + iclen);
624         if (avail < 0) {
625                 FREE_MB_T(m);
626                 return -1;
627         }
628         if (xtra > avail)
629                 xtra = avail;
630         iclen += xtra;
631         m->m_data += max_linkhdr;
632         m->m_pkthdr.rcvif = (struct ifnet *)0;
633         m->m_pkthdr.len = iclen;
634         m->m_len = iclen;
635         ip = mtod(m, ip_t *);
636         icmp = (struct icmp *)((char *)ip + hlen);
637         ip2 = (ip_t *)&icmp->icmp_ip;
638
639         icmp->icmp_type = type;
640         icmp->icmp_code = fin->fin_icode;
641         icmp->icmp_cksum = 0;
642 #ifdef icmp_nextmtu
643         if (type == ICMP_UNREACH && fin->fin_icode == ICMP_UNREACH_NEEDFRAG) {
644                 if (fin->fin_mtu != 0) {
645                         icmp->icmp_nextmtu = htons(fin->fin_mtu);
646
647                 } else if (ifp != NULL) {
648                         icmp->icmp_nextmtu = htons(GETIFMTU_4(ifp));
649
650                 } else {        /* make up a number... */
651                         icmp->icmp_nextmtu = htons(fin->fin_plen - 20);
652                 }
653         }
654 #endif
655
656         bcopy((char *)fin->fin_ip, (char *)ip2, ohlen);
657
658 #ifdef USE_INET6
659         ip6 = (ip6_t *)ip;
660         if (fin->fin_v == 6) {
661                 ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow;
662                 ip6->ip6_plen = htons(iclen - hlen);
663                 ip6->ip6_nxt = IPPROTO_ICMPV6;
664                 ip6->ip6_hlim = 0;
665                 ip6->ip6_src = dst6.in6;
666                 ip6->ip6_dst = fin->fin_src6.in6;
667                 if (xtra > 0)
668                         bcopy((char *)fin->fin_ip + ohlen,
669                               (char *)&icmp->icmp_ip + ohlen, xtra);
670                 icmp->icmp_cksum = in6_cksum(m, IPPROTO_ICMPV6,
671                                              sizeof(*ip6), iclen - hlen);
672         } else
673 #endif
674         {
675                 ip->ip_p = IPPROTO_ICMP;
676                 ip->ip_src.s_addr = dst4.s_addr;
677                 ip->ip_dst.s_addr = fin->fin_saddr;
678
679                 if (xtra > 0)
680                         bcopy((char *)fin->fin_ip + ohlen,
681                               (char *)&icmp->icmp_ip + ohlen, xtra);
682                 icmp->icmp_cksum = ipf_cksum((u_short *)icmp,
683                                              sizeof(*icmp) + 8);
684                 ip->ip_len = htons(iclen);
685                 ip->ip_p = IPPROTO_ICMP;
686         }
687         err = ipf_send_ip(fin, m);
688         return err;
689 }
690
691
692
693
694 /*
695  * m0 - pointer to mbuf where the IP packet starts
696  * mpp - pointer to the mbuf pointer that is the start of the mbuf chain
697  */
698 int
699 ipf_fastroute(m0, mpp, fin, fdp)
700         mb_t *m0, **mpp;
701         fr_info_t *fin;
702         frdest_t *fdp;
703 {
704         register struct ip *ip, *mhip;
705         register struct mbuf *m = *mpp;
706         register struct route *ro;
707         int len, off, error = 0, hlen, code;
708         struct ifnet *ifp, *sifp;
709         struct sockaddr_in *dst;
710         struct route iproute;
711         u_short ip_off;
712         frdest_t node;
713         frentry_t *fr;
714
715         ro = NULL;
716
717 #ifdef M_WRITABLE
718         /*
719         * HOT FIX/KLUDGE:
720         *
721         * If the mbuf we're about to send is not writable (because of
722         * a cluster reference, for example) we'll need to make a copy
723         * of it since this routine modifies the contents.
724         *
725         * If you have non-crappy network hardware that can transmit data
726         * from the mbuf, rather than making a copy, this is gonna be a
727         * problem.
728         */
729         if (M_WRITABLE(m) == 0) {
730                 m0 = m_dup(m, M_DONTWAIT);
731                 if (m0 != NULL) {
732                         FREE_MB_T(m);
733                         m = m0;
734                         *mpp = m;
735                 } else {
736                         error = ENOBUFS;
737                         FREE_MB_T(m);
738                         goto done;
739                 }
740         }
741 #endif
742
743 #ifdef USE_INET6
744         if (fin->fin_v == 6) {
745                 /*
746                  * currently "to <if>" and "to <if>:ip#" are not supported
747                  * for IPv6
748                  */
749                 return ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);
750         }
751 #endif
752
753         hlen = fin->fin_hlen;
754         ip = mtod(m0, struct ip *);
755         ifp = NULL;
756
757         /*
758          * Route packet.
759          */
760         ro = &iproute;
761         bzero(ro, sizeof (*ro));
762         dst = (struct sockaddr_in *)&ro->ro_dst;
763         dst->sin_family = AF_INET;
764         dst->sin_addr = ip->ip_dst;
765
766         fr = fin->fin_fr;
767         if ((fr != NULL) && !(fr->fr_flags & FR_KEEPSTATE) && (fdp != NULL) &&
768             (fdp->fd_type == FRD_DSTLIST)) {
769                 if (ipf_dstlist_select_node(fin, fdp->fd_ptr, NULL, &node) == 0)
770                         fdp = &node;
771         }
772
773         if (fdp != NULL)
774                 ifp = fdp->fd_ptr;
775         else
776                 ifp = fin->fin_ifp;
777
778         if ((ifp == NULL) && ((fr == NULL) || !(fr->fr_flags & FR_FASTROUTE))) {
779                 error = -2;
780                 goto bad;
781         }
782
783         if ((fdp != NULL) && (fdp->fd_ip.s_addr != 0))
784                 dst->sin_addr = fdp->fd_ip;
785
786         dst->sin_len = sizeof(*dst);
787         in_rtalloc(ro, M_GETFIB(m0));
788
789         if ((ifp == NULL) && (ro->ro_rt != NULL))
790                 ifp = ro->ro_rt->rt_ifp;
791
792         if ((ro->ro_rt == NULL) || (ifp == NULL)) {
793                 if (in_localaddr(ip->ip_dst))
794                         error = EHOSTUNREACH;
795                 else
796                         error = ENETUNREACH;
797                 goto bad;
798         }
799         if (ro->ro_rt->rt_flags & RTF_GATEWAY)
800                 dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway;
801         if (ro->ro_rt)
802                 counter_u64_add(ro->ro_rt->rt_pksent, 1);
803
804         /*
805          * For input packets which are being "fastrouted", they won't
806          * go back through output filtering and miss their chance to get
807          * NAT'd and counted.  Duplicated packets aren't considered to be
808          * part of the normal packet stream, so do not NAT them or pass
809          * them through stateful checking, etc.
810          */
811         if ((fdp != &fr->fr_dif) && (fin->fin_out == 0)) {
812                 sifp = fin->fin_ifp;
813                 fin->fin_ifp = ifp;
814                 fin->fin_out = 1;
815                 (void) ipf_acctpkt(fin, NULL);
816                 fin->fin_fr = NULL;
817                 if (!fr || !(fr->fr_flags & FR_RETMASK)) {
818                         u_32_t pass;
819
820                         (void) ipf_state_check(fin, &pass);
821                 }
822
823                 switch (ipf_nat_checkout(fin, NULL))
824                 {
825                 case 0 :
826                         break;
827                 case 1 :
828                         ip->ip_sum = 0;
829                         break;
830                 case -1 :
831                         error = -1;
832                         goto bad;
833                         break;
834                 }
835
836                 fin->fin_ifp = sifp;
837                 fin->fin_out = 0;
838         } else
839                 ip->ip_sum = 0;
840         /*
841          * If small enough for interface, can just send directly.
842          */
843         if (ntohs(ip->ip_len) <= ifp->if_mtu) {
844                 if (!ip->ip_sum)
845                         ip->ip_sum = in_cksum(m, hlen);
846                 error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst,
847                             ro
848                         );
849                 goto done;
850         }
851         /*
852          * Too large for interface; fragment if possible.
853          * Must be able to put at least 8 bytes per fragment.
854          */
855         ip_off = ntohs(ip->ip_off);
856         if (ip_off & IP_DF) {
857                 error = EMSGSIZE;
858                 goto bad;
859         }
860         len = (ifp->if_mtu - hlen) &~ 7;
861         if (len < 8) {
862                 error = EMSGSIZE;
863                 goto bad;
864         }
865
866     {
867         int mhlen, firstlen = len;
868         struct mbuf **mnext = &m->m_act;
869
870         /*
871          * Loop through length of segment after first fragment,
872          * make new header and copy data of each part and link onto chain.
873          */
874         m0 = m;
875         mhlen = sizeof (struct ip);
876         for (off = hlen + len; off < ntohs(ip->ip_len); off += len) {
877 #ifdef MGETHDR
878                 MGETHDR(m, M_DONTWAIT, MT_HEADER);
879 #else
880                 MGET(m, M_DONTWAIT, MT_HEADER);
881 #endif
882                 if (m == NULL) {
883                         m = m0;
884                         error = ENOBUFS;
885                         goto bad;
886                 }
887                 m->m_data += max_linkhdr;
888                 mhip = mtod(m, struct ip *);
889                 bcopy((char *)ip, (char *)mhip, sizeof(*ip));
890                 if (hlen > sizeof (struct ip)) {
891                         mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
892                         IP_HL_A(mhip, mhlen >> 2);
893                 }
894                 m->m_len = mhlen;
895                 mhip->ip_off = ((off - hlen) >> 3) + ip_off;
896                 if (off + len >= ntohs(ip->ip_len))
897                         len = ntohs(ip->ip_len) - off;
898                 else
899                         mhip->ip_off |= IP_MF;
900                 mhip->ip_len = htons((u_short)(len + mhlen));
901                 *mnext = m;
902                 m->m_next = m_copy(m0, off, len);
903                 if (m->m_next == 0) {
904                         error = ENOBUFS;        /* ??? */
905                         goto sendorfree;
906                 }
907                 m->m_pkthdr.len = mhlen + len;
908                 m->m_pkthdr.rcvif = NULL;
909                 mhip->ip_off = htons((u_short)mhip->ip_off);
910                 mhip->ip_sum = 0;
911                 mhip->ip_sum = in_cksum(m, mhlen);
912                 mnext = &m->m_act;
913         }
914         /*
915          * Update first fragment by trimming what's been copied out
916          * and updating header, then send each fragment (in order).
917          */
918         m_adj(m0, hlen + firstlen - ip->ip_len);
919         ip->ip_len = htons((u_short)(hlen + firstlen));
920         ip->ip_off = htons((u_short)IP_MF);
921         ip->ip_sum = 0;
922         ip->ip_sum = in_cksum(m0, hlen);
923 sendorfree:
924         for (m = m0; m; m = m0) {
925                 m0 = m->m_act;
926                 m->m_act = 0;
927                 if (error == 0)
928                         error = (*ifp->if_output)(ifp, m,
929                             (struct sockaddr *)dst,
930                             ro
931                             );
932                 else
933                         FREE_MB_T(m);
934         }
935     }
936 done:
937         if (!error)
938                 ipfmain.ipf_frouteok[0]++;
939         else
940                 ipfmain.ipf_frouteok[1]++;
941
942         if ((ro != NULL) && (ro->ro_rt != NULL)) {
943                 RTFREE(ro->ro_rt);
944         }
945         return 0;
946 bad:
947         if (error == EMSGSIZE) {
948                 sifp = fin->fin_ifp;
949                 code = fin->fin_icode;
950                 fin->fin_icode = ICMP_UNREACH_NEEDFRAG;
951                 fin->fin_ifp = ifp;
952                 (void) ipf_send_icmp_err(ICMP_UNREACH, fin, 1);
953                 fin->fin_ifp = sifp;
954                 fin->fin_icode = code;
955         }
956         FREE_MB_T(m);
957         goto done;
958 }
959
960
961 int
962 ipf_verifysrc(fin)
963         fr_info_t *fin;
964 {
965         struct sockaddr_in *dst;
966         struct route iproute;
967
968         bzero((char *)&iproute, sizeof(iproute));
969         dst = (struct sockaddr_in *)&iproute.ro_dst;
970         dst->sin_len = sizeof(*dst);
971         dst->sin_family = AF_INET;
972         dst->sin_addr = fin->fin_src;
973         in_rtalloc(&iproute, 0);
974         if (iproute.ro_rt == NULL)
975                 return 0;
976         return (fin->fin_ifp == iproute.ro_rt->rt_ifp);
977 }
978
979
980 /*
981  * return the first IP Address associated with an interface
982  */
983 int
984 ipf_ifpaddr(softc, v, atype, ifptr, inp, inpmask)
985         ipf_main_softc_t *softc;
986         int v, atype;
987         void *ifptr;
988         i6addr_t *inp, *inpmask;
989 {
990 #ifdef USE_INET6
991         struct in6_addr *inp6 = NULL;
992 #endif
993         struct sockaddr *sock, *mask;
994         struct sockaddr_in *sin;
995         struct ifaddr *ifa;
996         struct ifnet *ifp;
997
998         if ((ifptr == NULL) || (ifptr == (void *)-1))
999                 return -1;
1000
1001         sin = NULL;
1002         ifp = ifptr;
1003
1004         if (v == 4)
1005                 inp->in4.s_addr = 0;
1006 #ifdef USE_INET6
1007         else if (v == 6)
1008                 bzero((char *)inp, sizeof(*inp));
1009 #endif
1010         ifa = TAILQ_FIRST(&ifp->if_addrhead);
1011
1012         sock = ifa->ifa_addr;
1013         while (sock != NULL && ifa != NULL) {
1014                 sin = (struct sockaddr_in *)sock;
1015                 if ((v == 4) && (sin->sin_family == AF_INET))
1016                         break;
1017 #ifdef USE_INET6
1018                 if ((v == 6) && (sin->sin_family == AF_INET6)) {
1019                         inp6 = &((struct sockaddr_in6 *)sin)->sin6_addr;
1020                         if (!IN6_IS_ADDR_LINKLOCAL(inp6) &&
1021                             !IN6_IS_ADDR_LOOPBACK(inp6))
1022                                 break;
1023                 }
1024 #endif
1025                 ifa = TAILQ_NEXT(ifa, ifa_link);
1026                 if (ifa != NULL)
1027                         sock = ifa->ifa_addr;
1028         }
1029
1030         if (ifa == NULL || sin == NULL)
1031                 return -1;
1032
1033         mask = ifa->ifa_netmask;
1034         if (atype == FRI_BROADCAST)
1035                 sock = ifa->ifa_broadaddr;
1036         else if (atype == FRI_PEERADDR)
1037                 sock = ifa->ifa_dstaddr;
1038
1039         if (sock == NULL)
1040                 return -1;
1041
1042 #ifdef USE_INET6
1043         if (v == 6) {
1044                 return ipf_ifpfillv6addr(atype, (struct sockaddr_in6 *)sock,
1045                                          (struct sockaddr_in6 *)mask,
1046                                          inp, inpmask);
1047         }
1048 #endif
1049         return ipf_ifpfillv4addr(atype, (struct sockaddr_in *)sock,
1050                                  (struct sockaddr_in *)mask,
1051                                  &inp->in4, &inpmask->in4);
1052 }
1053
1054
1055 u_32_t
1056 ipf_newisn(fin)
1057         fr_info_t *fin;
1058 {
1059         u_32_t newiss;
1060         newiss = arc4random();
1061         return newiss;
1062 }
1063
1064
1065 /* ------------------------------------------------------------------------ */
1066 /* Function:    ipf_nextipid                                                */
1067 /* Returns:     int - 0 == success, -1 == error (packet should be droppped) */
1068 /* Parameters:  fin(I) - pointer to packet information                      */
1069 /*                                                                          */
1070 /* Returns the next IPv4 ID to use for this packet.                         */
1071 /* ------------------------------------------------------------------------ */
1072 u_short
1073 ipf_nextipid(fin)
1074         fr_info_t *fin;
1075 {
1076         u_short id;
1077
1078 #ifndef RANDOM_IP_ID
1079         MUTEX_ENTER(&ipfmain.ipf_rw);
1080         id = ipid++;
1081         MUTEX_EXIT(&ipfmain.ipf_rw);
1082 #else
1083         id = ip_randomid();
1084 #endif
1085
1086         return id;
1087 }
1088
1089
1090 INLINE int
1091 ipf_checkv4sum(fin)
1092         fr_info_t *fin;
1093 {
1094 #ifdef CSUM_DATA_VALID
1095         int manual = 0;
1096         u_short sum;
1097         ip_t *ip;
1098         mb_t *m;
1099
1100         if ((fin->fin_flx & FI_NOCKSUM) != 0)
1101                 return 0;
1102
1103         if ((fin->fin_flx & FI_SHORT) != 0)
1104                 return 1;
1105
1106         if (fin->fin_cksum != FI_CK_NEEDED)
1107                 return (fin->fin_cksum > FI_CK_NEEDED) ? 0 : -1;
1108
1109         m = fin->fin_m;
1110         if (m == NULL) {
1111                 manual = 1;
1112                 goto skipauto;
1113         }
1114         ip = fin->fin_ip;
1115
1116         if ((m->m_pkthdr.csum_flags & (CSUM_IP_CHECKED|CSUM_IP_VALID)) ==
1117             CSUM_IP_CHECKED) {
1118                 fin->fin_cksum = FI_CK_BAD;
1119                 fin->fin_flx |= FI_BAD;
1120                 return -1;
1121         }
1122         if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) {
1123                 /* Depending on the driver, UDP may have zero checksum */
1124                 if (fin->fin_p == IPPROTO_UDP && (fin->fin_flx &
1125                     (FI_FRAG|FI_SHORT|FI_BAD)) == 0) {
1126                         udphdr_t *udp = fin->fin_dp;
1127                         if (udp->uh_sum == 0) {
1128                                 /*
1129                                  * we're good no matter what the hardware
1130                                  * checksum flags and csum_data say (handling
1131                                  * of csum_data for zero UDP checksum is not
1132                                  * consistent across all drivers)
1133                                  */
1134                                 fin->fin_cksum = 1;
1135                                 return 0;
1136                         }
1137                 }
1138
1139                 if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR)
1140                         sum = m->m_pkthdr.csum_data;
1141                 else
1142                         sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr,
1143                                         htonl(m->m_pkthdr.csum_data +
1144                                         fin->fin_dlen + fin->fin_p));
1145                 sum ^= 0xffff;
1146                 if (sum != 0) {
1147                         fin->fin_cksum = FI_CK_BAD;
1148                         fin->fin_flx |= FI_BAD;
1149                 } else {
1150                         fin->fin_cksum = FI_CK_SUMOK;
1151                         return 0;
1152                 }
1153         } else {
1154                 if (m->m_pkthdr.csum_flags == CSUM_DELAY_DATA) {
1155                         fin->fin_cksum = FI_CK_L4FULL;
1156                         return 0;
1157                 } else if (m->m_pkthdr.csum_flags == CSUM_TCP ||
1158                            m->m_pkthdr.csum_flags == CSUM_UDP) {
1159                         fin->fin_cksum = FI_CK_L4PART;
1160                         return 0;
1161                 } else if (m->m_pkthdr.csum_flags == CSUM_IP) {
1162                         fin->fin_cksum = FI_CK_L4PART;
1163                         return 0;
1164                 } else {
1165                         manual = 1;
1166                 }
1167         }
1168 skipauto:
1169         if (manual != 0) {
1170                 if (ipf_checkl4sum(fin) == -1) {
1171                         fin->fin_flx |= FI_BAD;
1172                         return -1;
1173                 }
1174         }
1175 #else
1176         if (ipf_checkl4sum(fin) == -1) {
1177                 fin->fin_flx |= FI_BAD;
1178                 return -1;
1179         }
1180 #endif
1181         return 0;
1182 }
1183
1184
1185 #ifdef USE_INET6
1186 INLINE int
1187 ipf_checkv6sum(fin)
1188         fr_info_t *fin;
1189 {
1190         if ((fin->fin_flx & FI_NOCKSUM) != 0)
1191                 return 0;
1192
1193         if ((fin->fin_flx & FI_SHORT) != 0)
1194                 return 1;
1195
1196         if (fin->fin_cksum != FI_CK_NEEDED)
1197                 return (fin->fin_cksum > FI_CK_NEEDED) ? 0 : -1;
1198
1199         if (ipf_checkl4sum(fin) == -1) {
1200                 fin->fin_flx |= FI_BAD;
1201                 return -1;
1202         }
1203         return 0;
1204 }
1205 #endif /* USE_INET6 */
1206
1207
1208 size_t
1209 mbufchainlen(m0)
1210         struct mbuf *m0;
1211         {
1212         size_t len;
1213
1214         if ((m0->m_flags & M_PKTHDR) != 0) {
1215                 len = m0->m_pkthdr.len;
1216         } else {
1217                 struct mbuf *m;
1218
1219                 for (m = m0, len = 0; m != NULL; m = m->m_next)
1220                         len += m->m_len;
1221         }
1222         return len;
1223 }
1224
1225
1226 /* ------------------------------------------------------------------------ */
1227 /* Function:    ipf_pullup                                                  */
1228 /* Returns:     NULL == pullup failed, else pointer to protocol header      */
1229 /* Parameters:  xmin(I)- pointer to buffer where data packet starts         */
1230 /*              fin(I) - pointer to packet information                      */
1231 /*              len(I) - number of bytes to pullup                          */
1232 /*                                                                          */
1233 /* Attempt to move at least len bytes (from the start of the buffer) into a */
1234 /* single buffer for ease of access.  Operating system native functions are */
1235 /* used to manage buffers - if necessary.  If the entire packet ends up in  */
1236 /* a single buffer, set the FI_COALESCE flag even though ipf_coalesce() has */
1237 /* not been called.  Both fin_ip and fin_dp are updated before exiting _IF_ */
1238 /* and ONLY if the pullup succeeds.                                         */
1239 /*                                                                          */
1240 /* We assume that 'xmin' is a pointer to a buffer that is part of the chain */
1241 /* of buffers that starts at *fin->fin_mp.                                  */
1242 /* ------------------------------------------------------------------------ */
1243 void *
1244 ipf_pullup(xmin, fin, len)
1245         mb_t *xmin;
1246         fr_info_t *fin;
1247         int len;
1248 {
1249         int dpoff, ipoff;
1250         mb_t *m = xmin;
1251         char *ip;
1252
1253         if (m == NULL)
1254                 return NULL;
1255
1256         ip = (char *)fin->fin_ip;
1257         if ((fin->fin_flx & FI_COALESCE) != 0)
1258                 return ip;
1259
1260         ipoff = fin->fin_ipoff;
1261         if (fin->fin_dp != NULL)
1262                 dpoff = (char *)fin->fin_dp - (char *)ip;
1263         else
1264                 dpoff = 0;
1265
1266         if (M_LEN(m) < len) {
1267                 mb_t *n = *fin->fin_mp;
1268                 /*
1269                  * Assume that M_PKTHDR is set and just work with what is left
1270                  * rather than check..
1271                  * Should not make any real difference, anyway.
1272                  */
1273                 if (m != n) {
1274                         /*
1275                          * Record the mbuf that points to the mbuf that we're
1276                          * about to go to work on so that we can update the
1277                          * m_next appropriately later.
1278                          */
1279                         for (; n->m_next != m; n = n->m_next)
1280                                 ;
1281                 } else {
1282                         n = NULL;
1283                 }
1284
1285 #ifdef MHLEN
1286                 if (len > MHLEN)
1287 #else
1288                 if (len > MLEN)
1289 #endif
1290                 {
1291 #ifdef HAVE_M_PULLDOWN
1292                         if (m_pulldown(m, 0, len, NULL) == NULL)
1293                                 m = NULL;
1294 #else
1295                         FREE_MB_T(*fin->fin_mp);
1296                         m = NULL;
1297                         n = NULL;
1298 #endif
1299                 } else
1300                 {
1301                         m = m_pullup(m, len);
1302                 }
1303                 if (n != NULL)
1304                         n->m_next = m;
1305                 if (m == NULL) {
1306                         /*
1307                          * When n is non-NULL, it indicates that m pointed to
1308                          * a sub-chain (tail) of the mbuf and that the head
1309                          * of this chain has not yet been free'd.
1310                          */
1311                         if (n != NULL) {
1312                                 FREE_MB_T(*fin->fin_mp);
1313                         }
1314
1315                         *fin->fin_mp = NULL;
1316                         fin->fin_m = NULL;
1317                         return NULL;
1318                 }
1319
1320                 if (n == NULL)
1321                         *fin->fin_mp = m;
1322
1323                 while (M_LEN(m) == 0) {
1324                         m = m->m_next;
1325                 }
1326                 fin->fin_m = m;
1327                 ip = MTOD(m, char *) + ipoff;
1328
1329                 fin->fin_ip = (ip_t *)ip;
1330                 if (fin->fin_dp != NULL)
1331                         fin->fin_dp = (char *)fin->fin_ip + dpoff;
1332                 if (fin->fin_fraghdr != NULL)
1333                         fin->fin_fraghdr = (char *)ip +
1334                                            ((char *)fin->fin_fraghdr -
1335                                             (char *)fin->fin_ip);
1336         }
1337
1338         if (len == fin->fin_plen)
1339                 fin->fin_flx |= FI_COALESCE;
1340         return ip;
1341 }
1342
1343
1344 int
1345 ipf_inject(fin, m)
1346         fr_info_t *fin;
1347         mb_t *m;
1348 {
1349         int error = 0;
1350
1351         if (fin->fin_out == 0) {
1352                 netisr_dispatch(NETISR_IP, m);
1353         } else {
1354                 fin->fin_ip->ip_len = ntohs(fin->fin_ip->ip_len);
1355                 fin->fin_ip->ip_off = ntohs(fin->fin_ip->ip_off);
1356                 error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL);
1357         }
1358
1359         return error;
1360 }
1361
1362 int ipf_pfil_unhook(void) {
1363 #if defined(NETBSD_PF) && (__FreeBSD_version >= 500011)
1364         struct pfil_head *ph_inet;
1365 #  ifdef USE_INET6
1366         struct pfil_head *ph_inet6;
1367 #  endif
1368 #endif
1369
1370 #ifdef NETBSD_PF
1371         ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
1372         if (ph_inet != NULL)
1373                 pfil_remove_hook((void *)ipf_check_wrapper, NULL,
1374                     PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet);
1375 # ifdef USE_INET6
1376         ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
1377         if (ph_inet6 != NULL)
1378                 pfil_remove_hook((void *)ipf_check_wrapper6, NULL,
1379                     PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet6);
1380 # endif
1381 #endif
1382
1383         return (0);
1384 }
1385
1386 int ipf_pfil_hook(void) {
1387 #if defined(NETBSD_PF) && (__FreeBSD_version >= 500011)
1388         struct pfil_head *ph_inet;
1389 #  ifdef USE_INET6
1390         struct pfil_head *ph_inet6;
1391 #  endif
1392 #endif
1393
1394 # ifdef NETBSD_PF
1395         ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
1396 #    ifdef USE_INET6
1397         ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
1398 #    endif
1399         if (ph_inet == NULL
1400 #    ifdef USE_INET6
1401             && ph_inet6 == NULL
1402 #    endif
1403            ) {
1404                 return ENODEV;
1405         }
1406
1407         if (ph_inet != NULL)
1408                 pfil_add_hook((void *)ipf_check_wrapper, NULL,
1409                     PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet);
1410 #  ifdef USE_INET6
1411         if (ph_inet6 != NULL)
1412                 pfil_add_hook((void *)ipf_check_wrapper6, NULL,
1413                                       PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet6);
1414 #  endif
1415 # endif
1416         return (0);
1417 }
1418
1419 void
1420 ipf_event_reg(void)
1421 {
1422         ipf_arrivetag = EVENTHANDLER_REGISTER(ifnet_arrival_event, \
1423                                                ipf_ifevent, &ipfmain, \
1424                                                EVENTHANDLER_PRI_ANY);
1425         ipf_departtag = EVENTHANDLER_REGISTER(ifnet_departure_event, \
1426                                                ipf_ifevent, &ipfmain, \
1427                                                EVENTHANDLER_PRI_ANY);
1428         ipf_clonetag  = EVENTHANDLER_REGISTER(if_clone_event, ipf_ifevent, \
1429                                                &ipfmain, EVENTHANDLER_PRI_ANY);
1430 }
1431
1432 void
1433 ipf_event_dereg(void)
1434 {
1435         if (ipf_arrivetag != NULL) {
1436                 EVENTHANDLER_DEREGISTER(ifnet_arrival_event, ipf_arrivetag);
1437         }
1438         if (ipf_departtag != NULL) {
1439                 EVENTHANDLER_DEREGISTER(ifnet_departure_event, ipf_departtag);
1440         }
1441         if (ipf_clonetag != NULL) {
1442                 EVENTHANDLER_DEREGISTER(if_clone_event, ipf_clonetag);
1443         }
1444 }
1445
1446
1447 u_32_t
1448 ipf_random()
1449 {
1450         return arc4random();
1451 }
1452
1453
1454 u_int
1455 ipf_pcksum(fin, hlen, sum)
1456         fr_info_t *fin;
1457         int hlen;
1458         u_int sum;
1459 {
1460         struct mbuf *m;
1461         u_int sum2;
1462         int off;
1463
1464         m = fin->fin_m;
1465         off = (char *)fin->fin_dp - (char *)fin->fin_ip;
1466         m->m_data += hlen;
1467         m->m_len -= hlen;
1468         sum2 = in_cksum(fin->fin_m, fin->fin_plen - off);
1469         m->m_len += hlen;
1470         m->m_data -= hlen;
1471
1472         /*
1473          * Both sum and sum2 are partial sums, so combine them together.
1474          */
1475         sum += ~sum2 & 0xffff;
1476         while (sum > 0xffff)
1477                 sum = (sum & 0xffff) + (sum >> 16);
1478         sum2 = ~sum & 0xffff;
1479         return sum2;
1480 }