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