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