ip_fil_freebsd.c revision 298030
1145516Sdarrenr/* $FreeBSD: head/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c 298030 2016-04-15 03:43:16Z cy $ */ 2145516Sdarrenr 3145516Sdarrenr/* 4255332Scy * Copyright (C) 2012 by Darren Reed. 5145516Sdarrenr * 6145516Sdarrenr * See the IPFILTER.LICENCE file for details on licencing. 7145516Sdarrenr */ 8145516Sdarrenr#if !defined(lint) 9145516Sdarrenrstatic const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed"; 10255332Scystatic const char rcsid[] = "@(#)$Id$"; 11145516Sdarrenr#endif 12145516Sdarrenr 13145516Sdarrenr#if defined(KERNEL) || defined(_KERNEL) 14145516Sdarrenr# undef KERNEL 15145516Sdarrenr# undef _KERNEL 16145516Sdarrenr# define KERNEL 1 17145516Sdarrenr# define _KERNEL 1 18145516Sdarrenr#endif 19145516Sdarrenr#if defined(__FreeBSD_version) && (__FreeBSD_version >= 400000) && \ 20145516Sdarrenr !defined(KLD_MODULE) && !defined(IPFILTER_LKM) 21145516Sdarrenr# include "opt_inet6.h" 22145516Sdarrenr#endif 23145516Sdarrenr#if defined(__FreeBSD_version) && (__FreeBSD_version >= 440000) && \ 24145516Sdarrenr !defined(KLD_MODULE) && !defined(IPFILTER_LKM) 25145516Sdarrenr# include "opt_random_ip_id.h" 26145516Sdarrenr#endif 27145516Sdarrenr#include <sys/param.h> 28145516Sdarrenr#include <sys/errno.h> 29145516Sdarrenr#include <sys/types.h> 30145516Sdarrenr#include <sys/file.h> 31145516Sdarrenr# include <sys/fcntl.h> 32145516Sdarrenr# include <sys/filio.h> 33145516Sdarrenr#include <sys/time.h> 34145516Sdarrenr#include <sys/systm.h> 35145516Sdarrenr# include <sys/dirent.h> 36274744Srodrigc#if defined(__FreeBSD_version) && (__FreeBSD_version >= 800000) 37274744Srodrigc#include <sys/jail.h> 38274744Srodrigc#endif 39295126Sglebius# include <sys/malloc.h> 40255332Scy# include <sys/mbuf.h> 41255332Scy# include <sys/sockopt.h> 42145516Sdarrenr#if !defined(__hpux) 43145516Sdarrenr# include <sys/mbuf.h> 44145516Sdarrenr#endif 45145516Sdarrenr#include <sys/socket.h> 46170268Sdarrenr# include <sys/selinfo.h> 47195699Srwatson# include <netinet/tcp_var.h> 48145516Sdarrenr 49145516Sdarrenr#include <net/if.h> 50145516Sdarrenr# include <net/if_var.h> 51170268Sdarrenr# include <net/netisr.h> 52145516Sdarrenr#include <net/route.h> 53145516Sdarrenr#include <netinet/in.h> 54293628Smelifaro#include <netinet/in_fib.h> 55145516Sdarrenr#include <netinet/in_var.h> 56145516Sdarrenr#include <netinet/in_systm.h> 57145516Sdarrenr#include <netinet/ip.h> 58145516Sdarrenr#include <netinet/ip_var.h> 59145516Sdarrenr#include <netinet/tcp.h> 60274744Srodrigc#if defined(__FreeBSD_version) && (__FreeBSD_version >= 800000) 61274744Srodrigc#include <net/vnet.h> 62274744Srodrigc#else 63274744Srodrigc#define CURVNET_SET(arg) 64274744Srodrigc#define CURVNET_RESTORE() 65274744Srodrigc#endif 66145516Sdarrenr#if defined(__osf__) 67145516Sdarrenr# include <netinet/tcp_timer.h> 68145516Sdarrenr#endif 69145516Sdarrenr#include <netinet/udp.h> 70145516Sdarrenr#include <netinet/tcpip.h> 71145516Sdarrenr#include <netinet/ip_icmp.h> 72145516Sdarrenr#include "netinet/ip_compat.h" 73145516Sdarrenr#ifdef USE_INET6 74145516Sdarrenr# include <netinet/icmp6.h> 75145516Sdarrenr#endif 76145516Sdarrenr#include "netinet/ip_fil.h" 77145516Sdarrenr#include "netinet/ip_nat.h" 78145516Sdarrenr#include "netinet/ip_frag.h" 79145516Sdarrenr#include "netinet/ip_state.h" 80145516Sdarrenr#include "netinet/ip_proxy.h" 81145516Sdarrenr#include "netinet/ip_auth.h" 82145516Sdarrenr#include "netinet/ip_sync.h" 83255332Scy#include "netinet/ip_lookup.h" 84255332Scy#include "netinet/ip_dstlist.h" 85145516Sdarrenr#ifdef IPFILTER_SCAN 86145516Sdarrenr#include "netinet/ip_scan.h" 87145516Sdarrenr#endif 88145516Sdarrenr#include "netinet/ip_pool.h" 89145516Sdarrenr# include <sys/malloc.h> 90145516Sdarrenr#include <sys/kernel.h> 91145516Sdarrenr#ifdef CSUM_DATA_VALID 92145516Sdarrenr#include <machine/in_cksum.h> 93145516Sdarrenr#endif 94145516Sdarrenrextern int ip_optcopy __P((struct ip *, struct ip *)); 95145516Sdarrenr 96145516Sdarrenr 97145516Sdarrenr# ifdef IPFILTER_M_IPFILTER 98151897SrwatsonMALLOC_DEFINE(M_IPFILTER, "ipfilter", "IP Filter packet filter data structures"); 99145516Sdarrenr# endif 100145516Sdarrenr 101145516Sdarrenr 102255332Scystatic int (*ipf_savep) __P((void *, ip_t *, int, void *, int, struct mbuf **)); 103255332Scystatic int ipf_send_ip __P((fr_info_t *, mb_t *)); 104255332Scystatic void ipf_timer_func __P((void *arg)); 105145516Sdarrenrint ipf_locks_done = 0; 106145516Sdarrenr 107255332Scyipf_main_softc_t ipfmain; 108145516Sdarrenr 109145516Sdarrenr# include <sys/conf.h> 110145516Sdarrenr# if defined(NETBSD_PF) 111145516Sdarrenr# include <net/pfil.h> 112255332Scy# endif /* NETBSD_PF */ 113145516Sdarrenr/* 114255332Scy * We provide the ipf_checkp name just to minimize changes later. 115145516Sdarrenr */ 116255332Scyint (*ipf_checkp) __P((void *, ip_t *ip, int hlen, void *ifp, int out, mb_t **mp)); 117145516Sdarrenr 118145516Sdarrenr 119153876Sguidostatic eventhandler_tag ipf_arrivetag, ipf_departtag, ipf_clonetag; 120153876Sguido 121153876Sguidostatic void ipf_ifevent(void *arg); 122153876Sguido 123153876Sguidostatic void ipf_ifevent(arg) 124255332Scy void *arg; 125153876Sguido{ 126255332Scy ipf_sync(arg, NULL); 127153876Sguido} 128153876Sguido 129153876Sguido 130145516Sdarrenr 131145516Sdarrenrstatic int 132255332Scyipf_check_wrapper(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir) 133145516Sdarrenr{ 134145516Sdarrenr struct ip *ip = mtod(*mp, struct ip *); 135255332Scy int rv; 136255332Scy 137255332Scy /* 138255332Scy * IPFilter expects evreything in network byte order 139255332Scy */ 140255332Scy#if (__FreeBSD_version < 1000019) 141255332Scy ip->ip_len = htons(ip->ip_len); 142255332Scy ip->ip_off = htons(ip->ip_off); 143255332Scy#endif 144255332Scy rv = ipf_check(&ipfmain, ip, ip->ip_hl << 2, ifp, (dir == PFIL_OUT), 145255332Scy mp); 146255332Scy#if (__FreeBSD_version < 1000019) 147255332Scy if ((rv == 0) && (*mp != NULL)) { 148255332Scy ip = mtod(*mp, struct ip *); 149255332Scy ip->ip_len = ntohs(ip->ip_len); 150255332Scy ip->ip_off = ntohs(ip->ip_off); 151255332Scy } 152255332Scy#endif 153255332Scy return rv; 154145516Sdarrenr} 155145516Sdarrenr 156145516Sdarrenr# ifdef USE_INET6 157145516Sdarrenr# include <netinet/ip6.h> 158145516Sdarrenr 159145516Sdarrenrstatic int 160255332Scyipf_check_wrapper6(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir) 161145516Sdarrenr{ 162255332Scy return (ipf_check(&ipfmain, mtod(*mp, struct ip *), 163255332Scy sizeof(struct ip6_hdr), ifp, (dir == PFIL_OUT), mp)); 164145516Sdarrenr} 165145516Sdarrenr# endif 166145516Sdarrenr#if defined(IPFILTER_LKM) 167255332Scyint ipf_identify(s) 168255332Scy char *s; 169145516Sdarrenr{ 170145516Sdarrenr if (strcmp(s, "ipl") == 0) 171145516Sdarrenr return 1; 172145516Sdarrenr return 0; 173145516Sdarrenr} 174145516Sdarrenr#endif /* IPFILTER_LKM */ 175145516Sdarrenr 176145516Sdarrenr 177255332Scystatic void 178255332Scyipf_timer_func(arg) 179255332Scy void *arg; 180145516Sdarrenr{ 181255332Scy ipf_main_softc_t *softc = arg; 182255332Scy SPL_INT(s); 183255332Scy 184255332Scy SPL_NET(s); 185255332Scy READ_ENTER(&softc->ipf_global); 186255332Scy 187255332Scy if (softc->ipf_running > 0) 188255332Scy ipf_slowtimer(softc); 189255332Scy 190255332Scy if (softc->ipf_running == -1 || softc->ipf_running == 1) { 191255755Scy#if 0 192255332Scy softc->ipf_slow_ch = timeout(ipf_timer_func, softc, hz/2); 193255332Scy#endif 194283291Sjkim callout_init(&softc->ipf_slow_ch, 1); 195255755Scy callout_reset(&softc->ipf_slow_ch, 196255755Scy (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT, 197255755Scy ipf_timer_func, softc); 198255332Scy } 199255332Scy RWLOCK_EXIT(&softc->ipf_global); 200255332Scy SPL_X(s); 201255332Scy} 202255332Scy 203255332Scy 204255332Scyint 205255332Scyipfattach(softc) 206255332Scy ipf_main_softc_t *softc; 207255332Scy{ 208145516Sdarrenr#ifdef USE_SPL 209145516Sdarrenr int s; 210145516Sdarrenr#endif 211145516Sdarrenr 212145516Sdarrenr SPL_NET(s); 213255332Scy if (softc->ipf_running > 0) { 214145516Sdarrenr SPL_X(s); 215145516Sdarrenr return EBUSY; 216145516Sdarrenr } 217145516Sdarrenr 218255332Scy if (ipf_init_all(softc) < 0) { 219145516Sdarrenr SPL_X(s); 220145516Sdarrenr return EIO; 221145516Sdarrenr } 222145516Sdarrenr 223145516Sdarrenr 224255332Scy if (ipf_checkp != ipf_check) { 225255332Scy ipf_savep = ipf_checkp; 226255332Scy ipf_checkp = ipf_check; 227145516Sdarrenr } 228145516Sdarrenr 229255332Scy bzero((char *)ipfmain.ipf_selwait, sizeof(ipfmain.ipf_selwait)); 230255332Scy softc->ipf_running = 1; 231145516Sdarrenr 232255332Scy if (softc->ipf_control_forwarding & 1) 233181803Sbz V_ipforwarding = 1; 234145516Sdarrenr 235145516Sdarrenr SPL_X(s); 236255755Scy#if 0 237255332Scy softc->ipf_slow_ch = timeout(ipf_timer_func, softc, 238255332Scy (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT); 239255755Scy#endif 240283291Sjkim callout_init(&softc->ipf_slow_ch, 1); 241255755Scy callout_reset(&softc->ipf_slow_ch, (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT, 242255755Scy ipf_timer_func, softc); 243145516Sdarrenr return 0; 244145516Sdarrenr} 245145516Sdarrenr 246145516Sdarrenr 247145516Sdarrenr/* 248145516Sdarrenr * Disable the filter by removing the hooks from the IP input/output 249145516Sdarrenr * stream. 250145516Sdarrenr */ 251255332Scyint 252255332Scyipfdetach(softc) 253255332Scy ipf_main_softc_t *softc; 254145516Sdarrenr{ 255145516Sdarrenr#ifdef USE_SPL 256145516Sdarrenr int s; 257145516Sdarrenr#endif 258255332Scy 259255332Scy if (softc->ipf_control_forwarding & 2) 260181803Sbz V_ipforwarding = 0; 261145516Sdarrenr 262145516Sdarrenr SPL_NET(s); 263145516Sdarrenr 264255755Scy#if 0 265255332Scy if (softc->ipf_slow_ch.callout != NULL) 266255332Scy untimeout(ipf_timer_func, softc, softc->ipf_slow_ch); 267255332Scy bzero(&softc->ipf_slow, sizeof(softc->ipf_slow)); 268255755Scy#endif 269255755Scy callout_drain(&softc->ipf_slow_ch); 270145516Sdarrenr 271145516Sdarrenr#ifndef NETBSD_PF 272255332Scy if (ipf_checkp != NULL) 273255332Scy ipf_checkp = ipf_savep; 274255332Scy ipf_savep = NULL; 275145516Sdarrenr#endif 276145516Sdarrenr 277255332Scy ipf_fini_all(softc); 278145516Sdarrenr 279255332Scy softc->ipf_running = -2; 280145516Sdarrenr 281145516Sdarrenr SPL_X(s); 282145516Sdarrenr 283145516Sdarrenr return 0; 284145516Sdarrenr} 285145516Sdarrenr 286145516Sdarrenr 287145516Sdarrenr/* 288145516Sdarrenr * Filter ioctl interface. 289145516Sdarrenr */ 290255332Scyint 291255332Scyipfioctl(dev, cmd, data, mode 292145516Sdarrenr, p) 293255332Scy struct thread *p; 294192895Sjamie# define p_cred td_ucred 295170268Sdarrenr# define p_uid td_ucred->cr_ruid 296255332Scy struct cdev *dev; 297255332Scy ioctlcmd_t cmd; 298255332Scy caddr_t data; 299255332Scy int mode; 300145516Sdarrenr{ 301170268Sdarrenr int error = 0, unit = 0; 302170268Sdarrenr SPL_INT(s); 303145516Sdarrenr 304255332Scy#if (BSD >= 199306) 305255332Scy if (securelevel_ge(p->p_cred, 3) && (mode & FWRITE)) 306255332Scy { 307255332Scy ipfmain.ipf_interror = 130001; 308145516Sdarrenr return EPERM; 309255332Scy } 310145516Sdarrenr#endif 311145516Sdarrenr 312145516Sdarrenr unit = GET_MINOR(dev); 313255332Scy if ((IPL_LOGMAX < unit) || (unit < 0)) { 314255332Scy ipfmain.ipf_interror = 130002; 315145516Sdarrenr return ENXIO; 316255332Scy } 317145516Sdarrenr 318255332Scy if (ipfmain.ipf_running <= 0) { 319255332Scy if (unit != IPL_LOGIPF && cmd != SIOCIPFINTERROR) { 320255332Scy ipfmain.ipf_interror = 130003; 321145516Sdarrenr return EIO; 322255332Scy } 323145516Sdarrenr if (cmd != SIOCIPFGETNEXT && cmd != SIOCIPFGET && 324173181Sdarrenr cmd != SIOCIPFSET && cmd != SIOCFRENB && 325255332Scy cmd != SIOCGETFS && cmd != SIOCGETFF && 326255332Scy cmd != SIOCIPFINTERROR) { 327255332Scy ipfmain.ipf_interror = 130004; 328145516Sdarrenr return EIO; 329255332Scy } 330145516Sdarrenr } 331145516Sdarrenr 332145516Sdarrenr SPL_NET(s); 333145516Sdarrenr 334274744Srodrigc CURVNET_SET(TD_TO_VNET(p)); 335255332Scy error = ipf_ioctlswitch(&ipfmain, unit, data, cmd, mode, p->p_uid, p); 336274744Srodrigc CURVNET_RESTORE(); 337145516Sdarrenr if (error != -1) { 338145516Sdarrenr SPL_X(s); 339145516Sdarrenr return error; 340145516Sdarrenr } 341145516Sdarrenr 342145516Sdarrenr SPL_X(s); 343161356Sguido 344145516Sdarrenr return error; 345145516Sdarrenr} 346145516Sdarrenr 347145516Sdarrenr 348145516Sdarrenr/* 349255332Scy * ipf_send_reset - this could conceivably be a call to tcp_respond(), but that 350145516Sdarrenr * requires a large amount of setting up and isn't any more efficient. 351145516Sdarrenr */ 352255332Scyint 353255332Scyipf_send_reset(fin) 354255332Scy fr_info_t *fin; 355145516Sdarrenr{ 356145516Sdarrenr struct tcphdr *tcp, *tcp2; 357145516Sdarrenr int tlen = 0, hlen; 358145516Sdarrenr struct mbuf *m; 359145516Sdarrenr#ifdef USE_INET6 360145516Sdarrenr ip6_t *ip6; 361145516Sdarrenr#endif 362145516Sdarrenr ip_t *ip; 363145516Sdarrenr 364145516Sdarrenr tcp = fin->fin_dp; 365145516Sdarrenr if (tcp->th_flags & TH_RST) 366145516Sdarrenr return -1; /* feedback loop */ 367145516Sdarrenr 368255332Scy if (ipf_checkl4sum(fin) == -1) 369145516Sdarrenr return -1; 370145516Sdarrenr 371145516Sdarrenr tlen = fin->fin_dlen - (TCP_OFF(tcp) << 2) + 372145516Sdarrenr ((tcp->th_flags & TH_SYN) ? 1 : 0) + 373145516Sdarrenr ((tcp->th_flags & TH_FIN) ? 1 : 0); 374145516Sdarrenr 375145516Sdarrenr#ifdef USE_INET6 376145516Sdarrenr hlen = (fin->fin_v == 6) ? sizeof(ip6_t) : sizeof(ip_t); 377145516Sdarrenr#else 378145516Sdarrenr hlen = sizeof(ip_t); 379145516Sdarrenr#endif 380145516Sdarrenr#ifdef MGETHDR 381260715Sglebius MGETHDR(m, M_NOWAIT, MT_HEADER); 382145516Sdarrenr#else 383260715Sglebius MGET(m, M_NOWAIT, MT_HEADER); 384145516Sdarrenr#endif 385145516Sdarrenr if (m == NULL) 386145516Sdarrenr return -1; 387145516Sdarrenr if (sizeof(*tcp2) + hlen > MLEN) { 388276750Srwatson if (!(MCLGET(m, M_NOWAIT))) { 389145516Sdarrenr FREE_MB_T(m); 390145516Sdarrenr return -1; 391145516Sdarrenr } 392145516Sdarrenr } 393145516Sdarrenr 394145516Sdarrenr m->m_len = sizeof(*tcp2) + hlen; 395145516Sdarrenr#if (BSD >= 199103) 396145516Sdarrenr m->m_data += max_linkhdr; 397145516Sdarrenr m->m_pkthdr.len = m->m_len; 398145516Sdarrenr m->m_pkthdr.rcvif = (struct ifnet *)0; 399145516Sdarrenr#endif 400145516Sdarrenr ip = mtod(m, struct ip *); 401145516Sdarrenr bzero((char *)ip, hlen); 402145516Sdarrenr#ifdef USE_INET6 403145516Sdarrenr ip6 = (ip6_t *)ip; 404145516Sdarrenr#endif 405145516Sdarrenr tcp2 = (struct tcphdr *)((char *)ip + hlen); 406145516Sdarrenr tcp2->th_sport = tcp->th_dport; 407145516Sdarrenr tcp2->th_dport = tcp->th_sport; 408145516Sdarrenr 409145516Sdarrenr if (tcp->th_flags & TH_ACK) { 410145516Sdarrenr tcp2->th_seq = tcp->th_ack; 411145516Sdarrenr tcp2->th_flags = TH_RST; 412145516Sdarrenr tcp2->th_ack = 0; 413145516Sdarrenr } else { 414145516Sdarrenr tcp2->th_seq = 0; 415145516Sdarrenr tcp2->th_ack = ntohl(tcp->th_seq); 416145516Sdarrenr tcp2->th_ack += tlen; 417145516Sdarrenr tcp2->th_ack = htonl(tcp2->th_ack); 418145516Sdarrenr tcp2->th_flags = TH_RST|TH_ACK; 419145516Sdarrenr } 420145516Sdarrenr TCP_X2_A(tcp2, 0); 421145516Sdarrenr TCP_OFF_A(tcp2, sizeof(*tcp2) >> 2); 422145516Sdarrenr tcp2->th_win = tcp->th_win; 423145516Sdarrenr tcp2->th_sum = 0; 424145516Sdarrenr tcp2->th_urp = 0; 425145516Sdarrenr 426145516Sdarrenr#ifdef USE_INET6 427145516Sdarrenr if (fin->fin_v == 6) { 428145516Sdarrenr ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; 429145516Sdarrenr ip6->ip6_plen = htons(sizeof(struct tcphdr)); 430145516Sdarrenr ip6->ip6_nxt = IPPROTO_TCP; 431145516Sdarrenr ip6->ip6_hlim = 0; 432255332Scy ip6->ip6_src = fin->fin_dst6.in6; 433255332Scy ip6->ip6_dst = fin->fin_src6.in6; 434145516Sdarrenr tcp2->th_sum = in6_cksum(m, IPPROTO_TCP, 435145516Sdarrenr sizeof(*ip6), sizeof(*tcp2)); 436255332Scy return ipf_send_ip(fin, m); 437145516Sdarrenr } 438145516Sdarrenr#endif 439145516Sdarrenr ip->ip_p = IPPROTO_TCP; 440145516Sdarrenr ip->ip_len = htons(sizeof(struct tcphdr)); 441145516Sdarrenr ip->ip_src.s_addr = fin->fin_daddr; 442145516Sdarrenr ip->ip_dst.s_addr = fin->fin_saddr; 443145516Sdarrenr tcp2->th_sum = in_cksum(m, hlen + sizeof(*tcp2)); 444255332Scy ip->ip_len = htons(hlen + sizeof(*tcp2)); 445255332Scy return ipf_send_ip(fin, m); 446145516Sdarrenr} 447145516Sdarrenr 448145516Sdarrenr 449255332Scy/* 450255332Scy * ip_len must be in network byte order when called. 451255332Scy */ 452255332Scystatic int 453255332Scyipf_send_ip(fin, m) 454255332Scy fr_info_t *fin; 455255332Scy mb_t *m; 456145516Sdarrenr{ 457145516Sdarrenr fr_info_t fnew; 458145516Sdarrenr ip_t *ip, *oip; 459145516Sdarrenr int hlen; 460145516Sdarrenr 461145516Sdarrenr ip = mtod(m, ip_t *); 462145516Sdarrenr bzero((char *)&fnew, sizeof(fnew)); 463255332Scy fnew.fin_main_soft = fin->fin_main_soft; 464145516Sdarrenr 465145516Sdarrenr IP_V_A(ip, fin->fin_v); 466145516Sdarrenr switch (fin->fin_v) 467145516Sdarrenr { 468145516Sdarrenr case 4 : 469255332Scy oip = fin->fin_ip; 470255332Scy hlen = sizeof(*oip); 471145516Sdarrenr fnew.fin_v = 4; 472255332Scy fnew.fin_p = ip->ip_p; 473255332Scy fnew.fin_plen = ntohs(ip->ip_len); 474145516Sdarrenr IP_HL_A(ip, sizeof(*oip) >> 2); 475145516Sdarrenr ip->ip_tos = oip->ip_tos; 476145516Sdarrenr ip->ip_id = fin->fin_ip->ip_id; 477255332Scy#if defined(FreeBSD) && (__FreeBSD_version > 460000) 478255332Scy ip->ip_off = htons(path_mtu_discovery ? IP_DF : 0); 479145516Sdarrenr#else 480145516Sdarrenr ip->ip_off = 0; 481145516Sdarrenr#endif 482181803Sbz ip->ip_ttl = V_ip_defttl; 483145516Sdarrenr ip->ip_sum = 0; 484145516Sdarrenr break; 485145516Sdarrenr#ifdef USE_INET6 486145516Sdarrenr case 6 : 487145516Sdarrenr { 488145516Sdarrenr ip6_t *ip6 = (ip6_t *)ip; 489145516Sdarrenr 490145516Sdarrenr ip6->ip6_vfc = 0x60; 491145516Sdarrenr ip6->ip6_hlim = IPDEFTTL; 492145516Sdarrenr 493255332Scy hlen = sizeof(*ip6); 494255332Scy fnew.fin_p = ip6->ip6_nxt; 495145516Sdarrenr fnew.fin_v = 6; 496255332Scy fnew.fin_plen = ntohs(ip6->ip6_plen) + hlen; 497145516Sdarrenr break; 498145516Sdarrenr } 499145516Sdarrenr#endif 500145516Sdarrenr default : 501145516Sdarrenr return EINVAL; 502145516Sdarrenr } 503145516Sdarrenr#ifdef IPSEC 504145516Sdarrenr m->m_pkthdr.rcvif = NULL; 505145516Sdarrenr#endif 506145516Sdarrenr 507145516Sdarrenr fnew.fin_ifp = fin->fin_ifp; 508145516Sdarrenr fnew.fin_flx = FI_NOCKSUM; 509145516Sdarrenr fnew.fin_m = m; 510145516Sdarrenr fnew.fin_ip = ip; 511255332Scy fnew.fin_mp = &m; 512145516Sdarrenr fnew.fin_hlen = hlen; 513145516Sdarrenr fnew.fin_dp = (char *)ip + hlen; 514255332Scy (void) ipf_makefrip(hlen, ip, &fnew); 515145516Sdarrenr 516255332Scy return ipf_fastroute(m, &m, &fnew, NULL); 517145516Sdarrenr} 518145516Sdarrenr 519145516Sdarrenr 520255332Scyint 521255332Scyipf_send_icmp_err(type, fin, dst) 522255332Scy int type; 523255332Scy fr_info_t *fin; 524255332Scy int dst; 525145516Sdarrenr{ 526145516Sdarrenr int err, hlen, xtra, iclen, ohlen, avail, code; 527145516Sdarrenr struct in_addr dst4; 528145516Sdarrenr struct icmp *icmp; 529145516Sdarrenr struct mbuf *m; 530255332Scy i6addr_t dst6; 531145516Sdarrenr void *ifp; 532145516Sdarrenr#ifdef USE_INET6 533145516Sdarrenr ip6_t *ip6; 534145516Sdarrenr#endif 535145516Sdarrenr ip_t *ip, *ip2; 536145516Sdarrenr 537172776Sdarrenr if ((type < 0) || (type >= ICMP_MAXTYPE)) 538145516Sdarrenr return -1; 539145516Sdarrenr 540145516Sdarrenr code = fin->fin_icode; 541145516Sdarrenr#ifdef USE_INET6 542255332Scy#if 0 543255332Scy /* XXX Fix an off by one error: s/>/>=/ 544255332Scy was: 545255332Scy if ((code < 0) || (code > sizeof(icmptoicmp6unreach)/sizeof(int))) 546255332Scy Fix obtained from NetBSD ip_fil_netbsd.c r1.4: */ 547255332Scy#endif 548255332Scy if ((code < 0) || (code >= sizeof(icmptoicmp6unreach)/sizeof(int))) 549145516Sdarrenr return -1; 550145516Sdarrenr#endif 551145516Sdarrenr 552255332Scy if (ipf_checkl4sum(fin) == -1) 553145516Sdarrenr return -1; 554145516Sdarrenr#ifdef MGETHDR 555260715Sglebius MGETHDR(m, M_NOWAIT, MT_HEADER); 556145516Sdarrenr#else 557260715Sglebius MGET(m, M_NOWAIT, MT_HEADER); 558145516Sdarrenr#endif 559145516Sdarrenr if (m == NULL) 560145516Sdarrenr return -1; 561145516Sdarrenr avail = MHLEN; 562145516Sdarrenr 563145516Sdarrenr xtra = 0; 564145516Sdarrenr hlen = 0; 565145516Sdarrenr ohlen = 0; 566255332Scy dst4.s_addr = 0; 567145516Sdarrenr ifp = fin->fin_ifp; 568145516Sdarrenr if (fin->fin_v == 4) { 569255332Scy if ((fin->fin_p == IPPROTO_ICMP) && !(fin->fin_flx & FI_SHORT)) 570145516Sdarrenr switch (ntohs(fin->fin_data[0]) >> 8) 571145516Sdarrenr { 572145516Sdarrenr case ICMP_ECHO : 573145516Sdarrenr case ICMP_TSTAMP : 574145516Sdarrenr case ICMP_IREQ : 575145516Sdarrenr case ICMP_MASKREQ : 576145516Sdarrenr break; 577145516Sdarrenr default : 578145516Sdarrenr FREE_MB_T(m); 579145516Sdarrenr return 0; 580145516Sdarrenr } 581145516Sdarrenr 582145516Sdarrenr if (dst == 0) { 583255332Scy if (ipf_ifpaddr(&ipfmain, 4, FRI_NORMAL, ifp, 584255332Scy &dst6, NULL) == -1) { 585145516Sdarrenr FREE_MB_T(m); 586145516Sdarrenr return -1; 587145516Sdarrenr } 588255332Scy dst4 = dst6.in4; 589145516Sdarrenr } else 590145516Sdarrenr dst4.s_addr = fin->fin_daddr; 591145516Sdarrenr 592145516Sdarrenr hlen = sizeof(ip_t); 593145516Sdarrenr ohlen = fin->fin_hlen; 594255332Scy iclen = hlen + offsetof(struct icmp, icmp_ip) + ohlen; 595145516Sdarrenr if (fin->fin_hlen < fin->fin_plen) 596145516Sdarrenr xtra = MIN(fin->fin_dlen, 8); 597145516Sdarrenr else 598145516Sdarrenr xtra = 0; 599145516Sdarrenr } 600145516Sdarrenr 601145516Sdarrenr#ifdef USE_INET6 602145516Sdarrenr else if (fin->fin_v == 6) { 603145516Sdarrenr hlen = sizeof(ip6_t); 604145516Sdarrenr ohlen = sizeof(ip6_t); 605255332Scy iclen = hlen + offsetof(struct icmp, icmp_ip) + ohlen; 606145516Sdarrenr type = icmptoicmp6types[type]; 607145516Sdarrenr if (type == ICMP6_DST_UNREACH) 608145516Sdarrenr code = icmptoicmp6unreach[code]; 609145516Sdarrenr 610255332Scy if (iclen + max_linkhdr + fin->fin_plen > avail) { 611276750Srwatson if (!(MCLGET(m, M_NOWAIT))) { 612145516Sdarrenr FREE_MB_T(m); 613145516Sdarrenr return -1; 614145516Sdarrenr } 615145516Sdarrenr avail = MCLBYTES; 616145516Sdarrenr } 617255332Scy xtra = MIN(fin->fin_plen, avail - iclen - max_linkhdr); 618255332Scy xtra = MIN(xtra, IPV6_MMTU - iclen); 619145516Sdarrenr if (dst == 0) { 620255332Scy if (ipf_ifpaddr(&ipfmain, 6, FRI_NORMAL, ifp, 621255332Scy &dst6, NULL) == -1) { 622145516Sdarrenr FREE_MB_T(m); 623145516Sdarrenr return -1; 624145516Sdarrenr } 625145516Sdarrenr } else 626145516Sdarrenr dst6 = fin->fin_dst6; 627145516Sdarrenr } 628145516Sdarrenr#endif 629145516Sdarrenr else { 630145516Sdarrenr FREE_MB_T(m); 631145516Sdarrenr return -1; 632145516Sdarrenr } 633145516Sdarrenr 634145516Sdarrenr avail -= (max_linkhdr + iclen); 635145516Sdarrenr if (avail < 0) { 636145516Sdarrenr FREE_MB_T(m); 637145516Sdarrenr return -1; 638145516Sdarrenr } 639145516Sdarrenr if (xtra > avail) 640145516Sdarrenr xtra = avail; 641145516Sdarrenr iclen += xtra; 642145516Sdarrenr m->m_data += max_linkhdr; 643145516Sdarrenr m->m_pkthdr.rcvif = (struct ifnet *)0; 644145516Sdarrenr m->m_pkthdr.len = iclen; 645145516Sdarrenr m->m_len = iclen; 646145516Sdarrenr ip = mtod(m, ip_t *); 647145516Sdarrenr icmp = (struct icmp *)((char *)ip + hlen); 648145516Sdarrenr ip2 = (ip_t *)&icmp->icmp_ip; 649145516Sdarrenr 650145516Sdarrenr icmp->icmp_type = type; 651145516Sdarrenr icmp->icmp_code = fin->fin_icode; 652145516Sdarrenr icmp->icmp_cksum = 0; 653145516Sdarrenr#ifdef icmp_nextmtu 654255332Scy if (type == ICMP_UNREACH && fin->fin_icode == ICMP_UNREACH_NEEDFRAG) { 655255332Scy if (fin->fin_mtu != 0) { 656255332Scy icmp->icmp_nextmtu = htons(fin->fin_mtu); 657255332Scy 658255332Scy } else if (ifp != NULL) { 659255332Scy icmp->icmp_nextmtu = htons(GETIFMTU_4(ifp)); 660255332Scy 661255332Scy } else { /* make up a number... */ 662255332Scy icmp->icmp_nextmtu = htons(fin->fin_plen - 20); 663255332Scy } 664255332Scy } 665145516Sdarrenr#endif 666145516Sdarrenr 667145516Sdarrenr bcopy((char *)fin->fin_ip, (char *)ip2, ohlen); 668145516Sdarrenr 669145516Sdarrenr#ifdef USE_INET6 670145516Sdarrenr ip6 = (ip6_t *)ip; 671145516Sdarrenr if (fin->fin_v == 6) { 672145516Sdarrenr ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; 673145516Sdarrenr ip6->ip6_plen = htons(iclen - hlen); 674145516Sdarrenr ip6->ip6_nxt = IPPROTO_ICMPV6; 675145516Sdarrenr ip6->ip6_hlim = 0; 676255332Scy ip6->ip6_src = dst6.in6; 677255332Scy ip6->ip6_dst = fin->fin_src6.in6; 678145516Sdarrenr if (xtra > 0) 679145516Sdarrenr bcopy((char *)fin->fin_ip + ohlen, 680145516Sdarrenr (char *)&icmp->icmp_ip + ohlen, xtra); 681145516Sdarrenr icmp->icmp_cksum = in6_cksum(m, IPPROTO_ICMPV6, 682145516Sdarrenr sizeof(*ip6), iclen - hlen); 683145516Sdarrenr } else 684145516Sdarrenr#endif 685145516Sdarrenr { 686145516Sdarrenr ip->ip_p = IPPROTO_ICMP; 687145516Sdarrenr ip->ip_src.s_addr = dst4.s_addr; 688145516Sdarrenr ip->ip_dst.s_addr = fin->fin_saddr; 689145516Sdarrenr 690145516Sdarrenr if (xtra > 0) 691145516Sdarrenr bcopy((char *)fin->fin_ip + ohlen, 692145516Sdarrenr (char *)&icmp->icmp_ip + ohlen, xtra); 693145516Sdarrenr icmp->icmp_cksum = ipf_cksum((u_short *)icmp, 694145516Sdarrenr sizeof(*icmp) + 8); 695255332Scy ip->ip_len = htons(iclen); 696145516Sdarrenr ip->ip_p = IPPROTO_ICMP; 697145516Sdarrenr } 698255332Scy err = ipf_send_ip(fin, m); 699145516Sdarrenr return err; 700145516Sdarrenr} 701145516Sdarrenr 702145516Sdarrenr 703145516Sdarrenr 704145516Sdarrenr 705173181Sdarrenr/* 706173181Sdarrenr * m0 - pointer to mbuf where the IP packet starts 707173181Sdarrenr * mpp - pointer to the mbuf pointer that is the start of the mbuf chain 708173181Sdarrenr */ 709255332Scyint 710255332Scyipf_fastroute(m0, mpp, fin, fdp) 711255332Scy mb_t *m0, **mpp; 712255332Scy fr_info_t *fin; 713255332Scy frdest_t *fdp; 714145516Sdarrenr{ 715145516Sdarrenr register struct ip *ip, *mhip; 716173181Sdarrenr register struct mbuf *m = *mpp; 717145516Sdarrenr int len, off, error = 0, hlen, code; 718145516Sdarrenr struct ifnet *ifp, *sifp; 719293628Smelifaro struct sockaddr_in dst; 720293628Smelifaro struct nhop4_extended nh4; 721293628Smelifaro int has_nhop = 0; 722293628Smelifaro u_long fibnum = 0; 723145516Sdarrenr u_short ip_off; 724255332Scy frdest_t node; 725145516Sdarrenr frentry_t *fr; 726145516Sdarrenr 727145516Sdarrenr#ifdef M_WRITABLE 728145516Sdarrenr /* 729145516Sdarrenr * HOT FIX/KLUDGE: 730145516Sdarrenr * 731145516Sdarrenr * If the mbuf we're about to send is not writable (because of 732145516Sdarrenr * a cluster reference, for example) we'll need to make a copy 733145516Sdarrenr * of it since this routine modifies the contents. 734145516Sdarrenr * 735145516Sdarrenr * If you have non-crappy network hardware that can transmit data 736145516Sdarrenr * from the mbuf, rather than making a copy, this is gonna be a 737145516Sdarrenr * problem. 738145516Sdarrenr */ 739145516Sdarrenr if (M_WRITABLE(m) == 0) { 740260715Sglebius m0 = m_dup(m, M_NOWAIT); 741298030Scy if (m0 != NULL) { 742145516Sdarrenr FREE_MB_T(m); 743145516Sdarrenr m = m0; 744145516Sdarrenr *mpp = m; 745145516Sdarrenr } else { 746145516Sdarrenr error = ENOBUFS; 747145516Sdarrenr FREE_MB_T(m); 748161356Sguido goto done; 749145516Sdarrenr } 750145516Sdarrenr } 751145516Sdarrenr#endif 752145516Sdarrenr 753145516Sdarrenr#ifdef USE_INET6 754145516Sdarrenr if (fin->fin_v == 6) { 755145516Sdarrenr /* 756145516Sdarrenr * currently "to <if>" and "to <if>:ip#" are not supported 757145516Sdarrenr * for IPv6 758145516Sdarrenr */ 759255332Scy return ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL); 760145516Sdarrenr } 761145516Sdarrenr#endif 762145516Sdarrenr 763145516Sdarrenr hlen = fin->fin_hlen; 764145516Sdarrenr ip = mtod(m0, struct ip *); 765255332Scy ifp = NULL; 766145516Sdarrenr 767145516Sdarrenr /* 768145516Sdarrenr * Route packet. 769145516Sdarrenr */ 770293628Smelifaro bzero(&dst, sizeof (dst)); 771293628Smelifaro dst.sin_family = AF_INET; 772293628Smelifaro dst.sin_addr = ip->ip_dst; 773293628Smelifaro dst.sin_len = sizeof(dst); 774145516Sdarrenr 775145516Sdarrenr fr = fin->fin_fr; 776255332Scy if ((fr != NULL) && !(fr->fr_flags & FR_KEEPSTATE) && (fdp != NULL) && 777255332Scy (fdp->fd_type == FRD_DSTLIST)) { 778255332Scy if (ipf_dstlist_select_node(fin, fdp->fd_ptr, NULL, &node) == 0) 779255332Scy fdp = &node; 780255332Scy } 781255332Scy 782145516Sdarrenr if (fdp != NULL) 783255332Scy ifp = fdp->fd_ptr; 784145516Sdarrenr else 785145516Sdarrenr ifp = fin->fin_ifp; 786145516Sdarrenr 787255332Scy if ((ifp == NULL) && ((fr == NULL) || !(fr->fr_flags & FR_FASTROUTE))) { 788145516Sdarrenr error = -2; 789145516Sdarrenr goto bad; 790145516Sdarrenr } 791145516Sdarrenr 792161356Sguido if ((fdp != NULL) && (fdp->fd_ip.s_addr != 0)) 793293628Smelifaro dst.sin_addr = fdp->fd_ip; 794145516Sdarrenr 795293628Smelifaro fibnum = M_GETFIB(m0); 796293628Smelifaro if (fib4_lookup_nh_ext(fibnum, dst.sin_addr, NHR_REF, 0, &nh4) != 0) { 797145516Sdarrenr if (in_localaddr(ip->ip_dst)) 798145516Sdarrenr error = EHOSTUNREACH; 799145516Sdarrenr else 800145516Sdarrenr error = ENETUNREACH; 801145516Sdarrenr goto bad; 802145516Sdarrenr } 803145516Sdarrenr 804293628Smelifaro has_nhop = 1; 805293628Smelifaro if (ifp == NULL) 806293628Smelifaro ifp = nh4.nh_ifp; 807293628Smelifaro if (nh4.nh_flags & NHF_GATEWAY) 808293628Smelifaro dst.sin_addr = nh4.nh_addr; 809293628Smelifaro 810145516Sdarrenr /* 811145516Sdarrenr * For input packets which are being "fastrouted", they won't 812145516Sdarrenr * go back through output filtering and miss their chance to get 813170268Sdarrenr * NAT'd and counted. Duplicated packets aren't considered to be 814170268Sdarrenr * part of the normal packet stream, so do not NAT them or pass 815170268Sdarrenr * them through stateful checking, etc. 816145516Sdarrenr */ 817170268Sdarrenr if ((fdp != &fr->fr_dif) && (fin->fin_out == 0)) { 818145516Sdarrenr sifp = fin->fin_ifp; 819145516Sdarrenr fin->fin_ifp = ifp; 820145516Sdarrenr fin->fin_out = 1; 821255332Scy (void) ipf_acctpkt(fin, NULL); 822145516Sdarrenr fin->fin_fr = NULL; 823145516Sdarrenr if (!fr || !(fr->fr_flags & FR_RETMASK)) { 824145516Sdarrenr u_32_t pass; 825145516Sdarrenr 826255332Scy (void) ipf_state_check(fin, &pass); 827145516Sdarrenr } 828145516Sdarrenr 829255332Scy switch (ipf_nat_checkout(fin, NULL)) 830145516Sdarrenr { 831145516Sdarrenr case 0 : 832145516Sdarrenr break; 833145516Sdarrenr case 1 : 834145516Sdarrenr ip->ip_sum = 0; 835145516Sdarrenr break; 836145516Sdarrenr case -1 : 837145516Sdarrenr error = -1; 838173181Sdarrenr goto bad; 839145516Sdarrenr break; 840145516Sdarrenr } 841145516Sdarrenr 842145516Sdarrenr fin->fin_ifp = sifp; 843145516Sdarrenr fin->fin_out = 0; 844145516Sdarrenr } else 845145516Sdarrenr ip->ip_sum = 0; 846145516Sdarrenr /* 847145516Sdarrenr * If small enough for interface, can just send directly. 848145516Sdarrenr */ 849255332Scy if (ntohs(ip->ip_len) <= ifp->if_mtu) { 850145516Sdarrenr if (!ip->ip_sum) 851145516Sdarrenr ip->ip_sum = in_cksum(m, hlen); 852293628Smelifaro error = (*ifp->if_output)(ifp, m, (struct sockaddr *)&dst, 853293628Smelifaro NULL 854255332Scy ); 855145516Sdarrenr goto done; 856145516Sdarrenr } 857145516Sdarrenr /* 858145516Sdarrenr * Too large for interface; fragment if possible. 859145516Sdarrenr * Must be able to put at least 8 bytes per fragment. 860145516Sdarrenr */ 861145516Sdarrenr ip_off = ntohs(ip->ip_off); 862145516Sdarrenr if (ip_off & IP_DF) { 863145516Sdarrenr error = EMSGSIZE; 864145516Sdarrenr goto bad; 865145516Sdarrenr } 866145516Sdarrenr len = (ifp->if_mtu - hlen) &~ 7; 867145516Sdarrenr if (len < 8) { 868145516Sdarrenr error = EMSGSIZE; 869145516Sdarrenr goto bad; 870145516Sdarrenr } 871145516Sdarrenr 872145516Sdarrenr { 873145516Sdarrenr int mhlen, firstlen = len; 874145516Sdarrenr struct mbuf **mnext = &m->m_act; 875145516Sdarrenr 876145516Sdarrenr /* 877145516Sdarrenr * Loop through length of segment after first fragment, 878145516Sdarrenr * make new header and copy data of each part and link onto chain. 879145516Sdarrenr */ 880145516Sdarrenr m0 = m; 881145516Sdarrenr mhlen = sizeof (struct ip); 882255332Scy for (off = hlen + len; off < ntohs(ip->ip_len); off += len) { 883145516Sdarrenr#ifdef MGETHDR 884260715Sglebius MGETHDR(m, M_NOWAIT, MT_HEADER); 885145516Sdarrenr#else 886260715Sglebius MGET(m, M_NOWAIT, MT_HEADER); 887145516Sdarrenr#endif 888298030Scy if (m == NULL) { 889145516Sdarrenr m = m0; 890145516Sdarrenr error = ENOBUFS; 891145516Sdarrenr goto bad; 892145516Sdarrenr } 893145516Sdarrenr m->m_data += max_linkhdr; 894145516Sdarrenr mhip = mtod(m, struct ip *); 895145516Sdarrenr bcopy((char *)ip, (char *)mhip, sizeof(*ip)); 896145516Sdarrenr if (hlen > sizeof (struct ip)) { 897145516Sdarrenr mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip); 898145516Sdarrenr IP_HL_A(mhip, mhlen >> 2); 899145516Sdarrenr } 900145516Sdarrenr m->m_len = mhlen; 901145516Sdarrenr mhip->ip_off = ((off - hlen) >> 3) + ip_off; 902255332Scy if (off + len >= ntohs(ip->ip_len)) 903255332Scy len = ntohs(ip->ip_len) - off; 904145516Sdarrenr else 905145516Sdarrenr mhip->ip_off |= IP_MF; 906145516Sdarrenr mhip->ip_len = htons((u_short)(len + mhlen)); 907161356Sguido *mnext = m; 908145516Sdarrenr m->m_next = m_copy(m0, off, len); 909145516Sdarrenr if (m->m_next == 0) { 910145516Sdarrenr error = ENOBUFS; /* ??? */ 911145516Sdarrenr goto sendorfree; 912145516Sdarrenr } 913145516Sdarrenr m->m_pkthdr.len = mhlen + len; 914145516Sdarrenr m->m_pkthdr.rcvif = NULL; 915145516Sdarrenr mhip->ip_off = htons((u_short)mhip->ip_off); 916145516Sdarrenr mhip->ip_sum = 0; 917145516Sdarrenr mhip->ip_sum = in_cksum(m, mhlen); 918145516Sdarrenr mnext = &m->m_act; 919145516Sdarrenr } 920145516Sdarrenr /* 921145516Sdarrenr * Update first fragment by trimming what's been copied out 922145516Sdarrenr * and updating header, then send each fragment (in order). 923145516Sdarrenr */ 924145516Sdarrenr m_adj(m0, hlen + firstlen - ip->ip_len); 925145516Sdarrenr ip->ip_len = htons((u_short)(hlen + firstlen)); 926145516Sdarrenr ip->ip_off = htons((u_short)IP_MF); 927145516Sdarrenr ip->ip_sum = 0; 928145516Sdarrenr ip->ip_sum = in_cksum(m0, hlen); 929145516Sdarrenrsendorfree: 930145516Sdarrenr for (m = m0; m; m = m0) { 931145516Sdarrenr m0 = m->m_act; 932145516Sdarrenr m->m_act = 0; 933145516Sdarrenr if (error == 0) 934145516Sdarrenr error = (*ifp->if_output)(ifp, m, 935293628Smelifaro (struct sockaddr *)&dst, 936293628Smelifaro NULL 937255332Scy ); 938145516Sdarrenr else 939145516Sdarrenr FREE_MB_T(m); 940145516Sdarrenr } 941255332Scy } 942145516Sdarrenrdone: 943145516Sdarrenr if (!error) 944255332Scy ipfmain.ipf_frouteok[0]++; 945145516Sdarrenr else 946255332Scy ipfmain.ipf_frouteok[1]++; 947145516Sdarrenr 948293628Smelifaro if (has_nhop) 949293628Smelifaro fib4_free_nh_ext(fibnum, &nh4); 950293628Smelifaro 951145516Sdarrenr return 0; 952145516Sdarrenrbad: 953145516Sdarrenr if (error == EMSGSIZE) { 954145516Sdarrenr sifp = fin->fin_ifp; 955145516Sdarrenr code = fin->fin_icode; 956145516Sdarrenr fin->fin_icode = ICMP_UNREACH_NEEDFRAG; 957145516Sdarrenr fin->fin_ifp = ifp; 958255332Scy (void) ipf_send_icmp_err(ICMP_UNREACH, fin, 1); 959145516Sdarrenr fin->fin_ifp = sifp; 960145516Sdarrenr fin->fin_icode = code; 961145516Sdarrenr } 962145516Sdarrenr FREE_MB_T(m); 963145516Sdarrenr goto done; 964145516Sdarrenr} 965145516Sdarrenr 966145516Sdarrenr 967255332Scyint 968255332Scyipf_verifysrc(fin) 969255332Scy fr_info_t *fin; 970145516Sdarrenr{ 971293628Smelifaro struct nhop4_basic nh4; 972145516Sdarrenr 973293628Smelifaro if (fib4_lookup_nh_basic(0, fin->fin_src, 0, 0, &nh4) != 0) 974293628Smelifaro return (0); 975293628Smelifaro return (fin->fin_ifp == nh4.nh_ifp); 976145516Sdarrenr} 977145516Sdarrenr 978145516Sdarrenr 979145516Sdarrenr/* 980145516Sdarrenr * return the first IP Address associated with an interface 981145516Sdarrenr */ 982255332Scyint 983255332Scyipf_ifpaddr(softc, v, atype, ifptr, inp, inpmask) 984255332Scy ipf_main_softc_t *softc; 985255332Scy int v, atype; 986255332Scy void *ifptr; 987255332Scy i6addr_t *inp, *inpmask; 988145516Sdarrenr{ 989145516Sdarrenr#ifdef USE_INET6 990145516Sdarrenr struct in6_addr *inp6 = NULL; 991145516Sdarrenr#endif 992145516Sdarrenr struct sockaddr *sock, *mask; 993145516Sdarrenr struct sockaddr_in *sin; 994145516Sdarrenr struct ifaddr *ifa; 995145516Sdarrenr struct ifnet *ifp; 996145516Sdarrenr 997145516Sdarrenr if ((ifptr == NULL) || (ifptr == (void *)-1)) 998145516Sdarrenr return -1; 999145516Sdarrenr 1000145516Sdarrenr sin = NULL; 1001145516Sdarrenr ifp = ifptr; 1002145516Sdarrenr 1003145516Sdarrenr if (v == 4) 1004255332Scy inp->in4.s_addr = 0; 1005145516Sdarrenr#ifdef USE_INET6 1006145516Sdarrenr else if (v == 6) 1007255332Scy bzero((char *)inp, sizeof(*inp)); 1008145516Sdarrenr#endif 1009145516Sdarrenr ifa = TAILQ_FIRST(&ifp->if_addrhead); 1010145516Sdarrenr 1011145516Sdarrenr sock = ifa->ifa_addr; 1012145516Sdarrenr while (sock != NULL && ifa != NULL) { 1013145516Sdarrenr sin = (struct sockaddr_in *)sock; 1014145516Sdarrenr if ((v == 4) && (sin->sin_family == AF_INET)) 1015145516Sdarrenr break; 1016145516Sdarrenr#ifdef USE_INET6 1017145516Sdarrenr if ((v == 6) && (sin->sin_family == AF_INET6)) { 1018145516Sdarrenr inp6 = &((struct sockaddr_in6 *)sin)->sin6_addr; 1019145516Sdarrenr if (!IN6_IS_ADDR_LINKLOCAL(inp6) && 1020145516Sdarrenr !IN6_IS_ADDR_LOOPBACK(inp6)) 1021145516Sdarrenr break; 1022145516Sdarrenr } 1023145516Sdarrenr#endif 1024145516Sdarrenr ifa = TAILQ_NEXT(ifa, ifa_link); 1025145516Sdarrenr if (ifa != NULL) 1026145516Sdarrenr sock = ifa->ifa_addr; 1027145516Sdarrenr } 1028145516Sdarrenr 1029145516Sdarrenr if (ifa == NULL || sin == NULL) 1030145516Sdarrenr return -1; 1031145516Sdarrenr 1032145516Sdarrenr mask = ifa->ifa_netmask; 1033145516Sdarrenr if (atype == FRI_BROADCAST) 1034145516Sdarrenr sock = ifa->ifa_broadaddr; 1035145516Sdarrenr else if (atype == FRI_PEERADDR) 1036145516Sdarrenr sock = ifa->ifa_dstaddr; 1037145516Sdarrenr 1038161356Sguido if (sock == NULL) 1039161356Sguido return -1; 1040161356Sguido 1041145516Sdarrenr#ifdef USE_INET6 1042145516Sdarrenr if (v == 6) { 1043255332Scy return ipf_ifpfillv6addr(atype, (struct sockaddr_in6 *)sock, 1044255332Scy (struct sockaddr_in6 *)mask, 1045255332Scy inp, inpmask); 1046145516Sdarrenr } 1047145516Sdarrenr#endif 1048255332Scy return ipf_ifpfillv4addr(atype, (struct sockaddr_in *)sock, 1049255332Scy (struct sockaddr_in *)mask, 1050255332Scy &inp->in4, &inpmask->in4); 1051145516Sdarrenr} 1052145516Sdarrenr 1053145516Sdarrenr 1054255332Scyu_32_t 1055255332Scyipf_newisn(fin) 1056255332Scy fr_info_t *fin; 1057145516Sdarrenr{ 1058145516Sdarrenr u_32_t newiss; 1059145516Sdarrenr newiss = arc4random(); 1060145516Sdarrenr return newiss; 1061145516Sdarrenr} 1062145516Sdarrenr 1063145516Sdarrenr 1064255332ScyINLINE int 1065255332Scyipf_checkv4sum(fin) 1066255332Scy fr_info_t *fin; 1067145516Sdarrenr{ 1068145516Sdarrenr#ifdef CSUM_DATA_VALID 1069145516Sdarrenr int manual = 0; 1070145516Sdarrenr u_short sum; 1071145516Sdarrenr ip_t *ip; 1072145516Sdarrenr mb_t *m; 1073145516Sdarrenr 1074145516Sdarrenr if ((fin->fin_flx & FI_NOCKSUM) != 0) 1075255332Scy return 0; 1076145516Sdarrenr 1077255332Scy if ((fin->fin_flx & FI_SHORT) != 0) 1078255332Scy return 1; 1079172776Sdarrenr 1080255332Scy if (fin->fin_cksum != FI_CK_NEEDED) 1081255332Scy return (fin->fin_cksum > FI_CK_NEEDED) ? 0 : -1; 1082255332Scy 1083145516Sdarrenr m = fin->fin_m; 1084145516Sdarrenr if (m == NULL) { 1085145516Sdarrenr manual = 1; 1086145516Sdarrenr goto skipauto; 1087145516Sdarrenr } 1088145516Sdarrenr ip = fin->fin_ip; 1089145516Sdarrenr 1090255332Scy if ((m->m_pkthdr.csum_flags & (CSUM_IP_CHECKED|CSUM_IP_VALID)) == 1091255332Scy CSUM_IP_CHECKED) { 1092255332Scy fin->fin_cksum = FI_CK_BAD; 1093255332Scy fin->fin_flx |= FI_BAD; 1094297632Scy 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)); 1095255332Scy return -1; 1096255332Scy } 1097145516Sdarrenr if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) { 1098288910Scy /* Depending on the driver, UDP may have zero checksum */ 1099288910Scy if (fin->fin_p == IPPROTO_UDP && (fin->fin_flx & 1100288910Scy (FI_FRAG|FI_SHORT|FI_BAD)) == 0) { 1101288910Scy udphdr_t *udp = fin->fin_dp; 1102288910Scy if (udp->uh_sum == 0) { 1103288910Scy /* 1104288910Scy * we're good no matter what the hardware 1105288910Scy * checksum flags and csum_data say (handling 1106288910Scy * of csum_data for zero UDP checksum is not 1107288910Scy * consistent across all drivers) 1108288910Scy */ 1109288910Scy fin->fin_cksum = 1; 1110288910Scy return 0; 1111288910Scy } 1112288910Scy } 1113288910Scy 1114145516Sdarrenr if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) 1115145516Sdarrenr sum = m->m_pkthdr.csum_data; 1116145516Sdarrenr else 1117145516Sdarrenr sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, 1118145516Sdarrenr htonl(m->m_pkthdr.csum_data + 1119255332Scy fin->fin_dlen + fin->fin_p)); 1120145516Sdarrenr sum ^= 0xffff; 1121172776Sdarrenr if (sum != 0) { 1122255332Scy fin->fin_cksum = FI_CK_BAD; 1123145516Sdarrenr fin->fin_flx |= FI_BAD; 1124297632Scy DT2(ipf_fi_bad_checkv4sum_sum, fr_info_t *, fin, u_int, sum); 1125172776Sdarrenr } else { 1126255332Scy fin->fin_cksum = FI_CK_SUMOK; 1127255332Scy return 0; 1128172776Sdarrenr } 1129255332Scy } else { 1130255332Scy if (m->m_pkthdr.csum_flags == CSUM_DELAY_DATA) { 1131255332Scy fin->fin_cksum = FI_CK_L4FULL; 1132255332Scy return 0; 1133255332Scy } else if (m->m_pkthdr.csum_flags == CSUM_TCP || 1134255332Scy m->m_pkthdr.csum_flags == CSUM_UDP) { 1135255332Scy fin->fin_cksum = FI_CK_L4PART; 1136255332Scy return 0; 1137255332Scy } else if (m->m_pkthdr.csum_flags == CSUM_IP) { 1138255332Scy fin->fin_cksum = FI_CK_L4PART; 1139255332Scy return 0; 1140255332Scy } else { 1141255332Scy manual = 1; 1142255332Scy } 1143255332Scy } 1144145516Sdarrenrskipauto: 1145255332Scy if (manual != 0) { 1146255332Scy if (ipf_checkl4sum(fin) == -1) { 1147145516Sdarrenr fin->fin_flx |= FI_BAD; 1148297632Scy DT2(ipf_fi_bad_checkv4sum_manual, fr_info_t *, fin, u_int, manual); 1149255332Scy return -1; 1150255332Scy } 1151255332Scy } 1152145516Sdarrenr#else 1153255332Scy if (ipf_checkl4sum(fin) == -1) { 1154145516Sdarrenr fin->fin_flx |= FI_BAD; 1155297632Scy DT2(ipf_fi_bad_checkv4sum_checkl4sum, fr_info_t *, fin, u_int, -1); 1156255332Scy return -1; 1157255332Scy } 1158145516Sdarrenr#endif 1159255332Scy return 0; 1160145516Sdarrenr} 1161145516Sdarrenr 1162145516Sdarrenr 1163145516Sdarrenr#ifdef USE_INET6 1164255332ScyINLINE int 1165255332Scyipf_checkv6sum(fin) 1166255332Scy fr_info_t *fin; 1167145516Sdarrenr{ 1168255332Scy if ((fin->fin_flx & FI_NOCKSUM) != 0) 1169297632Scy DT(ipf_checkv6sum_fi_nocksum); 1170255332Scy return 0; 1171255332Scy 1172255332Scy if ((fin->fin_flx & FI_SHORT) != 0) 1173297632Scy DT(ipf_checkv6sum_fi_short); 1174255332Scy return 1; 1175255332Scy 1176255332Scy if (fin->fin_cksum != FI_CK_NEEDED) 1177297632Scy DT(ipf_checkv6sum_fi_ck_needed); 1178255332Scy return (fin->fin_cksum > FI_CK_NEEDED) ? 0 : -1; 1179255332Scy 1180255332Scy if (ipf_checkl4sum(fin) == -1) { 1181145516Sdarrenr fin->fin_flx |= FI_BAD; 1182297632Scy DT2(ipf_fi_bad_checkv6sum_checkl4sum, fr_info_t *, fin, u_int, -1); 1183255332Scy return -1; 1184255332Scy } 1185255332Scy return 0; 1186145516Sdarrenr} 1187145516Sdarrenr#endif /* USE_INET6 */ 1188145516Sdarrenr 1189145516Sdarrenr 1190255332Scysize_t 1191255332Scymbufchainlen(m0) 1192255332Scy struct mbuf *m0; 1193255332Scy { 1194145516Sdarrenr size_t len; 1195145516Sdarrenr 1196145516Sdarrenr if ((m0->m_flags & M_PKTHDR) != 0) { 1197145516Sdarrenr len = m0->m_pkthdr.len; 1198145516Sdarrenr } else { 1199145516Sdarrenr struct mbuf *m; 1200145516Sdarrenr 1201145516Sdarrenr for (m = m0, len = 0; m != NULL; m = m->m_next) 1202145516Sdarrenr len += m->m_len; 1203145516Sdarrenr } 1204145516Sdarrenr return len; 1205145516Sdarrenr} 1206145516Sdarrenr 1207145516Sdarrenr 1208145516Sdarrenr/* ------------------------------------------------------------------------ */ 1209255332Scy/* Function: ipf_pullup */ 1210145516Sdarrenr/* Returns: NULL == pullup failed, else pointer to protocol header */ 1211255332Scy/* Parameters: xmin(I)- pointer to buffer where data packet starts */ 1212145516Sdarrenr/* fin(I) - pointer to packet information */ 1213145516Sdarrenr/* len(I) - number of bytes to pullup */ 1214145516Sdarrenr/* */ 1215145516Sdarrenr/* Attempt to move at least len bytes (from the start of the buffer) into a */ 1216145516Sdarrenr/* single buffer for ease of access. Operating system native functions are */ 1217145516Sdarrenr/* used to manage buffers - if necessary. If the entire packet ends up in */ 1218255332Scy/* a single buffer, set the FI_COALESCE flag even though ipf_coalesce() has */ 1219145516Sdarrenr/* not been called. Both fin_ip and fin_dp are updated before exiting _IF_ */ 1220145516Sdarrenr/* and ONLY if the pullup succeeds. */ 1221145516Sdarrenr/* */ 1222255332Scy/* We assume that 'xmin' is a pointer to a buffer that is part of the chain */ 1223145516Sdarrenr/* of buffers that starts at *fin->fin_mp. */ 1224145516Sdarrenr/* ------------------------------------------------------------------------ */ 1225255332Scyvoid * 1226255332Scyipf_pullup(xmin, fin, len) 1227255332Scy mb_t *xmin; 1228255332Scy fr_info_t *fin; 1229255332Scy int len; 1230145516Sdarrenr{ 1231255332Scy int dpoff, ipoff; 1232255332Scy mb_t *m = xmin; 1233145516Sdarrenr char *ip; 1234145516Sdarrenr 1235145516Sdarrenr if (m == NULL) 1236145516Sdarrenr return NULL; 1237145516Sdarrenr 1238145516Sdarrenr ip = (char *)fin->fin_ip; 1239145516Sdarrenr if ((fin->fin_flx & FI_COALESCE) != 0) 1240145516Sdarrenr return ip; 1241145516Sdarrenr 1242145516Sdarrenr ipoff = fin->fin_ipoff; 1243145516Sdarrenr if (fin->fin_dp != NULL) 1244145516Sdarrenr dpoff = (char *)fin->fin_dp - (char *)ip; 1245145516Sdarrenr else 1246145516Sdarrenr dpoff = 0; 1247145516Sdarrenr 1248145516Sdarrenr if (M_LEN(m) < len) { 1249255332Scy mb_t *n = *fin->fin_mp; 1250145516Sdarrenr /* 1251145516Sdarrenr * Assume that M_PKTHDR is set and just work with what is left 1252145516Sdarrenr * rather than check.. 1253145516Sdarrenr * Should not make any real difference, anyway. 1254145516Sdarrenr */ 1255255332Scy if (m != n) { 1256255332Scy /* 1257255332Scy * Record the mbuf that points to the mbuf that we're 1258255332Scy * about to go to work on so that we can update the 1259255332Scy * m_next appropriately later. 1260255332Scy */ 1261255332Scy for (; n->m_next != m; n = n->m_next) 1262255332Scy ; 1263255332Scy } else { 1264255332Scy n = NULL; 1265255332Scy } 1266255332Scy 1267255332Scy#ifdef MHLEN 1268145516Sdarrenr if (len > MHLEN) 1269145516Sdarrenr#else 1270145516Sdarrenr if (len > MLEN) 1271145516Sdarrenr#endif 1272145516Sdarrenr { 1273145516Sdarrenr#ifdef HAVE_M_PULLDOWN 1274145516Sdarrenr if (m_pulldown(m, 0, len, NULL) == NULL) 1275145516Sdarrenr m = NULL; 1276145516Sdarrenr#else 1277145516Sdarrenr FREE_MB_T(*fin->fin_mp); 1278145516Sdarrenr m = NULL; 1279255332Scy n = NULL; 1280145516Sdarrenr#endif 1281145516Sdarrenr } else 1282145516Sdarrenr { 1283145516Sdarrenr m = m_pullup(m, len); 1284145516Sdarrenr } 1285255332Scy if (n != NULL) 1286255332Scy n->m_next = m; 1287145516Sdarrenr if (m == NULL) { 1288255332Scy /* 1289255332Scy * When n is non-NULL, it indicates that m pointed to 1290255332Scy * a sub-chain (tail) of the mbuf and that the head 1291255332Scy * of this chain has not yet been free'd. 1292255332Scy */ 1293255332Scy if (n != NULL) { 1294255332Scy FREE_MB_T(*fin->fin_mp); 1295255332Scy } 1296255332Scy 1297255332Scy *fin->fin_mp = NULL; 1298172776Sdarrenr fin->fin_m = NULL; 1299145516Sdarrenr return NULL; 1300145516Sdarrenr } 1301172776Sdarrenr 1302255332Scy if (n == NULL) 1303255332Scy *fin->fin_mp = m; 1304255332Scy 1305172776Sdarrenr while (M_LEN(m) == 0) { 1306172776Sdarrenr m = m->m_next; 1307172776Sdarrenr } 1308172776Sdarrenr fin->fin_m = m; 1309145516Sdarrenr ip = MTOD(m, char *) + ipoff; 1310255332Scy 1311255332Scy fin->fin_ip = (ip_t *)ip; 1312255332Scy if (fin->fin_dp != NULL) 1313255332Scy fin->fin_dp = (char *)fin->fin_ip + dpoff; 1314255332Scy if (fin->fin_fraghdr != NULL) 1315255332Scy fin->fin_fraghdr = (char *)ip + 1316255332Scy ((char *)fin->fin_fraghdr - 1317255332Scy (char *)fin->fin_ip); 1318145516Sdarrenr } 1319145516Sdarrenr 1320145516Sdarrenr if (len == fin->fin_plen) 1321145516Sdarrenr fin->fin_flx |= FI_COALESCE; 1322145516Sdarrenr return ip; 1323145516Sdarrenr} 1324170268Sdarrenr 1325170268Sdarrenr 1326255332Scyint 1327255332Scyipf_inject(fin, m) 1328255332Scy fr_info_t *fin; 1329255332Scy mb_t *m; 1330170268Sdarrenr{ 1331170268Sdarrenr int error = 0; 1332170268Sdarrenr 1333170268Sdarrenr if (fin->fin_out == 0) { 1334170268Sdarrenr netisr_dispatch(NETISR_IP, m); 1335170268Sdarrenr } else { 1336173931Sdarrenr fin->fin_ip->ip_len = ntohs(fin->fin_ip->ip_len); 1337173931Sdarrenr fin->fin_ip->ip_off = ntohs(fin->fin_ip->ip_off); 1338170268Sdarrenr error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL); 1339170268Sdarrenr } 1340170268Sdarrenr 1341170268Sdarrenr return error; 1342170268Sdarrenr} 1343172776Sdarrenr 1344172776Sdarrenrint ipf_pfil_unhook(void) { 1345172776Sdarrenr#if defined(NETBSD_PF) && (__FreeBSD_version >= 500011) 1346172776Sdarrenr struct pfil_head *ph_inet; 1347172776Sdarrenr# ifdef USE_INET6 1348172776Sdarrenr struct pfil_head *ph_inet6; 1349172776Sdarrenr# endif 1350172776Sdarrenr#endif 1351172776Sdarrenr 1352172776Sdarrenr#ifdef NETBSD_PF 1353172776Sdarrenr ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); 1354172776Sdarrenr if (ph_inet != NULL) 1355255332Scy pfil_remove_hook((void *)ipf_check_wrapper, NULL, 1356172776Sdarrenr PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet); 1357172776Sdarrenr# ifdef USE_INET6 1358172776Sdarrenr ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6); 1359172776Sdarrenr if (ph_inet6 != NULL) 1360255332Scy pfil_remove_hook((void *)ipf_check_wrapper6, NULL, 1361172776Sdarrenr PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet6); 1362172776Sdarrenr# endif 1363172776Sdarrenr#endif 1364172776Sdarrenr 1365172776Sdarrenr return (0); 1366172776Sdarrenr} 1367172776Sdarrenr 1368172776Sdarrenrint ipf_pfil_hook(void) { 1369172776Sdarrenr#if defined(NETBSD_PF) && (__FreeBSD_version >= 500011) 1370172776Sdarrenr struct pfil_head *ph_inet; 1371172776Sdarrenr# ifdef USE_INET6 1372172776Sdarrenr struct pfil_head *ph_inet6; 1373172776Sdarrenr# endif 1374172776Sdarrenr#endif 1375172776Sdarrenr 1376172776Sdarrenr# ifdef NETBSD_PF 1377172776Sdarrenr ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); 1378172776Sdarrenr# ifdef USE_INET6 1379172776Sdarrenr ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6); 1380172776Sdarrenr# endif 1381172776Sdarrenr if (ph_inet == NULL 1382172776Sdarrenr# ifdef USE_INET6 1383172776Sdarrenr && ph_inet6 == NULL 1384172776Sdarrenr# endif 1385255332Scy ) { 1386172776Sdarrenr return ENODEV; 1387255332Scy } 1388172776Sdarrenr 1389172776Sdarrenr if (ph_inet != NULL) 1390255332Scy pfil_add_hook((void *)ipf_check_wrapper, NULL, 1391172776Sdarrenr PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet); 1392172776Sdarrenr# ifdef USE_INET6 1393172776Sdarrenr if (ph_inet6 != NULL) 1394255332Scy pfil_add_hook((void *)ipf_check_wrapper6, NULL, 1395172776Sdarrenr PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet6); 1396172776Sdarrenr# endif 1397172776Sdarrenr# endif 1398172776Sdarrenr return (0); 1399172776Sdarrenr} 1400172776Sdarrenr 1401172776Sdarrenrvoid 1402172776Sdarrenripf_event_reg(void) 1403172776Sdarrenr{ 1404255332Scy ipf_arrivetag = EVENTHANDLER_REGISTER(ifnet_arrival_event, \ 1405255332Scy ipf_ifevent, &ipfmain, \ 1406172776Sdarrenr EVENTHANDLER_PRI_ANY); 1407255332Scy ipf_departtag = EVENTHANDLER_REGISTER(ifnet_departure_event, \ 1408255332Scy ipf_ifevent, &ipfmain, \ 1409172776Sdarrenr EVENTHANDLER_PRI_ANY); 1410255332Scy ipf_clonetag = EVENTHANDLER_REGISTER(if_clone_event, ipf_ifevent, \ 1411255332Scy &ipfmain, EVENTHANDLER_PRI_ANY); 1412172776Sdarrenr} 1413172776Sdarrenr 1414172776Sdarrenrvoid 1415172776Sdarrenripf_event_dereg(void) 1416172776Sdarrenr{ 1417172776Sdarrenr if (ipf_arrivetag != NULL) { 1418172776Sdarrenr EVENTHANDLER_DEREGISTER(ifnet_arrival_event, ipf_arrivetag); 1419172776Sdarrenr } 1420172776Sdarrenr if (ipf_departtag != NULL) { 1421172776Sdarrenr EVENTHANDLER_DEREGISTER(ifnet_departure_event, ipf_departtag); 1422172776Sdarrenr } 1423172776Sdarrenr if (ipf_clonetag != NULL) { 1424172776Sdarrenr EVENTHANDLER_DEREGISTER(if_clone_event, ipf_clonetag); 1425172776Sdarrenr } 1426172776Sdarrenr} 1427255332Scy 1428255332Scy 1429255332Scyu_32_t 1430255332Scyipf_random() 1431255332Scy{ 1432255332Scy return arc4random(); 1433255332Scy} 1434255332Scy 1435255332Scy 1436255332Scyu_int 1437255332Scyipf_pcksum(fin, hlen, sum) 1438255332Scy fr_info_t *fin; 1439255332Scy int hlen; 1440255332Scy u_int sum; 1441255332Scy{ 1442255332Scy struct mbuf *m; 1443255332Scy u_int sum2; 1444255332Scy int off; 1445255332Scy 1446255332Scy m = fin->fin_m; 1447255332Scy off = (char *)fin->fin_dp - (char *)fin->fin_ip; 1448255332Scy m->m_data += hlen; 1449255332Scy m->m_len -= hlen; 1450255332Scy sum2 = in_cksum(fin->fin_m, fin->fin_plen - off); 1451255332Scy m->m_len += hlen; 1452255332Scy m->m_data -= hlen; 1453255332Scy 1454255332Scy /* 1455255332Scy * Both sum and sum2 are partial sums, so combine them together. 1456255332Scy */ 1457255332Scy sum += ~sum2 & 0xffff; 1458255332Scy while (sum > 0xffff) 1459255332Scy sum = (sum & 0xffff) + (sum >> 16); 1460255332Scy sum2 = ~sum & 0xffff; 1461255332Scy return sum2; 1462255332Scy} 1463