1145516Sdarrenr/* $FreeBSD: releng/10.3/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c 289210 2015-10-13 04:19:49Z 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> 36275213Scy#if defined(__FreeBSD_version) && (__FreeBSD_version >= 800000) 37275213Scy#include <sys/jail.h> 38275213Scy#endif 39255332Scy# include <sys/mbuf.h> 40255332Scy# include <sys/sockopt.h> 41145516Sdarrenr#if !defined(__hpux) 42145516Sdarrenr# include <sys/mbuf.h> 43145516Sdarrenr#endif 44145516Sdarrenr#include <sys/socket.h> 45170268Sdarrenr# include <sys/selinfo.h> 46195699Srwatson# include <netinet/tcp_var.h> 47145516Sdarrenr 48145516Sdarrenr#include <net/if.h> 49145516Sdarrenr# include <net/if_var.h> 50170268Sdarrenr# include <net/netisr.h> 51145516Sdarrenr#include <net/route.h> 52145516Sdarrenr#include <netinet/in.h> 53145516Sdarrenr#include <netinet/in_var.h> 54145516Sdarrenr#include <netinet/in_systm.h> 55145516Sdarrenr#include <netinet/ip.h> 56145516Sdarrenr#include <netinet/ip_var.h> 57145516Sdarrenr#include <netinet/tcp.h> 58275213Scy#if defined(__FreeBSD_version) && (__FreeBSD_version >= 800000) 59275213Scy#include <net/vnet.h> 60275213Scy#else 61275213Scy#define CURVNET_SET(arg) 62275213Scy#define CURVNET_RESTORE() 63275213Scy#endif 64145516Sdarrenr#if defined(__osf__) 65145516Sdarrenr# include <netinet/tcp_timer.h> 66145516Sdarrenr#endif 67145516Sdarrenr#include <netinet/udp.h> 68145516Sdarrenr#include <netinet/tcpip.h> 69145516Sdarrenr#include <netinet/ip_icmp.h> 70145516Sdarrenr#include "netinet/ip_compat.h" 71145516Sdarrenr#ifdef USE_INET6 72145516Sdarrenr# include <netinet/icmp6.h> 73145516Sdarrenr#endif 74145516Sdarrenr#include "netinet/ip_fil.h" 75145516Sdarrenr#include "netinet/ip_nat.h" 76145516Sdarrenr#include "netinet/ip_frag.h" 77145516Sdarrenr#include "netinet/ip_state.h" 78145516Sdarrenr#include "netinet/ip_proxy.h" 79145516Sdarrenr#include "netinet/ip_auth.h" 80145516Sdarrenr#include "netinet/ip_sync.h" 81255332Scy#include "netinet/ip_lookup.h" 82255332Scy#include "netinet/ip_dstlist.h" 83145516Sdarrenr#ifdef IPFILTER_SCAN 84145516Sdarrenr#include "netinet/ip_scan.h" 85145516Sdarrenr#endif 86145516Sdarrenr#include "netinet/ip_pool.h" 87145516Sdarrenr# include <sys/malloc.h> 88145516Sdarrenr#include <sys/kernel.h> 89145516Sdarrenr#ifdef CSUM_DATA_VALID 90145516Sdarrenr#include <machine/in_cksum.h> 91145516Sdarrenr#endif 92145516Sdarrenrextern int ip_optcopy __P((struct ip *, struct ip *)); 93145516Sdarrenr 94145516Sdarrenr 95145516Sdarrenr# ifdef IPFILTER_M_IPFILTER 96151897SrwatsonMALLOC_DEFINE(M_IPFILTER, "ipfilter", "IP Filter packet filter data structures"); 97145516Sdarrenr# endif 98145516Sdarrenr 99145516Sdarrenr 100255332Scystatic u_short ipid = 0; 101255332Scystatic int (*ipf_savep) __P((void *, ip_t *, int, void *, int, struct mbuf **)); 102255332Scystatic int ipf_send_ip __P((fr_info_t *, mb_t *)); 103255332Scystatic void ipf_timer_func __P((void *arg)); 104145516Sdarrenrint ipf_locks_done = 0; 105145516Sdarrenr 106255332Scyipf_main_softc_t ipfmain; 107145516Sdarrenr 108145516Sdarrenr# include <sys/conf.h> 109145516Sdarrenr# if defined(NETBSD_PF) 110145516Sdarrenr# include <net/pfil.h> 111255332Scy# endif /* NETBSD_PF */ 112145516Sdarrenr/* 113255332Scy * We provide the ipf_checkp name just to minimize changes later. 114145516Sdarrenr */ 115255332Scyint (*ipf_checkp) __P((void *, ip_t *ip, int hlen, void *ifp, int out, mb_t **mp)); 116145516Sdarrenr 117145516Sdarrenr 118153876Sguidostatic eventhandler_tag ipf_arrivetag, ipf_departtag, ipf_clonetag; 119153876Sguido 120153876Sguidostatic void ipf_ifevent(void *arg); 121153876Sguido 122153876Sguidostatic void ipf_ifevent(arg) 123255332Scy void *arg; 124153876Sguido{ 125255332Scy ipf_sync(arg, NULL); 126153876Sguido} 127153876Sguido 128153876Sguido 129145516Sdarrenr 130145516Sdarrenrstatic int 131255332Scyipf_check_wrapper(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir) 132145516Sdarrenr{ 133145516Sdarrenr struct ip *ip = mtod(*mp, struct ip *); 134255332Scy int rv; 135255332Scy 136255332Scy /* 137255332Scy * IPFilter expects evreything in network byte order 138255332Scy */ 139255332Scy#if (__FreeBSD_version < 1000019) 140255332Scy ip->ip_len = htons(ip->ip_len); 141255332Scy ip->ip_off = htons(ip->ip_off); 142255332Scy#endif 143255332Scy rv = ipf_check(&ipfmain, ip, ip->ip_hl << 2, ifp, (dir == PFIL_OUT), 144255332Scy mp); 145255332Scy#if (__FreeBSD_version < 1000019) 146255332Scy if ((rv == 0) && (*mp != NULL)) { 147255332Scy ip = mtod(*mp, struct ip *); 148255332Scy ip->ip_len = ntohs(ip->ip_len); 149255332Scy ip->ip_off = ntohs(ip->ip_off); 150255332Scy } 151255332Scy#endif 152255332Scy return rv; 153145516Sdarrenr} 154145516Sdarrenr 155145516Sdarrenr# ifdef USE_INET6 156145516Sdarrenr# include <netinet/ip6.h> 157145516Sdarrenr 158145516Sdarrenrstatic int 159255332Scyipf_check_wrapper6(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir) 160145516Sdarrenr{ 161255332Scy return (ipf_check(&ipfmain, mtod(*mp, struct ip *), 162255332Scy sizeof(struct ip6_hdr), ifp, (dir == PFIL_OUT), mp)); 163145516Sdarrenr} 164145516Sdarrenr# endif 165145516Sdarrenr#if defined(IPFILTER_LKM) 166255332Scyint ipf_identify(s) 167255332Scy char *s; 168145516Sdarrenr{ 169145516Sdarrenr if (strcmp(s, "ipl") == 0) 170145516Sdarrenr return 1; 171145516Sdarrenr return 0; 172145516Sdarrenr} 173145516Sdarrenr#endif /* IPFILTER_LKM */ 174145516Sdarrenr 175145516Sdarrenr 176255332Scystatic void 177255332Scyipf_timer_func(arg) 178255332Scy void *arg; 179145516Sdarrenr{ 180255332Scy ipf_main_softc_t *softc = arg; 181255332Scy SPL_INT(s); 182255332Scy 183255332Scy SPL_NET(s); 184255332Scy READ_ENTER(&softc->ipf_global); 185255332Scy 186255332Scy if (softc->ipf_running > 0) 187255332Scy ipf_slowtimer(softc); 188255332Scy 189255332Scy if (softc->ipf_running == -1 || softc->ipf_running == 1) { 190255755Scy#if 0 191255332Scy softc->ipf_slow_ch = timeout(ipf_timer_func, softc, hz/2); 192255332Scy#endif 193255755Scy callout_init(&softc->ipf_slow_ch, CALLOUT_MPSAFE); 194255755Scy callout_reset(&softc->ipf_slow_ch, 195255755Scy (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT, 196255755Scy ipf_timer_func, softc); 197255332Scy } 198255332Scy RWLOCK_EXIT(&softc->ipf_global); 199255332Scy SPL_X(s); 200255332Scy} 201255332Scy 202255332Scy 203255332Scyint 204255332Scyipfattach(softc) 205255332Scy ipf_main_softc_t *softc; 206255332Scy{ 207145516Sdarrenr#ifdef USE_SPL 208145516Sdarrenr int s; 209145516Sdarrenr#endif 210145516Sdarrenr 211145516Sdarrenr SPL_NET(s); 212255332Scy if (softc->ipf_running > 0) { 213145516Sdarrenr SPL_X(s); 214145516Sdarrenr return EBUSY; 215145516Sdarrenr } 216145516Sdarrenr 217255332Scy if (ipf_init_all(softc) < 0) { 218145516Sdarrenr SPL_X(s); 219145516Sdarrenr return EIO; 220145516Sdarrenr } 221145516Sdarrenr 222145516Sdarrenr 223255332Scy if (ipf_checkp != ipf_check) { 224255332Scy ipf_savep = ipf_checkp; 225255332Scy ipf_checkp = ipf_check; 226145516Sdarrenr } 227145516Sdarrenr 228255332Scy bzero((char *)ipfmain.ipf_selwait, sizeof(ipfmain.ipf_selwait)); 229255332Scy softc->ipf_running = 1; 230145516Sdarrenr 231255332Scy if (softc->ipf_control_forwarding & 1) 232181803Sbz V_ipforwarding = 1; 233145516Sdarrenr 234255332Scy ipid = 0; 235255332Scy 236145516Sdarrenr SPL_X(s); 237255755Scy#if 0 238255332Scy softc->ipf_slow_ch = timeout(ipf_timer_func, softc, 239255332Scy (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT); 240255755Scy#endif 241255755Scy callout_init(&softc->ipf_slow_ch, CALLOUT_MPSAFE); 242255755Scy callout_reset(&softc->ipf_slow_ch, (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT, 243255755Scy ipf_timer_func, softc); 244145516Sdarrenr return 0; 245145516Sdarrenr} 246145516Sdarrenr 247145516Sdarrenr 248145516Sdarrenr/* 249145516Sdarrenr * Disable the filter by removing the hooks from the IP input/output 250145516Sdarrenr * stream. 251145516Sdarrenr */ 252255332Scyint 253255332Scyipfdetach(softc) 254255332Scy ipf_main_softc_t *softc; 255145516Sdarrenr{ 256145516Sdarrenr#ifdef USE_SPL 257145516Sdarrenr int s; 258145516Sdarrenr#endif 259255332Scy 260255332Scy if (softc->ipf_control_forwarding & 2) 261181803Sbz V_ipforwarding = 0; 262145516Sdarrenr 263145516Sdarrenr SPL_NET(s); 264145516Sdarrenr 265255755Scy#if 0 266255332Scy if (softc->ipf_slow_ch.callout != NULL) 267255332Scy untimeout(ipf_timer_func, softc, softc->ipf_slow_ch); 268255332Scy bzero(&softc->ipf_slow, sizeof(softc->ipf_slow)); 269255755Scy#endif 270255755Scy callout_drain(&softc->ipf_slow_ch); 271145516Sdarrenr 272145516Sdarrenr#ifndef NETBSD_PF 273255332Scy if (ipf_checkp != NULL) 274255332Scy ipf_checkp = ipf_savep; 275255332Scy ipf_savep = NULL; 276145516Sdarrenr#endif 277145516Sdarrenr 278255332Scy ipf_fini_all(softc); 279145516Sdarrenr 280255332Scy softc->ipf_running = -2; 281145516Sdarrenr 282145516Sdarrenr SPL_X(s); 283145516Sdarrenr 284145516Sdarrenr return 0; 285145516Sdarrenr} 286145516Sdarrenr 287145516Sdarrenr 288145516Sdarrenr/* 289145516Sdarrenr * Filter ioctl interface. 290145516Sdarrenr */ 291255332Scyint 292255332Scyipfioctl(dev, cmd, data, mode 293145516Sdarrenr, p) 294255332Scy struct thread *p; 295192895Sjamie# define p_cred td_ucred 296170268Sdarrenr# define p_uid td_ucred->cr_ruid 297255332Scy struct cdev *dev; 298255332Scy ioctlcmd_t cmd; 299255332Scy caddr_t data; 300255332Scy int mode; 301145516Sdarrenr{ 302170268Sdarrenr int error = 0, unit = 0; 303170268Sdarrenr SPL_INT(s); 304145516Sdarrenr 305255332Scy#if (BSD >= 199306) 306255332Scy if (securelevel_ge(p->p_cred, 3) && (mode & FWRITE)) 307255332Scy { 308255332Scy ipfmain.ipf_interror = 130001; 309145516Sdarrenr return EPERM; 310255332Scy } 311145516Sdarrenr#endif 312145516Sdarrenr 313145516Sdarrenr unit = GET_MINOR(dev); 314255332Scy if ((IPL_LOGMAX < unit) || (unit < 0)) { 315255332Scy ipfmain.ipf_interror = 130002; 316145516Sdarrenr return ENXIO; 317255332Scy } 318145516Sdarrenr 319255332Scy if (ipfmain.ipf_running <= 0) { 320255332Scy if (unit != IPL_LOGIPF && cmd != SIOCIPFINTERROR) { 321255332Scy ipfmain.ipf_interror = 130003; 322145516Sdarrenr return EIO; 323255332Scy } 324145516Sdarrenr if (cmd != SIOCIPFGETNEXT && cmd != SIOCIPFGET && 325173181Sdarrenr cmd != SIOCIPFSET && cmd != SIOCFRENB && 326255332Scy cmd != SIOCGETFS && cmd != SIOCGETFF && 327255332Scy cmd != SIOCIPFINTERROR) { 328255332Scy ipfmain.ipf_interror = 130004; 329145516Sdarrenr return EIO; 330255332Scy } 331145516Sdarrenr } 332145516Sdarrenr 333145516Sdarrenr SPL_NET(s); 334145516Sdarrenr 335275213Scy CURVNET_SET(TD_TO_VNET(p)); 336255332Scy error = ipf_ioctlswitch(&ipfmain, unit, data, cmd, mode, p->p_uid, p); 337275213Scy CURVNET_RESTORE(); 338145516Sdarrenr if (error != -1) { 339145516Sdarrenr SPL_X(s); 340145516Sdarrenr return error; 341145516Sdarrenr } 342145516Sdarrenr 343145516Sdarrenr SPL_X(s); 344161356Sguido 345145516Sdarrenr return error; 346145516Sdarrenr} 347145516Sdarrenr 348145516Sdarrenr 349145516Sdarrenr/* 350255332Scy * ipf_send_reset - this could conceivably be a call to tcp_respond(), but that 351145516Sdarrenr * requires a large amount of setting up and isn't any more efficient. 352145516Sdarrenr */ 353255332Scyint 354255332Scyipf_send_reset(fin) 355255332Scy fr_info_t *fin; 356145516Sdarrenr{ 357145516Sdarrenr struct tcphdr *tcp, *tcp2; 358145516Sdarrenr int tlen = 0, hlen; 359145516Sdarrenr struct mbuf *m; 360145516Sdarrenr#ifdef USE_INET6 361145516Sdarrenr ip6_t *ip6; 362145516Sdarrenr#endif 363145516Sdarrenr ip_t *ip; 364145516Sdarrenr 365145516Sdarrenr tcp = fin->fin_dp; 366145516Sdarrenr if (tcp->th_flags & TH_RST) 367145516Sdarrenr return -1; /* feedback loop */ 368145516Sdarrenr 369255332Scy if (ipf_checkl4sum(fin) == -1) 370145516Sdarrenr return -1; 371145516Sdarrenr 372145516Sdarrenr tlen = fin->fin_dlen - (TCP_OFF(tcp) << 2) + 373145516Sdarrenr ((tcp->th_flags & TH_SYN) ? 1 : 0) + 374145516Sdarrenr ((tcp->th_flags & TH_FIN) ? 1 : 0); 375145516Sdarrenr 376145516Sdarrenr#ifdef USE_INET6 377145516Sdarrenr hlen = (fin->fin_v == 6) ? sizeof(ip6_t) : sizeof(ip_t); 378145516Sdarrenr#else 379145516Sdarrenr hlen = sizeof(ip_t); 380145516Sdarrenr#endif 381145516Sdarrenr#ifdef MGETHDR 382145516Sdarrenr MGETHDR(m, M_DONTWAIT, MT_HEADER); 383145516Sdarrenr#else 384145516Sdarrenr MGET(m, M_DONTWAIT, MT_HEADER); 385145516Sdarrenr#endif 386145516Sdarrenr if (m == NULL) 387145516Sdarrenr return -1; 388145516Sdarrenr if (sizeof(*tcp2) + hlen > MLEN) { 389145516Sdarrenr MCLGET(m, M_DONTWAIT); 390145516Sdarrenr if ((m->m_flags & M_EXT) == 0) { 391145516Sdarrenr FREE_MB_T(m); 392145516Sdarrenr return -1; 393145516Sdarrenr } 394145516Sdarrenr } 395145516Sdarrenr 396145516Sdarrenr m->m_len = sizeof(*tcp2) + hlen; 397145516Sdarrenr#if (BSD >= 199103) 398145516Sdarrenr m->m_data += max_linkhdr; 399145516Sdarrenr m->m_pkthdr.len = m->m_len; 400145516Sdarrenr m->m_pkthdr.rcvif = (struct ifnet *)0; 401145516Sdarrenr#endif 402145516Sdarrenr ip = mtod(m, struct ip *); 403145516Sdarrenr bzero((char *)ip, hlen); 404145516Sdarrenr#ifdef USE_INET6 405145516Sdarrenr ip6 = (ip6_t *)ip; 406145516Sdarrenr#endif 407145516Sdarrenr tcp2 = (struct tcphdr *)((char *)ip + hlen); 408145516Sdarrenr tcp2->th_sport = tcp->th_dport; 409145516Sdarrenr tcp2->th_dport = tcp->th_sport; 410145516Sdarrenr 411145516Sdarrenr if (tcp->th_flags & TH_ACK) { 412145516Sdarrenr tcp2->th_seq = tcp->th_ack; 413145516Sdarrenr tcp2->th_flags = TH_RST; 414145516Sdarrenr tcp2->th_ack = 0; 415145516Sdarrenr } else { 416145516Sdarrenr tcp2->th_seq = 0; 417145516Sdarrenr tcp2->th_ack = ntohl(tcp->th_seq); 418145516Sdarrenr tcp2->th_ack += tlen; 419145516Sdarrenr tcp2->th_ack = htonl(tcp2->th_ack); 420145516Sdarrenr tcp2->th_flags = TH_RST|TH_ACK; 421145516Sdarrenr } 422145516Sdarrenr TCP_X2_A(tcp2, 0); 423145516Sdarrenr TCP_OFF_A(tcp2, sizeof(*tcp2) >> 2); 424145516Sdarrenr tcp2->th_win = tcp->th_win; 425145516Sdarrenr tcp2->th_sum = 0; 426145516Sdarrenr tcp2->th_urp = 0; 427145516Sdarrenr 428145516Sdarrenr#ifdef USE_INET6 429145516Sdarrenr if (fin->fin_v == 6) { 430145516Sdarrenr ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; 431145516Sdarrenr ip6->ip6_plen = htons(sizeof(struct tcphdr)); 432145516Sdarrenr ip6->ip6_nxt = IPPROTO_TCP; 433145516Sdarrenr ip6->ip6_hlim = 0; 434255332Scy ip6->ip6_src = fin->fin_dst6.in6; 435255332Scy ip6->ip6_dst = fin->fin_src6.in6; 436145516Sdarrenr tcp2->th_sum = in6_cksum(m, IPPROTO_TCP, 437145516Sdarrenr sizeof(*ip6), sizeof(*tcp2)); 438255332Scy return ipf_send_ip(fin, m); 439145516Sdarrenr } 440145516Sdarrenr#endif 441145516Sdarrenr ip->ip_p = IPPROTO_TCP; 442145516Sdarrenr ip->ip_len = htons(sizeof(struct tcphdr)); 443145516Sdarrenr ip->ip_src.s_addr = fin->fin_daddr; 444145516Sdarrenr ip->ip_dst.s_addr = fin->fin_saddr; 445145516Sdarrenr tcp2->th_sum = in_cksum(m, hlen + sizeof(*tcp2)); 446255332Scy ip->ip_len = htons(hlen + sizeof(*tcp2)); 447255332Scy return ipf_send_ip(fin, m); 448145516Sdarrenr} 449145516Sdarrenr 450145516Sdarrenr 451255332Scy/* 452255332Scy * ip_len must be in network byte order when called. 453255332Scy */ 454255332Scystatic int 455255332Scyipf_send_ip(fin, m) 456255332Scy fr_info_t *fin; 457255332Scy mb_t *m; 458145516Sdarrenr{ 459145516Sdarrenr fr_info_t fnew; 460145516Sdarrenr ip_t *ip, *oip; 461145516Sdarrenr int hlen; 462145516Sdarrenr 463145516Sdarrenr ip = mtod(m, ip_t *); 464145516Sdarrenr bzero((char *)&fnew, sizeof(fnew)); 465255332Scy fnew.fin_main_soft = fin->fin_main_soft; 466145516Sdarrenr 467145516Sdarrenr IP_V_A(ip, fin->fin_v); 468145516Sdarrenr switch (fin->fin_v) 469145516Sdarrenr { 470145516Sdarrenr case 4 : 471255332Scy oip = fin->fin_ip; 472255332Scy hlen = sizeof(*oip); 473145516Sdarrenr fnew.fin_v = 4; 474255332Scy fnew.fin_p = ip->ip_p; 475255332Scy fnew.fin_plen = ntohs(ip->ip_len); 476145516Sdarrenr IP_HL_A(ip, sizeof(*oip) >> 2); 477145516Sdarrenr ip->ip_tos = oip->ip_tos; 478145516Sdarrenr ip->ip_id = fin->fin_ip->ip_id; 479255332Scy#if defined(FreeBSD) && (__FreeBSD_version > 460000) 480255332Scy ip->ip_off = htons(path_mtu_discovery ? IP_DF : 0); 481145516Sdarrenr#else 482145516Sdarrenr ip->ip_off = 0; 483145516Sdarrenr#endif 484181803Sbz ip->ip_ttl = V_ip_defttl; 485145516Sdarrenr ip->ip_sum = 0; 486145516Sdarrenr break; 487145516Sdarrenr#ifdef USE_INET6 488145516Sdarrenr case 6 : 489145516Sdarrenr { 490145516Sdarrenr ip6_t *ip6 = (ip6_t *)ip; 491145516Sdarrenr 492145516Sdarrenr ip6->ip6_vfc = 0x60; 493145516Sdarrenr ip6->ip6_hlim = IPDEFTTL; 494145516Sdarrenr 495255332Scy hlen = sizeof(*ip6); 496255332Scy fnew.fin_p = ip6->ip6_nxt; 497145516Sdarrenr fnew.fin_v = 6; 498255332Scy fnew.fin_plen = ntohs(ip6->ip6_plen) + hlen; 499145516Sdarrenr break; 500145516Sdarrenr } 501145516Sdarrenr#endif 502145516Sdarrenr default : 503145516Sdarrenr return EINVAL; 504145516Sdarrenr } 505145516Sdarrenr#ifdef IPSEC 506145516Sdarrenr m->m_pkthdr.rcvif = NULL; 507145516Sdarrenr#endif 508145516Sdarrenr 509145516Sdarrenr fnew.fin_ifp = fin->fin_ifp; 510145516Sdarrenr fnew.fin_flx = FI_NOCKSUM; 511145516Sdarrenr fnew.fin_m = m; 512145516Sdarrenr fnew.fin_ip = ip; 513255332Scy fnew.fin_mp = &m; 514145516Sdarrenr fnew.fin_hlen = hlen; 515145516Sdarrenr fnew.fin_dp = (char *)ip + hlen; 516255332Scy (void) ipf_makefrip(hlen, ip, &fnew); 517145516Sdarrenr 518255332Scy return ipf_fastroute(m, &m, &fnew, NULL); 519145516Sdarrenr} 520145516Sdarrenr 521145516Sdarrenr 522255332Scyint 523255332Scyipf_send_icmp_err(type, fin, dst) 524255332Scy int type; 525255332Scy fr_info_t *fin; 526255332Scy int dst; 527145516Sdarrenr{ 528145516Sdarrenr int err, hlen, xtra, iclen, ohlen, avail, code; 529145516Sdarrenr struct in_addr dst4; 530145516Sdarrenr struct icmp *icmp; 531145516Sdarrenr struct mbuf *m; 532255332Scy i6addr_t dst6; 533145516Sdarrenr void *ifp; 534145516Sdarrenr#ifdef USE_INET6 535145516Sdarrenr ip6_t *ip6; 536145516Sdarrenr#endif 537145516Sdarrenr ip_t *ip, *ip2; 538145516Sdarrenr 539172776Sdarrenr if ((type < 0) || (type >= ICMP_MAXTYPE)) 540145516Sdarrenr return -1; 541145516Sdarrenr 542145516Sdarrenr code = fin->fin_icode; 543145516Sdarrenr#ifdef USE_INET6 544255332Scy#if 0 545255332Scy /* XXX Fix an off by one error: s/>/>=/ 546255332Scy was: 547255332Scy if ((code < 0) || (code > sizeof(icmptoicmp6unreach)/sizeof(int))) 548255332Scy Fix obtained from NetBSD ip_fil_netbsd.c r1.4: */ 549255332Scy#endif 550255332Scy if ((code < 0) || (code >= sizeof(icmptoicmp6unreach)/sizeof(int))) 551145516Sdarrenr return -1; 552145516Sdarrenr#endif 553145516Sdarrenr 554255332Scy if (ipf_checkl4sum(fin) == -1) 555145516Sdarrenr return -1; 556145516Sdarrenr#ifdef MGETHDR 557145516Sdarrenr MGETHDR(m, M_DONTWAIT, MT_HEADER); 558145516Sdarrenr#else 559145516Sdarrenr MGET(m, M_DONTWAIT, MT_HEADER); 560145516Sdarrenr#endif 561145516Sdarrenr if (m == NULL) 562145516Sdarrenr return -1; 563145516Sdarrenr avail = MHLEN; 564145516Sdarrenr 565145516Sdarrenr xtra = 0; 566145516Sdarrenr hlen = 0; 567145516Sdarrenr ohlen = 0; 568255332Scy dst4.s_addr = 0; 569145516Sdarrenr ifp = fin->fin_ifp; 570145516Sdarrenr if (fin->fin_v == 4) { 571255332Scy if ((fin->fin_p == IPPROTO_ICMP) && !(fin->fin_flx & FI_SHORT)) 572145516Sdarrenr switch (ntohs(fin->fin_data[0]) >> 8) 573145516Sdarrenr { 574145516Sdarrenr case ICMP_ECHO : 575145516Sdarrenr case ICMP_TSTAMP : 576145516Sdarrenr case ICMP_IREQ : 577145516Sdarrenr case ICMP_MASKREQ : 578145516Sdarrenr break; 579145516Sdarrenr default : 580145516Sdarrenr FREE_MB_T(m); 581145516Sdarrenr return 0; 582145516Sdarrenr } 583145516Sdarrenr 584145516Sdarrenr if (dst == 0) { 585255332Scy if (ipf_ifpaddr(&ipfmain, 4, FRI_NORMAL, ifp, 586255332Scy &dst6, NULL) == -1) { 587145516Sdarrenr FREE_MB_T(m); 588145516Sdarrenr return -1; 589145516Sdarrenr } 590255332Scy dst4 = dst6.in4; 591145516Sdarrenr } else 592145516Sdarrenr dst4.s_addr = fin->fin_daddr; 593145516Sdarrenr 594145516Sdarrenr hlen = sizeof(ip_t); 595145516Sdarrenr ohlen = fin->fin_hlen; 596255332Scy iclen = hlen + offsetof(struct icmp, icmp_ip) + ohlen; 597145516Sdarrenr if (fin->fin_hlen < fin->fin_plen) 598145516Sdarrenr xtra = MIN(fin->fin_dlen, 8); 599145516Sdarrenr else 600145516Sdarrenr xtra = 0; 601145516Sdarrenr } 602145516Sdarrenr 603145516Sdarrenr#ifdef USE_INET6 604145516Sdarrenr else if (fin->fin_v == 6) { 605145516Sdarrenr hlen = sizeof(ip6_t); 606145516Sdarrenr ohlen = sizeof(ip6_t); 607255332Scy iclen = hlen + offsetof(struct icmp, icmp_ip) + ohlen; 608145516Sdarrenr type = icmptoicmp6types[type]; 609145516Sdarrenr if (type == ICMP6_DST_UNREACH) 610145516Sdarrenr code = icmptoicmp6unreach[code]; 611145516Sdarrenr 612255332Scy if (iclen + max_linkhdr + fin->fin_plen > avail) { 613145516Sdarrenr MCLGET(m, M_DONTWAIT); 614145516Sdarrenr if ((m->m_flags & M_EXT) == 0) { 615145516Sdarrenr FREE_MB_T(m); 616145516Sdarrenr return -1; 617145516Sdarrenr } 618145516Sdarrenr avail = MCLBYTES; 619145516Sdarrenr } 620255332Scy xtra = MIN(fin->fin_plen, avail - iclen - max_linkhdr); 621255332Scy xtra = MIN(xtra, IPV6_MMTU - iclen); 622145516Sdarrenr if (dst == 0) { 623255332Scy if (ipf_ifpaddr(&ipfmain, 6, FRI_NORMAL, ifp, 624255332Scy &dst6, NULL) == -1) { 625145516Sdarrenr FREE_MB_T(m); 626145516Sdarrenr return -1; 627145516Sdarrenr } 628145516Sdarrenr } else 629145516Sdarrenr dst6 = fin->fin_dst6; 630145516Sdarrenr } 631145516Sdarrenr#endif 632145516Sdarrenr else { 633145516Sdarrenr FREE_MB_T(m); 634145516Sdarrenr return -1; 635145516Sdarrenr } 636145516Sdarrenr 637145516Sdarrenr avail -= (max_linkhdr + iclen); 638145516Sdarrenr if (avail < 0) { 639145516Sdarrenr FREE_MB_T(m); 640145516Sdarrenr return -1; 641145516Sdarrenr } 642145516Sdarrenr if (xtra > avail) 643145516Sdarrenr xtra = avail; 644145516Sdarrenr iclen += xtra; 645145516Sdarrenr m->m_data += max_linkhdr; 646145516Sdarrenr m->m_pkthdr.rcvif = (struct ifnet *)0; 647145516Sdarrenr m->m_pkthdr.len = iclen; 648145516Sdarrenr m->m_len = iclen; 649145516Sdarrenr ip = mtod(m, ip_t *); 650145516Sdarrenr icmp = (struct icmp *)((char *)ip + hlen); 651145516Sdarrenr ip2 = (ip_t *)&icmp->icmp_ip; 652145516Sdarrenr 653145516Sdarrenr icmp->icmp_type = type; 654145516Sdarrenr icmp->icmp_code = fin->fin_icode; 655145516Sdarrenr icmp->icmp_cksum = 0; 656145516Sdarrenr#ifdef icmp_nextmtu 657255332Scy if (type == ICMP_UNREACH && fin->fin_icode == ICMP_UNREACH_NEEDFRAG) { 658255332Scy if (fin->fin_mtu != 0) { 659255332Scy icmp->icmp_nextmtu = htons(fin->fin_mtu); 660255332Scy 661255332Scy } else if (ifp != NULL) { 662255332Scy icmp->icmp_nextmtu = htons(GETIFMTU_4(ifp)); 663255332Scy 664255332Scy } else { /* make up a number... */ 665255332Scy icmp->icmp_nextmtu = htons(fin->fin_plen - 20); 666255332Scy } 667255332Scy } 668145516Sdarrenr#endif 669145516Sdarrenr 670145516Sdarrenr bcopy((char *)fin->fin_ip, (char *)ip2, ohlen); 671145516Sdarrenr 672145516Sdarrenr#ifdef USE_INET6 673145516Sdarrenr ip6 = (ip6_t *)ip; 674145516Sdarrenr if (fin->fin_v == 6) { 675145516Sdarrenr ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; 676145516Sdarrenr ip6->ip6_plen = htons(iclen - hlen); 677145516Sdarrenr ip6->ip6_nxt = IPPROTO_ICMPV6; 678145516Sdarrenr ip6->ip6_hlim = 0; 679255332Scy ip6->ip6_src = dst6.in6; 680255332Scy ip6->ip6_dst = fin->fin_src6.in6; 681145516Sdarrenr if (xtra > 0) 682145516Sdarrenr bcopy((char *)fin->fin_ip + ohlen, 683145516Sdarrenr (char *)&icmp->icmp_ip + ohlen, xtra); 684145516Sdarrenr icmp->icmp_cksum = in6_cksum(m, IPPROTO_ICMPV6, 685145516Sdarrenr sizeof(*ip6), iclen - hlen); 686145516Sdarrenr } else 687145516Sdarrenr#endif 688145516Sdarrenr { 689145516Sdarrenr ip->ip_p = IPPROTO_ICMP; 690145516Sdarrenr ip->ip_src.s_addr = dst4.s_addr; 691145516Sdarrenr ip->ip_dst.s_addr = fin->fin_saddr; 692145516Sdarrenr 693145516Sdarrenr if (xtra > 0) 694145516Sdarrenr bcopy((char *)fin->fin_ip + ohlen, 695145516Sdarrenr (char *)&icmp->icmp_ip + ohlen, xtra); 696145516Sdarrenr icmp->icmp_cksum = ipf_cksum((u_short *)icmp, 697145516Sdarrenr sizeof(*icmp) + 8); 698255332Scy ip->ip_len = htons(iclen); 699145516Sdarrenr ip->ip_p = IPPROTO_ICMP; 700145516Sdarrenr } 701255332Scy err = ipf_send_ip(fin, m); 702145516Sdarrenr return err; 703145516Sdarrenr} 704145516Sdarrenr 705145516Sdarrenr 706145516Sdarrenr 707145516Sdarrenr 708173181Sdarrenr/* 709173181Sdarrenr * m0 - pointer to mbuf where the IP packet starts 710173181Sdarrenr * mpp - pointer to the mbuf pointer that is the start of the mbuf chain 711173181Sdarrenr */ 712255332Scyint 713255332Scyipf_fastroute(m0, mpp, fin, fdp) 714255332Scy mb_t *m0, **mpp; 715255332Scy fr_info_t *fin; 716255332Scy frdest_t *fdp; 717145516Sdarrenr{ 718145516Sdarrenr register struct ip *ip, *mhip; 719173181Sdarrenr register struct mbuf *m = *mpp; 720145516Sdarrenr register struct route *ro; 721145516Sdarrenr int len, off, error = 0, hlen, code; 722145516Sdarrenr struct ifnet *ifp, *sifp; 723145516Sdarrenr struct sockaddr_in *dst; 724145516Sdarrenr struct route iproute; 725145516Sdarrenr u_short ip_off; 726255332Scy frdest_t node; 727145516Sdarrenr frentry_t *fr; 728145516Sdarrenr 729161356Sguido ro = NULL; 730161356Sguido 731145516Sdarrenr#ifdef M_WRITABLE 732145516Sdarrenr /* 733145516Sdarrenr * HOT FIX/KLUDGE: 734145516Sdarrenr * 735145516Sdarrenr * If the mbuf we're about to send is not writable (because of 736145516Sdarrenr * a cluster reference, for example) we'll need to make a copy 737145516Sdarrenr * of it since this routine modifies the contents. 738145516Sdarrenr * 739145516Sdarrenr * If you have non-crappy network hardware that can transmit data 740145516Sdarrenr * from the mbuf, rather than making a copy, this is gonna be a 741145516Sdarrenr * problem. 742145516Sdarrenr */ 743145516Sdarrenr if (M_WRITABLE(m) == 0) { 744161356Sguido m0 = m_dup(m, M_DONTWAIT); 745161356Sguido if (m0 != 0) { 746145516Sdarrenr FREE_MB_T(m); 747145516Sdarrenr m = m0; 748145516Sdarrenr *mpp = m; 749145516Sdarrenr } else { 750145516Sdarrenr error = ENOBUFS; 751145516Sdarrenr FREE_MB_T(m); 752161356Sguido goto done; 753145516Sdarrenr } 754145516Sdarrenr } 755145516Sdarrenr#endif 756145516Sdarrenr 757145516Sdarrenr#ifdef USE_INET6 758145516Sdarrenr if (fin->fin_v == 6) { 759145516Sdarrenr /* 760145516Sdarrenr * currently "to <if>" and "to <if>:ip#" are not supported 761145516Sdarrenr * for IPv6 762145516Sdarrenr */ 763255332Scy return ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL); 764145516Sdarrenr } 765145516Sdarrenr#endif 766145516Sdarrenr 767145516Sdarrenr hlen = fin->fin_hlen; 768145516Sdarrenr ip = mtod(m0, struct ip *); 769255332Scy ifp = NULL; 770145516Sdarrenr 771145516Sdarrenr /* 772145516Sdarrenr * Route packet. 773145516Sdarrenr */ 774145516Sdarrenr ro = &iproute; 775255332Scy bzero(ro, sizeof (*ro)); 776145516Sdarrenr dst = (struct sockaddr_in *)&ro->ro_dst; 777145516Sdarrenr dst->sin_family = AF_INET; 778145516Sdarrenr dst->sin_addr = ip->ip_dst; 779145516Sdarrenr 780145516Sdarrenr fr = fin->fin_fr; 781255332Scy if ((fr != NULL) && !(fr->fr_flags & FR_KEEPSTATE) && (fdp != NULL) && 782255332Scy (fdp->fd_type == FRD_DSTLIST)) { 783255332Scy if (ipf_dstlist_select_node(fin, fdp->fd_ptr, NULL, &node) == 0) 784255332Scy fdp = &node; 785255332Scy } 786255332Scy 787145516Sdarrenr if (fdp != NULL) 788255332Scy ifp = fdp->fd_ptr; 789145516Sdarrenr else 790145516Sdarrenr ifp = fin->fin_ifp; 791145516Sdarrenr 792255332Scy if ((ifp == NULL) && ((fr == NULL) || !(fr->fr_flags & FR_FASTROUTE))) { 793145516Sdarrenr error = -2; 794145516Sdarrenr goto bad; 795145516Sdarrenr } 796145516Sdarrenr 797161356Sguido if ((fdp != NULL) && (fdp->fd_ip.s_addr != 0)) 798161356Sguido dst->sin_addr = fdp->fd_ip; 799145516Sdarrenr 800145516Sdarrenr dst->sin_len = sizeof(*dst); 801267868Scy in_rtalloc(ro, M_GETFIB(m0)); 802145516Sdarrenr 803145516Sdarrenr if ((ifp == NULL) && (ro->ro_rt != NULL)) 804145516Sdarrenr ifp = ro->ro_rt->rt_ifp; 805145516Sdarrenr 806145516Sdarrenr if ((ro->ro_rt == NULL) || (ifp == NULL)) { 807145516Sdarrenr if (in_localaddr(ip->ip_dst)) 808145516Sdarrenr error = EHOSTUNREACH; 809145516Sdarrenr else 810145516Sdarrenr error = ENETUNREACH; 811145516Sdarrenr goto bad; 812145516Sdarrenr } 813145516Sdarrenr if (ro->ro_rt->rt_flags & RTF_GATEWAY) 814145516Sdarrenr dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway; 815145516Sdarrenr if (ro->ro_rt) 816263478Sglebius counter_u64_add(ro->ro_rt->rt_pksent, 1); 817145516Sdarrenr 818145516Sdarrenr /* 819145516Sdarrenr * For input packets which are being "fastrouted", they won't 820145516Sdarrenr * go back through output filtering and miss their chance to get 821170268Sdarrenr * NAT'd and counted. Duplicated packets aren't considered to be 822170268Sdarrenr * part of the normal packet stream, so do not NAT them or pass 823170268Sdarrenr * them through stateful checking, etc. 824145516Sdarrenr */ 825170268Sdarrenr if ((fdp != &fr->fr_dif) && (fin->fin_out == 0)) { 826145516Sdarrenr sifp = fin->fin_ifp; 827145516Sdarrenr fin->fin_ifp = ifp; 828145516Sdarrenr fin->fin_out = 1; 829255332Scy (void) ipf_acctpkt(fin, NULL); 830145516Sdarrenr fin->fin_fr = NULL; 831145516Sdarrenr if (!fr || !(fr->fr_flags & FR_RETMASK)) { 832145516Sdarrenr u_32_t pass; 833145516Sdarrenr 834255332Scy (void) ipf_state_check(fin, &pass); 835145516Sdarrenr } 836145516Sdarrenr 837255332Scy switch (ipf_nat_checkout(fin, NULL)) 838145516Sdarrenr { 839145516Sdarrenr case 0 : 840145516Sdarrenr break; 841145516Sdarrenr case 1 : 842145516Sdarrenr ip->ip_sum = 0; 843145516Sdarrenr break; 844145516Sdarrenr case -1 : 845145516Sdarrenr error = -1; 846173181Sdarrenr goto bad; 847145516Sdarrenr break; 848145516Sdarrenr } 849145516Sdarrenr 850145516Sdarrenr fin->fin_ifp = sifp; 851145516Sdarrenr fin->fin_out = 0; 852145516Sdarrenr } else 853145516Sdarrenr ip->ip_sum = 0; 854145516Sdarrenr /* 855145516Sdarrenr * If small enough for interface, can just send directly. 856145516Sdarrenr */ 857255332Scy if (ntohs(ip->ip_len) <= ifp->if_mtu) { 858145516Sdarrenr if (!ip->ip_sum) 859145516Sdarrenr ip->ip_sum = in_cksum(m, hlen); 860145516Sdarrenr error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst, 861255332Scy ro 862255332Scy ); 863145516Sdarrenr goto done; 864145516Sdarrenr } 865145516Sdarrenr /* 866145516Sdarrenr * Too large for interface; fragment if possible. 867145516Sdarrenr * Must be able to put at least 8 bytes per fragment. 868145516Sdarrenr */ 869145516Sdarrenr ip_off = ntohs(ip->ip_off); 870145516Sdarrenr if (ip_off & IP_DF) { 871145516Sdarrenr error = EMSGSIZE; 872145516Sdarrenr goto bad; 873145516Sdarrenr } 874145516Sdarrenr len = (ifp->if_mtu - hlen) &~ 7; 875145516Sdarrenr if (len < 8) { 876145516Sdarrenr error = EMSGSIZE; 877145516Sdarrenr goto bad; 878145516Sdarrenr } 879145516Sdarrenr 880145516Sdarrenr { 881145516Sdarrenr int mhlen, firstlen = len; 882145516Sdarrenr struct mbuf **mnext = &m->m_act; 883145516Sdarrenr 884145516Sdarrenr /* 885145516Sdarrenr * Loop through length of segment after first fragment, 886145516Sdarrenr * make new header and copy data of each part and link onto chain. 887145516Sdarrenr */ 888145516Sdarrenr m0 = m; 889145516Sdarrenr mhlen = sizeof (struct ip); 890255332Scy for (off = hlen + len; off < ntohs(ip->ip_len); off += len) { 891145516Sdarrenr#ifdef MGETHDR 892145516Sdarrenr MGETHDR(m, M_DONTWAIT, MT_HEADER); 893145516Sdarrenr#else 894145516Sdarrenr MGET(m, M_DONTWAIT, MT_HEADER); 895145516Sdarrenr#endif 896145516Sdarrenr if (m == 0) { 897145516Sdarrenr m = m0; 898145516Sdarrenr error = ENOBUFS; 899145516Sdarrenr goto bad; 900145516Sdarrenr } 901145516Sdarrenr m->m_data += max_linkhdr; 902145516Sdarrenr mhip = mtod(m, struct ip *); 903145516Sdarrenr bcopy((char *)ip, (char *)mhip, sizeof(*ip)); 904145516Sdarrenr if (hlen > sizeof (struct ip)) { 905145516Sdarrenr mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip); 906145516Sdarrenr IP_HL_A(mhip, mhlen >> 2); 907145516Sdarrenr } 908145516Sdarrenr m->m_len = mhlen; 909145516Sdarrenr mhip->ip_off = ((off - hlen) >> 3) + ip_off; 910255332Scy if (off + len >= ntohs(ip->ip_len)) 911255332Scy len = ntohs(ip->ip_len) - off; 912145516Sdarrenr else 913145516Sdarrenr mhip->ip_off |= IP_MF; 914145516Sdarrenr mhip->ip_len = htons((u_short)(len + mhlen)); 915161356Sguido *mnext = m; 916145516Sdarrenr m->m_next = m_copy(m0, off, len); 917145516Sdarrenr if (m->m_next == 0) { 918145516Sdarrenr error = ENOBUFS; /* ??? */ 919145516Sdarrenr goto sendorfree; 920145516Sdarrenr } 921145516Sdarrenr m->m_pkthdr.len = mhlen + len; 922145516Sdarrenr m->m_pkthdr.rcvif = NULL; 923145516Sdarrenr mhip->ip_off = htons((u_short)mhip->ip_off); 924145516Sdarrenr mhip->ip_sum = 0; 925145516Sdarrenr mhip->ip_sum = in_cksum(m, mhlen); 926145516Sdarrenr mnext = &m->m_act; 927145516Sdarrenr } 928145516Sdarrenr /* 929145516Sdarrenr * Update first fragment by trimming what's been copied out 930145516Sdarrenr * and updating header, then send each fragment (in order). 931145516Sdarrenr */ 932145516Sdarrenr m_adj(m0, hlen + firstlen - ip->ip_len); 933145516Sdarrenr ip->ip_len = htons((u_short)(hlen + firstlen)); 934145516Sdarrenr ip->ip_off = htons((u_short)IP_MF); 935145516Sdarrenr ip->ip_sum = 0; 936145516Sdarrenr ip->ip_sum = in_cksum(m0, hlen); 937145516Sdarrenrsendorfree: 938145516Sdarrenr for (m = m0; m; m = m0) { 939145516Sdarrenr m0 = m->m_act; 940145516Sdarrenr m->m_act = 0; 941145516Sdarrenr if (error == 0) 942145516Sdarrenr error = (*ifp->if_output)(ifp, m, 943255332Scy (struct sockaddr *)dst, 944255332Scy ro 945255332Scy ); 946145516Sdarrenr else 947145516Sdarrenr FREE_MB_T(m); 948145516Sdarrenr } 949255332Scy } 950145516Sdarrenrdone: 951145516Sdarrenr if (!error) 952255332Scy ipfmain.ipf_frouteok[0]++; 953145516Sdarrenr else 954255332Scy ipfmain.ipf_frouteok[1]++; 955145516Sdarrenr 956161356Sguido if ((ro != NULL) && (ro->ro_rt != NULL)) { 957145516Sdarrenr RTFREE(ro->ro_rt); 958145516Sdarrenr } 959145516Sdarrenr return 0; 960145516Sdarrenrbad: 961145516Sdarrenr if (error == EMSGSIZE) { 962145516Sdarrenr sifp = fin->fin_ifp; 963145516Sdarrenr code = fin->fin_icode; 964145516Sdarrenr fin->fin_icode = ICMP_UNREACH_NEEDFRAG; 965145516Sdarrenr fin->fin_ifp = ifp; 966255332Scy (void) ipf_send_icmp_err(ICMP_UNREACH, fin, 1); 967145516Sdarrenr fin->fin_ifp = sifp; 968145516Sdarrenr fin->fin_icode = code; 969145516Sdarrenr } 970145516Sdarrenr FREE_MB_T(m); 971145516Sdarrenr goto done; 972145516Sdarrenr} 973145516Sdarrenr 974145516Sdarrenr 975255332Scyint 976255332Scyipf_verifysrc(fin) 977255332Scy fr_info_t *fin; 978145516Sdarrenr{ 979145516Sdarrenr struct sockaddr_in *dst; 980145516Sdarrenr struct route iproute; 981145516Sdarrenr 982145516Sdarrenr bzero((char *)&iproute, sizeof(iproute)); 983145516Sdarrenr dst = (struct sockaddr_in *)&iproute.ro_dst; 984145516Sdarrenr dst->sin_len = sizeof(*dst); 985145516Sdarrenr dst->sin_family = AF_INET; 986145516Sdarrenr dst->sin_addr = fin->fin_src; 987178888Sjulian in_rtalloc(&iproute, 0); 988145516Sdarrenr if (iproute.ro_rt == NULL) 989145516Sdarrenr return 0; 990145516Sdarrenr return (fin->fin_ifp == iproute.ro_rt->rt_ifp); 991145516Sdarrenr} 992145516Sdarrenr 993145516Sdarrenr 994145516Sdarrenr/* 995145516Sdarrenr * return the first IP Address associated with an interface 996145516Sdarrenr */ 997255332Scyint 998255332Scyipf_ifpaddr(softc, v, atype, ifptr, inp, inpmask) 999255332Scy ipf_main_softc_t *softc; 1000255332Scy int v, atype; 1001255332Scy void *ifptr; 1002255332Scy i6addr_t *inp, *inpmask; 1003145516Sdarrenr{ 1004145516Sdarrenr#ifdef USE_INET6 1005145516Sdarrenr struct in6_addr *inp6 = NULL; 1006145516Sdarrenr#endif 1007145516Sdarrenr struct sockaddr *sock, *mask; 1008145516Sdarrenr struct sockaddr_in *sin; 1009145516Sdarrenr struct ifaddr *ifa; 1010145516Sdarrenr struct ifnet *ifp; 1011145516Sdarrenr 1012145516Sdarrenr if ((ifptr == NULL) || (ifptr == (void *)-1)) 1013145516Sdarrenr return -1; 1014145516Sdarrenr 1015145516Sdarrenr sin = NULL; 1016145516Sdarrenr ifp = ifptr; 1017145516Sdarrenr 1018145516Sdarrenr if (v == 4) 1019255332Scy inp->in4.s_addr = 0; 1020145516Sdarrenr#ifdef USE_INET6 1021145516Sdarrenr else if (v == 6) 1022255332Scy bzero((char *)inp, sizeof(*inp)); 1023145516Sdarrenr#endif 1024145516Sdarrenr ifa = TAILQ_FIRST(&ifp->if_addrhead); 1025145516Sdarrenr 1026145516Sdarrenr sock = ifa->ifa_addr; 1027145516Sdarrenr while (sock != NULL && ifa != NULL) { 1028145516Sdarrenr sin = (struct sockaddr_in *)sock; 1029145516Sdarrenr if ((v == 4) && (sin->sin_family == AF_INET)) 1030145516Sdarrenr break; 1031145516Sdarrenr#ifdef USE_INET6 1032145516Sdarrenr if ((v == 6) && (sin->sin_family == AF_INET6)) { 1033145516Sdarrenr inp6 = &((struct sockaddr_in6 *)sin)->sin6_addr; 1034145516Sdarrenr if (!IN6_IS_ADDR_LINKLOCAL(inp6) && 1035145516Sdarrenr !IN6_IS_ADDR_LOOPBACK(inp6)) 1036145516Sdarrenr break; 1037145516Sdarrenr } 1038145516Sdarrenr#endif 1039145516Sdarrenr ifa = TAILQ_NEXT(ifa, ifa_link); 1040145516Sdarrenr if (ifa != NULL) 1041145516Sdarrenr sock = ifa->ifa_addr; 1042145516Sdarrenr } 1043145516Sdarrenr 1044145516Sdarrenr if (ifa == NULL || sin == NULL) 1045145516Sdarrenr return -1; 1046145516Sdarrenr 1047145516Sdarrenr mask = ifa->ifa_netmask; 1048145516Sdarrenr if (atype == FRI_BROADCAST) 1049145516Sdarrenr sock = ifa->ifa_broadaddr; 1050145516Sdarrenr else if (atype == FRI_PEERADDR) 1051145516Sdarrenr sock = ifa->ifa_dstaddr; 1052145516Sdarrenr 1053161356Sguido if (sock == NULL) 1054161356Sguido return -1; 1055161356Sguido 1056145516Sdarrenr#ifdef USE_INET6 1057145516Sdarrenr if (v == 6) { 1058255332Scy return ipf_ifpfillv6addr(atype, (struct sockaddr_in6 *)sock, 1059255332Scy (struct sockaddr_in6 *)mask, 1060255332Scy inp, inpmask); 1061145516Sdarrenr } 1062145516Sdarrenr#endif 1063255332Scy return ipf_ifpfillv4addr(atype, (struct sockaddr_in *)sock, 1064255332Scy (struct sockaddr_in *)mask, 1065255332Scy &inp->in4, &inpmask->in4); 1066145516Sdarrenr} 1067145516Sdarrenr 1068145516Sdarrenr 1069255332Scyu_32_t 1070255332Scyipf_newisn(fin) 1071255332Scy fr_info_t *fin; 1072145516Sdarrenr{ 1073145516Sdarrenr u_32_t newiss; 1074145516Sdarrenr newiss = arc4random(); 1075145516Sdarrenr return newiss; 1076145516Sdarrenr} 1077145516Sdarrenr 1078145516Sdarrenr 1079145516Sdarrenr/* ------------------------------------------------------------------------ */ 1080255332Scy/* Function: ipf_nextipid */ 1081145516Sdarrenr/* Returns: int - 0 == success, -1 == error (packet should be droppped) */ 1082145516Sdarrenr/* Parameters: fin(I) - pointer to packet information */ 1083145516Sdarrenr/* */ 1084145516Sdarrenr/* Returns the next IPv4 ID to use for this packet. */ 1085145516Sdarrenr/* ------------------------------------------------------------------------ */ 1086255332Scyu_short 1087255332Scyipf_nextipid(fin) 1088255332Scy fr_info_t *fin; 1089145516Sdarrenr{ 1090145516Sdarrenr u_short id; 1091145516Sdarrenr 1092255332Scy#ifndef RANDOM_IP_ID 1093255332Scy MUTEX_ENTER(&ipfmain.ipf_rw); 1094145516Sdarrenr id = ipid++; 1095255332Scy MUTEX_EXIT(&ipfmain.ipf_rw); 1096145516Sdarrenr#else 1097145516Sdarrenr id = ip_randomid(); 1098145516Sdarrenr#endif 1099145516Sdarrenr 1100145516Sdarrenr return id; 1101145516Sdarrenr} 1102145516Sdarrenr 1103145516Sdarrenr 1104255332ScyINLINE int 1105255332Scyipf_checkv4sum(fin) 1106255332Scy fr_info_t *fin; 1107145516Sdarrenr{ 1108145516Sdarrenr#ifdef CSUM_DATA_VALID 1109145516Sdarrenr int manual = 0; 1110145516Sdarrenr u_short sum; 1111145516Sdarrenr ip_t *ip; 1112145516Sdarrenr mb_t *m; 1113145516Sdarrenr 1114145516Sdarrenr if ((fin->fin_flx & FI_NOCKSUM) != 0) 1115255332Scy return 0; 1116145516Sdarrenr 1117255332Scy if ((fin->fin_flx & FI_SHORT) != 0) 1118255332Scy return 1; 1119172776Sdarrenr 1120255332Scy if (fin->fin_cksum != FI_CK_NEEDED) 1121255332Scy return (fin->fin_cksum > FI_CK_NEEDED) ? 0 : -1; 1122255332Scy 1123145516Sdarrenr m = fin->fin_m; 1124145516Sdarrenr if (m == NULL) { 1125145516Sdarrenr manual = 1; 1126145516Sdarrenr goto skipauto; 1127145516Sdarrenr } 1128145516Sdarrenr ip = fin->fin_ip; 1129145516Sdarrenr 1130255332Scy if ((m->m_pkthdr.csum_flags & (CSUM_IP_CHECKED|CSUM_IP_VALID)) == 1131255332Scy CSUM_IP_CHECKED) { 1132255332Scy fin->fin_cksum = FI_CK_BAD; 1133255332Scy fin->fin_flx |= FI_BAD; 1134255332Scy return -1; 1135255332Scy } 1136145516Sdarrenr if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) { 1137289210Scy /* Depending on the driver, UDP may have zero checksum */ 1138289210Scy if (fin->fin_p == IPPROTO_UDP && (fin->fin_flx & 1139289210Scy (FI_FRAG|FI_SHORT|FI_BAD)) == 0) { 1140289210Scy udphdr_t *udp = fin->fin_dp; 1141289210Scy if (udp->uh_sum == 0) { 1142289210Scy /* 1143289210Scy * we're good no matter what the hardware 1144289210Scy * checksum flags and csum_data say (handling 1145289210Scy * of csum_data for zero UDP checksum is not 1146289210Scy * consistent across all drivers) 1147289210Scy */ 1148289210Scy fin->fin_cksum = 1; 1149289210Scy return 0; 1150289210Scy } 1151289210Scy } 1152289210Scy 1153145516Sdarrenr if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) 1154145516Sdarrenr sum = m->m_pkthdr.csum_data; 1155145516Sdarrenr else 1156145516Sdarrenr sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, 1157145516Sdarrenr htonl(m->m_pkthdr.csum_data + 1158255332Scy fin->fin_dlen + fin->fin_p)); 1159145516Sdarrenr sum ^= 0xffff; 1160172776Sdarrenr if (sum != 0) { 1161255332Scy fin->fin_cksum = FI_CK_BAD; 1162145516Sdarrenr fin->fin_flx |= FI_BAD; 1163172776Sdarrenr } else { 1164255332Scy fin->fin_cksum = FI_CK_SUMOK; 1165255332Scy return 0; 1166172776Sdarrenr } 1167255332Scy } else { 1168255332Scy if (m->m_pkthdr.csum_flags == CSUM_DELAY_DATA) { 1169255332Scy fin->fin_cksum = FI_CK_L4FULL; 1170255332Scy return 0; 1171255332Scy } else if (m->m_pkthdr.csum_flags == CSUM_TCP || 1172255332Scy m->m_pkthdr.csum_flags == CSUM_UDP) { 1173255332Scy fin->fin_cksum = FI_CK_L4PART; 1174255332Scy return 0; 1175255332Scy } else if (m->m_pkthdr.csum_flags == CSUM_IP) { 1176255332Scy fin->fin_cksum = FI_CK_L4PART; 1177255332Scy return 0; 1178255332Scy } else { 1179255332Scy manual = 1; 1180255332Scy } 1181255332Scy } 1182145516Sdarrenrskipauto: 1183255332Scy if (manual != 0) { 1184255332Scy if (ipf_checkl4sum(fin) == -1) { 1185145516Sdarrenr fin->fin_flx |= FI_BAD; 1186255332Scy return -1; 1187255332Scy } 1188255332Scy } 1189145516Sdarrenr#else 1190255332Scy if (ipf_checkl4sum(fin) == -1) { 1191145516Sdarrenr fin->fin_flx |= FI_BAD; 1192255332Scy return -1; 1193255332Scy } 1194145516Sdarrenr#endif 1195255332Scy return 0; 1196145516Sdarrenr} 1197145516Sdarrenr 1198145516Sdarrenr 1199145516Sdarrenr#ifdef USE_INET6 1200255332ScyINLINE int 1201255332Scyipf_checkv6sum(fin) 1202255332Scy fr_info_t *fin; 1203145516Sdarrenr{ 1204255332Scy if ((fin->fin_flx & FI_NOCKSUM) != 0) 1205255332Scy return 0; 1206255332Scy 1207255332Scy if ((fin->fin_flx & FI_SHORT) != 0) 1208255332Scy return 1; 1209255332Scy 1210255332Scy if (fin->fin_cksum != FI_CK_NEEDED) 1211255332Scy return (fin->fin_cksum > FI_CK_NEEDED) ? 0 : -1; 1212255332Scy 1213255332Scy if (ipf_checkl4sum(fin) == -1) { 1214145516Sdarrenr fin->fin_flx |= FI_BAD; 1215255332Scy return -1; 1216255332Scy } 1217255332Scy return 0; 1218145516Sdarrenr} 1219145516Sdarrenr#endif /* USE_INET6 */ 1220145516Sdarrenr 1221145516Sdarrenr 1222255332Scysize_t 1223255332Scymbufchainlen(m0) 1224255332Scy struct mbuf *m0; 1225255332Scy { 1226145516Sdarrenr size_t len; 1227145516Sdarrenr 1228145516Sdarrenr if ((m0->m_flags & M_PKTHDR) != 0) { 1229145516Sdarrenr len = m0->m_pkthdr.len; 1230145516Sdarrenr } else { 1231145516Sdarrenr struct mbuf *m; 1232145516Sdarrenr 1233145516Sdarrenr for (m = m0, len = 0; m != NULL; m = m->m_next) 1234145516Sdarrenr len += m->m_len; 1235145516Sdarrenr } 1236145516Sdarrenr return len; 1237145516Sdarrenr} 1238145516Sdarrenr 1239145516Sdarrenr 1240145516Sdarrenr/* ------------------------------------------------------------------------ */ 1241255332Scy/* Function: ipf_pullup */ 1242145516Sdarrenr/* Returns: NULL == pullup failed, else pointer to protocol header */ 1243255332Scy/* Parameters: xmin(I)- pointer to buffer where data packet starts */ 1244145516Sdarrenr/* fin(I) - pointer to packet information */ 1245145516Sdarrenr/* len(I) - number of bytes to pullup */ 1246145516Sdarrenr/* */ 1247145516Sdarrenr/* Attempt to move at least len bytes (from the start of the buffer) into a */ 1248145516Sdarrenr/* single buffer for ease of access. Operating system native functions are */ 1249145516Sdarrenr/* used to manage buffers - if necessary. If the entire packet ends up in */ 1250255332Scy/* a single buffer, set the FI_COALESCE flag even though ipf_coalesce() has */ 1251145516Sdarrenr/* not been called. Both fin_ip and fin_dp are updated before exiting _IF_ */ 1252145516Sdarrenr/* and ONLY if the pullup succeeds. */ 1253145516Sdarrenr/* */ 1254255332Scy/* We assume that 'xmin' is a pointer to a buffer that is part of the chain */ 1255145516Sdarrenr/* of buffers that starts at *fin->fin_mp. */ 1256145516Sdarrenr/* ------------------------------------------------------------------------ */ 1257255332Scyvoid * 1258255332Scyipf_pullup(xmin, fin, len) 1259255332Scy mb_t *xmin; 1260255332Scy fr_info_t *fin; 1261255332Scy int len; 1262145516Sdarrenr{ 1263255332Scy int dpoff, ipoff; 1264255332Scy mb_t *m = xmin; 1265145516Sdarrenr char *ip; 1266145516Sdarrenr 1267145516Sdarrenr if (m == NULL) 1268145516Sdarrenr return NULL; 1269145516Sdarrenr 1270145516Sdarrenr ip = (char *)fin->fin_ip; 1271145516Sdarrenr if ((fin->fin_flx & FI_COALESCE) != 0) 1272145516Sdarrenr return ip; 1273145516Sdarrenr 1274145516Sdarrenr ipoff = fin->fin_ipoff; 1275145516Sdarrenr if (fin->fin_dp != NULL) 1276145516Sdarrenr dpoff = (char *)fin->fin_dp - (char *)ip; 1277145516Sdarrenr else 1278145516Sdarrenr dpoff = 0; 1279145516Sdarrenr 1280145516Sdarrenr if (M_LEN(m) < len) { 1281255332Scy mb_t *n = *fin->fin_mp; 1282145516Sdarrenr /* 1283145516Sdarrenr * Assume that M_PKTHDR is set and just work with what is left 1284145516Sdarrenr * rather than check.. 1285145516Sdarrenr * Should not make any real difference, anyway. 1286145516Sdarrenr */ 1287255332Scy if (m != n) { 1288255332Scy /* 1289255332Scy * Record the mbuf that points to the mbuf that we're 1290255332Scy * about to go to work on so that we can update the 1291255332Scy * m_next appropriately later. 1292255332Scy */ 1293255332Scy for (; n->m_next != m; n = n->m_next) 1294255332Scy ; 1295255332Scy } else { 1296255332Scy n = NULL; 1297255332Scy } 1298255332Scy 1299255332Scy#ifdef MHLEN 1300145516Sdarrenr if (len > MHLEN) 1301145516Sdarrenr#else 1302145516Sdarrenr if (len > MLEN) 1303145516Sdarrenr#endif 1304145516Sdarrenr { 1305145516Sdarrenr#ifdef HAVE_M_PULLDOWN 1306145516Sdarrenr if (m_pulldown(m, 0, len, NULL) == NULL) 1307145516Sdarrenr m = NULL; 1308145516Sdarrenr#else 1309145516Sdarrenr FREE_MB_T(*fin->fin_mp); 1310145516Sdarrenr m = NULL; 1311255332Scy n = NULL; 1312145516Sdarrenr#endif 1313145516Sdarrenr } else 1314145516Sdarrenr { 1315145516Sdarrenr m = m_pullup(m, len); 1316145516Sdarrenr } 1317255332Scy if (n != NULL) 1318255332Scy n->m_next = m; 1319145516Sdarrenr if (m == NULL) { 1320255332Scy /* 1321255332Scy * When n is non-NULL, it indicates that m pointed to 1322255332Scy * a sub-chain (tail) of the mbuf and that the head 1323255332Scy * of this chain has not yet been free'd. 1324255332Scy */ 1325255332Scy if (n != NULL) { 1326255332Scy FREE_MB_T(*fin->fin_mp); 1327255332Scy } 1328255332Scy 1329255332Scy *fin->fin_mp = NULL; 1330172776Sdarrenr fin->fin_m = NULL; 1331145516Sdarrenr return NULL; 1332145516Sdarrenr } 1333172776Sdarrenr 1334255332Scy if (n == NULL) 1335255332Scy *fin->fin_mp = m; 1336255332Scy 1337172776Sdarrenr while (M_LEN(m) == 0) { 1338172776Sdarrenr m = m->m_next; 1339172776Sdarrenr } 1340172776Sdarrenr fin->fin_m = m; 1341145516Sdarrenr ip = MTOD(m, char *) + ipoff; 1342255332Scy 1343255332Scy fin->fin_ip = (ip_t *)ip; 1344255332Scy if (fin->fin_dp != NULL) 1345255332Scy fin->fin_dp = (char *)fin->fin_ip + dpoff; 1346255332Scy if (fin->fin_fraghdr != NULL) 1347255332Scy fin->fin_fraghdr = (char *)ip + 1348255332Scy ((char *)fin->fin_fraghdr - 1349255332Scy (char *)fin->fin_ip); 1350145516Sdarrenr } 1351145516Sdarrenr 1352145516Sdarrenr if (len == fin->fin_plen) 1353145516Sdarrenr fin->fin_flx |= FI_COALESCE; 1354145516Sdarrenr return ip; 1355145516Sdarrenr} 1356170268Sdarrenr 1357170268Sdarrenr 1358255332Scyint 1359255332Scyipf_inject(fin, m) 1360255332Scy fr_info_t *fin; 1361255332Scy mb_t *m; 1362170268Sdarrenr{ 1363170268Sdarrenr int error = 0; 1364170268Sdarrenr 1365170268Sdarrenr if (fin->fin_out == 0) { 1366170268Sdarrenr netisr_dispatch(NETISR_IP, m); 1367170268Sdarrenr } else { 1368173931Sdarrenr fin->fin_ip->ip_len = ntohs(fin->fin_ip->ip_len); 1369173931Sdarrenr fin->fin_ip->ip_off = ntohs(fin->fin_ip->ip_off); 1370170268Sdarrenr error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL); 1371170268Sdarrenr } 1372170268Sdarrenr 1373170268Sdarrenr return error; 1374170268Sdarrenr} 1375172776Sdarrenr 1376172776Sdarrenrint ipf_pfil_unhook(void) { 1377172776Sdarrenr#if defined(NETBSD_PF) && (__FreeBSD_version >= 500011) 1378172776Sdarrenr struct pfil_head *ph_inet; 1379172776Sdarrenr# ifdef USE_INET6 1380172776Sdarrenr struct pfil_head *ph_inet6; 1381172776Sdarrenr# endif 1382172776Sdarrenr#endif 1383172776Sdarrenr 1384172776Sdarrenr#ifdef NETBSD_PF 1385172776Sdarrenr ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); 1386172776Sdarrenr if (ph_inet != NULL) 1387255332Scy pfil_remove_hook((void *)ipf_check_wrapper, NULL, 1388172776Sdarrenr PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet); 1389172776Sdarrenr# ifdef USE_INET6 1390172776Sdarrenr ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6); 1391172776Sdarrenr if (ph_inet6 != NULL) 1392255332Scy pfil_remove_hook((void *)ipf_check_wrapper6, NULL, 1393172776Sdarrenr PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet6); 1394172776Sdarrenr# endif 1395172776Sdarrenr#endif 1396172776Sdarrenr 1397172776Sdarrenr return (0); 1398172776Sdarrenr} 1399172776Sdarrenr 1400172776Sdarrenrint ipf_pfil_hook(void) { 1401172776Sdarrenr#if defined(NETBSD_PF) && (__FreeBSD_version >= 500011) 1402172776Sdarrenr struct pfil_head *ph_inet; 1403172776Sdarrenr# ifdef USE_INET6 1404172776Sdarrenr struct pfil_head *ph_inet6; 1405172776Sdarrenr# endif 1406172776Sdarrenr#endif 1407172776Sdarrenr 1408172776Sdarrenr# ifdef NETBSD_PF 1409172776Sdarrenr ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); 1410172776Sdarrenr# ifdef USE_INET6 1411172776Sdarrenr ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6); 1412172776Sdarrenr# endif 1413172776Sdarrenr if (ph_inet == NULL 1414172776Sdarrenr# ifdef USE_INET6 1415172776Sdarrenr && ph_inet6 == NULL 1416172776Sdarrenr# endif 1417255332Scy ) { 1418172776Sdarrenr return ENODEV; 1419255332Scy } 1420172776Sdarrenr 1421172776Sdarrenr if (ph_inet != NULL) 1422255332Scy pfil_add_hook((void *)ipf_check_wrapper, NULL, 1423172776Sdarrenr PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet); 1424172776Sdarrenr# ifdef USE_INET6 1425172776Sdarrenr if (ph_inet6 != NULL) 1426255332Scy pfil_add_hook((void *)ipf_check_wrapper6, NULL, 1427172776Sdarrenr PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet6); 1428172776Sdarrenr# endif 1429172776Sdarrenr# endif 1430172776Sdarrenr return (0); 1431172776Sdarrenr} 1432172776Sdarrenr 1433172776Sdarrenrvoid 1434172776Sdarrenripf_event_reg(void) 1435172776Sdarrenr{ 1436255332Scy ipf_arrivetag = EVENTHANDLER_REGISTER(ifnet_arrival_event, \ 1437255332Scy ipf_ifevent, &ipfmain, \ 1438172776Sdarrenr EVENTHANDLER_PRI_ANY); 1439255332Scy ipf_departtag = EVENTHANDLER_REGISTER(ifnet_departure_event, \ 1440255332Scy ipf_ifevent, &ipfmain, \ 1441172776Sdarrenr EVENTHANDLER_PRI_ANY); 1442255332Scy ipf_clonetag = EVENTHANDLER_REGISTER(if_clone_event, ipf_ifevent, \ 1443255332Scy &ipfmain, EVENTHANDLER_PRI_ANY); 1444172776Sdarrenr} 1445172776Sdarrenr 1446172776Sdarrenrvoid 1447172776Sdarrenripf_event_dereg(void) 1448172776Sdarrenr{ 1449172776Sdarrenr if (ipf_arrivetag != NULL) { 1450172776Sdarrenr EVENTHANDLER_DEREGISTER(ifnet_arrival_event, ipf_arrivetag); 1451172776Sdarrenr } 1452172776Sdarrenr if (ipf_departtag != NULL) { 1453172776Sdarrenr EVENTHANDLER_DEREGISTER(ifnet_departure_event, ipf_departtag); 1454172776Sdarrenr } 1455172776Sdarrenr if (ipf_clonetag != NULL) { 1456172776Sdarrenr EVENTHANDLER_DEREGISTER(if_clone_event, ipf_clonetag); 1457172776Sdarrenr } 1458172776Sdarrenr} 1459255332Scy 1460255332Scy 1461255332Scyu_32_t 1462255332Scyipf_random() 1463255332Scy{ 1464255332Scy return arc4random(); 1465255332Scy} 1466255332Scy 1467255332Scy 1468255332Scyu_int 1469255332Scyipf_pcksum(fin, hlen, sum) 1470255332Scy fr_info_t *fin; 1471255332Scy int hlen; 1472255332Scy u_int sum; 1473255332Scy{ 1474255332Scy struct mbuf *m; 1475255332Scy u_int sum2; 1476255332Scy int off; 1477255332Scy 1478255332Scy m = fin->fin_m; 1479255332Scy off = (char *)fin->fin_dp - (char *)fin->fin_ip; 1480255332Scy m->m_data += hlen; 1481255332Scy m->m_len -= hlen; 1482255332Scy sum2 = in_cksum(fin->fin_m, fin->fin_plen - off); 1483255332Scy m->m_len += hlen; 1484255332Scy m->m_data -= hlen; 1485255332Scy 1486255332Scy /* 1487255332Scy * Both sum and sum2 are partial sums, so combine them together. 1488255332Scy */ 1489255332Scy sum += ~sum2 & 0xffff; 1490255332Scy while (sum > 0xffff) 1491255332Scy sum = (sum & 0xffff) + (sum >> 16); 1492255332Scy sum2 = ~sum & 0xffff; 1493255332Scy return sum2; 1494255332Scy} 1495