1145516Sdarrenr/* $FreeBSD$ */ 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> 36255332Scy# include <sys/mbuf.h> 37255332Scy# include <sys/sockopt.h> 38145516Sdarrenr#if !defined(__hpux) 39145516Sdarrenr# include <sys/mbuf.h> 40145516Sdarrenr#endif 41145516Sdarrenr#include <sys/socket.h> 42170268Sdarrenr# include <sys/selinfo.h> 43195699Srwatson# include <netinet/tcp_var.h> 44145516Sdarrenr 45145516Sdarrenr#include <net/if.h> 46145516Sdarrenr# include <net/if_var.h> 47170268Sdarrenr# include <net/netisr.h> 48145516Sdarrenr#include <net/route.h> 49145516Sdarrenr#include <netinet/in.h> 50145516Sdarrenr#include <netinet/in_var.h> 51145516Sdarrenr#include <netinet/in_systm.h> 52145516Sdarrenr#include <netinet/ip.h> 53145516Sdarrenr#include <netinet/ip_var.h> 54145516Sdarrenr#include <netinet/tcp.h> 55145516Sdarrenr#if defined(__osf__) 56145516Sdarrenr# include <netinet/tcp_timer.h> 57145516Sdarrenr#endif 58145516Sdarrenr#include <netinet/udp.h> 59145516Sdarrenr#include <netinet/tcpip.h> 60145516Sdarrenr#include <netinet/ip_icmp.h> 61145516Sdarrenr#include "netinet/ip_compat.h" 62145516Sdarrenr#ifdef USE_INET6 63145516Sdarrenr# include <netinet/icmp6.h> 64145516Sdarrenr#endif 65145516Sdarrenr#include "netinet/ip_fil.h" 66145516Sdarrenr#include "netinet/ip_nat.h" 67145516Sdarrenr#include "netinet/ip_frag.h" 68145516Sdarrenr#include "netinet/ip_state.h" 69145516Sdarrenr#include "netinet/ip_proxy.h" 70145516Sdarrenr#include "netinet/ip_auth.h" 71145516Sdarrenr#include "netinet/ip_sync.h" 72255332Scy#include "netinet/ip_lookup.h" 73255332Scy#include "netinet/ip_dstlist.h" 74145516Sdarrenr#ifdef IPFILTER_SCAN 75145516Sdarrenr#include "netinet/ip_scan.h" 76145516Sdarrenr#endif 77145516Sdarrenr#include "netinet/ip_pool.h" 78145516Sdarrenr# include <sys/malloc.h> 79145516Sdarrenr#include <sys/kernel.h> 80145516Sdarrenr#ifdef CSUM_DATA_VALID 81145516Sdarrenr#include <machine/in_cksum.h> 82145516Sdarrenr#endif 83145516Sdarrenrextern int ip_optcopy __P((struct ip *, struct ip *)); 84145516Sdarrenr 85145516Sdarrenr 86145516Sdarrenr# ifdef IPFILTER_M_IPFILTER 87151897SrwatsonMALLOC_DEFINE(M_IPFILTER, "ipfilter", "IP Filter packet filter data structures"); 88145516Sdarrenr# endif 89145516Sdarrenr 90145516Sdarrenr 91255332Scystatic u_short ipid = 0; 92255332Scystatic int (*ipf_savep) __P((void *, ip_t *, int, void *, int, struct mbuf **)); 93255332Scystatic int ipf_send_ip __P((fr_info_t *, mb_t *)); 94255332Scystatic void ipf_timer_func __P((void *arg)); 95145516Sdarrenrint ipf_locks_done = 0; 96145516Sdarrenr 97255332Scyipf_main_softc_t ipfmain; 98145516Sdarrenr 99145516Sdarrenr# include <sys/conf.h> 100145516Sdarrenr# if defined(NETBSD_PF) 101145516Sdarrenr# include <net/pfil.h> 102255332Scy# endif /* NETBSD_PF */ 103145516Sdarrenr/* 104255332Scy * We provide the ipf_checkp name just to minimize changes later. 105145516Sdarrenr */ 106255332Scyint (*ipf_checkp) __P((void *, ip_t *ip, int hlen, void *ifp, int out, mb_t **mp)); 107145516Sdarrenr 108145516Sdarrenr 109153876Sguidostatic eventhandler_tag ipf_arrivetag, ipf_departtag, ipf_clonetag; 110153876Sguido 111153876Sguidostatic void ipf_ifevent(void *arg); 112153876Sguido 113153876Sguidostatic void ipf_ifevent(arg) 114255332Scy void *arg; 115153876Sguido{ 116255332Scy ipf_sync(arg, NULL); 117153876Sguido} 118153876Sguido 119153876Sguido 120145516Sdarrenr 121145516Sdarrenrstatic int 122255332Scyipf_check_wrapper(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir) 123145516Sdarrenr{ 124145516Sdarrenr struct ip *ip = mtod(*mp, struct ip *); 125255332Scy int rv; 126255332Scy 127255332Scy /* 128255332Scy * IPFilter expects evreything in network byte order 129255332Scy */ 130255332Scy#if (__FreeBSD_version < 1000019) 131255332Scy ip->ip_len = htons(ip->ip_len); 132255332Scy ip->ip_off = htons(ip->ip_off); 133255332Scy#endif 134255332Scy rv = ipf_check(&ipfmain, ip, ip->ip_hl << 2, ifp, (dir == PFIL_OUT), 135255332Scy mp); 136255332Scy#if (__FreeBSD_version < 1000019) 137255332Scy if ((rv == 0) && (*mp != NULL)) { 138255332Scy ip = mtod(*mp, struct ip *); 139255332Scy ip->ip_len = ntohs(ip->ip_len); 140255332Scy ip->ip_off = ntohs(ip->ip_off); 141255332Scy } 142255332Scy#endif 143255332Scy return rv; 144145516Sdarrenr} 145145516Sdarrenr 146145516Sdarrenr# ifdef USE_INET6 147145516Sdarrenr# include <netinet/ip6.h> 148145516Sdarrenr 149145516Sdarrenrstatic int 150255332Scyipf_check_wrapper6(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir) 151145516Sdarrenr{ 152255332Scy return (ipf_check(&ipfmain, mtod(*mp, struct ip *), 153255332Scy sizeof(struct ip6_hdr), ifp, (dir == PFIL_OUT), mp)); 154145516Sdarrenr} 155145516Sdarrenr# endif 156145516Sdarrenr#if defined(IPFILTER_LKM) 157255332Scyint ipf_identify(s) 158255332Scy char *s; 159145516Sdarrenr{ 160145516Sdarrenr if (strcmp(s, "ipl") == 0) 161145516Sdarrenr return 1; 162145516Sdarrenr return 0; 163145516Sdarrenr} 164145516Sdarrenr#endif /* IPFILTER_LKM */ 165145516Sdarrenr 166145516Sdarrenr 167255332Scystatic void 168255332Scyipf_timer_func(arg) 169255332Scy void *arg; 170145516Sdarrenr{ 171255332Scy ipf_main_softc_t *softc = arg; 172255332Scy SPL_INT(s); 173255332Scy 174255332Scy SPL_NET(s); 175255332Scy READ_ENTER(&softc->ipf_global); 176255332Scy 177255332Scy if (softc->ipf_running > 0) 178255332Scy ipf_slowtimer(softc); 179255332Scy 180255332Scy if (softc->ipf_running == -1 || softc->ipf_running == 1) { 181255755Scy#if 0 182255332Scy softc->ipf_slow_ch = timeout(ipf_timer_func, softc, hz/2); 183255332Scy#endif 184255755Scy callout_init(&softc->ipf_slow_ch, CALLOUT_MPSAFE); 185255755Scy callout_reset(&softc->ipf_slow_ch, 186255755Scy (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT, 187255755Scy ipf_timer_func, softc); 188255332Scy } 189255332Scy RWLOCK_EXIT(&softc->ipf_global); 190255332Scy SPL_X(s); 191255332Scy} 192255332Scy 193255332Scy 194255332Scyint 195255332Scyipfattach(softc) 196255332Scy ipf_main_softc_t *softc; 197255332Scy{ 198145516Sdarrenr#ifdef USE_SPL 199145516Sdarrenr int s; 200145516Sdarrenr#endif 201145516Sdarrenr 202145516Sdarrenr SPL_NET(s); 203255332Scy if (softc->ipf_running > 0) { 204145516Sdarrenr SPL_X(s); 205145516Sdarrenr return EBUSY; 206145516Sdarrenr } 207145516Sdarrenr 208255332Scy if (ipf_init_all(softc) < 0) { 209145516Sdarrenr SPL_X(s); 210145516Sdarrenr return EIO; 211145516Sdarrenr } 212145516Sdarrenr 213145516Sdarrenr 214255332Scy if (ipf_checkp != ipf_check) { 215255332Scy ipf_savep = ipf_checkp; 216255332Scy ipf_checkp = ipf_check; 217145516Sdarrenr } 218145516Sdarrenr 219255332Scy bzero((char *)ipfmain.ipf_selwait, sizeof(ipfmain.ipf_selwait)); 220255332Scy softc->ipf_running = 1; 221145516Sdarrenr 222255332Scy if (softc->ipf_control_forwarding & 1) 223181803Sbz V_ipforwarding = 1; 224145516Sdarrenr 225255332Scy ipid = 0; 226255332Scy 227145516Sdarrenr SPL_X(s); 228255755Scy#if 0 229255332Scy softc->ipf_slow_ch = timeout(ipf_timer_func, softc, 230255332Scy (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT); 231255755Scy#endif 232255755Scy callout_init(&softc->ipf_slow_ch, CALLOUT_MPSAFE); 233255755Scy callout_reset(&softc->ipf_slow_ch, (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT, 234255755Scy ipf_timer_func, softc); 235145516Sdarrenr return 0; 236145516Sdarrenr} 237145516Sdarrenr 238145516Sdarrenr 239145516Sdarrenr/* 240145516Sdarrenr * Disable the filter by removing the hooks from the IP input/output 241145516Sdarrenr * stream. 242145516Sdarrenr */ 243255332Scyint 244255332Scyipfdetach(softc) 245255332Scy ipf_main_softc_t *softc; 246145516Sdarrenr{ 247145516Sdarrenr#ifdef USE_SPL 248145516Sdarrenr int s; 249145516Sdarrenr#endif 250255332Scy 251255332Scy if (softc->ipf_control_forwarding & 2) 252181803Sbz V_ipforwarding = 0; 253145516Sdarrenr 254145516Sdarrenr SPL_NET(s); 255145516Sdarrenr 256255755Scy#if 0 257255332Scy if (softc->ipf_slow_ch.callout != NULL) 258255332Scy untimeout(ipf_timer_func, softc, softc->ipf_slow_ch); 259255332Scy bzero(&softc->ipf_slow, sizeof(softc->ipf_slow)); 260255755Scy#endif 261255755Scy callout_drain(&softc->ipf_slow_ch); 262145516Sdarrenr 263145516Sdarrenr#ifndef NETBSD_PF 264255332Scy if (ipf_checkp != NULL) 265255332Scy ipf_checkp = ipf_savep; 266255332Scy ipf_savep = NULL; 267145516Sdarrenr#endif 268145516Sdarrenr 269255332Scy ipf_fini_all(softc); 270145516Sdarrenr 271255332Scy softc->ipf_running = -2; 272145516Sdarrenr 273145516Sdarrenr SPL_X(s); 274145516Sdarrenr 275145516Sdarrenr return 0; 276145516Sdarrenr} 277145516Sdarrenr 278145516Sdarrenr 279145516Sdarrenr/* 280145516Sdarrenr * Filter ioctl interface. 281145516Sdarrenr */ 282255332Scyint 283255332Scyipfioctl(dev, cmd, data, mode 284145516Sdarrenr, p) 285255332Scy struct thread *p; 286192895Sjamie# define p_cred td_ucred 287170268Sdarrenr# define p_uid td_ucred->cr_ruid 288255332Scy struct cdev *dev; 289255332Scy ioctlcmd_t cmd; 290255332Scy caddr_t data; 291255332Scy int mode; 292145516Sdarrenr{ 293170268Sdarrenr int error = 0, unit = 0; 294170268Sdarrenr SPL_INT(s); 295145516Sdarrenr 296255332Scy#if (BSD >= 199306) 297255332Scy if (securelevel_ge(p->p_cred, 3) && (mode & FWRITE)) 298255332Scy { 299255332Scy ipfmain.ipf_interror = 130001; 300145516Sdarrenr return EPERM; 301255332Scy } 302145516Sdarrenr#endif 303145516Sdarrenr 304145516Sdarrenr unit = GET_MINOR(dev); 305255332Scy if ((IPL_LOGMAX < unit) || (unit < 0)) { 306255332Scy ipfmain.ipf_interror = 130002; 307145516Sdarrenr return ENXIO; 308255332Scy } 309145516Sdarrenr 310255332Scy if (ipfmain.ipf_running <= 0) { 311255332Scy if (unit != IPL_LOGIPF && cmd != SIOCIPFINTERROR) { 312255332Scy ipfmain.ipf_interror = 130003; 313145516Sdarrenr return EIO; 314255332Scy } 315145516Sdarrenr if (cmd != SIOCIPFGETNEXT && cmd != SIOCIPFGET && 316173181Sdarrenr cmd != SIOCIPFSET && cmd != SIOCFRENB && 317255332Scy cmd != SIOCGETFS && cmd != SIOCGETFF && 318255332Scy cmd != SIOCIPFINTERROR) { 319255332Scy ipfmain.ipf_interror = 130004; 320145516Sdarrenr return EIO; 321255332Scy } 322145516Sdarrenr } 323145516Sdarrenr 324145516Sdarrenr SPL_NET(s); 325145516Sdarrenr 326255332Scy error = ipf_ioctlswitch(&ipfmain, unit, data, cmd, mode, p->p_uid, p); 327145516Sdarrenr if (error != -1) { 328145516Sdarrenr SPL_X(s); 329145516Sdarrenr return error; 330145516Sdarrenr } 331145516Sdarrenr 332145516Sdarrenr SPL_X(s); 333161356Sguido 334145516Sdarrenr return error; 335145516Sdarrenr} 336145516Sdarrenr 337145516Sdarrenr 338145516Sdarrenr/* 339255332Scy * ipf_send_reset - this could conceivably be a call to tcp_respond(), but that 340145516Sdarrenr * requires a large amount of setting up and isn't any more efficient. 341145516Sdarrenr */ 342255332Scyint 343255332Scyipf_send_reset(fin) 344255332Scy fr_info_t *fin; 345145516Sdarrenr{ 346145516Sdarrenr struct tcphdr *tcp, *tcp2; 347145516Sdarrenr int tlen = 0, hlen; 348145516Sdarrenr struct mbuf *m; 349145516Sdarrenr#ifdef USE_INET6 350145516Sdarrenr ip6_t *ip6; 351145516Sdarrenr#endif 352145516Sdarrenr ip_t *ip; 353145516Sdarrenr 354145516Sdarrenr tcp = fin->fin_dp; 355145516Sdarrenr if (tcp->th_flags & TH_RST) 356145516Sdarrenr return -1; /* feedback loop */ 357145516Sdarrenr 358255332Scy if (ipf_checkl4sum(fin) == -1) 359145516Sdarrenr return -1; 360145516Sdarrenr 361145516Sdarrenr tlen = fin->fin_dlen - (TCP_OFF(tcp) << 2) + 362145516Sdarrenr ((tcp->th_flags & TH_SYN) ? 1 : 0) + 363145516Sdarrenr ((tcp->th_flags & TH_FIN) ? 1 : 0); 364145516Sdarrenr 365145516Sdarrenr#ifdef USE_INET6 366145516Sdarrenr hlen = (fin->fin_v == 6) ? sizeof(ip6_t) : sizeof(ip_t); 367145516Sdarrenr#else 368145516Sdarrenr hlen = sizeof(ip_t); 369145516Sdarrenr#endif 370145516Sdarrenr#ifdef MGETHDR 371145516Sdarrenr MGETHDR(m, M_DONTWAIT, MT_HEADER); 372145516Sdarrenr#else 373145516Sdarrenr MGET(m, M_DONTWAIT, MT_HEADER); 374145516Sdarrenr#endif 375145516Sdarrenr if (m == NULL) 376145516Sdarrenr return -1; 377145516Sdarrenr if (sizeof(*tcp2) + hlen > MLEN) { 378145516Sdarrenr MCLGET(m, M_DONTWAIT); 379145516Sdarrenr if ((m->m_flags & M_EXT) == 0) { 380145516Sdarrenr FREE_MB_T(m); 381145516Sdarrenr return -1; 382145516Sdarrenr } 383145516Sdarrenr } 384145516Sdarrenr 385145516Sdarrenr m->m_len = sizeof(*tcp2) + hlen; 386145516Sdarrenr#if (BSD >= 199103) 387145516Sdarrenr m->m_data += max_linkhdr; 388145516Sdarrenr m->m_pkthdr.len = m->m_len; 389145516Sdarrenr m->m_pkthdr.rcvif = (struct ifnet *)0; 390145516Sdarrenr#endif 391145516Sdarrenr ip = mtod(m, struct ip *); 392145516Sdarrenr bzero((char *)ip, hlen); 393145516Sdarrenr#ifdef USE_INET6 394145516Sdarrenr ip6 = (ip6_t *)ip; 395145516Sdarrenr#endif 396145516Sdarrenr tcp2 = (struct tcphdr *)((char *)ip + hlen); 397145516Sdarrenr tcp2->th_sport = tcp->th_dport; 398145516Sdarrenr tcp2->th_dport = tcp->th_sport; 399145516Sdarrenr 400145516Sdarrenr if (tcp->th_flags & TH_ACK) { 401145516Sdarrenr tcp2->th_seq = tcp->th_ack; 402145516Sdarrenr tcp2->th_flags = TH_RST; 403145516Sdarrenr tcp2->th_ack = 0; 404145516Sdarrenr } else { 405145516Sdarrenr tcp2->th_seq = 0; 406145516Sdarrenr tcp2->th_ack = ntohl(tcp->th_seq); 407145516Sdarrenr tcp2->th_ack += tlen; 408145516Sdarrenr tcp2->th_ack = htonl(tcp2->th_ack); 409145516Sdarrenr tcp2->th_flags = TH_RST|TH_ACK; 410145516Sdarrenr } 411145516Sdarrenr TCP_X2_A(tcp2, 0); 412145516Sdarrenr TCP_OFF_A(tcp2, sizeof(*tcp2) >> 2); 413145516Sdarrenr tcp2->th_win = tcp->th_win; 414145516Sdarrenr tcp2->th_sum = 0; 415145516Sdarrenr tcp2->th_urp = 0; 416145516Sdarrenr 417145516Sdarrenr#ifdef USE_INET6 418145516Sdarrenr if (fin->fin_v == 6) { 419145516Sdarrenr ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; 420145516Sdarrenr ip6->ip6_plen = htons(sizeof(struct tcphdr)); 421145516Sdarrenr ip6->ip6_nxt = IPPROTO_TCP; 422145516Sdarrenr ip6->ip6_hlim = 0; 423255332Scy ip6->ip6_src = fin->fin_dst6.in6; 424255332Scy ip6->ip6_dst = fin->fin_src6.in6; 425145516Sdarrenr tcp2->th_sum = in6_cksum(m, IPPROTO_TCP, 426145516Sdarrenr sizeof(*ip6), sizeof(*tcp2)); 427255332Scy return ipf_send_ip(fin, m); 428145516Sdarrenr } 429145516Sdarrenr#endif 430145516Sdarrenr ip->ip_p = IPPROTO_TCP; 431145516Sdarrenr ip->ip_len = htons(sizeof(struct tcphdr)); 432145516Sdarrenr ip->ip_src.s_addr = fin->fin_daddr; 433145516Sdarrenr ip->ip_dst.s_addr = fin->fin_saddr; 434145516Sdarrenr tcp2->th_sum = in_cksum(m, hlen + sizeof(*tcp2)); 435255332Scy ip->ip_len = htons(hlen + sizeof(*tcp2)); 436255332Scy return ipf_send_ip(fin, m); 437145516Sdarrenr} 438145516Sdarrenr 439145516Sdarrenr 440255332Scy/* 441255332Scy * ip_len must be in network byte order when called. 442255332Scy */ 443255332Scystatic int 444255332Scyipf_send_ip(fin, m) 445255332Scy fr_info_t *fin; 446255332Scy mb_t *m; 447145516Sdarrenr{ 448145516Sdarrenr fr_info_t fnew; 449145516Sdarrenr ip_t *ip, *oip; 450145516Sdarrenr int hlen; 451145516Sdarrenr 452145516Sdarrenr ip = mtod(m, ip_t *); 453145516Sdarrenr bzero((char *)&fnew, sizeof(fnew)); 454255332Scy fnew.fin_main_soft = fin->fin_main_soft; 455145516Sdarrenr 456145516Sdarrenr IP_V_A(ip, fin->fin_v); 457145516Sdarrenr switch (fin->fin_v) 458145516Sdarrenr { 459145516Sdarrenr case 4 : 460255332Scy oip = fin->fin_ip; 461255332Scy hlen = sizeof(*oip); 462145516Sdarrenr fnew.fin_v = 4; 463255332Scy fnew.fin_p = ip->ip_p; 464255332Scy fnew.fin_plen = ntohs(ip->ip_len); 465145516Sdarrenr IP_HL_A(ip, sizeof(*oip) >> 2); 466145516Sdarrenr ip->ip_tos = oip->ip_tos; 467145516Sdarrenr ip->ip_id = fin->fin_ip->ip_id; 468255332Scy#if defined(FreeBSD) && (__FreeBSD_version > 460000) 469255332Scy ip->ip_off = htons(path_mtu_discovery ? IP_DF : 0); 470145516Sdarrenr#else 471145516Sdarrenr ip->ip_off = 0; 472145516Sdarrenr#endif 473181803Sbz ip->ip_ttl = V_ip_defttl; 474145516Sdarrenr ip->ip_sum = 0; 475145516Sdarrenr break; 476145516Sdarrenr#ifdef USE_INET6 477145516Sdarrenr case 6 : 478145516Sdarrenr { 479145516Sdarrenr ip6_t *ip6 = (ip6_t *)ip; 480145516Sdarrenr 481145516Sdarrenr ip6->ip6_vfc = 0x60; 482145516Sdarrenr ip6->ip6_hlim = IPDEFTTL; 483145516Sdarrenr 484255332Scy hlen = sizeof(*ip6); 485255332Scy fnew.fin_p = ip6->ip6_nxt; 486145516Sdarrenr fnew.fin_v = 6; 487255332Scy fnew.fin_plen = ntohs(ip6->ip6_plen) + hlen; 488145516Sdarrenr break; 489145516Sdarrenr } 490145516Sdarrenr#endif 491145516Sdarrenr default : 492145516Sdarrenr return EINVAL; 493145516Sdarrenr } 494145516Sdarrenr#ifdef IPSEC 495145516Sdarrenr m->m_pkthdr.rcvif = NULL; 496145516Sdarrenr#endif 497145516Sdarrenr 498145516Sdarrenr fnew.fin_ifp = fin->fin_ifp; 499145516Sdarrenr fnew.fin_flx = FI_NOCKSUM; 500145516Sdarrenr fnew.fin_m = m; 501145516Sdarrenr fnew.fin_ip = ip; 502255332Scy fnew.fin_mp = &m; 503145516Sdarrenr fnew.fin_hlen = hlen; 504145516Sdarrenr fnew.fin_dp = (char *)ip + hlen; 505255332Scy (void) ipf_makefrip(hlen, ip, &fnew); 506145516Sdarrenr 507255332Scy return ipf_fastroute(m, &m, &fnew, NULL); 508145516Sdarrenr} 509145516Sdarrenr 510145516Sdarrenr 511255332Scyint 512255332Scyipf_send_icmp_err(type, fin, dst) 513255332Scy int type; 514255332Scy fr_info_t *fin; 515255332Scy int dst; 516145516Sdarrenr{ 517145516Sdarrenr int err, hlen, xtra, iclen, ohlen, avail, code; 518145516Sdarrenr struct in_addr dst4; 519145516Sdarrenr struct icmp *icmp; 520145516Sdarrenr struct mbuf *m; 521255332Scy i6addr_t dst6; 522145516Sdarrenr void *ifp; 523145516Sdarrenr#ifdef USE_INET6 524145516Sdarrenr ip6_t *ip6; 525145516Sdarrenr#endif 526145516Sdarrenr ip_t *ip, *ip2; 527145516Sdarrenr 528172776Sdarrenr if ((type < 0) || (type >= ICMP_MAXTYPE)) 529145516Sdarrenr return -1; 530145516Sdarrenr 531145516Sdarrenr code = fin->fin_icode; 532145516Sdarrenr#ifdef USE_INET6 533255332Scy#if 0 534255332Scy /* XXX Fix an off by one error: s/>/>=/ 535255332Scy was: 536255332Scy if ((code < 0) || (code > sizeof(icmptoicmp6unreach)/sizeof(int))) 537255332Scy Fix obtained from NetBSD ip_fil_netbsd.c r1.4: */ 538255332Scy#endif 539255332Scy if ((code < 0) || (code >= sizeof(icmptoicmp6unreach)/sizeof(int))) 540145516Sdarrenr return -1; 541145516Sdarrenr#endif 542145516Sdarrenr 543255332Scy if (ipf_checkl4sum(fin) == -1) 544145516Sdarrenr return -1; 545145516Sdarrenr#ifdef MGETHDR 546145516Sdarrenr MGETHDR(m, M_DONTWAIT, MT_HEADER); 547145516Sdarrenr#else 548145516Sdarrenr MGET(m, M_DONTWAIT, MT_HEADER); 549145516Sdarrenr#endif 550145516Sdarrenr if (m == NULL) 551145516Sdarrenr return -1; 552145516Sdarrenr avail = MHLEN; 553145516Sdarrenr 554145516Sdarrenr xtra = 0; 555145516Sdarrenr hlen = 0; 556145516Sdarrenr ohlen = 0; 557255332Scy dst4.s_addr = 0; 558145516Sdarrenr ifp = fin->fin_ifp; 559145516Sdarrenr if (fin->fin_v == 4) { 560255332Scy if ((fin->fin_p == IPPROTO_ICMP) && !(fin->fin_flx & FI_SHORT)) 561145516Sdarrenr switch (ntohs(fin->fin_data[0]) >> 8) 562145516Sdarrenr { 563145516Sdarrenr case ICMP_ECHO : 564145516Sdarrenr case ICMP_TSTAMP : 565145516Sdarrenr case ICMP_IREQ : 566145516Sdarrenr case ICMP_MASKREQ : 567145516Sdarrenr break; 568145516Sdarrenr default : 569145516Sdarrenr FREE_MB_T(m); 570145516Sdarrenr return 0; 571145516Sdarrenr } 572145516Sdarrenr 573145516Sdarrenr if (dst == 0) { 574255332Scy if (ipf_ifpaddr(&ipfmain, 4, FRI_NORMAL, ifp, 575255332Scy &dst6, NULL) == -1) { 576145516Sdarrenr FREE_MB_T(m); 577145516Sdarrenr return -1; 578145516Sdarrenr } 579255332Scy dst4 = dst6.in4; 580145516Sdarrenr } else 581145516Sdarrenr dst4.s_addr = fin->fin_daddr; 582145516Sdarrenr 583145516Sdarrenr hlen = sizeof(ip_t); 584145516Sdarrenr ohlen = fin->fin_hlen; 585255332Scy iclen = hlen + offsetof(struct icmp, icmp_ip) + ohlen; 586145516Sdarrenr if (fin->fin_hlen < fin->fin_plen) 587145516Sdarrenr xtra = MIN(fin->fin_dlen, 8); 588145516Sdarrenr else 589145516Sdarrenr xtra = 0; 590145516Sdarrenr } 591145516Sdarrenr 592145516Sdarrenr#ifdef USE_INET6 593145516Sdarrenr else if (fin->fin_v == 6) { 594145516Sdarrenr hlen = sizeof(ip6_t); 595145516Sdarrenr ohlen = sizeof(ip6_t); 596255332Scy iclen = hlen + offsetof(struct icmp, icmp_ip) + ohlen; 597145516Sdarrenr type = icmptoicmp6types[type]; 598145516Sdarrenr if (type == ICMP6_DST_UNREACH) 599145516Sdarrenr code = icmptoicmp6unreach[code]; 600145516Sdarrenr 601255332Scy if (iclen + max_linkhdr + fin->fin_plen > avail) { 602145516Sdarrenr MCLGET(m, M_DONTWAIT); 603145516Sdarrenr if ((m->m_flags & M_EXT) == 0) { 604145516Sdarrenr FREE_MB_T(m); 605145516Sdarrenr return -1; 606145516Sdarrenr } 607145516Sdarrenr avail = MCLBYTES; 608145516Sdarrenr } 609255332Scy xtra = MIN(fin->fin_plen, avail - iclen - max_linkhdr); 610255332Scy xtra = MIN(xtra, IPV6_MMTU - iclen); 611145516Sdarrenr if (dst == 0) { 612255332Scy if (ipf_ifpaddr(&ipfmain, 6, FRI_NORMAL, ifp, 613255332Scy &dst6, NULL) == -1) { 614145516Sdarrenr FREE_MB_T(m); 615145516Sdarrenr return -1; 616145516Sdarrenr } 617145516Sdarrenr } else 618145516Sdarrenr dst6 = fin->fin_dst6; 619145516Sdarrenr } 620145516Sdarrenr#endif 621145516Sdarrenr else { 622145516Sdarrenr FREE_MB_T(m); 623145516Sdarrenr return -1; 624145516Sdarrenr } 625145516Sdarrenr 626145516Sdarrenr avail -= (max_linkhdr + iclen); 627145516Sdarrenr if (avail < 0) { 628145516Sdarrenr FREE_MB_T(m); 629145516Sdarrenr return -1; 630145516Sdarrenr } 631145516Sdarrenr if (xtra > avail) 632145516Sdarrenr xtra = avail; 633145516Sdarrenr iclen += xtra; 634145516Sdarrenr m->m_data += max_linkhdr; 635145516Sdarrenr m->m_pkthdr.rcvif = (struct ifnet *)0; 636145516Sdarrenr m->m_pkthdr.len = iclen; 637145516Sdarrenr m->m_len = iclen; 638145516Sdarrenr ip = mtod(m, ip_t *); 639145516Sdarrenr icmp = (struct icmp *)((char *)ip + hlen); 640145516Sdarrenr ip2 = (ip_t *)&icmp->icmp_ip; 641145516Sdarrenr 642145516Sdarrenr icmp->icmp_type = type; 643145516Sdarrenr icmp->icmp_code = fin->fin_icode; 644145516Sdarrenr icmp->icmp_cksum = 0; 645145516Sdarrenr#ifdef icmp_nextmtu 646255332Scy if (type == ICMP_UNREACH && fin->fin_icode == ICMP_UNREACH_NEEDFRAG) { 647255332Scy if (fin->fin_mtu != 0) { 648255332Scy icmp->icmp_nextmtu = htons(fin->fin_mtu); 649255332Scy 650255332Scy } else if (ifp != NULL) { 651255332Scy icmp->icmp_nextmtu = htons(GETIFMTU_4(ifp)); 652255332Scy 653255332Scy } else { /* make up a number... */ 654255332Scy icmp->icmp_nextmtu = htons(fin->fin_plen - 20); 655255332Scy } 656255332Scy } 657145516Sdarrenr#endif 658145516Sdarrenr 659145516Sdarrenr bcopy((char *)fin->fin_ip, (char *)ip2, ohlen); 660145516Sdarrenr 661145516Sdarrenr#ifdef USE_INET6 662145516Sdarrenr ip6 = (ip6_t *)ip; 663145516Sdarrenr if (fin->fin_v == 6) { 664145516Sdarrenr ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; 665145516Sdarrenr ip6->ip6_plen = htons(iclen - hlen); 666145516Sdarrenr ip6->ip6_nxt = IPPROTO_ICMPV6; 667145516Sdarrenr ip6->ip6_hlim = 0; 668255332Scy ip6->ip6_src = dst6.in6; 669255332Scy ip6->ip6_dst = fin->fin_src6.in6; 670145516Sdarrenr if (xtra > 0) 671145516Sdarrenr bcopy((char *)fin->fin_ip + ohlen, 672145516Sdarrenr (char *)&icmp->icmp_ip + ohlen, xtra); 673145516Sdarrenr icmp->icmp_cksum = in6_cksum(m, IPPROTO_ICMPV6, 674145516Sdarrenr sizeof(*ip6), iclen - hlen); 675145516Sdarrenr } else 676145516Sdarrenr#endif 677145516Sdarrenr { 678145516Sdarrenr ip->ip_p = IPPROTO_ICMP; 679145516Sdarrenr ip->ip_src.s_addr = dst4.s_addr; 680145516Sdarrenr ip->ip_dst.s_addr = fin->fin_saddr; 681145516Sdarrenr 682145516Sdarrenr if (xtra > 0) 683145516Sdarrenr bcopy((char *)fin->fin_ip + ohlen, 684145516Sdarrenr (char *)&icmp->icmp_ip + ohlen, xtra); 685145516Sdarrenr icmp->icmp_cksum = ipf_cksum((u_short *)icmp, 686145516Sdarrenr sizeof(*icmp) + 8); 687255332Scy ip->ip_len = htons(iclen); 688145516Sdarrenr ip->ip_p = IPPROTO_ICMP; 689145516Sdarrenr } 690255332Scy err = ipf_send_ip(fin, m); 691145516Sdarrenr return err; 692145516Sdarrenr} 693145516Sdarrenr 694145516Sdarrenr 695145516Sdarrenr 696145516Sdarrenr 697173181Sdarrenr/* 698173181Sdarrenr * m0 - pointer to mbuf where the IP packet starts 699173181Sdarrenr * mpp - pointer to the mbuf pointer that is the start of the mbuf chain 700173181Sdarrenr */ 701255332Scyint 702255332Scyipf_fastroute(m0, mpp, fin, fdp) 703255332Scy mb_t *m0, **mpp; 704255332Scy fr_info_t *fin; 705255332Scy frdest_t *fdp; 706145516Sdarrenr{ 707145516Sdarrenr register struct ip *ip, *mhip; 708173181Sdarrenr register struct mbuf *m = *mpp; 709145516Sdarrenr register struct route *ro; 710145516Sdarrenr int len, off, error = 0, hlen, code; 711145516Sdarrenr struct ifnet *ifp, *sifp; 712145516Sdarrenr struct sockaddr_in *dst; 713145516Sdarrenr struct route iproute; 714145516Sdarrenr u_short ip_off; 715255332Scy frdest_t node; 716145516Sdarrenr frentry_t *fr; 717145516Sdarrenr 718161356Sguido ro = NULL; 719161356Sguido 720145516Sdarrenr#ifdef M_WRITABLE 721145516Sdarrenr /* 722145516Sdarrenr * HOT FIX/KLUDGE: 723145516Sdarrenr * 724145516Sdarrenr * If the mbuf we're about to send is not writable (because of 725145516Sdarrenr * a cluster reference, for example) we'll need to make a copy 726145516Sdarrenr * of it since this routine modifies the contents. 727145516Sdarrenr * 728145516Sdarrenr * If you have non-crappy network hardware that can transmit data 729145516Sdarrenr * from the mbuf, rather than making a copy, this is gonna be a 730145516Sdarrenr * problem. 731145516Sdarrenr */ 732145516Sdarrenr if (M_WRITABLE(m) == 0) { 733161356Sguido m0 = m_dup(m, M_DONTWAIT); 734161356Sguido if (m0 != 0) { 735145516Sdarrenr FREE_MB_T(m); 736145516Sdarrenr m = m0; 737145516Sdarrenr *mpp = m; 738145516Sdarrenr } else { 739145516Sdarrenr error = ENOBUFS; 740145516Sdarrenr FREE_MB_T(m); 741161356Sguido goto done; 742145516Sdarrenr } 743145516Sdarrenr } 744145516Sdarrenr#endif 745145516Sdarrenr 746145516Sdarrenr#ifdef USE_INET6 747145516Sdarrenr if (fin->fin_v == 6) { 748145516Sdarrenr /* 749145516Sdarrenr * currently "to <if>" and "to <if>:ip#" are not supported 750145516Sdarrenr * for IPv6 751145516Sdarrenr */ 752255332Scy return ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL); 753145516Sdarrenr } 754145516Sdarrenr#endif 755145516Sdarrenr 756145516Sdarrenr hlen = fin->fin_hlen; 757145516Sdarrenr ip = mtod(m0, struct ip *); 758255332Scy ifp = NULL; 759145516Sdarrenr 760145516Sdarrenr /* 761145516Sdarrenr * Route packet. 762145516Sdarrenr */ 763145516Sdarrenr ro = &iproute; 764255332Scy bzero(ro, sizeof (*ro)); 765145516Sdarrenr dst = (struct sockaddr_in *)&ro->ro_dst; 766145516Sdarrenr dst->sin_family = AF_INET; 767145516Sdarrenr dst->sin_addr = ip->ip_dst; 768145516Sdarrenr 769145516Sdarrenr fr = fin->fin_fr; 770255332Scy if ((fr != NULL) && !(fr->fr_flags & FR_KEEPSTATE) && (fdp != NULL) && 771255332Scy (fdp->fd_type == FRD_DSTLIST)) { 772255332Scy if (ipf_dstlist_select_node(fin, fdp->fd_ptr, NULL, &node) == 0) 773255332Scy fdp = &node; 774255332Scy } 775255332Scy 776145516Sdarrenr if (fdp != NULL) 777255332Scy ifp = fdp->fd_ptr; 778145516Sdarrenr else 779145516Sdarrenr ifp = fin->fin_ifp; 780145516Sdarrenr 781255332Scy if ((ifp == NULL) && ((fr == NULL) || !(fr->fr_flags & FR_FASTROUTE))) { 782145516Sdarrenr error = -2; 783145516Sdarrenr goto bad; 784145516Sdarrenr } 785145516Sdarrenr 786161356Sguido if ((fdp != NULL) && (fdp->fd_ip.s_addr != 0)) 787161356Sguido dst->sin_addr = fdp->fd_ip; 788145516Sdarrenr 789145516Sdarrenr dst->sin_len = sizeof(*dst); 790178888Sjulian in_rtalloc(ro, 0); 791145516Sdarrenr 792145516Sdarrenr if ((ifp == NULL) && (ro->ro_rt != NULL)) 793145516Sdarrenr ifp = ro->ro_rt->rt_ifp; 794145516Sdarrenr 795145516Sdarrenr if ((ro->ro_rt == NULL) || (ifp == NULL)) { 796145516Sdarrenr if (in_localaddr(ip->ip_dst)) 797145516Sdarrenr error = EHOSTUNREACH; 798145516Sdarrenr else 799145516Sdarrenr error = ENETUNREACH; 800145516Sdarrenr goto bad; 801145516Sdarrenr } 802145516Sdarrenr if (ro->ro_rt->rt_flags & RTF_GATEWAY) 803145516Sdarrenr dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway; 804145516Sdarrenr if (ro->ro_rt) 805145516Sdarrenr ro->ro_rt->rt_use++; 806145516Sdarrenr 807145516Sdarrenr /* 808145516Sdarrenr * For input packets which are being "fastrouted", they won't 809145516Sdarrenr * go back through output filtering and miss their chance to get 810170268Sdarrenr * NAT'd and counted. Duplicated packets aren't considered to be 811170268Sdarrenr * part of the normal packet stream, so do not NAT them or pass 812170268Sdarrenr * them through stateful checking, etc. 813145516Sdarrenr */ 814170268Sdarrenr if ((fdp != &fr->fr_dif) && (fin->fin_out == 0)) { 815145516Sdarrenr sifp = fin->fin_ifp; 816145516Sdarrenr fin->fin_ifp = ifp; 817145516Sdarrenr fin->fin_out = 1; 818255332Scy (void) ipf_acctpkt(fin, NULL); 819145516Sdarrenr fin->fin_fr = NULL; 820145516Sdarrenr if (!fr || !(fr->fr_flags & FR_RETMASK)) { 821145516Sdarrenr u_32_t pass; 822145516Sdarrenr 823255332Scy (void) ipf_state_check(fin, &pass); 824145516Sdarrenr } 825145516Sdarrenr 826255332Scy switch (ipf_nat_checkout(fin, NULL)) 827145516Sdarrenr { 828145516Sdarrenr case 0 : 829145516Sdarrenr break; 830145516Sdarrenr case 1 : 831145516Sdarrenr ip->ip_sum = 0; 832145516Sdarrenr break; 833145516Sdarrenr case -1 : 834145516Sdarrenr error = -1; 835173181Sdarrenr goto bad; 836145516Sdarrenr break; 837145516Sdarrenr } 838145516Sdarrenr 839145516Sdarrenr fin->fin_ifp = sifp; 840145516Sdarrenr fin->fin_out = 0; 841145516Sdarrenr } else 842145516Sdarrenr ip->ip_sum = 0; 843145516Sdarrenr /* 844145516Sdarrenr * If small enough for interface, can just send directly. 845145516Sdarrenr */ 846255332Scy if (ntohs(ip->ip_len) <= ifp->if_mtu) { 847145516Sdarrenr if (!ip->ip_sum) 848145516Sdarrenr ip->ip_sum = in_cksum(m, hlen); 849145516Sdarrenr error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst, 850255332Scy ro 851255332Scy ); 852145516Sdarrenr goto done; 853145516Sdarrenr } 854145516Sdarrenr /* 855145516Sdarrenr * Too large for interface; fragment if possible. 856145516Sdarrenr * Must be able to put at least 8 bytes per fragment. 857145516Sdarrenr */ 858145516Sdarrenr ip_off = ntohs(ip->ip_off); 859145516Sdarrenr if (ip_off & IP_DF) { 860145516Sdarrenr error = EMSGSIZE; 861145516Sdarrenr goto bad; 862145516Sdarrenr } 863145516Sdarrenr len = (ifp->if_mtu - hlen) &~ 7; 864145516Sdarrenr if (len < 8) { 865145516Sdarrenr error = EMSGSIZE; 866145516Sdarrenr goto bad; 867145516Sdarrenr } 868145516Sdarrenr 869145516Sdarrenr { 870145516Sdarrenr int mhlen, firstlen = len; 871145516Sdarrenr struct mbuf **mnext = &m->m_act; 872145516Sdarrenr 873145516Sdarrenr /* 874145516Sdarrenr * Loop through length of segment after first fragment, 875145516Sdarrenr * make new header and copy data of each part and link onto chain. 876145516Sdarrenr */ 877145516Sdarrenr m0 = m; 878145516Sdarrenr mhlen = sizeof (struct ip); 879255332Scy for (off = hlen + len; off < ntohs(ip->ip_len); off += len) { 880145516Sdarrenr#ifdef MGETHDR 881145516Sdarrenr MGETHDR(m, M_DONTWAIT, MT_HEADER); 882145516Sdarrenr#else 883145516Sdarrenr MGET(m, M_DONTWAIT, MT_HEADER); 884145516Sdarrenr#endif 885145516Sdarrenr if (m == 0) { 886145516Sdarrenr m = m0; 887145516Sdarrenr error = ENOBUFS; 888145516Sdarrenr goto bad; 889145516Sdarrenr } 890145516Sdarrenr m->m_data += max_linkhdr; 891145516Sdarrenr mhip = mtod(m, struct ip *); 892145516Sdarrenr bcopy((char *)ip, (char *)mhip, sizeof(*ip)); 893145516Sdarrenr if (hlen > sizeof (struct ip)) { 894145516Sdarrenr mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip); 895145516Sdarrenr IP_HL_A(mhip, mhlen >> 2); 896145516Sdarrenr } 897145516Sdarrenr m->m_len = mhlen; 898145516Sdarrenr mhip->ip_off = ((off - hlen) >> 3) + ip_off; 899255332Scy if (off + len >= ntohs(ip->ip_len)) 900255332Scy len = ntohs(ip->ip_len) - off; 901145516Sdarrenr else 902145516Sdarrenr mhip->ip_off |= IP_MF; 903145516Sdarrenr mhip->ip_len = htons((u_short)(len + mhlen)); 904161356Sguido *mnext = m; 905145516Sdarrenr m->m_next = m_copy(m0, off, len); 906145516Sdarrenr if (m->m_next == 0) { 907145516Sdarrenr error = ENOBUFS; /* ??? */ 908145516Sdarrenr goto sendorfree; 909145516Sdarrenr } 910145516Sdarrenr m->m_pkthdr.len = mhlen + len; 911145516Sdarrenr m->m_pkthdr.rcvif = NULL; 912145516Sdarrenr mhip->ip_off = htons((u_short)mhip->ip_off); 913145516Sdarrenr mhip->ip_sum = 0; 914145516Sdarrenr mhip->ip_sum = in_cksum(m, mhlen); 915145516Sdarrenr mnext = &m->m_act; 916145516Sdarrenr } 917145516Sdarrenr /* 918145516Sdarrenr * Update first fragment by trimming what's been copied out 919145516Sdarrenr * and updating header, then send each fragment (in order). 920145516Sdarrenr */ 921145516Sdarrenr m_adj(m0, hlen + firstlen - ip->ip_len); 922145516Sdarrenr ip->ip_len = htons((u_short)(hlen + firstlen)); 923145516Sdarrenr ip->ip_off = htons((u_short)IP_MF); 924145516Sdarrenr ip->ip_sum = 0; 925145516Sdarrenr ip->ip_sum = in_cksum(m0, hlen); 926145516Sdarrenrsendorfree: 927145516Sdarrenr for (m = m0; m; m = m0) { 928145516Sdarrenr m0 = m->m_act; 929145516Sdarrenr m->m_act = 0; 930145516Sdarrenr if (error == 0) 931145516Sdarrenr error = (*ifp->if_output)(ifp, m, 932255332Scy (struct sockaddr *)dst, 933255332Scy ro 934255332Scy ); 935145516Sdarrenr else 936145516Sdarrenr FREE_MB_T(m); 937145516Sdarrenr } 938255332Scy } 939145516Sdarrenrdone: 940145516Sdarrenr if (!error) 941255332Scy ipfmain.ipf_frouteok[0]++; 942145516Sdarrenr else 943255332Scy ipfmain.ipf_frouteok[1]++; 944145516Sdarrenr 945161356Sguido if ((ro != NULL) && (ro->ro_rt != NULL)) { 946145516Sdarrenr RTFREE(ro->ro_rt); 947145516Sdarrenr } 948145516Sdarrenr return 0; 949145516Sdarrenrbad: 950145516Sdarrenr if (error == EMSGSIZE) { 951145516Sdarrenr sifp = fin->fin_ifp; 952145516Sdarrenr code = fin->fin_icode; 953145516Sdarrenr fin->fin_icode = ICMP_UNREACH_NEEDFRAG; 954145516Sdarrenr fin->fin_ifp = ifp; 955255332Scy (void) ipf_send_icmp_err(ICMP_UNREACH, fin, 1); 956145516Sdarrenr fin->fin_ifp = sifp; 957145516Sdarrenr fin->fin_icode = code; 958145516Sdarrenr } 959145516Sdarrenr FREE_MB_T(m); 960145516Sdarrenr goto done; 961145516Sdarrenr} 962145516Sdarrenr 963145516Sdarrenr 964255332Scyint 965255332Scyipf_verifysrc(fin) 966255332Scy fr_info_t *fin; 967145516Sdarrenr{ 968145516Sdarrenr struct sockaddr_in *dst; 969145516Sdarrenr struct route iproute; 970145516Sdarrenr 971145516Sdarrenr bzero((char *)&iproute, sizeof(iproute)); 972145516Sdarrenr dst = (struct sockaddr_in *)&iproute.ro_dst; 973145516Sdarrenr dst->sin_len = sizeof(*dst); 974145516Sdarrenr dst->sin_family = AF_INET; 975145516Sdarrenr dst->sin_addr = fin->fin_src; 976178888Sjulian in_rtalloc(&iproute, 0); 977145516Sdarrenr if (iproute.ro_rt == NULL) 978145516Sdarrenr return 0; 979145516Sdarrenr return (fin->fin_ifp == iproute.ro_rt->rt_ifp); 980145516Sdarrenr} 981145516Sdarrenr 982145516Sdarrenr 983145516Sdarrenr/* 984145516Sdarrenr * return the first IP Address associated with an interface 985145516Sdarrenr */ 986255332Scyint 987255332Scyipf_ifpaddr(softc, v, atype, ifptr, inp, inpmask) 988255332Scy ipf_main_softc_t *softc; 989255332Scy int v, atype; 990255332Scy void *ifptr; 991255332Scy i6addr_t *inp, *inpmask; 992145516Sdarrenr{ 993145516Sdarrenr#ifdef USE_INET6 994145516Sdarrenr struct in6_addr *inp6 = NULL; 995145516Sdarrenr#endif 996145516Sdarrenr struct sockaddr *sock, *mask; 997145516Sdarrenr struct sockaddr_in *sin; 998145516Sdarrenr struct ifaddr *ifa; 999145516Sdarrenr struct ifnet *ifp; 1000145516Sdarrenr 1001145516Sdarrenr if ((ifptr == NULL) || (ifptr == (void *)-1)) 1002145516Sdarrenr return -1; 1003145516Sdarrenr 1004145516Sdarrenr sin = NULL; 1005145516Sdarrenr ifp = ifptr; 1006145516Sdarrenr 1007145516Sdarrenr if (v == 4) 1008255332Scy inp->in4.s_addr = 0; 1009145516Sdarrenr#ifdef USE_INET6 1010145516Sdarrenr else if (v == 6) 1011255332Scy bzero((char *)inp, sizeof(*inp)); 1012145516Sdarrenr#endif 1013145516Sdarrenr ifa = TAILQ_FIRST(&ifp->if_addrhead); 1014145516Sdarrenr 1015145516Sdarrenr sock = ifa->ifa_addr; 1016145516Sdarrenr while (sock != NULL && ifa != NULL) { 1017145516Sdarrenr sin = (struct sockaddr_in *)sock; 1018145516Sdarrenr if ((v == 4) && (sin->sin_family == AF_INET)) 1019145516Sdarrenr break; 1020145516Sdarrenr#ifdef USE_INET6 1021145516Sdarrenr if ((v == 6) && (sin->sin_family == AF_INET6)) { 1022145516Sdarrenr inp6 = &((struct sockaddr_in6 *)sin)->sin6_addr; 1023145516Sdarrenr if (!IN6_IS_ADDR_LINKLOCAL(inp6) && 1024145516Sdarrenr !IN6_IS_ADDR_LOOPBACK(inp6)) 1025145516Sdarrenr break; 1026145516Sdarrenr } 1027145516Sdarrenr#endif 1028145516Sdarrenr ifa = TAILQ_NEXT(ifa, ifa_link); 1029145516Sdarrenr if (ifa != NULL) 1030145516Sdarrenr sock = ifa->ifa_addr; 1031145516Sdarrenr } 1032145516Sdarrenr 1033145516Sdarrenr if (ifa == NULL || sin == NULL) 1034145516Sdarrenr return -1; 1035145516Sdarrenr 1036145516Sdarrenr mask = ifa->ifa_netmask; 1037145516Sdarrenr if (atype == FRI_BROADCAST) 1038145516Sdarrenr sock = ifa->ifa_broadaddr; 1039145516Sdarrenr else if (atype == FRI_PEERADDR) 1040145516Sdarrenr sock = ifa->ifa_dstaddr; 1041145516Sdarrenr 1042161356Sguido if (sock == NULL) 1043161356Sguido return -1; 1044161356Sguido 1045145516Sdarrenr#ifdef USE_INET6 1046145516Sdarrenr if (v == 6) { 1047255332Scy return ipf_ifpfillv6addr(atype, (struct sockaddr_in6 *)sock, 1048255332Scy (struct sockaddr_in6 *)mask, 1049255332Scy inp, inpmask); 1050145516Sdarrenr } 1051145516Sdarrenr#endif 1052255332Scy return ipf_ifpfillv4addr(atype, (struct sockaddr_in *)sock, 1053255332Scy (struct sockaddr_in *)mask, 1054255332Scy &inp->in4, &inpmask->in4); 1055145516Sdarrenr} 1056145516Sdarrenr 1057145516Sdarrenr 1058255332Scyu_32_t 1059255332Scyipf_newisn(fin) 1060255332Scy fr_info_t *fin; 1061145516Sdarrenr{ 1062145516Sdarrenr u_32_t newiss; 1063145516Sdarrenr newiss = arc4random(); 1064145516Sdarrenr return newiss; 1065145516Sdarrenr} 1066145516Sdarrenr 1067145516Sdarrenr 1068145516Sdarrenr/* ------------------------------------------------------------------------ */ 1069255332Scy/* Function: ipf_nextipid */ 1070145516Sdarrenr/* Returns: int - 0 == success, -1 == error (packet should be droppped) */ 1071145516Sdarrenr/* Parameters: fin(I) - pointer to packet information */ 1072145516Sdarrenr/* */ 1073145516Sdarrenr/* Returns the next IPv4 ID to use for this packet. */ 1074145516Sdarrenr/* ------------------------------------------------------------------------ */ 1075255332Scyu_short 1076255332Scyipf_nextipid(fin) 1077255332Scy fr_info_t *fin; 1078145516Sdarrenr{ 1079145516Sdarrenr u_short id; 1080145516Sdarrenr 1081255332Scy#ifndef RANDOM_IP_ID 1082255332Scy MUTEX_ENTER(&ipfmain.ipf_rw); 1083145516Sdarrenr id = ipid++; 1084255332Scy MUTEX_EXIT(&ipfmain.ipf_rw); 1085145516Sdarrenr#else 1086145516Sdarrenr id = ip_randomid(); 1087145516Sdarrenr#endif 1088145516Sdarrenr 1089145516Sdarrenr return id; 1090145516Sdarrenr} 1091145516Sdarrenr 1092145516Sdarrenr 1093255332ScyINLINE int 1094255332Scyipf_checkv4sum(fin) 1095255332Scy fr_info_t *fin; 1096145516Sdarrenr{ 1097145516Sdarrenr#ifdef CSUM_DATA_VALID 1098145516Sdarrenr int manual = 0; 1099145516Sdarrenr u_short sum; 1100145516Sdarrenr ip_t *ip; 1101145516Sdarrenr mb_t *m; 1102145516Sdarrenr 1103145516Sdarrenr if ((fin->fin_flx & FI_NOCKSUM) != 0) 1104255332Scy return 0; 1105145516Sdarrenr 1106255332Scy if ((fin->fin_flx & FI_SHORT) != 0) 1107255332Scy return 1; 1108172776Sdarrenr 1109255332Scy if (fin->fin_cksum != FI_CK_NEEDED) 1110255332Scy return (fin->fin_cksum > FI_CK_NEEDED) ? 0 : -1; 1111255332Scy 1112145516Sdarrenr m = fin->fin_m; 1113145516Sdarrenr if (m == NULL) { 1114145516Sdarrenr manual = 1; 1115145516Sdarrenr goto skipauto; 1116145516Sdarrenr } 1117145516Sdarrenr ip = fin->fin_ip; 1118145516Sdarrenr 1119255332Scy if ((m->m_pkthdr.csum_flags & (CSUM_IP_CHECKED|CSUM_IP_VALID)) == 1120255332Scy CSUM_IP_CHECKED) { 1121255332Scy fin->fin_cksum = FI_CK_BAD; 1122255332Scy fin->fin_flx |= FI_BAD; 1123255332Scy return -1; 1124255332Scy } 1125145516Sdarrenr if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) { 1126145516Sdarrenr if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) 1127145516Sdarrenr sum = m->m_pkthdr.csum_data; 1128145516Sdarrenr else 1129145516Sdarrenr sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, 1130145516Sdarrenr htonl(m->m_pkthdr.csum_data + 1131255332Scy fin->fin_dlen + fin->fin_p)); 1132145516Sdarrenr sum ^= 0xffff; 1133172776Sdarrenr if (sum != 0) { 1134255332Scy fin->fin_cksum = FI_CK_BAD; 1135145516Sdarrenr fin->fin_flx |= FI_BAD; 1136172776Sdarrenr } else { 1137255332Scy fin->fin_cksum = FI_CK_SUMOK; 1138255332Scy return 0; 1139172776Sdarrenr } 1140255332Scy } else { 1141255332Scy if (m->m_pkthdr.csum_flags == CSUM_DELAY_DATA) { 1142255332Scy fin->fin_cksum = FI_CK_L4FULL; 1143255332Scy return 0; 1144255332Scy } else if (m->m_pkthdr.csum_flags == CSUM_TCP || 1145255332Scy m->m_pkthdr.csum_flags == CSUM_UDP) { 1146255332Scy fin->fin_cksum = FI_CK_L4PART; 1147255332Scy return 0; 1148255332Scy } else if (m->m_pkthdr.csum_flags == CSUM_IP) { 1149255332Scy fin->fin_cksum = FI_CK_L4PART; 1150255332Scy return 0; 1151255332Scy } else { 1152255332Scy manual = 1; 1153255332Scy } 1154255332Scy } 1155145516Sdarrenrskipauto: 1156255332Scy if (manual != 0) { 1157255332Scy if (ipf_checkl4sum(fin) == -1) { 1158145516Sdarrenr fin->fin_flx |= FI_BAD; 1159255332Scy return -1; 1160255332Scy } 1161255332Scy } 1162145516Sdarrenr#else 1163255332Scy if (ipf_checkl4sum(fin) == -1) { 1164145516Sdarrenr fin->fin_flx |= FI_BAD; 1165255332Scy return -1; 1166255332Scy } 1167145516Sdarrenr#endif 1168255332Scy return 0; 1169145516Sdarrenr} 1170145516Sdarrenr 1171145516Sdarrenr 1172145516Sdarrenr#ifdef USE_INET6 1173255332ScyINLINE int 1174255332Scyipf_checkv6sum(fin) 1175255332Scy fr_info_t *fin; 1176145516Sdarrenr{ 1177255332Scy if ((fin->fin_flx & FI_NOCKSUM) != 0) 1178255332Scy return 0; 1179255332Scy 1180255332Scy if ((fin->fin_flx & FI_SHORT) != 0) 1181255332Scy return 1; 1182255332Scy 1183255332Scy if (fin->fin_cksum != FI_CK_NEEDED) 1184255332Scy return (fin->fin_cksum > FI_CK_NEEDED) ? 0 : -1; 1185255332Scy 1186255332Scy if (ipf_checkl4sum(fin) == -1) { 1187145516Sdarrenr fin->fin_flx |= FI_BAD; 1188255332Scy return -1; 1189255332Scy } 1190255332Scy return 0; 1191145516Sdarrenr} 1192145516Sdarrenr#endif /* USE_INET6 */ 1193145516Sdarrenr 1194145516Sdarrenr 1195255332Scysize_t 1196255332Scymbufchainlen(m0) 1197255332Scy struct mbuf *m0; 1198255332Scy { 1199145516Sdarrenr size_t len; 1200145516Sdarrenr 1201145516Sdarrenr if ((m0->m_flags & M_PKTHDR) != 0) { 1202145516Sdarrenr len = m0->m_pkthdr.len; 1203145516Sdarrenr } else { 1204145516Sdarrenr struct mbuf *m; 1205145516Sdarrenr 1206145516Sdarrenr for (m = m0, len = 0; m != NULL; m = m->m_next) 1207145516Sdarrenr len += m->m_len; 1208145516Sdarrenr } 1209145516Sdarrenr return len; 1210145516Sdarrenr} 1211145516Sdarrenr 1212145516Sdarrenr 1213145516Sdarrenr/* ------------------------------------------------------------------------ */ 1214255332Scy/* Function: ipf_pullup */ 1215145516Sdarrenr/* Returns: NULL == pullup failed, else pointer to protocol header */ 1216255332Scy/* Parameters: xmin(I)- pointer to buffer where data packet starts */ 1217145516Sdarrenr/* fin(I) - pointer to packet information */ 1218145516Sdarrenr/* len(I) - number of bytes to pullup */ 1219145516Sdarrenr/* */ 1220145516Sdarrenr/* Attempt to move at least len bytes (from the start of the buffer) into a */ 1221145516Sdarrenr/* single buffer for ease of access. Operating system native functions are */ 1222145516Sdarrenr/* used to manage buffers - if necessary. If the entire packet ends up in */ 1223255332Scy/* a single buffer, set the FI_COALESCE flag even though ipf_coalesce() has */ 1224145516Sdarrenr/* not been called. Both fin_ip and fin_dp are updated before exiting _IF_ */ 1225145516Sdarrenr/* and ONLY if the pullup succeeds. */ 1226145516Sdarrenr/* */ 1227255332Scy/* We assume that 'xmin' is a pointer to a buffer that is part of the chain */ 1228145516Sdarrenr/* of buffers that starts at *fin->fin_mp. */ 1229145516Sdarrenr/* ------------------------------------------------------------------------ */ 1230255332Scyvoid * 1231255332Scyipf_pullup(xmin, fin, len) 1232255332Scy mb_t *xmin; 1233255332Scy fr_info_t *fin; 1234255332Scy int len; 1235145516Sdarrenr{ 1236255332Scy int dpoff, ipoff; 1237255332Scy mb_t *m = xmin; 1238145516Sdarrenr char *ip; 1239145516Sdarrenr 1240145516Sdarrenr if (m == NULL) 1241145516Sdarrenr return NULL; 1242145516Sdarrenr 1243145516Sdarrenr ip = (char *)fin->fin_ip; 1244145516Sdarrenr if ((fin->fin_flx & FI_COALESCE) != 0) 1245145516Sdarrenr return ip; 1246145516Sdarrenr 1247145516Sdarrenr ipoff = fin->fin_ipoff; 1248145516Sdarrenr if (fin->fin_dp != NULL) 1249145516Sdarrenr dpoff = (char *)fin->fin_dp - (char *)ip; 1250145516Sdarrenr else 1251145516Sdarrenr dpoff = 0; 1252145516Sdarrenr 1253145516Sdarrenr if (M_LEN(m) < len) { 1254255332Scy mb_t *n = *fin->fin_mp; 1255145516Sdarrenr /* 1256145516Sdarrenr * Assume that M_PKTHDR is set and just work with what is left 1257145516Sdarrenr * rather than check.. 1258145516Sdarrenr * Should not make any real difference, anyway. 1259145516Sdarrenr */ 1260255332Scy if (m != n) { 1261255332Scy /* 1262255332Scy * Record the mbuf that points to the mbuf that we're 1263255332Scy * about to go to work on so that we can update the 1264255332Scy * m_next appropriately later. 1265255332Scy */ 1266255332Scy for (; n->m_next != m; n = n->m_next) 1267255332Scy ; 1268255332Scy } else { 1269255332Scy n = NULL; 1270255332Scy } 1271255332Scy 1272255332Scy#ifdef MHLEN 1273145516Sdarrenr if (len > MHLEN) 1274145516Sdarrenr#else 1275145516Sdarrenr if (len > MLEN) 1276145516Sdarrenr#endif 1277145516Sdarrenr { 1278145516Sdarrenr#ifdef HAVE_M_PULLDOWN 1279145516Sdarrenr if (m_pulldown(m, 0, len, NULL) == NULL) 1280145516Sdarrenr m = NULL; 1281145516Sdarrenr#else 1282145516Sdarrenr FREE_MB_T(*fin->fin_mp); 1283145516Sdarrenr m = NULL; 1284255332Scy n = NULL; 1285145516Sdarrenr#endif 1286145516Sdarrenr } else 1287145516Sdarrenr { 1288145516Sdarrenr m = m_pullup(m, len); 1289145516Sdarrenr } 1290255332Scy if (n != NULL) 1291255332Scy n->m_next = m; 1292145516Sdarrenr if (m == NULL) { 1293255332Scy /* 1294255332Scy * When n is non-NULL, it indicates that m pointed to 1295255332Scy * a sub-chain (tail) of the mbuf and that the head 1296255332Scy * of this chain has not yet been free'd. 1297255332Scy */ 1298255332Scy if (n != NULL) { 1299255332Scy FREE_MB_T(*fin->fin_mp); 1300255332Scy } 1301255332Scy 1302255332Scy *fin->fin_mp = NULL; 1303172776Sdarrenr fin->fin_m = NULL; 1304145516Sdarrenr return NULL; 1305145516Sdarrenr } 1306172776Sdarrenr 1307255332Scy if (n == NULL) 1308255332Scy *fin->fin_mp = m; 1309255332Scy 1310172776Sdarrenr while (M_LEN(m) == 0) { 1311172776Sdarrenr m = m->m_next; 1312172776Sdarrenr } 1313172776Sdarrenr fin->fin_m = m; 1314145516Sdarrenr ip = MTOD(m, char *) + ipoff; 1315255332Scy 1316255332Scy fin->fin_ip = (ip_t *)ip; 1317255332Scy if (fin->fin_dp != NULL) 1318255332Scy fin->fin_dp = (char *)fin->fin_ip + dpoff; 1319255332Scy if (fin->fin_fraghdr != NULL) 1320255332Scy fin->fin_fraghdr = (char *)ip + 1321255332Scy ((char *)fin->fin_fraghdr - 1322255332Scy (char *)fin->fin_ip); 1323145516Sdarrenr } 1324145516Sdarrenr 1325145516Sdarrenr if (len == fin->fin_plen) 1326145516Sdarrenr fin->fin_flx |= FI_COALESCE; 1327145516Sdarrenr return ip; 1328145516Sdarrenr} 1329170268Sdarrenr 1330170268Sdarrenr 1331255332Scyint 1332255332Scyipf_inject(fin, m) 1333255332Scy fr_info_t *fin; 1334255332Scy mb_t *m; 1335170268Sdarrenr{ 1336170268Sdarrenr int error = 0; 1337170268Sdarrenr 1338170268Sdarrenr if (fin->fin_out == 0) { 1339170268Sdarrenr netisr_dispatch(NETISR_IP, m); 1340170268Sdarrenr } else { 1341173931Sdarrenr fin->fin_ip->ip_len = ntohs(fin->fin_ip->ip_len); 1342173931Sdarrenr fin->fin_ip->ip_off = ntohs(fin->fin_ip->ip_off); 1343170268Sdarrenr error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL); 1344170268Sdarrenr } 1345170268Sdarrenr 1346170268Sdarrenr return error; 1347170268Sdarrenr} 1348172776Sdarrenr 1349172776Sdarrenrint ipf_pfil_unhook(void) { 1350172776Sdarrenr#if defined(NETBSD_PF) && (__FreeBSD_version >= 500011) 1351172776Sdarrenr struct pfil_head *ph_inet; 1352172776Sdarrenr# ifdef USE_INET6 1353172776Sdarrenr struct pfil_head *ph_inet6; 1354172776Sdarrenr# endif 1355172776Sdarrenr#endif 1356172776Sdarrenr 1357172776Sdarrenr#ifdef NETBSD_PF 1358172776Sdarrenr ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); 1359172776Sdarrenr if (ph_inet != NULL) 1360255332Scy pfil_remove_hook((void *)ipf_check_wrapper, NULL, 1361172776Sdarrenr PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet); 1362172776Sdarrenr# ifdef USE_INET6 1363172776Sdarrenr ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6); 1364172776Sdarrenr if (ph_inet6 != NULL) 1365255332Scy pfil_remove_hook((void *)ipf_check_wrapper6, NULL, 1366172776Sdarrenr PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet6); 1367172776Sdarrenr# endif 1368172776Sdarrenr#endif 1369172776Sdarrenr 1370172776Sdarrenr return (0); 1371172776Sdarrenr} 1372172776Sdarrenr 1373172776Sdarrenrint ipf_pfil_hook(void) { 1374172776Sdarrenr#if defined(NETBSD_PF) && (__FreeBSD_version >= 500011) 1375172776Sdarrenr struct pfil_head *ph_inet; 1376172776Sdarrenr# ifdef USE_INET6 1377172776Sdarrenr struct pfil_head *ph_inet6; 1378172776Sdarrenr# endif 1379172776Sdarrenr#endif 1380172776Sdarrenr 1381172776Sdarrenr# ifdef NETBSD_PF 1382172776Sdarrenr ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); 1383172776Sdarrenr# ifdef USE_INET6 1384172776Sdarrenr ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6); 1385172776Sdarrenr# endif 1386172776Sdarrenr if (ph_inet == NULL 1387172776Sdarrenr# ifdef USE_INET6 1388172776Sdarrenr && ph_inet6 == NULL 1389172776Sdarrenr# endif 1390255332Scy ) { 1391172776Sdarrenr return ENODEV; 1392255332Scy } 1393172776Sdarrenr 1394172776Sdarrenr if (ph_inet != NULL) 1395255332Scy pfil_add_hook((void *)ipf_check_wrapper, NULL, 1396172776Sdarrenr PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet); 1397172776Sdarrenr# ifdef USE_INET6 1398172776Sdarrenr if (ph_inet6 != NULL) 1399255332Scy pfil_add_hook((void *)ipf_check_wrapper6, NULL, 1400172776Sdarrenr PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet6); 1401172776Sdarrenr# endif 1402172776Sdarrenr# endif 1403172776Sdarrenr return (0); 1404172776Sdarrenr} 1405172776Sdarrenr 1406172776Sdarrenrvoid 1407172776Sdarrenripf_event_reg(void) 1408172776Sdarrenr{ 1409255332Scy ipf_arrivetag = EVENTHANDLER_REGISTER(ifnet_arrival_event, \ 1410255332Scy ipf_ifevent, &ipfmain, \ 1411172776Sdarrenr EVENTHANDLER_PRI_ANY); 1412255332Scy ipf_departtag = EVENTHANDLER_REGISTER(ifnet_departure_event, \ 1413255332Scy ipf_ifevent, &ipfmain, \ 1414172776Sdarrenr EVENTHANDLER_PRI_ANY); 1415255332Scy ipf_clonetag = EVENTHANDLER_REGISTER(if_clone_event, ipf_ifevent, \ 1416255332Scy &ipfmain, EVENTHANDLER_PRI_ANY); 1417172776Sdarrenr} 1418172776Sdarrenr 1419172776Sdarrenrvoid 1420172776Sdarrenripf_event_dereg(void) 1421172776Sdarrenr{ 1422172776Sdarrenr if (ipf_arrivetag != NULL) { 1423172776Sdarrenr EVENTHANDLER_DEREGISTER(ifnet_arrival_event, ipf_arrivetag); 1424172776Sdarrenr } 1425172776Sdarrenr if (ipf_departtag != NULL) { 1426172776Sdarrenr EVENTHANDLER_DEREGISTER(ifnet_departure_event, ipf_departtag); 1427172776Sdarrenr } 1428172776Sdarrenr if (ipf_clonetag != NULL) { 1429172776Sdarrenr EVENTHANDLER_DEREGISTER(if_clone_event, ipf_clonetag); 1430172776Sdarrenr } 1431172776Sdarrenr} 1432255332Scy 1433255332Scy 1434255332Scyu_32_t 1435255332Scyipf_random() 1436255332Scy{ 1437255332Scy return arc4random(); 1438255332Scy} 1439255332Scy 1440255332Scy 1441255332Scyu_int 1442255332Scyipf_pcksum(fin, hlen, sum) 1443255332Scy fr_info_t *fin; 1444255332Scy int hlen; 1445255332Scy u_int sum; 1446255332Scy{ 1447255332Scy struct mbuf *m; 1448255332Scy u_int sum2; 1449255332Scy int off; 1450255332Scy 1451255332Scy m = fin->fin_m; 1452255332Scy off = (char *)fin->fin_dp - (char *)fin->fin_ip; 1453255332Scy m->m_data += hlen; 1454255332Scy m->m_len -= hlen; 1455255332Scy sum2 = in_cksum(fin->fin_m, fin->fin_plen - off); 1456255332Scy m->m_len += hlen; 1457255332Scy m->m_data -= hlen; 1458255332Scy 1459255332Scy /* 1460255332Scy * Both sum and sum2 are partial sums, so combine them together. 1461255332Scy */ 1462255332Scy sum += ~sum2 & 0xffff; 1463255332Scy while (sum > 0xffff) 1464255332Scy sum = (sum & 0xffff) + (sum >> 16); 1465255332Scy sum2 = ~sum & 0xffff; 1466255332Scy return sum2; 1467255332Scy} 1468