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