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