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(fin)
928 fr_info_t *fin;
929 {
930 struct nhop_object *nh;
931
932 NET_EPOCH_ASSERT();
933 nh = fib4_lookup(RT_DEFAULT_FIB, fin->fin_src, 0, NHR_NONE, 0);
934 if (nh == NULL)
935 return (0);
936 return (fin->fin_ifp == nh->nh_ifp);
937 }
938
939
940 /*
941 * return the first IP Address associated with an interface
942 */
943 int
944 ipf_ifpaddr(ipf_main_softc_t *softc, int v, int atype, void *ifptr,
945 i6addr_t *inp, i6addr_t *inpmask)
946 {
947 #ifdef USE_INET6
948 struct in6_addr *ia6 = NULL;
949 #endif
950 struct sockaddr *sock, *mask;
951 struct sockaddr_in *sin;
952 struct ifaddr *ifa;
953 struct ifnet *ifp;
954
955 if ((ifptr == NULL) || (ifptr == (void *)-1))
956 return (-1);
957
958 sin = NULL;
959 ifp = ifptr;
960
961 if (v == 4)
962 inp->in4.s_addr = 0;
963 #ifdef USE_INET6
964 else if (v == 6)
965 bzero((char *)inp, sizeof(*inp));
966 #endif
967 ifa = CK_STAILQ_FIRST(&ifp->if_addrhead);
968
969 sock = ifa->ifa_addr;
970 while (sock != NULL && ifa != NULL) {
971 sin = (struct sockaddr_in *)sock;
972 if ((v == 4) && (sin->sin_family == AF_INET))
973 break;
974 #ifdef USE_INET6
975 if ((v == 6) && (sin->sin_family == AF_INET6)) {
976 ia6 = &((struct sockaddr_in6 *)sin)->sin6_addr;
977 if (!IN6_IS_ADDR_LINKLOCAL(ia6) &&
978 !IN6_IS_ADDR_LOOPBACK(ia6))
979 break;
980 }
981 #endif
982 ifa = CK_STAILQ_NEXT(ifa, ifa_link);
983 if (ifa != NULL)
984 sock = ifa->ifa_addr;
985 }
986
987 if (ifa == NULL || sin == NULL)
988 return (-1);
989
990 mask = ifa->ifa_netmask;
991 if (atype == FRI_BROADCAST)
992 sock = ifa->ifa_broadaddr;
993 else if (atype == FRI_PEERADDR)
994 sock = ifa->ifa_dstaddr;
995
996 if (sock == NULL)
997 return (-1);
998
999 #ifdef USE_INET6
1000 if (v == 6) {
1001 return (ipf_ifpfillv6addr(atype, (struct sockaddr_in6 *)sock,
1002 (struct sockaddr_in6 *)mask,
1003 inp, inpmask));
1004 }
1005 #endif
1006 return (ipf_ifpfillv4addr(atype, (struct sockaddr_in *)sock,
1007 (struct sockaddr_in *)mask,
1008 &inp->in4, &inpmask->in4));
1009 }
1010
1011
1012 u_32_t
1013 ipf_newisn(fin)
1014 fr_info_t *fin;
1015 {
1016 u_32_t newiss;
1017 newiss = arc4random();
1018 return (newiss);
1019 }
1020
1021
1022 int
1023 ipf_checkv4sum(fr_info_t *fin)
1024 {
1025 #ifdef CSUM_DATA_VALID
1026 int manual = 0;
1027 u_short sum;
1028 ip_t *ip;
1029 mb_t *m;
1030
1031 if ((fin->fin_flx & FI_NOCKSUM) != 0)
1032 return (0);
1033
1034 if ((fin->fin_flx & FI_SHORT) != 0)
1035 return (1);
1036
1037 if (fin->fin_cksum != FI_CK_NEEDED)
1038 return (fin->fin_cksum > FI_CK_NEEDED) ? 0 : -1;
1039
1040 m = fin->fin_m;
1041 if (m == NULL) {
1042 manual = 1;
1043 goto skipauto;
1044 }
1045 ip = fin->fin_ip;
1046
1047 if ((m->m_pkthdr.csum_flags & (CSUM_IP_CHECKED|CSUM_IP_VALID)) ==
1048 CSUM_IP_CHECKED) {
1049 fin->fin_cksum = FI_CK_BAD;
1050 fin->fin_flx |= FI_BAD;
1051 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));
1052 return (-1);
1053 }
1054 if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) {
1055 /* Depending on the driver, UDP may have zero checksum */
1056 if (fin->fin_p == IPPROTO_UDP && (fin->fin_flx &
1057 (FI_FRAG|FI_SHORT|FI_BAD)) == 0) {
1058 udphdr_t *udp = fin->fin_dp;
1059 if (udp->uh_sum == 0) {
1060 /*
1061 * we're good no matter what the hardware
1062 * checksum flags and csum_data say (handling
1063 * of csum_data for zero UDP checksum is not
1064 * consistent across all drivers)
1065 */
1066 fin->fin_cksum = 1;
1067 return (0);
1068 }
1069 }
1070
1071 if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR)
1072 sum = m->m_pkthdr.csum_data;
1073 else
1074 sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr,
1075 htonl(m->m_pkthdr.csum_data +
1076 fin->fin_dlen + fin->fin_p));
1077 sum ^= 0xffff;
1078 if (sum != 0) {
1079 fin->fin_cksum = FI_CK_BAD;
1080 fin->fin_flx |= FI_BAD;
1081 DT2(ipf_fi_bad_checkv4sum_sum, fr_info_t *, fin, u_int, sum);
1082 } else {
1083 fin->fin_cksum = FI_CK_SUMOK;
1084 return (0);
1085 }
1086 } else {
1087 if (m->m_pkthdr.csum_flags == CSUM_DELAY_DATA) {
1088 fin->fin_cksum = FI_CK_L4FULL;
1089 return (0);
1090 } else if (m->m_pkthdr.csum_flags == CSUM_TCP ||
1091 m->m_pkthdr.csum_flags == CSUM_UDP ||
1092 m->m_pkthdr.csum_flags == CSUM_IP) {
1093 fin->fin_cksum = FI_CK_L4PART;
1094 return (0);
1095 } else {
1096 manual = 1;
1097 }
1098 }
1099 skipauto:
1100 if (manual != 0) {
1101 if (ipf_checkl4sum(fin) == -1) {
1102 fin->fin_flx |= FI_BAD;
1103 DT2(ipf_fi_bad_checkv4sum_manual, fr_info_t *, fin, u_int, manual);
1104 return (-1);
1105 }
1106 }
1107 #else
1108 if (ipf_checkl4sum(fin) == -1) {
1109 fin->fin_flx |= FI_BAD;
1110 DT2(ipf_fi_bad_checkv4sum_checkl4sum, fr_info_t *, fin, u_int, -1);
1111 return (-1);
1112 }
1113 #endif
1114 return (0);
1115 }
1116
1117
1118 #ifdef USE_INET6
1119 int
1120 ipf_checkv6sum(fr_info_t *fin)
1121 {
1122 if ((fin->fin_flx & FI_NOCKSUM) != 0) {
1123 DT(ipf_checkv6sum_fi_nocksum);
1124 return (0);
1125 }
1126
1127 if ((fin->fin_flx & FI_SHORT) != 0) {
1128 DT(ipf_checkv6sum_fi_short);
1129 return (1);
1130 }
1131
1132 if (fin->fin_cksum != FI_CK_NEEDED) {
1133 DT(ipf_checkv6sum_fi_ck_needed);
1134 return (fin->fin_cksum > FI_CK_NEEDED) ? 0 : -1;
1135 }
1136
1137 if (ipf_checkl4sum(fin) == -1) {
1138 fin->fin_flx |= FI_BAD;
1139 DT2(ipf_fi_bad_checkv6sum_checkl4sum, fr_info_t *, fin, u_int, -1);
1140 return (-1);
1141 }
1142 return (0);
1143 }
1144 #endif /* USE_INET6 */
1145
1146
1147 size_t
1148 mbufchainlen(struct mbuf *m0)
1149 {
1150 size_t len;
1151
1152 if ((m0->m_flags & M_PKTHDR) != 0) {
1153 len = m0->m_pkthdr.len;
1154 } else {
1155 struct mbuf *m;
1156
1157 for (m = m0, len = 0; m != NULL; m = m->m_next)
1158 len += m->m_len;
1159 }
1160 return (len);
1161 }
1162
1163
1164 /* ------------------------------------------------------------------------ */
1165 /* Function: ipf_pullup */
1166 /* Returns: NULL == pullup failed, else pointer to protocol header */
1167 /* Parameters: xmin(I)- pointer to buffer where data packet starts */
1168 /* fin(I) - pointer to packet information */
1169 /* len(I) - number of bytes to pullup */
1170 /* */
1171 /* Attempt to move at least len bytes (from the start of the buffer) into a */
1172 /* single buffer for ease of access. Operating system native functions are */
1173 /* used to manage buffers - if necessary. If the entire packet ends up in */
1174 /* a single buffer, set the FI_COALESCE flag even though ipf_coalesce() has */
1175 /* not been called. Both fin_ip and fin_dp are updated before exiting _IF_ */
1176 /* and ONLY if the pullup succeeds. */
1177 /* */
1178 /* We assume that 'xmin' is a pointer to a buffer that is part of the chain */
1179 /* of buffers that starts at *fin->fin_mp. */
1180 /* ------------------------------------------------------------------------ */
1181 void *
1182 ipf_pullup(mb_t *xmin, fr_info_t *fin, int len)
1183 {
1184 int dpoff, ipoff;
1185 mb_t *m = xmin;
1186 char *ip;
1187
1188 if (m == NULL)
1189 return (NULL);
1190
1191 ip = (char *)fin->fin_ip;
1192 if ((fin->fin_flx & FI_COALESCE) != 0)
1193 return (ip);
1194
1195 ipoff = fin->fin_ipoff;
1196 if (fin->fin_dp != NULL)
1197 dpoff = (char *)fin->fin_dp - (char *)ip;
1198 else
1199 dpoff = 0;
1200
1201 if (M_LEN(m) < len) {
1202 mb_t *n = *fin->fin_mp;
1203 /*
1204 * Assume that M_PKTHDR is set and just work with what is left
1205 * rather than check..
1206 * Should not make any real difference, anyway.
1207 */
1208 if (m != n) {
1209 /*
1210 * Record the mbuf that points to the mbuf that we're
1211 * about to go to work on so that we can update the
1212 * m_next appropriately later.
1213 */
1214 for (; n->m_next != m; n = n->m_next)
1215 ;
1216 } else {
1217 n = NULL;
1218 }
1219
1220 #ifdef MHLEN
1221 if (len > MHLEN)
1222 #else
1223 if (len > MLEN)
1224 #endif
1225 {
1226 #ifdef HAVE_M_PULLDOWN
1227 if (m_pulldown(m, 0, len, NULL) == NULL)
1228 m = NULL;
1229 #else
1230 FREE_MB_T(*fin->fin_mp);
1231 m = NULL;
1232 n = NULL;
1233 #endif
1234 } else
1235 {
1236 m = m_pullup(m, len);
1237 }
1238 if (n != NULL)
1239 n->m_next = m;
1240 if (m == NULL) {
1241 /*
1242 * When n is non-NULL, it indicates that m pointed to
1243 * a sub-chain (tail) of the mbuf and that the head
1244 * of this chain has not yet been free'd.
1245 */
1246 if (n != NULL) {
1247 FREE_MB_T(*fin->fin_mp);
1248 }
1249
1250 *fin->fin_mp = NULL;
1251 fin->fin_m = NULL;
1252 return (NULL);
1253 }
1254
1255 if (n == NULL)
1256 *fin->fin_mp = m;
1257
1258 while (M_LEN(m) == 0) {
1259 m = m->m_next;
1260 }
1261 fin->fin_m = m;
1262 ip = MTOD(m, char *) + ipoff;
1263
1264 fin->fin_ip = (ip_t *)ip;
1265 if (fin->fin_dp != NULL)
1266 fin->fin_dp = (char *)fin->fin_ip + dpoff;
1267 if (fin->fin_fraghdr != NULL)
1268 fin->fin_fraghdr = (char *)ip +
1269 ((char *)fin->fin_fraghdr -
1270 (char *)fin->fin_ip);
1271 }
1272
1273 if (len == fin->fin_plen)
1274 fin->fin_flx |= FI_COALESCE;
1275 return (ip);
1276 }
1277
1278
1279 int
1280 ipf_inject(fr_info_t *fin, mb_t *m)
1281 {
1282 struct epoch_tracker et;
1283 int error = 0;
1284
1285 NET_EPOCH_ENTER(et);
1286 if (fin->fin_out == 0) {
1287 netisr_dispatch(NETISR_IP, m);
1288 } else {
1289 fin->fin_ip->ip_len = ntohs(fin->fin_ip->ip_len);
1290 fin->fin_ip->ip_off = ntohs(fin->fin_ip->ip_off);
1291 error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL);
1292 }
1293 NET_EPOCH_EXIT(et);
1294
1295 return (error);
1296 }
1297
1298 VNET_DEFINE_STATIC(pfil_hook_t, ipf_inet_hook);
1299 VNET_DEFINE_STATIC(pfil_hook_t, ipf_inet6_hook);
1300 #define V_ipf_inet_hook VNET(ipf_inet_hook)
1301 #define V_ipf_inet6_hook VNET(ipf_inet6_hook)
1302
1303 int ipf_pfil_unhook(void) {
1304
1305 pfil_remove_hook(V_ipf_inet_hook);
1306
1307 #ifdef USE_INET6
1308 pfil_remove_hook(V_ipf_inet6_hook);
1309 #endif
1310
1311 return (0);
1312 }
1313
1314 int ipf_pfil_hook(void) {
1315 struct pfil_hook_args pha;
1316 struct pfil_link_args pla;
1317 int error, error6;
1318
1319 pha.pa_version = PFIL_VERSION;
1320 pha.pa_flags = PFIL_IN | PFIL_OUT;
1321 pha.pa_modname = "ipfilter";
1322 pha.pa_rulname = "default-ip4";
1323 pha.pa_func = ipf_check_wrapper;
1324 pha.pa_ruleset = NULL;
1325 pha.pa_type = PFIL_TYPE_IP4;
1326 V_ipf_inet_hook = pfil_add_hook(&pha);
1327
1328 #ifdef USE_INET6
1329 pha.pa_rulname = "default-ip6";
1330 pha.pa_func = ipf_check_wrapper6;
1331 pha.pa_type = PFIL_TYPE_IP6;
1332 V_ipf_inet6_hook = pfil_add_hook(&pha);
1333 #endif
1334
1335 pla.pa_version = PFIL_VERSION;
1336 pla.pa_flags = PFIL_IN | PFIL_OUT |
1337 PFIL_HEADPTR | PFIL_HOOKPTR;
1338 pla.pa_head = V_inet_pfil_head;
1339 pla.pa_hook = V_ipf_inet_hook;
1340 error = pfil_link(&pla);
1341
1342 error6 = 0;
1343 #ifdef USE_INET6
1344 pla.pa_head = V_inet6_pfil_head;
1345 pla.pa_hook = V_ipf_inet6_hook;
1346 error6 = pfil_link(&pla);
1347 #endif
1348
1349 if (error || error6)
1350 error = ENODEV;
1351 else
1352 error = 0;
1353
1354 return (error);
1355 }
1356
1357 void
1358 ipf_event_reg(void)
1359 {
1360 V_ipf_arrivetag = EVENTHANDLER_REGISTER(ifnet_arrival_event, \
1361 ipf_ifevent, NULL, \
1362 EVENTHANDLER_PRI_ANY);
1363 V_ipf_departtag = EVENTHANDLER_REGISTER(ifnet_departure_event, \
1364 ipf_ifevent, NULL, \
1365 EVENTHANDLER_PRI_ANY);
1366 #if 0
1367 V_ipf_clonetag = EVENTHANDLER_REGISTER(if_clone_event, ipf_ifevent, \
1368 NULL, EVENTHANDLER_PRI_ANY);
1369 #endif
1370 }
1371
1372 void
1373 ipf_event_dereg(void)
1374 {
1375 if (V_ipf_arrivetag != NULL) {
1376 EVENTHANDLER_DEREGISTER(ifnet_arrival_event, V_ipf_arrivetag);
1377 }
1378 if (V_ipf_departtag != NULL) {
1379 EVENTHANDLER_DEREGISTER(ifnet_departure_event, V_ipf_departtag);
1380 }
1381 #if 0
1382 if (V_ipf_clonetag != NULL) {
1383 EVENTHANDLER_DEREGISTER(if_clone_event, V_ipf_clonetag);
1384 }
1385 #endif
1386 }
1387
1388
1389 u_32_t
1390 ipf_random(void)
1391 {
1392 return (arc4random());
1393 }
1394
1395
1396 u_int
1397 ipf_pcksum(fr_info_t *fin, int hlen, u_int sum)
1398 {
1399 struct mbuf *m;
1400 u_int sum2;
1401 int off;
1402
1403 m = fin->fin_m;
1404 off = (char *)fin->fin_dp - (char *)fin->fin_ip;
1405 m->m_data += hlen;
1406 m->m_len -= hlen;
1407 sum2 = in_cksum(fin->fin_m, fin->fin_plen - off);
1408 m->m_len += hlen;
1409 m->m_data -= hlen;
1410
1411 /*
1412 * Both sum and sum2 are partial sums, so combine them together.
1413 */
1414 sum += ~sum2 & 0xffff;
1415 while (sum > 0xffff)
1416 sum = (sum & 0xffff) + (sum >> 16);
1417 sum2 = ~sum & 0xffff;
1418 return (sum2);
1419 }
1420
1421 #ifdef USE_INET6
1422 u_int
1423 ipf_pcksum6(struct mbuf *m, ip6_t *ip6, u_int32_t off, u_int32_t len)
1424 {
1425 #ifdef _KERNEL
1426 int sum;
1427
1428 if (m->m_len < sizeof(struct ip6_hdr)) {
1429 return (0xffff);
1430 }
1431
1432 sum = in6_cksum(m, ip6->ip6_nxt, off, len);
1433 return (sum);
1434 #else
1435 u_short *sp;
1436 u_int sum;
1437
1438 sp = (u_short *)&ip6->ip6_src;
1439 sum = *sp++; /* ip6_src */
1440 sum += *sp++;
1441 sum += *sp++;
1442 sum += *sp++;
1443 sum += *sp++;
1444 sum += *sp++;
1445 sum += *sp++;
1446 sum += *sp++;
1447 sum += *sp++; /* ip6_dst */
1448 sum += *sp++;
1449 sum += *sp++;
1450 sum += *sp++;
1451 sum += *sp++;
1452 sum += *sp++;
1453 sum += *sp++;
1454 sum += *sp++;
1455 return (ipf_pcksum(fin, off, sum));
1456 #endif
1457 }
1458 #endif
1459
1460 void
1461 ipf_fbsd_kenv_get(ipf_main_softc_t *softc)
1462 {
1463 TUNABLE_INT_FETCH("net.inet.ipf.large_nat",
1464 &softc->ipf_large_nat);
1465 }
Cache object: 1da565a7c667160e0a4dbfa8047dc0e6
|