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