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