ip_fil_freebsd.c revision 192895
1145516Sdarrenr/* $FreeBSD: head/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c 192895 2009-05-27 14:11:23Z jamie $ */ 2145516Sdarrenr 3145516Sdarrenr/* 4145516Sdarrenr * Copyright (C) 1993-2003 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"; 10172776Sdarrenrstatic const char rcsid[] = "@(#)$Id: ip_fil_freebsd.c,v 2.53.2.50 2007/09/20 12:51:50 darrenr Exp $"; 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#if defined(__FreeBSD__) && !defined(__FreeBSD_version) 29145516Sdarrenr# if defined(IPFILTER_LKM) 30145516Sdarrenr# ifndef __FreeBSD_cc_version 31145516Sdarrenr# include <osreldate.h> 32145516Sdarrenr# else 33145516Sdarrenr# if __FreeBSD_cc_version < 430000 34145516Sdarrenr# include <osreldate.h> 35145516Sdarrenr# endif 36145516Sdarrenr# endif 37145516Sdarrenr# endif 38145516Sdarrenr#endif 39145516Sdarrenr#include <sys/errno.h> 40145516Sdarrenr#include <sys/types.h> 41145516Sdarrenr#include <sys/file.h> 42145516Sdarrenr#if __FreeBSD_version >= 220000 43145516Sdarrenr# include <sys/fcntl.h> 44145516Sdarrenr# include <sys/filio.h> 45145516Sdarrenr#else 46145516Sdarrenr# include <sys/ioctl.h> 47145516Sdarrenr#endif 48145516Sdarrenr#include <sys/time.h> 49145516Sdarrenr#include <sys/systm.h> 50145516Sdarrenr#if (__FreeBSD_version >= 300000) 51145516Sdarrenr# include <sys/dirent.h> 52145516Sdarrenr#else 53145516Sdarrenr# include <sys/dir.h> 54145516Sdarrenr#endif 55145516Sdarrenr#if !defined(__hpux) 56145516Sdarrenr# include <sys/mbuf.h> 57145516Sdarrenr#endif 58145516Sdarrenr#include <sys/protosw.h> 59145516Sdarrenr#include <sys/socket.h> 60170268Sdarrenr#if __FreeBSD_version >= 500043 61170268Sdarrenr# include <sys/selinfo.h> 62170268Sdarrenr#else 63170268Sdarrenr# include <sys/select.h> 64170268Sdarrenr#endif 65181803Sbz#if __FreeBSD_version >= 800044 66181803Sbz# include <sys/vimage.h> 67181803Sbz#else 68181803Sbz#define V_path_mtu_discovery path_mtu_discovery 69181803Sbz#define V_ipforwarding ipforwarding 70181803Sbz#endif 71145516Sdarrenr 72145516Sdarrenr#include <net/if.h> 73145516Sdarrenr#if __FreeBSD_version >= 300000 74145516Sdarrenr# include <net/if_var.h> 75170268Sdarrenr# if __FreeBSD_version >= 500043 76170268Sdarrenr# include <net/netisr.h> 77170268Sdarrenr# endif 78145516Sdarrenr# if !defined(IPFILTER_LKM) 79145516Sdarrenr# include "opt_ipfilter.h" 80145516Sdarrenr# endif 81145516Sdarrenr#endif 82145516Sdarrenr#include <net/route.h> 83145516Sdarrenr#include <netinet/in.h> 84145516Sdarrenr#include <netinet/in_var.h> 85145516Sdarrenr#include <netinet/in_systm.h> 86145516Sdarrenr#include <netinet/ip.h> 87145516Sdarrenr#include <netinet/ip_var.h> 88145516Sdarrenr#include <netinet/tcp.h> 89145516Sdarrenr#if defined(__osf__) 90145516Sdarrenr# include <netinet/tcp_timer.h> 91145516Sdarrenr#endif 92145516Sdarrenr#include <netinet/udp.h> 93145516Sdarrenr#include <netinet/tcpip.h> 94145516Sdarrenr#include <netinet/ip_icmp.h> 95189105Sbz#if defined(__FreeBSD_version) && (__FreeBSD_version >= 800056) 96189105Sbz# include <netinet/vinet.h> 97189105Sbz#endif 98145516Sdarrenr#ifndef _KERNEL 99145516Sdarrenr# include "netinet/ipf.h" 100145516Sdarrenr#endif 101145516Sdarrenr#include "netinet/ip_compat.h" 102145516Sdarrenr#ifdef USE_INET6 103145516Sdarrenr# include <netinet/icmp6.h> 104145516Sdarrenr#endif 105145516Sdarrenr#include "netinet/ip_fil.h" 106145516Sdarrenr#include "netinet/ip_nat.h" 107145516Sdarrenr#include "netinet/ip_frag.h" 108145516Sdarrenr#include "netinet/ip_state.h" 109145516Sdarrenr#include "netinet/ip_proxy.h" 110145516Sdarrenr#include "netinet/ip_auth.h" 111145516Sdarrenr#ifdef IPFILTER_SYNC 112145516Sdarrenr#include "netinet/ip_sync.h" 113145516Sdarrenr#endif 114145516Sdarrenr#ifdef IPFILTER_SCAN 115145516Sdarrenr#include "netinet/ip_scan.h" 116145516Sdarrenr#endif 117145516Sdarrenr#include "netinet/ip_pool.h" 118145516Sdarrenr#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) 119145516Sdarrenr# include <sys/malloc.h> 120145516Sdarrenr#endif 121145516Sdarrenr#include <sys/kernel.h> 122145516Sdarrenr#ifdef CSUM_DATA_VALID 123145516Sdarrenr#include <machine/in_cksum.h> 124145516Sdarrenr#endif 125145516Sdarrenrextern int ip_optcopy __P((struct ip *, struct ip *)); 126145516Sdarrenr 127185419Szec#if (__FreeBSD_version > 460000) && (__FreeBSD_version < 800055) 128145516Sdarrenrextern int path_mtu_discovery; 129145516Sdarrenr#endif 130145516Sdarrenr 131145516Sdarrenr# ifdef IPFILTER_M_IPFILTER 132151897SrwatsonMALLOC_DEFINE(M_IPFILTER, "ipfilter", "IP Filter packet filter data structures"); 133145516Sdarrenr# endif 134145516Sdarrenr 135145516Sdarrenr 136145516Sdarrenr#if !defined(__osf__) 137145516Sdarrenrextern struct protosw inetsw[]; 138145516Sdarrenr#endif 139145516Sdarrenr 140145516Sdarrenrstatic int (*fr_savep) __P((ip_t *, int, void *, int, struct mbuf **)); 141145516Sdarrenrstatic int fr_send_ip __P((fr_info_t *, mb_t *, mb_t **)); 142145516Sdarrenr# ifdef USE_MUTEXES 143145516Sdarrenripfmutex_t ipl_mutex, ipf_authmx, ipf_rw, ipf_stinsert; 144145516Sdarrenripfmutex_t ipf_nat_new, ipf_natio, ipf_timeoutlock; 145170268Sdarrenripfrwlock_t ipf_mutex, ipf_global, ipf_ipidfrag, ipf_frcache, ipf_tokens; 146145516Sdarrenripfrwlock_t ipf_frag, ipf_state, ipf_nat, ipf_natfrag, ipf_auth; 147145516Sdarrenr# endif 148145516Sdarrenrint ipf_locks_done = 0; 149145516Sdarrenr 150145516Sdarrenr#if (__FreeBSD_version >= 300000) 151145516Sdarrenrstruct callout_handle fr_slowtimer_ch; 152145516Sdarrenr#endif 153161356Sguidostruct selinfo ipfselwait[IPL_LOGSIZE]; 154145516Sdarrenr 155145516Sdarrenr#if (__FreeBSD_version >= 500011) 156145516Sdarrenr# include <sys/conf.h> 157145516Sdarrenr# if defined(NETBSD_PF) 158145516Sdarrenr# include <net/pfil.h> 159186436Sbz# if (__FreeBSD_version < 501108) 160186436Sbz# include <netinet/ipprotosw.h> 161186436Sbz# endif 162145516Sdarrenr/* 163145516Sdarrenr * We provide the fr_checkp name just to minimize changes later. 164145516Sdarrenr */ 165145516Sdarrenrint (*fr_checkp) __P((ip_t *ip, int hlen, void *ifp, int out, mb_t **mp)); 166145516Sdarrenr# endif /* NETBSD_PF */ 167145516Sdarrenr#endif /* __FreeBSD_version >= 500011 */ 168145516Sdarrenr 169145516Sdarrenr 170153876Sguido#if (__FreeBSD_version >= 502103) 171153876Sguidostatic eventhandler_tag ipf_arrivetag, ipf_departtag, ipf_clonetag; 172153876Sguido 173153876Sguidostatic void ipf_ifevent(void *arg); 174153876Sguido 175153876Sguidostatic void ipf_ifevent(arg) 176153876Sguidovoid *arg; 177153876Sguido{ 178153876Sguido frsync(NULL); 179153876Sguido} 180153876Sguido#endif 181153876Sguido 182153876Sguido 183145516Sdarrenr#if (__FreeBSD_version >= 501108) && defined(_KERNEL) 184145516Sdarrenr 185145516Sdarrenrstatic int 186145516Sdarrenrfr_check_wrapper(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir) 187145516Sdarrenr{ 188145516Sdarrenr struct ip *ip = mtod(*mp, struct ip *); 189145516Sdarrenr return fr_check(ip, ip->ip_hl << 2, ifp, (dir == PFIL_OUT), mp); 190145516Sdarrenr} 191145516Sdarrenr 192145516Sdarrenr# ifdef USE_INET6 193145516Sdarrenr# include <netinet/ip6.h> 194145516Sdarrenr 195145516Sdarrenrstatic int 196145516Sdarrenrfr_check_wrapper6(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir) 197145516Sdarrenr{ 198145516Sdarrenr return (fr_check(mtod(*mp, struct ip *), sizeof(struct ip6_hdr), 199145516Sdarrenr ifp, (dir == PFIL_OUT), mp)); 200145516Sdarrenr} 201145516Sdarrenr# endif 202145516Sdarrenr#endif /* __FreeBSD_version >= 501108 */ 203145516Sdarrenr#if defined(IPFILTER_LKM) 204145516Sdarrenrint iplidentify(s) 205145516Sdarrenrchar *s; 206145516Sdarrenr{ 207145516Sdarrenr if (strcmp(s, "ipl") == 0) 208145516Sdarrenr return 1; 209145516Sdarrenr return 0; 210145516Sdarrenr} 211145516Sdarrenr#endif /* IPFILTER_LKM */ 212145516Sdarrenr 213145516Sdarrenr 214170268Sdarrenrint ipfattach() 215145516Sdarrenr{ 216191548Szec INIT_VNET_INET(curvnet); 217145516Sdarrenr#ifdef USE_SPL 218145516Sdarrenr int s; 219145516Sdarrenr#endif 220145516Sdarrenr 221145516Sdarrenr SPL_NET(s); 222145516Sdarrenr if (fr_running > 0) { 223145516Sdarrenr SPL_X(s); 224145516Sdarrenr return EBUSY; 225145516Sdarrenr } 226145516Sdarrenr 227145516Sdarrenr MUTEX_INIT(&ipf_rw, "ipf rw mutex"); 228145516Sdarrenr MUTEX_INIT(&ipf_timeoutlock, "ipf timeout queue mutex"); 229145516Sdarrenr RWLOCK_INIT(&ipf_ipidfrag, "ipf IP NAT-Frag rwlock"); 230170268Sdarrenr RWLOCK_INIT(&ipf_tokens, "ipf token rwlock"); 231145516Sdarrenr ipf_locks_done = 1; 232145516Sdarrenr 233145516Sdarrenr if (fr_initialise() < 0) { 234145516Sdarrenr SPL_X(s); 235145516Sdarrenr return EIO; 236145516Sdarrenr } 237145516Sdarrenr 238145516Sdarrenr 239145516Sdarrenr if (fr_checkp != fr_check) { 240145516Sdarrenr fr_savep = fr_checkp; 241145516Sdarrenr fr_checkp = fr_check; 242145516Sdarrenr } 243145516Sdarrenr 244161356Sguido bzero((char *)ipfselwait, sizeof(ipfselwait)); 245145516Sdarrenr bzero((char *)frcache, sizeof(frcache)); 246145516Sdarrenr fr_running = 1; 247145516Sdarrenr 248145516Sdarrenr if (fr_control_forwarding & 1) 249181803Sbz V_ipforwarding = 1; 250145516Sdarrenr 251145516Sdarrenr SPL_X(s); 252145516Sdarrenr#if (__FreeBSD_version >= 300000) 253145516Sdarrenr fr_slowtimer_ch = timeout(fr_slowtimer, NULL, 254145516Sdarrenr (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT); 255145516Sdarrenr#else 256145516Sdarrenr timeout(fr_slowtimer, NULL, (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT); 257145516Sdarrenr#endif 258145516Sdarrenr return 0; 259145516Sdarrenr} 260145516Sdarrenr 261145516Sdarrenr 262145516Sdarrenr/* 263145516Sdarrenr * Disable the filter by removing the hooks from the IP input/output 264145516Sdarrenr * stream. 265145516Sdarrenr */ 266170268Sdarrenrint ipfdetach() 267145516Sdarrenr{ 268191548Szec INIT_VNET_INET(curvnet); 269145516Sdarrenr#ifdef USE_SPL 270145516Sdarrenr int s; 271145516Sdarrenr#endif 272145516Sdarrenr if (fr_control_forwarding & 2) 273181803Sbz V_ipforwarding = 0; 274145516Sdarrenr 275145516Sdarrenr SPL_NET(s); 276145516Sdarrenr 277145516Sdarrenr#if (__FreeBSD_version >= 300000) 278145516Sdarrenr if (fr_slowtimer_ch.callout != NULL) 279145516Sdarrenr untimeout(fr_slowtimer, NULL, fr_slowtimer_ch); 280145516Sdarrenr bzero(&fr_slowtimer_ch, sizeof(fr_slowtimer_ch)); 281145516Sdarrenr#else 282145516Sdarrenr untimeout(fr_slowtimer, NULL); 283145516Sdarrenr#endif /* FreeBSD */ 284145516Sdarrenr 285145516Sdarrenr#ifndef NETBSD_PF 286145516Sdarrenr if (fr_checkp != NULL) 287145516Sdarrenr fr_checkp = fr_savep; 288145516Sdarrenr fr_savep = NULL; 289145516Sdarrenr#endif 290145516Sdarrenr 291145516Sdarrenr fr_deinitialise(); 292145516Sdarrenr 293145516Sdarrenr fr_running = -2; 294145516Sdarrenr 295145516Sdarrenr (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE); 296145516Sdarrenr (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE); 297145516Sdarrenr 298145516Sdarrenr if (ipf_locks_done == 1) { 299145516Sdarrenr MUTEX_DESTROY(&ipf_timeoutlock); 300145516Sdarrenr MUTEX_DESTROY(&ipf_rw); 301145516Sdarrenr RW_DESTROY(&ipf_ipidfrag); 302170268Sdarrenr RW_DESTROY(&ipf_tokens); 303145516Sdarrenr ipf_locks_done = 0; 304145516Sdarrenr } 305145516Sdarrenr 306145516Sdarrenr SPL_X(s); 307145516Sdarrenr 308145516Sdarrenr return 0; 309145516Sdarrenr} 310145516Sdarrenr 311145516Sdarrenr 312145516Sdarrenr/* 313145516Sdarrenr * Filter ioctl interface. 314145516Sdarrenr */ 315145516Sdarrenrint iplioctl(dev, cmd, data, mode 316145516Sdarrenr# if defined(_KERNEL) && ((BSD >= 199506) || (__FreeBSD_version >= 220000)) 317145516Sdarrenr, p) 318145516Sdarrenr# if (__FreeBSD_version >= 500024) 319145516Sdarrenrstruct thread *p; 320170268Sdarrenr# if (__FreeBSD_version >= 500043) 321192895Sjamie# define p_cred td_ucred 322170268Sdarrenr# define p_uid td_ucred->cr_ruid 323170268Sdarrenr# else 324192895Sjamie# define p_cred t_proc->p_cred 325170268Sdarrenr# define p_uid t_proc->p_cred->p_ruid 326170268Sdarrenr# endif 327145516Sdarrenr# else 328145516Sdarrenrstruct proc *p; 329170268Sdarrenr# define p_uid p_cred->p_ruid 330145516Sdarrenr# endif /* __FreeBSD_version >= 500024 */ 331145516Sdarrenr# else 332145516Sdarrenr) 333145516Sdarrenr# endif 334145516Sdarrenr#if defined(_KERNEL) && (__FreeBSD_version >= 502116) 335145516Sdarrenrstruct cdev *dev; 336145516Sdarrenr#else 337145516Sdarrenrdev_t dev; 338145516Sdarrenr#endif 339145516Sdarrenrioctlcmd_t cmd; 340145516Sdarrenrcaddr_t data; 341145516Sdarrenrint mode; 342145516Sdarrenr{ 343170268Sdarrenr int error = 0, unit = 0; 344170268Sdarrenr SPL_INT(s); 345145516Sdarrenr 346145516Sdarrenr#if (BSD >= 199306) && defined(_KERNEL) 347192895Sjamie# if (__FreeBSD_version >= 500034) 348192895Sjamie if (securelevel_ge(p->p_cred, 3) && (mode & FWRITE)) 349192895Sjamie# else 350153876Sguido if ((securelevel >= 3) && (mode & FWRITE)) 351192895Sjamie# endif 352145516Sdarrenr return EPERM; 353145516Sdarrenr#endif 354145516Sdarrenr 355145516Sdarrenr unit = GET_MINOR(dev); 356145516Sdarrenr if ((IPL_LOGMAX < unit) || (unit < 0)) 357145516Sdarrenr return ENXIO; 358145516Sdarrenr 359145516Sdarrenr if (fr_running <= 0) { 360145516Sdarrenr if (unit != IPL_LOGIPF) 361145516Sdarrenr return EIO; 362145516Sdarrenr if (cmd != SIOCIPFGETNEXT && cmd != SIOCIPFGET && 363173181Sdarrenr cmd != SIOCIPFSET && cmd != SIOCFRENB && 364145516Sdarrenr cmd != SIOCGETFS && cmd != SIOCGETFF) 365145516Sdarrenr return EIO; 366145516Sdarrenr } 367145516Sdarrenr 368145516Sdarrenr SPL_NET(s); 369145516Sdarrenr 370170268Sdarrenr error = fr_ioctlswitch(unit, data, cmd, mode, p->p_uid, p); 371145516Sdarrenr if (error != -1) { 372145516Sdarrenr SPL_X(s); 373145516Sdarrenr return error; 374145516Sdarrenr } 375145516Sdarrenr 376145516Sdarrenr SPL_X(s); 377161356Sguido 378145516Sdarrenr return error; 379145516Sdarrenr} 380145516Sdarrenr 381145516Sdarrenr 382145516Sdarrenr#if 0 383145516Sdarrenrvoid fr_forgetifp(ifp) 384145516Sdarrenrvoid *ifp; 385145516Sdarrenr{ 386145516Sdarrenr register frentry_t *f; 387145516Sdarrenr 388145516Sdarrenr WRITE_ENTER(&ipf_mutex); 389145516Sdarrenr for (f = ipacct[0][fr_active]; (f != NULL); f = f->fr_next) 390145516Sdarrenr if (f->fr_ifa == ifp) 391145516Sdarrenr f->fr_ifa = (void *)-1; 392145516Sdarrenr for (f = ipacct[1][fr_active]; (f != NULL); f = f->fr_next) 393145516Sdarrenr if (f->fr_ifa == ifp) 394145516Sdarrenr f->fr_ifa = (void *)-1; 395145516Sdarrenr for (f = ipfilter[0][fr_active]; (f != NULL); f = f->fr_next) 396145516Sdarrenr if (f->fr_ifa == ifp) 397145516Sdarrenr f->fr_ifa = (void *)-1; 398145516Sdarrenr for (f = ipfilter[1][fr_active]; (f != NULL); f = f->fr_next) 399145516Sdarrenr if (f->fr_ifa == ifp) 400145516Sdarrenr f->fr_ifa = (void *)-1; 401145516Sdarrenr#ifdef USE_INET6 402145516Sdarrenr for (f = ipacct6[0][fr_active]; (f != NULL); f = f->fr_next) 403145516Sdarrenr if (f->fr_ifa == ifp) 404145516Sdarrenr f->fr_ifa = (void *)-1; 405145516Sdarrenr for (f = ipacct6[1][fr_active]; (f != NULL); f = f->fr_next) 406145516Sdarrenr if (f->fr_ifa == ifp) 407145516Sdarrenr f->fr_ifa = (void *)-1; 408145516Sdarrenr for (f = ipfilter6[0][fr_active]; (f != NULL); f = f->fr_next) 409145516Sdarrenr if (f->fr_ifa == ifp) 410145516Sdarrenr f->fr_ifa = (void *)-1; 411145516Sdarrenr for (f = ipfilter6[1][fr_active]; (f != NULL); f = f->fr_next) 412145516Sdarrenr if (f->fr_ifa == ifp) 413145516Sdarrenr f->fr_ifa = (void *)-1; 414145516Sdarrenr#endif 415145516Sdarrenr RWLOCK_EXIT(&ipf_mutex); 416145516Sdarrenr fr_natsync(ifp); 417145516Sdarrenr} 418145516Sdarrenr#endif 419145516Sdarrenr 420145516Sdarrenr 421145516Sdarrenr/* 422145516Sdarrenr * routines below for saving IP headers to buffer 423145516Sdarrenr */ 424145516Sdarrenrint iplopen(dev, flags 425145516Sdarrenr#if ((BSD >= 199506) || (__FreeBSD_version >= 220000)) && defined(_KERNEL) 426145516Sdarrenr, devtype, p) 427145516Sdarrenrint devtype; 428145516Sdarrenr# if (__FreeBSD_version >= 500024) 429145516Sdarrenrstruct thread *p; 430145516Sdarrenr# else 431145516Sdarrenrstruct proc *p; 432145516Sdarrenr# endif /* __FreeBSD_version >= 500024 */ 433145516Sdarrenr#else 434145516Sdarrenr) 435145516Sdarrenr#endif 436145516Sdarrenr#if defined(_KERNEL) && (__FreeBSD_version >= 502116) 437145516Sdarrenrstruct cdev *dev; 438145516Sdarrenr#else 439145516Sdarrenrdev_t dev; 440145516Sdarrenr#endif 441145516Sdarrenrint flags; 442145516Sdarrenr{ 443145516Sdarrenr u_int min = GET_MINOR(dev); 444145516Sdarrenr 445145516Sdarrenr if (IPL_LOGMAX < min) 446145516Sdarrenr min = ENXIO; 447145516Sdarrenr else 448145516Sdarrenr min = 0; 449145516Sdarrenr return min; 450145516Sdarrenr} 451145516Sdarrenr 452145516Sdarrenr 453145516Sdarrenrint iplclose(dev, flags 454145516Sdarrenr#if ((BSD >= 199506) || (__FreeBSD_version >= 220000)) && defined(_KERNEL) 455145516Sdarrenr, devtype, p) 456145516Sdarrenrint devtype; 457145516Sdarrenr# if (__FreeBSD_version >= 500024) 458145516Sdarrenrstruct thread *p; 459145516Sdarrenr# else 460145516Sdarrenrstruct proc *p; 461145516Sdarrenr# endif /* __FreeBSD_version >= 500024 */ 462145516Sdarrenr#else 463145516Sdarrenr) 464145516Sdarrenr#endif 465145516Sdarrenr#if defined(_KERNEL) && (__FreeBSD_version >= 502116) 466145516Sdarrenrstruct cdev *dev; 467145516Sdarrenr#else 468145516Sdarrenrdev_t dev; 469145516Sdarrenr#endif 470145516Sdarrenrint flags; 471145516Sdarrenr{ 472145516Sdarrenr u_int min = GET_MINOR(dev); 473145516Sdarrenr 474145516Sdarrenr if (IPL_LOGMAX < min) 475145516Sdarrenr min = ENXIO; 476145516Sdarrenr else 477145516Sdarrenr min = 0; 478145516Sdarrenr return min; 479145516Sdarrenr} 480145516Sdarrenr 481145516Sdarrenr/* 482145516Sdarrenr * iplread/ipllog 483145516Sdarrenr * both of these must operate with at least splnet() lest they be 484145516Sdarrenr * called during packet processing and cause an inconsistancy to appear in 485145516Sdarrenr * the filter lists. 486145516Sdarrenr */ 487145516Sdarrenr#if (BSD >= 199306) 488145516Sdarrenrint iplread(dev, uio, ioflag) 489145516Sdarrenrint ioflag; 490145516Sdarrenr#else 491145516Sdarrenrint iplread(dev, uio) 492145516Sdarrenr#endif 493145516Sdarrenr#if defined(_KERNEL) && (__FreeBSD_version >= 502116) 494145516Sdarrenrstruct cdev *dev; 495145516Sdarrenr#else 496145516Sdarrenrdev_t dev; 497145516Sdarrenr#endif 498145516Sdarrenrregister struct uio *uio; 499145516Sdarrenr{ 500161356Sguido u_int xmin = GET_MINOR(dev); 501145516Sdarrenr 502170268Sdarrenr if (fr_running < 1) 503170268Sdarrenr return EIO; 504170268Sdarrenr 505161356Sguido if (xmin < 0) 506161356Sguido return ENXIO; 507161356Sguido 508145516Sdarrenr# ifdef IPFILTER_SYNC 509161356Sguido if (xmin == IPL_LOGSYNC) 510145516Sdarrenr return ipfsync_read(uio); 511145516Sdarrenr# endif 512145516Sdarrenr 513145516Sdarrenr#ifdef IPFILTER_LOG 514161356Sguido return ipflog_read(xmin, uio); 515145516Sdarrenr#else 516145516Sdarrenr return ENXIO; 517145516Sdarrenr#endif 518145516Sdarrenr} 519145516Sdarrenr 520145516Sdarrenr 521145516Sdarrenr/* 522145516Sdarrenr * iplwrite 523145516Sdarrenr * both of these must operate with at least splnet() lest they be 524145516Sdarrenr * called during packet processing and cause an inconsistancy to appear in 525145516Sdarrenr * the filter lists. 526145516Sdarrenr */ 527145516Sdarrenr#if (BSD >= 199306) 528145516Sdarrenrint iplwrite(dev, uio, ioflag) 529145516Sdarrenrint ioflag; 530145516Sdarrenr#else 531145516Sdarrenrint iplwrite(dev, uio) 532145516Sdarrenr#endif 533145516Sdarrenr#if defined(_KERNEL) && (__FreeBSD_version >= 502116) 534145516Sdarrenrstruct cdev *dev; 535145516Sdarrenr#else 536145516Sdarrenrdev_t dev; 537145516Sdarrenr#endif 538145516Sdarrenrregister struct uio *uio; 539145516Sdarrenr{ 540145516Sdarrenr 541170268Sdarrenr if (fr_running < 1) 542170268Sdarrenr return EIO; 543170268Sdarrenr 544145516Sdarrenr#ifdef IPFILTER_SYNC 545145516Sdarrenr if (GET_MINOR(dev) == IPL_LOGSYNC) 546145516Sdarrenr return ipfsync_write(uio); 547145516Sdarrenr#endif 548145516Sdarrenr return ENXIO; 549145516Sdarrenr} 550145516Sdarrenr 551145516Sdarrenr 552145516Sdarrenr/* 553145516Sdarrenr * fr_send_reset - this could conceivably be a call to tcp_respond(), but that 554145516Sdarrenr * requires a large amount of setting up and isn't any more efficient. 555145516Sdarrenr */ 556145516Sdarrenrint fr_send_reset(fin) 557145516Sdarrenrfr_info_t *fin; 558145516Sdarrenr{ 559145516Sdarrenr struct tcphdr *tcp, *tcp2; 560145516Sdarrenr int tlen = 0, hlen; 561145516Sdarrenr struct mbuf *m; 562145516Sdarrenr#ifdef USE_INET6 563145516Sdarrenr ip6_t *ip6; 564145516Sdarrenr#endif 565145516Sdarrenr ip_t *ip; 566145516Sdarrenr 567145516Sdarrenr tcp = fin->fin_dp; 568145516Sdarrenr if (tcp->th_flags & TH_RST) 569145516Sdarrenr return -1; /* feedback loop */ 570145516Sdarrenr 571145516Sdarrenr if (fr_checkl4sum(fin) == -1) 572145516Sdarrenr return -1; 573145516Sdarrenr 574145516Sdarrenr tlen = fin->fin_dlen - (TCP_OFF(tcp) << 2) + 575145516Sdarrenr ((tcp->th_flags & TH_SYN) ? 1 : 0) + 576145516Sdarrenr ((tcp->th_flags & TH_FIN) ? 1 : 0); 577145516Sdarrenr 578145516Sdarrenr#ifdef USE_INET6 579145516Sdarrenr hlen = (fin->fin_v == 6) ? sizeof(ip6_t) : sizeof(ip_t); 580145516Sdarrenr#else 581145516Sdarrenr hlen = sizeof(ip_t); 582145516Sdarrenr#endif 583145516Sdarrenr#ifdef MGETHDR 584145516Sdarrenr MGETHDR(m, M_DONTWAIT, MT_HEADER); 585145516Sdarrenr#else 586145516Sdarrenr MGET(m, M_DONTWAIT, MT_HEADER); 587145516Sdarrenr#endif 588145516Sdarrenr if (m == NULL) 589145516Sdarrenr return -1; 590145516Sdarrenr if (sizeof(*tcp2) + hlen > MLEN) { 591145516Sdarrenr MCLGET(m, M_DONTWAIT); 592145516Sdarrenr if ((m->m_flags & M_EXT) == 0) { 593145516Sdarrenr FREE_MB_T(m); 594145516Sdarrenr return -1; 595145516Sdarrenr } 596145516Sdarrenr } 597145516Sdarrenr 598145516Sdarrenr m->m_len = sizeof(*tcp2) + hlen; 599145516Sdarrenr#if (BSD >= 199103) 600145516Sdarrenr m->m_data += max_linkhdr; 601145516Sdarrenr m->m_pkthdr.len = m->m_len; 602145516Sdarrenr m->m_pkthdr.rcvif = (struct ifnet *)0; 603145516Sdarrenr#endif 604145516Sdarrenr ip = mtod(m, struct ip *); 605145516Sdarrenr bzero((char *)ip, hlen); 606145516Sdarrenr#ifdef USE_INET6 607145516Sdarrenr ip6 = (ip6_t *)ip; 608145516Sdarrenr#endif 609145516Sdarrenr tcp2 = (struct tcphdr *)((char *)ip + hlen); 610145516Sdarrenr tcp2->th_sport = tcp->th_dport; 611145516Sdarrenr tcp2->th_dport = tcp->th_sport; 612145516Sdarrenr 613145516Sdarrenr if (tcp->th_flags & TH_ACK) { 614145516Sdarrenr tcp2->th_seq = tcp->th_ack; 615145516Sdarrenr tcp2->th_flags = TH_RST; 616145516Sdarrenr tcp2->th_ack = 0; 617145516Sdarrenr } else { 618145516Sdarrenr tcp2->th_seq = 0; 619145516Sdarrenr tcp2->th_ack = ntohl(tcp->th_seq); 620145516Sdarrenr tcp2->th_ack += tlen; 621145516Sdarrenr tcp2->th_ack = htonl(tcp2->th_ack); 622145516Sdarrenr tcp2->th_flags = TH_RST|TH_ACK; 623145516Sdarrenr } 624145516Sdarrenr TCP_X2_A(tcp2, 0); 625145516Sdarrenr TCP_OFF_A(tcp2, sizeof(*tcp2) >> 2); 626145516Sdarrenr tcp2->th_win = tcp->th_win; 627145516Sdarrenr tcp2->th_sum = 0; 628145516Sdarrenr tcp2->th_urp = 0; 629145516Sdarrenr 630145516Sdarrenr#ifdef USE_INET6 631145516Sdarrenr if (fin->fin_v == 6) { 632145516Sdarrenr ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; 633145516Sdarrenr ip6->ip6_plen = htons(sizeof(struct tcphdr)); 634145516Sdarrenr ip6->ip6_nxt = IPPROTO_TCP; 635145516Sdarrenr ip6->ip6_hlim = 0; 636145516Sdarrenr ip6->ip6_src = fin->fin_dst6; 637145516Sdarrenr ip6->ip6_dst = fin->fin_src6; 638145516Sdarrenr tcp2->th_sum = in6_cksum(m, IPPROTO_TCP, 639145516Sdarrenr sizeof(*ip6), sizeof(*tcp2)); 640145516Sdarrenr return fr_send_ip(fin, m, &m); 641145516Sdarrenr } 642145516Sdarrenr#endif 643145516Sdarrenr ip->ip_p = IPPROTO_TCP; 644145516Sdarrenr ip->ip_len = htons(sizeof(struct tcphdr)); 645145516Sdarrenr ip->ip_src.s_addr = fin->fin_daddr; 646145516Sdarrenr ip->ip_dst.s_addr = fin->fin_saddr; 647145516Sdarrenr tcp2->th_sum = in_cksum(m, hlen + sizeof(*tcp2)); 648145516Sdarrenr ip->ip_len = hlen + sizeof(*tcp2); 649145516Sdarrenr return fr_send_ip(fin, m, &m); 650145516Sdarrenr} 651145516Sdarrenr 652145516Sdarrenr 653145516Sdarrenrstatic int fr_send_ip(fin, m, mpp) 654145516Sdarrenrfr_info_t *fin; 655145516Sdarrenrmb_t *m, **mpp; 656145516Sdarrenr{ 657191548Szec INIT_VNET_INET(curvnet); 658145516Sdarrenr fr_info_t fnew; 659145516Sdarrenr ip_t *ip, *oip; 660145516Sdarrenr int hlen; 661145516Sdarrenr 662145516Sdarrenr ip = mtod(m, ip_t *); 663145516Sdarrenr bzero((char *)&fnew, sizeof(fnew)); 664145516Sdarrenr 665145516Sdarrenr IP_V_A(ip, fin->fin_v); 666145516Sdarrenr switch (fin->fin_v) 667145516Sdarrenr { 668145516Sdarrenr case 4 : 669145516Sdarrenr fnew.fin_v = 4; 670145516Sdarrenr oip = fin->fin_ip; 671145516Sdarrenr IP_HL_A(ip, sizeof(*oip) >> 2); 672145516Sdarrenr ip->ip_tos = oip->ip_tos; 673145516Sdarrenr ip->ip_id = fin->fin_ip->ip_id; 674145516Sdarrenr#if (__FreeBSD_version > 460000) 675181803Sbz ip->ip_off = V_path_mtu_discovery ? IP_DF : 0; 676145516Sdarrenr#else 677145516Sdarrenr ip->ip_off = 0; 678145516Sdarrenr#endif 679181803Sbz ip->ip_ttl = V_ip_defttl; 680145516Sdarrenr ip->ip_sum = 0; 681145516Sdarrenr hlen = sizeof(*oip); 682145516Sdarrenr break; 683145516Sdarrenr#ifdef USE_INET6 684145516Sdarrenr case 6 : 685145516Sdarrenr { 686145516Sdarrenr ip6_t *ip6 = (ip6_t *)ip; 687145516Sdarrenr 688145516Sdarrenr ip6->ip6_vfc = 0x60; 689145516Sdarrenr ip6->ip6_hlim = IPDEFTTL; 690145516Sdarrenr 691145516Sdarrenr fnew.fin_v = 6; 692145516Sdarrenr hlen = sizeof(*ip6); 693145516Sdarrenr break; 694145516Sdarrenr } 695145516Sdarrenr#endif 696145516Sdarrenr default : 697145516Sdarrenr return EINVAL; 698145516Sdarrenr } 699145516Sdarrenr#ifdef IPSEC 700145516Sdarrenr m->m_pkthdr.rcvif = NULL; 701145516Sdarrenr#endif 702145516Sdarrenr 703145516Sdarrenr fnew.fin_ifp = fin->fin_ifp; 704145516Sdarrenr fnew.fin_flx = FI_NOCKSUM; 705145516Sdarrenr fnew.fin_m = m; 706145516Sdarrenr fnew.fin_ip = ip; 707145516Sdarrenr fnew.fin_mp = mpp; 708145516Sdarrenr fnew.fin_hlen = hlen; 709145516Sdarrenr fnew.fin_dp = (char *)ip + hlen; 710145516Sdarrenr (void) fr_makefrip(hlen, ip, &fnew); 711145516Sdarrenr 712145516Sdarrenr return fr_fastroute(m, mpp, &fnew, NULL); 713145516Sdarrenr} 714145516Sdarrenr 715145516Sdarrenr 716145516Sdarrenrint fr_send_icmp_err(type, fin, dst) 717145516Sdarrenrint type; 718145516Sdarrenrfr_info_t *fin; 719145516Sdarrenrint dst; 720145516Sdarrenr{ 721145516Sdarrenr int err, hlen, xtra, iclen, ohlen, avail, code; 722145516Sdarrenr struct in_addr dst4; 723145516Sdarrenr struct icmp *icmp; 724145516Sdarrenr struct mbuf *m; 725145516Sdarrenr void *ifp; 726145516Sdarrenr#ifdef USE_INET6 727145516Sdarrenr ip6_t *ip6; 728145516Sdarrenr struct in6_addr dst6; 729145516Sdarrenr#endif 730145516Sdarrenr ip_t *ip, *ip2; 731145516Sdarrenr 732172776Sdarrenr if ((type < 0) || (type >= ICMP_MAXTYPE)) 733145516Sdarrenr return -1; 734145516Sdarrenr 735145516Sdarrenr code = fin->fin_icode; 736145516Sdarrenr#ifdef USE_INET6 737145516Sdarrenr if ((code < 0) || (code > sizeof(icmptoicmp6unreach)/sizeof(int))) 738145516Sdarrenr return -1; 739145516Sdarrenr#endif 740145516Sdarrenr 741145516Sdarrenr if (fr_checkl4sum(fin) == -1) 742145516Sdarrenr return -1; 743145516Sdarrenr#ifdef MGETHDR 744145516Sdarrenr MGETHDR(m, M_DONTWAIT, MT_HEADER); 745145516Sdarrenr#else 746145516Sdarrenr MGET(m, M_DONTWAIT, MT_HEADER); 747145516Sdarrenr#endif 748145516Sdarrenr if (m == NULL) 749145516Sdarrenr return -1; 750145516Sdarrenr avail = MHLEN; 751145516Sdarrenr 752145516Sdarrenr xtra = 0; 753145516Sdarrenr hlen = 0; 754145516Sdarrenr ohlen = 0; 755145516Sdarrenr ifp = fin->fin_ifp; 756145516Sdarrenr if (fin->fin_v == 4) { 757145516Sdarrenr if ((fin->fin_p == IPPROTO_ICMP) && 758145516Sdarrenr !(fin->fin_flx & FI_SHORT)) 759145516Sdarrenr switch (ntohs(fin->fin_data[0]) >> 8) 760145516Sdarrenr { 761145516Sdarrenr case ICMP_ECHO : 762145516Sdarrenr case ICMP_TSTAMP : 763145516Sdarrenr case ICMP_IREQ : 764145516Sdarrenr case ICMP_MASKREQ : 765145516Sdarrenr break; 766145516Sdarrenr default : 767145516Sdarrenr FREE_MB_T(m); 768145516Sdarrenr return 0; 769145516Sdarrenr } 770145516Sdarrenr 771145516Sdarrenr if (dst == 0) { 772145516Sdarrenr if (fr_ifpaddr(4, FRI_NORMAL, ifp, 773145516Sdarrenr &dst4, NULL) == -1) { 774145516Sdarrenr FREE_MB_T(m); 775145516Sdarrenr return -1; 776145516Sdarrenr } 777145516Sdarrenr } else 778145516Sdarrenr dst4.s_addr = fin->fin_daddr; 779145516Sdarrenr 780145516Sdarrenr hlen = sizeof(ip_t); 781145516Sdarrenr ohlen = fin->fin_hlen; 782145516Sdarrenr if (fin->fin_hlen < fin->fin_plen) 783145516Sdarrenr xtra = MIN(fin->fin_dlen, 8); 784145516Sdarrenr else 785145516Sdarrenr xtra = 0; 786145516Sdarrenr } 787145516Sdarrenr 788145516Sdarrenr#ifdef USE_INET6 789145516Sdarrenr else if (fin->fin_v == 6) { 790145516Sdarrenr hlen = sizeof(ip6_t); 791145516Sdarrenr ohlen = sizeof(ip6_t); 792145516Sdarrenr type = icmptoicmp6types[type]; 793145516Sdarrenr if (type == ICMP6_DST_UNREACH) 794145516Sdarrenr code = icmptoicmp6unreach[code]; 795145516Sdarrenr 796145516Sdarrenr if (hlen + sizeof(*icmp) + max_linkhdr + 797145516Sdarrenr fin->fin_plen > avail) { 798145516Sdarrenr MCLGET(m, M_DONTWAIT); 799145516Sdarrenr if ((m->m_flags & M_EXT) == 0) { 800145516Sdarrenr FREE_MB_T(m); 801145516Sdarrenr return -1; 802145516Sdarrenr } 803145516Sdarrenr avail = MCLBYTES; 804145516Sdarrenr } 805145516Sdarrenr xtra = MIN(fin->fin_plen, 806145516Sdarrenr avail - hlen - sizeof(*icmp) - max_linkhdr); 807145516Sdarrenr if (dst == 0) { 808145516Sdarrenr if (fr_ifpaddr(6, FRI_NORMAL, ifp, 809145516Sdarrenr (struct in_addr *)&dst6, NULL) == -1) { 810145516Sdarrenr FREE_MB_T(m); 811145516Sdarrenr return -1; 812145516Sdarrenr } 813145516Sdarrenr } else 814145516Sdarrenr dst6 = fin->fin_dst6; 815145516Sdarrenr } 816145516Sdarrenr#endif 817145516Sdarrenr else { 818145516Sdarrenr FREE_MB_T(m); 819145516Sdarrenr return -1; 820145516Sdarrenr } 821145516Sdarrenr 822145516Sdarrenr iclen = hlen + sizeof(*icmp); 823145516Sdarrenr avail -= (max_linkhdr + iclen); 824145516Sdarrenr if (avail < 0) { 825145516Sdarrenr FREE_MB_T(m); 826145516Sdarrenr return -1; 827145516Sdarrenr } 828145516Sdarrenr if (xtra > avail) 829145516Sdarrenr xtra = avail; 830145516Sdarrenr iclen += xtra; 831145516Sdarrenr m->m_data += max_linkhdr; 832145516Sdarrenr m->m_pkthdr.rcvif = (struct ifnet *)0; 833145516Sdarrenr m->m_pkthdr.len = iclen; 834145516Sdarrenr m->m_len = iclen; 835145516Sdarrenr ip = mtod(m, ip_t *); 836145516Sdarrenr icmp = (struct icmp *)((char *)ip + hlen); 837145516Sdarrenr ip2 = (ip_t *)&icmp->icmp_ip; 838145516Sdarrenr 839145516Sdarrenr icmp->icmp_type = type; 840145516Sdarrenr icmp->icmp_code = fin->fin_icode; 841145516Sdarrenr icmp->icmp_cksum = 0; 842145516Sdarrenr#ifdef icmp_nextmtu 843145516Sdarrenr if (type == ICMP_UNREACH && 844145516Sdarrenr fin->fin_icode == ICMP_UNREACH_NEEDFRAG && ifp) 845145516Sdarrenr icmp->icmp_nextmtu = htons(((struct ifnet *)ifp)->if_mtu); 846145516Sdarrenr#endif 847145516Sdarrenr 848145516Sdarrenr bcopy((char *)fin->fin_ip, (char *)ip2, ohlen); 849145516Sdarrenr 850145516Sdarrenr#ifdef USE_INET6 851145516Sdarrenr ip6 = (ip6_t *)ip; 852145516Sdarrenr if (fin->fin_v == 6) { 853145516Sdarrenr ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; 854145516Sdarrenr ip6->ip6_plen = htons(iclen - hlen); 855145516Sdarrenr ip6->ip6_nxt = IPPROTO_ICMPV6; 856145516Sdarrenr ip6->ip6_hlim = 0; 857145516Sdarrenr ip6->ip6_src = dst6; 858145516Sdarrenr ip6->ip6_dst = fin->fin_src6; 859145516Sdarrenr if (xtra > 0) 860145516Sdarrenr bcopy((char *)fin->fin_ip + ohlen, 861145516Sdarrenr (char *)&icmp->icmp_ip + ohlen, xtra); 862145516Sdarrenr icmp->icmp_cksum = in6_cksum(m, IPPROTO_ICMPV6, 863145516Sdarrenr sizeof(*ip6), iclen - hlen); 864145516Sdarrenr } else 865145516Sdarrenr#endif 866145516Sdarrenr { 867145516Sdarrenr ip2->ip_len = htons(ip2->ip_len); 868145516Sdarrenr ip2->ip_off = htons(ip2->ip_off); 869145516Sdarrenr ip->ip_p = IPPROTO_ICMP; 870145516Sdarrenr ip->ip_src.s_addr = dst4.s_addr; 871145516Sdarrenr ip->ip_dst.s_addr = fin->fin_saddr; 872145516Sdarrenr 873145516Sdarrenr if (xtra > 0) 874145516Sdarrenr bcopy((char *)fin->fin_ip + ohlen, 875145516Sdarrenr (char *)&icmp->icmp_ip + ohlen, xtra); 876145516Sdarrenr icmp->icmp_cksum = ipf_cksum((u_short *)icmp, 877145516Sdarrenr sizeof(*icmp) + 8); 878145516Sdarrenr ip->ip_len = iclen; 879145516Sdarrenr ip->ip_p = IPPROTO_ICMP; 880145516Sdarrenr } 881145516Sdarrenr err = fr_send_ip(fin, m, &m); 882145516Sdarrenr return err; 883145516Sdarrenr} 884145516Sdarrenr 885145516Sdarrenr 886145516Sdarrenr#if !defined(IPFILTER_LKM) && (__FreeBSD_version < 300000) 887145516Sdarrenr# if (BSD < 199306) 888145516Sdarrenrint iplinit __P((void)); 889145516Sdarrenr 890145516Sdarrenrint 891145516Sdarrenr# else 892145516Sdarrenrvoid iplinit __P((void)); 893145516Sdarrenr 894145516Sdarrenrvoid 895145516Sdarrenr# endif 896145516Sdarrenriplinit() 897145516Sdarrenr{ 898170268Sdarrenr if (ipfattach() != 0) 899145516Sdarrenr printf("IP Filter failed to attach\n"); 900145516Sdarrenr ip_init(); 901145516Sdarrenr} 902145516Sdarrenr#endif /* __FreeBSD_version < 300000 */ 903145516Sdarrenr 904145516Sdarrenr 905173181Sdarrenr/* 906173181Sdarrenr * m0 - pointer to mbuf where the IP packet starts 907173181Sdarrenr * mpp - pointer to the mbuf pointer that is the start of the mbuf chain 908173181Sdarrenr */ 909145516Sdarrenrint fr_fastroute(m0, mpp, fin, fdp) 910145516Sdarrenrmb_t *m0, **mpp; 911145516Sdarrenrfr_info_t *fin; 912145516Sdarrenrfrdest_t *fdp; 913145516Sdarrenr{ 914145516Sdarrenr register struct ip *ip, *mhip; 915173181Sdarrenr register struct mbuf *m = *mpp; 916145516Sdarrenr register struct route *ro; 917145516Sdarrenr int len, off, error = 0, hlen, code; 918145516Sdarrenr struct ifnet *ifp, *sifp; 919145516Sdarrenr struct sockaddr_in *dst; 920145516Sdarrenr struct route iproute; 921145516Sdarrenr u_short ip_off; 922145516Sdarrenr frentry_t *fr; 923145516Sdarrenr 924161356Sguido ro = NULL; 925161356Sguido 926145516Sdarrenr#ifdef M_WRITABLE 927145516Sdarrenr /* 928145516Sdarrenr * HOT FIX/KLUDGE: 929145516Sdarrenr * 930145516Sdarrenr * If the mbuf we're about to send is not writable (because of 931145516Sdarrenr * a cluster reference, for example) we'll need to make a copy 932145516Sdarrenr * of it since this routine modifies the contents. 933145516Sdarrenr * 934145516Sdarrenr * If you have non-crappy network hardware that can transmit data 935145516Sdarrenr * from the mbuf, rather than making a copy, this is gonna be a 936145516Sdarrenr * problem. 937145516Sdarrenr */ 938145516Sdarrenr if (M_WRITABLE(m) == 0) { 939161356Sguido m0 = m_dup(m, M_DONTWAIT); 940161356Sguido if (m0 != 0) { 941145516Sdarrenr FREE_MB_T(m); 942145516Sdarrenr m = m0; 943145516Sdarrenr *mpp = m; 944145516Sdarrenr } else { 945145516Sdarrenr error = ENOBUFS; 946145516Sdarrenr FREE_MB_T(m); 947161356Sguido goto done; 948145516Sdarrenr } 949145516Sdarrenr } 950145516Sdarrenr#endif 951145516Sdarrenr 952145516Sdarrenr#ifdef USE_INET6 953145516Sdarrenr if (fin->fin_v == 6) { 954145516Sdarrenr /* 955145516Sdarrenr * currently "to <if>" and "to <if>:ip#" are not supported 956145516Sdarrenr * for IPv6 957145516Sdarrenr */ 958145516Sdarrenr#if (__FreeBSD_version >= 490000) 959145516Sdarrenr return ip6_output(m0, NULL, NULL, 0, NULL, NULL, NULL); 960145516Sdarrenr#else 961145516Sdarrenr return ip6_output(m0, NULL, NULL, 0, NULL, NULL); 962145516Sdarrenr#endif 963145516Sdarrenr } 964145516Sdarrenr#endif 965145516Sdarrenr 966145516Sdarrenr hlen = fin->fin_hlen; 967145516Sdarrenr ip = mtod(m0, struct ip *); 968145516Sdarrenr 969145516Sdarrenr /* 970145516Sdarrenr * Route packet. 971145516Sdarrenr */ 972145516Sdarrenr ro = &iproute; 973145516Sdarrenr bzero((caddr_t)ro, sizeof (*ro)); 974145516Sdarrenr dst = (struct sockaddr_in *)&ro->ro_dst; 975145516Sdarrenr dst->sin_family = AF_INET; 976145516Sdarrenr dst->sin_addr = ip->ip_dst; 977145516Sdarrenr 978145516Sdarrenr fr = fin->fin_fr; 979145516Sdarrenr if (fdp != NULL) 980145516Sdarrenr ifp = fdp->fd_ifp; 981145516Sdarrenr else 982145516Sdarrenr ifp = fin->fin_ifp; 983145516Sdarrenr 984145516Sdarrenr if ((ifp == NULL) && (!fr || !(fr->fr_flags & FR_FASTROUTE))) { 985145516Sdarrenr error = -2; 986145516Sdarrenr goto bad; 987145516Sdarrenr } 988145516Sdarrenr 989161356Sguido if ((fdp != NULL) && (fdp->fd_ip.s_addr != 0)) 990161356Sguido dst->sin_addr = fdp->fd_ip; 991145516Sdarrenr 992145516Sdarrenr dst->sin_len = sizeof(*dst); 993178888Sjulian in_rtalloc(ro, 0); 994145516Sdarrenr 995145516Sdarrenr if ((ifp == NULL) && (ro->ro_rt != NULL)) 996145516Sdarrenr ifp = ro->ro_rt->rt_ifp; 997145516Sdarrenr 998145516Sdarrenr if ((ro->ro_rt == NULL) || (ifp == NULL)) { 999145516Sdarrenr if (in_localaddr(ip->ip_dst)) 1000145516Sdarrenr error = EHOSTUNREACH; 1001145516Sdarrenr else 1002145516Sdarrenr error = ENETUNREACH; 1003145516Sdarrenr goto bad; 1004145516Sdarrenr } 1005145516Sdarrenr if (ro->ro_rt->rt_flags & RTF_GATEWAY) 1006145516Sdarrenr dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway; 1007145516Sdarrenr if (ro->ro_rt) 1008145516Sdarrenr ro->ro_rt->rt_use++; 1009145516Sdarrenr 1010145516Sdarrenr /* 1011145516Sdarrenr * For input packets which are being "fastrouted", they won't 1012145516Sdarrenr * go back through output filtering and miss their chance to get 1013170268Sdarrenr * NAT'd and counted. Duplicated packets aren't considered to be 1014170268Sdarrenr * part of the normal packet stream, so do not NAT them or pass 1015170268Sdarrenr * them through stateful checking, etc. 1016145516Sdarrenr */ 1017170268Sdarrenr if ((fdp != &fr->fr_dif) && (fin->fin_out == 0)) { 1018145516Sdarrenr sifp = fin->fin_ifp; 1019145516Sdarrenr fin->fin_ifp = ifp; 1020145516Sdarrenr fin->fin_out = 1; 1021145516Sdarrenr (void) fr_acctpkt(fin, NULL); 1022145516Sdarrenr fin->fin_fr = NULL; 1023145516Sdarrenr if (!fr || !(fr->fr_flags & FR_RETMASK)) { 1024145516Sdarrenr u_32_t pass; 1025145516Sdarrenr 1026170268Sdarrenr if (fr_checkstate(fin, &pass) != NULL) 1027170268Sdarrenr fr_statederef((ipstate_t **)&fin->fin_state); 1028145516Sdarrenr } 1029145516Sdarrenr 1030145516Sdarrenr switch (fr_checknatout(fin, NULL)) 1031145516Sdarrenr { 1032145516Sdarrenr case 0 : 1033145516Sdarrenr break; 1034145516Sdarrenr case 1 : 1035170268Sdarrenr fr_natderef((nat_t **)&fin->fin_nat); 1036145516Sdarrenr ip->ip_sum = 0; 1037145516Sdarrenr break; 1038145516Sdarrenr case -1 : 1039145516Sdarrenr error = -1; 1040173181Sdarrenr goto bad; 1041145516Sdarrenr break; 1042145516Sdarrenr } 1043145516Sdarrenr 1044145516Sdarrenr fin->fin_ifp = sifp; 1045145516Sdarrenr fin->fin_out = 0; 1046145516Sdarrenr } else 1047145516Sdarrenr ip->ip_sum = 0; 1048145516Sdarrenr /* 1049145516Sdarrenr * If small enough for interface, can just send directly. 1050145516Sdarrenr */ 1051145516Sdarrenr if (ip->ip_len <= ifp->if_mtu) { 1052145516Sdarrenr ip->ip_len = htons(ip->ip_len); 1053145516Sdarrenr ip->ip_off = htons(ip->ip_off); 1054145516Sdarrenr 1055145516Sdarrenr if (!ip->ip_sum) 1056145516Sdarrenr ip->ip_sum = in_cksum(m, hlen); 1057145516Sdarrenr error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst, 1058191148Skmacy ro); 1059145516Sdarrenr goto done; 1060145516Sdarrenr } 1061145516Sdarrenr /* 1062145516Sdarrenr * Too large for interface; fragment if possible. 1063145516Sdarrenr * Must be able to put at least 8 bytes per fragment. 1064145516Sdarrenr */ 1065145516Sdarrenr ip_off = ntohs(ip->ip_off); 1066145516Sdarrenr if (ip_off & IP_DF) { 1067145516Sdarrenr error = EMSGSIZE; 1068145516Sdarrenr goto bad; 1069145516Sdarrenr } 1070145516Sdarrenr len = (ifp->if_mtu - hlen) &~ 7; 1071145516Sdarrenr if (len < 8) { 1072145516Sdarrenr error = EMSGSIZE; 1073145516Sdarrenr goto bad; 1074145516Sdarrenr } 1075145516Sdarrenr 1076145516Sdarrenr { 1077145516Sdarrenr int mhlen, firstlen = len; 1078145516Sdarrenr struct mbuf **mnext = &m->m_act; 1079145516Sdarrenr 1080145516Sdarrenr /* 1081145516Sdarrenr * Loop through length of segment after first fragment, 1082145516Sdarrenr * make new header and copy data of each part and link onto chain. 1083145516Sdarrenr */ 1084145516Sdarrenr m0 = m; 1085145516Sdarrenr mhlen = sizeof (struct ip); 1086145516Sdarrenr for (off = hlen + len; off < ip->ip_len; off += len) { 1087145516Sdarrenr#ifdef MGETHDR 1088145516Sdarrenr MGETHDR(m, M_DONTWAIT, MT_HEADER); 1089145516Sdarrenr#else 1090145516Sdarrenr MGET(m, M_DONTWAIT, MT_HEADER); 1091145516Sdarrenr#endif 1092145516Sdarrenr if (m == 0) { 1093145516Sdarrenr m = m0; 1094145516Sdarrenr error = ENOBUFS; 1095145516Sdarrenr goto bad; 1096145516Sdarrenr } 1097145516Sdarrenr m->m_data += max_linkhdr; 1098145516Sdarrenr mhip = mtod(m, struct ip *); 1099145516Sdarrenr bcopy((char *)ip, (char *)mhip, sizeof(*ip)); 1100145516Sdarrenr if (hlen > sizeof (struct ip)) { 1101145516Sdarrenr mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip); 1102145516Sdarrenr IP_HL_A(mhip, mhlen >> 2); 1103145516Sdarrenr } 1104145516Sdarrenr m->m_len = mhlen; 1105145516Sdarrenr mhip->ip_off = ((off - hlen) >> 3) + ip_off; 1106145516Sdarrenr if (off + len >= ip->ip_len) 1107145516Sdarrenr len = ip->ip_len - off; 1108145516Sdarrenr else 1109145516Sdarrenr mhip->ip_off |= IP_MF; 1110145516Sdarrenr mhip->ip_len = htons((u_short)(len + mhlen)); 1111161356Sguido *mnext = m; 1112145516Sdarrenr m->m_next = m_copy(m0, off, len); 1113145516Sdarrenr if (m->m_next == 0) { 1114145516Sdarrenr error = ENOBUFS; /* ??? */ 1115145516Sdarrenr goto sendorfree; 1116145516Sdarrenr } 1117145516Sdarrenr m->m_pkthdr.len = mhlen + len; 1118145516Sdarrenr m->m_pkthdr.rcvif = NULL; 1119145516Sdarrenr mhip->ip_off = htons((u_short)mhip->ip_off); 1120145516Sdarrenr mhip->ip_sum = 0; 1121145516Sdarrenr mhip->ip_sum = in_cksum(m, mhlen); 1122145516Sdarrenr mnext = &m->m_act; 1123145516Sdarrenr } 1124145516Sdarrenr /* 1125145516Sdarrenr * Update first fragment by trimming what's been copied out 1126145516Sdarrenr * and updating header, then send each fragment (in order). 1127145516Sdarrenr */ 1128145516Sdarrenr m_adj(m0, hlen + firstlen - ip->ip_len); 1129145516Sdarrenr ip->ip_len = htons((u_short)(hlen + firstlen)); 1130145516Sdarrenr ip->ip_off = htons((u_short)IP_MF); 1131145516Sdarrenr ip->ip_sum = 0; 1132145516Sdarrenr ip->ip_sum = in_cksum(m0, hlen); 1133145516Sdarrenrsendorfree: 1134145516Sdarrenr for (m = m0; m; m = m0) { 1135145516Sdarrenr m0 = m->m_act; 1136145516Sdarrenr m->m_act = 0; 1137145516Sdarrenr if (error == 0) 1138145516Sdarrenr error = (*ifp->if_output)(ifp, m, 1139191148Skmacy (struct sockaddr *)dst, ro); 1140145516Sdarrenr else 1141145516Sdarrenr FREE_MB_T(m); 1142145516Sdarrenr } 1143145516Sdarrenr } 1144145516Sdarrenrdone: 1145145516Sdarrenr if (!error) 1146145516Sdarrenr fr_frouteok[0]++; 1147145516Sdarrenr else 1148145516Sdarrenr fr_frouteok[1]++; 1149145516Sdarrenr 1150161356Sguido if ((ro != NULL) && (ro->ro_rt != NULL)) { 1151145516Sdarrenr RTFREE(ro->ro_rt); 1152145516Sdarrenr } 1153145516Sdarrenr *mpp = NULL; 1154145516Sdarrenr return 0; 1155145516Sdarrenrbad: 1156145516Sdarrenr if (error == EMSGSIZE) { 1157145516Sdarrenr sifp = fin->fin_ifp; 1158145516Sdarrenr code = fin->fin_icode; 1159145516Sdarrenr fin->fin_icode = ICMP_UNREACH_NEEDFRAG; 1160145516Sdarrenr fin->fin_ifp = ifp; 1161145516Sdarrenr (void) fr_send_icmp_err(ICMP_UNREACH, fin, 1); 1162145516Sdarrenr fin->fin_ifp = sifp; 1163145516Sdarrenr fin->fin_icode = code; 1164145516Sdarrenr } 1165145516Sdarrenr FREE_MB_T(m); 1166145516Sdarrenr goto done; 1167145516Sdarrenr} 1168145516Sdarrenr 1169145516Sdarrenr 1170145516Sdarrenrint fr_verifysrc(fin) 1171145516Sdarrenrfr_info_t *fin; 1172145516Sdarrenr{ 1173145516Sdarrenr struct sockaddr_in *dst; 1174145516Sdarrenr struct route iproute; 1175145516Sdarrenr 1176145516Sdarrenr bzero((char *)&iproute, sizeof(iproute)); 1177145516Sdarrenr dst = (struct sockaddr_in *)&iproute.ro_dst; 1178145516Sdarrenr dst->sin_len = sizeof(*dst); 1179145516Sdarrenr dst->sin_family = AF_INET; 1180145516Sdarrenr dst->sin_addr = fin->fin_src; 1181178888Sjulian in_rtalloc(&iproute, 0); 1182145516Sdarrenr if (iproute.ro_rt == NULL) 1183145516Sdarrenr return 0; 1184145516Sdarrenr return (fin->fin_ifp == iproute.ro_rt->rt_ifp); 1185145516Sdarrenr} 1186145516Sdarrenr 1187145516Sdarrenr 1188145516Sdarrenr/* 1189145516Sdarrenr * return the first IP Address associated with an interface 1190145516Sdarrenr */ 1191145516Sdarrenrint fr_ifpaddr(v, atype, ifptr, inp, inpmask) 1192145516Sdarrenrint v, atype; 1193145516Sdarrenrvoid *ifptr; 1194145516Sdarrenrstruct in_addr *inp, *inpmask; 1195145516Sdarrenr{ 1196145516Sdarrenr#ifdef USE_INET6 1197145516Sdarrenr struct in6_addr *inp6 = NULL; 1198145516Sdarrenr#endif 1199145516Sdarrenr struct sockaddr *sock, *mask; 1200145516Sdarrenr struct sockaddr_in *sin; 1201145516Sdarrenr struct ifaddr *ifa; 1202145516Sdarrenr struct ifnet *ifp; 1203145516Sdarrenr 1204145516Sdarrenr if ((ifptr == NULL) || (ifptr == (void *)-1)) 1205145516Sdarrenr return -1; 1206145516Sdarrenr 1207145516Sdarrenr sin = NULL; 1208145516Sdarrenr ifp = ifptr; 1209145516Sdarrenr 1210145516Sdarrenr if (v == 4) 1211145516Sdarrenr inp->s_addr = 0; 1212145516Sdarrenr#ifdef USE_INET6 1213145516Sdarrenr else if (v == 6) 1214145516Sdarrenr bzero((char *)inp, sizeof(struct in6_addr)); 1215145516Sdarrenr#endif 1216145516Sdarrenr#if (__FreeBSD_version >= 300000) 1217145516Sdarrenr ifa = TAILQ_FIRST(&ifp->if_addrhead); 1218145516Sdarrenr#else 1219145516Sdarrenr ifa = ifp->if_addrlist; 1220145516Sdarrenr#endif /* __FreeBSD_version >= 300000 */ 1221145516Sdarrenr 1222145516Sdarrenr sock = ifa->ifa_addr; 1223145516Sdarrenr while (sock != NULL && ifa != NULL) { 1224145516Sdarrenr sin = (struct sockaddr_in *)sock; 1225145516Sdarrenr if ((v == 4) && (sin->sin_family == AF_INET)) 1226145516Sdarrenr break; 1227145516Sdarrenr#ifdef USE_INET6 1228145516Sdarrenr if ((v == 6) && (sin->sin_family == AF_INET6)) { 1229145516Sdarrenr inp6 = &((struct sockaddr_in6 *)sin)->sin6_addr; 1230145516Sdarrenr if (!IN6_IS_ADDR_LINKLOCAL(inp6) && 1231145516Sdarrenr !IN6_IS_ADDR_LOOPBACK(inp6)) 1232145516Sdarrenr break; 1233145516Sdarrenr } 1234145516Sdarrenr#endif 1235145516Sdarrenr#if (__FreeBSD_version >= 300000) 1236145516Sdarrenr ifa = TAILQ_NEXT(ifa, ifa_link); 1237145516Sdarrenr#else 1238145516Sdarrenr ifa = ifa->ifa_next; 1239145516Sdarrenr#endif /* __FreeBSD_version >= 300000 */ 1240145516Sdarrenr if (ifa != NULL) 1241145516Sdarrenr sock = ifa->ifa_addr; 1242145516Sdarrenr } 1243145516Sdarrenr 1244145516Sdarrenr if (ifa == NULL || sin == NULL) 1245145516Sdarrenr return -1; 1246145516Sdarrenr 1247145516Sdarrenr mask = ifa->ifa_netmask; 1248145516Sdarrenr if (atype == FRI_BROADCAST) 1249145516Sdarrenr sock = ifa->ifa_broadaddr; 1250145516Sdarrenr else if (atype == FRI_PEERADDR) 1251145516Sdarrenr sock = ifa->ifa_dstaddr; 1252145516Sdarrenr 1253161356Sguido if (sock == NULL) 1254161356Sguido return -1; 1255161356Sguido 1256145516Sdarrenr#ifdef USE_INET6 1257145516Sdarrenr if (v == 6) { 1258145516Sdarrenr return fr_ifpfillv6addr(atype, (struct sockaddr_in6 *)sock, 1259145516Sdarrenr (struct sockaddr_in6 *)mask, 1260145516Sdarrenr inp, inpmask); 1261145516Sdarrenr } 1262145516Sdarrenr#endif 1263145516Sdarrenr return fr_ifpfillv4addr(atype, (struct sockaddr_in *)sock, 1264145516Sdarrenr (struct sockaddr_in *)mask, inp, inpmask); 1265145516Sdarrenr} 1266145516Sdarrenr 1267145516Sdarrenr 1268145516Sdarrenru_32_t fr_newisn(fin) 1269145516Sdarrenrfr_info_t *fin; 1270145516Sdarrenr{ 1271145516Sdarrenr u_32_t newiss; 1272145516Sdarrenr#if (__FreeBSD_version >= 400000) 1273145516Sdarrenr newiss = arc4random(); 1274145516Sdarrenr#else 1275145516Sdarrenr static iss_seq_off = 0; 1276145516Sdarrenr u_char hash[16]; 1277145516Sdarrenr MD5_CTX ctx; 1278145516Sdarrenr 1279145516Sdarrenr /* 1280145516Sdarrenr * Compute the base value of the ISS. It is a hash 1281145516Sdarrenr * of (saddr, sport, daddr, dport, secret). 1282145516Sdarrenr */ 1283145516Sdarrenr MD5Init(&ctx); 1284145516Sdarrenr 1285145516Sdarrenr MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src, 1286145516Sdarrenr sizeof(fin->fin_fi.fi_src)); 1287145516Sdarrenr MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst, 1288145516Sdarrenr sizeof(fin->fin_fi.fi_dst)); 1289145516Sdarrenr MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat)); 1290145516Sdarrenr 1291145516Sdarrenr MD5Update(&ctx, ipf_iss_secret, sizeof(ipf_iss_secret)); 1292145516Sdarrenr 1293145516Sdarrenr MD5Final(hash, &ctx); 1294145516Sdarrenr 1295145516Sdarrenr memcpy(&newiss, hash, sizeof(newiss)); 1296145516Sdarrenr 1297145516Sdarrenr /* 1298145516Sdarrenr * Now increment our "timer", and add it in to 1299145516Sdarrenr * the computed value. 1300145516Sdarrenr * 1301145516Sdarrenr * XXX Use `addin'? 1302145516Sdarrenr * XXX TCP_ISSINCR too large to use? 1303145516Sdarrenr */ 1304145516Sdarrenr iss_seq_off += 0x00010000; 1305145516Sdarrenr newiss += iss_seq_off; 1306145516Sdarrenr#endif 1307145516Sdarrenr return newiss; 1308145516Sdarrenr} 1309145516Sdarrenr 1310145516Sdarrenr 1311145516Sdarrenr/* ------------------------------------------------------------------------ */ 1312145516Sdarrenr/* Function: fr_nextipid */ 1313145516Sdarrenr/* Returns: int - 0 == success, -1 == error (packet should be droppped) */ 1314145516Sdarrenr/* Parameters: fin(I) - pointer to packet information */ 1315145516Sdarrenr/* */ 1316145516Sdarrenr/* Returns the next IPv4 ID to use for this packet. */ 1317145516Sdarrenr/* ------------------------------------------------------------------------ */ 1318145516Sdarrenru_short fr_nextipid(fin) 1319145516Sdarrenrfr_info_t *fin; 1320145516Sdarrenr{ 1321145516Sdarrenr#ifndef RANDOM_IP_ID 1322145516Sdarrenr static u_short ipid = 0; 1323145516Sdarrenr u_short id; 1324145516Sdarrenr 1325145516Sdarrenr MUTEX_ENTER(&ipf_rw); 1326145516Sdarrenr id = ipid++; 1327145516Sdarrenr MUTEX_EXIT(&ipf_rw); 1328145516Sdarrenr#else 1329145516Sdarrenr u_short id; 1330145516Sdarrenr 1331145516Sdarrenr id = ip_randomid(); 1332145516Sdarrenr#endif 1333145516Sdarrenr 1334145516Sdarrenr return id; 1335145516Sdarrenr} 1336145516Sdarrenr 1337145516Sdarrenr 1338145516SdarrenrINLINE void fr_checkv4sum(fin) 1339145516Sdarrenrfr_info_t *fin; 1340145516Sdarrenr{ 1341145516Sdarrenr#ifdef CSUM_DATA_VALID 1342145516Sdarrenr int manual = 0; 1343145516Sdarrenr u_short sum; 1344145516Sdarrenr ip_t *ip; 1345145516Sdarrenr mb_t *m; 1346145516Sdarrenr 1347145516Sdarrenr if ((fin->fin_flx & FI_NOCKSUM) != 0) 1348145516Sdarrenr return; 1349145516Sdarrenr 1350172776Sdarrenr if (fin->fin_cksum != 0) 1351172776Sdarrenr return; 1352172776Sdarrenr 1353145516Sdarrenr m = fin->fin_m; 1354145516Sdarrenr if (m == NULL) { 1355145516Sdarrenr manual = 1; 1356145516Sdarrenr goto skipauto; 1357145516Sdarrenr } 1358145516Sdarrenr ip = fin->fin_ip; 1359145516Sdarrenr 1360145516Sdarrenr if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) { 1361145516Sdarrenr if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) 1362145516Sdarrenr sum = m->m_pkthdr.csum_data; 1363145516Sdarrenr else 1364145516Sdarrenr sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, 1365145516Sdarrenr htonl(m->m_pkthdr.csum_data + 1366145516Sdarrenr fin->fin_ip->ip_len + fin->fin_p)); 1367145516Sdarrenr sum ^= 0xffff; 1368172776Sdarrenr if (sum != 0) { 1369145516Sdarrenr fin->fin_flx |= FI_BAD; 1370172776Sdarrenr fin->fin_cksum = -1; 1371172776Sdarrenr } else { 1372172776Sdarrenr fin->fin_cksum = 1; 1373172776Sdarrenr } 1374145516Sdarrenr } else 1375145516Sdarrenr manual = 1; 1376145516Sdarrenrskipauto: 1377145516Sdarrenr# ifdef IPFILTER_CKSUM 1378145516Sdarrenr if (manual != 0) 1379145516Sdarrenr if (fr_checkl4sum(fin) == -1) 1380145516Sdarrenr fin->fin_flx |= FI_BAD; 1381145516Sdarrenr# else 1382145516Sdarrenr ; 1383145516Sdarrenr# endif 1384145516Sdarrenr#else 1385145516Sdarrenr# ifdef IPFILTER_CKSUM 1386145516Sdarrenr if (fr_checkl4sum(fin) == -1) 1387145516Sdarrenr fin->fin_flx |= FI_BAD; 1388145516Sdarrenr# endif 1389145516Sdarrenr#endif 1390145516Sdarrenr} 1391145516Sdarrenr 1392145516Sdarrenr 1393145516Sdarrenr#ifdef USE_INET6 1394145516SdarrenrINLINE void fr_checkv6sum(fin) 1395145516Sdarrenrfr_info_t *fin; 1396145516Sdarrenr{ 1397145516Sdarrenr# ifdef IPFILTER_CKSUM 1398145516Sdarrenr if (fr_checkl4sum(fin) == -1) 1399145516Sdarrenr fin->fin_flx |= FI_BAD; 1400145516Sdarrenr# endif 1401145516Sdarrenr} 1402145516Sdarrenr#endif /* USE_INET6 */ 1403145516Sdarrenr 1404145516Sdarrenr 1405145516Sdarrenrsize_t mbufchainlen(m0) 1406145516Sdarrenrstruct mbuf *m0; 1407145516Sdarrenr{ 1408145516Sdarrenr size_t len; 1409145516Sdarrenr 1410145516Sdarrenr if ((m0->m_flags & M_PKTHDR) != 0) { 1411145516Sdarrenr len = m0->m_pkthdr.len; 1412145516Sdarrenr } else { 1413145516Sdarrenr struct mbuf *m; 1414145516Sdarrenr 1415145516Sdarrenr for (m = m0, len = 0; m != NULL; m = m->m_next) 1416145516Sdarrenr len += m->m_len; 1417145516Sdarrenr } 1418145516Sdarrenr return len; 1419145516Sdarrenr} 1420145516Sdarrenr 1421145516Sdarrenr 1422145516Sdarrenr/* ------------------------------------------------------------------------ */ 1423145516Sdarrenr/* Function: fr_pullup */ 1424145516Sdarrenr/* Returns: NULL == pullup failed, else pointer to protocol header */ 1425145516Sdarrenr/* Parameters: m(I) - pointer to buffer where data packet starts */ 1426145516Sdarrenr/* fin(I) - pointer to packet information */ 1427145516Sdarrenr/* len(I) - number of bytes to pullup */ 1428145516Sdarrenr/* */ 1429145516Sdarrenr/* Attempt to move at least len bytes (from the start of the buffer) into a */ 1430145516Sdarrenr/* single buffer for ease of access. Operating system native functions are */ 1431145516Sdarrenr/* used to manage buffers - if necessary. If the entire packet ends up in */ 1432145516Sdarrenr/* a single buffer, set the FI_COALESCE flag even though fr_coalesce() has */ 1433145516Sdarrenr/* not been called. Both fin_ip and fin_dp are updated before exiting _IF_ */ 1434145516Sdarrenr/* and ONLY if the pullup succeeds. */ 1435145516Sdarrenr/* */ 1436145516Sdarrenr/* We assume that 'min' is a pointer to a buffer that is part of the chain */ 1437145516Sdarrenr/* of buffers that starts at *fin->fin_mp. */ 1438145516Sdarrenr/* ------------------------------------------------------------------------ */ 1439145516Sdarrenrvoid *fr_pullup(min, fin, len) 1440145516Sdarrenrmb_t *min; 1441145516Sdarrenrfr_info_t *fin; 1442145516Sdarrenrint len; 1443145516Sdarrenr{ 1444145516Sdarrenr int out = fin->fin_out, dpoff, ipoff; 1445145516Sdarrenr mb_t *m = min; 1446145516Sdarrenr char *ip; 1447145516Sdarrenr 1448145516Sdarrenr if (m == NULL) 1449145516Sdarrenr return NULL; 1450145516Sdarrenr 1451145516Sdarrenr ip = (char *)fin->fin_ip; 1452145516Sdarrenr if ((fin->fin_flx & FI_COALESCE) != 0) 1453145516Sdarrenr return ip; 1454145516Sdarrenr 1455145516Sdarrenr ipoff = fin->fin_ipoff; 1456145516Sdarrenr if (fin->fin_dp != NULL) 1457145516Sdarrenr dpoff = (char *)fin->fin_dp - (char *)ip; 1458145516Sdarrenr else 1459145516Sdarrenr dpoff = 0; 1460145516Sdarrenr 1461145516Sdarrenr if (M_LEN(m) < len) { 1462145516Sdarrenr#ifdef MHLEN 1463145516Sdarrenr /* 1464145516Sdarrenr * Assume that M_PKTHDR is set and just work with what is left 1465145516Sdarrenr * rather than check.. 1466145516Sdarrenr * Should not make any real difference, anyway. 1467145516Sdarrenr */ 1468145516Sdarrenr if (len > MHLEN) 1469145516Sdarrenr#else 1470145516Sdarrenr if (len > MLEN) 1471145516Sdarrenr#endif 1472145516Sdarrenr { 1473145516Sdarrenr#ifdef HAVE_M_PULLDOWN 1474145516Sdarrenr if (m_pulldown(m, 0, len, NULL) == NULL) 1475145516Sdarrenr m = NULL; 1476145516Sdarrenr#else 1477145516Sdarrenr FREE_MB_T(*fin->fin_mp); 1478145516Sdarrenr m = NULL; 1479145516Sdarrenr#endif 1480145516Sdarrenr } else 1481145516Sdarrenr { 1482145516Sdarrenr m = m_pullup(m, len); 1483145516Sdarrenr } 1484145516Sdarrenr *fin->fin_mp = m; 1485145516Sdarrenr if (m == NULL) { 1486172776Sdarrenr fin->fin_m = NULL; 1487145516Sdarrenr ATOMIC_INCL(frstats[out].fr_pull[1]); 1488145516Sdarrenr return NULL; 1489145516Sdarrenr } 1490172776Sdarrenr 1491172776Sdarrenr while (M_LEN(m) == 0) { 1492172776Sdarrenr m = m->m_next; 1493172776Sdarrenr } 1494172776Sdarrenr fin->fin_m = m; 1495145516Sdarrenr ip = MTOD(m, char *) + ipoff; 1496145516Sdarrenr } 1497145516Sdarrenr 1498145516Sdarrenr ATOMIC_INCL(frstats[out].fr_pull[0]); 1499145516Sdarrenr fin->fin_ip = (ip_t *)ip; 1500145516Sdarrenr if (fin->fin_dp != NULL) 1501145516Sdarrenr fin->fin_dp = (char *)fin->fin_ip + dpoff; 1502145516Sdarrenr 1503145516Sdarrenr if (len == fin->fin_plen) 1504145516Sdarrenr fin->fin_flx |= FI_COALESCE; 1505145516Sdarrenr return ip; 1506145516Sdarrenr} 1507170268Sdarrenr 1508170268Sdarrenr 1509170268Sdarrenrint ipf_inject(fin, m) 1510170268Sdarrenrfr_info_t *fin; 1511170268Sdarrenrmb_t *m; 1512170268Sdarrenr{ 1513170268Sdarrenr int error = 0; 1514170268Sdarrenr 1515170268Sdarrenr if (fin->fin_out == 0) { 1516170268Sdarrenr#if (__FreeBSD_version >= 501000) 1517170268Sdarrenr netisr_dispatch(NETISR_IP, m); 1518170268Sdarrenr#else 1519170268Sdarrenr struct ifqueue *ifq; 1520170268Sdarrenr 1521170268Sdarrenr ifq = &ipintrq; 1522170268Sdarrenr 1523170268Sdarrenr# ifdef _IF_QFULL 1524170268Sdarrenr if (_IF_QFULL(ifq)) 1525170268Sdarrenr# else 1526170268Sdarrenr if (IF_QFULL(ifq)) 1527170268Sdarrenr# endif 1528170268Sdarrenr { 1529170268Sdarrenr# ifdef _IF_DROP 1530170268Sdarrenr _IF_DROP(ifq); 1531170268Sdarrenr# else 1532170268Sdarrenr IF_DROP(ifq); 1533170268Sdarrenr# endif 1534170268Sdarrenr FREE_MB_T(m); 1535170268Sdarrenr error = ENOBUFS; 1536170268Sdarrenr } else { 1537170268Sdarrenr IF_ENQUEUE(ifq, m); 1538170268Sdarrenr } 1539170268Sdarrenr#endif 1540170268Sdarrenr } else { 1541173931Sdarrenr fin->fin_ip->ip_len = ntohs(fin->fin_ip->ip_len); 1542173931Sdarrenr fin->fin_ip->ip_off = ntohs(fin->fin_ip->ip_off); 1543170268Sdarrenr#if (__FreeBSD_version >= 470102) 1544170268Sdarrenr error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL); 1545170268Sdarrenr#else 1546170268Sdarrenr error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL); 1547170268Sdarrenr#endif 1548170268Sdarrenr } 1549170268Sdarrenr 1550170268Sdarrenr return error; 1551170268Sdarrenr} 1552172776Sdarrenr 1553172776Sdarrenrint ipf_pfil_unhook(void) { 1554172776Sdarrenr#if defined(NETBSD_PF) && (__FreeBSD_version >= 500011) 1555172776Sdarrenr# if __FreeBSD_version >= 501108 1556172776Sdarrenr struct pfil_head *ph_inet; 1557172776Sdarrenr# ifdef USE_INET6 1558172776Sdarrenr struct pfil_head *ph_inet6; 1559172776Sdarrenr# endif 1560172776Sdarrenr# endif 1561172776Sdarrenr#endif 1562172776Sdarrenr 1563172776Sdarrenr#ifdef NETBSD_PF 1564172776Sdarrenr# if (__FreeBSD_version >= 500011) 1565172776Sdarrenr# if (__FreeBSD_version >= 501108) 1566172776Sdarrenr ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); 1567172776Sdarrenr if (ph_inet != NULL) 1568172776Sdarrenr pfil_remove_hook((void *)fr_check_wrapper, NULL, 1569172776Sdarrenr PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet); 1570172776Sdarrenr# else 1571172776Sdarrenr pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK, 1572172776Sdarrenr &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); 1573172776Sdarrenr# endif 1574172776Sdarrenr# else 1575172776Sdarrenr pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK); 1576172776Sdarrenr# endif 1577172776Sdarrenr# ifdef USE_INET6 1578172776Sdarrenr# if (__FreeBSD_version >= 501108) 1579172776Sdarrenr ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6); 1580172776Sdarrenr if (ph_inet6 != NULL) 1581172776Sdarrenr pfil_remove_hook((void *)fr_check_wrapper6, NULL, 1582172776Sdarrenr PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet6); 1583172776Sdarrenr# else 1584172776Sdarrenr pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK, 1585172776Sdarrenr &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh); 1586172776Sdarrenr# endif 1587172776Sdarrenr# endif 1588172776Sdarrenr#endif 1589172776Sdarrenr 1590172776Sdarrenr return (0); 1591172776Sdarrenr} 1592172776Sdarrenr 1593172776Sdarrenrint ipf_pfil_hook(void) { 1594172776Sdarrenr#if defined(NETBSD_PF) && (__FreeBSD_version >= 500011) 1595172776Sdarrenr# if __FreeBSD_version >= 501108 1596172776Sdarrenr struct pfil_head *ph_inet; 1597172776Sdarrenr# ifdef USE_INET6 1598172776Sdarrenr struct pfil_head *ph_inet6; 1599172776Sdarrenr# endif 1600172776Sdarrenr# endif 1601172776Sdarrenr#endif 1602172776Sdarrenr 1603172776Sdarrenr# ifdef NETBSD_PF 1604172776Sdarrenr# if __FreeBSD_version >= 500011 1605172776Sdarrenr# if __FreeBSD_version >= 501108 1606172776Sdarrenr ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); 1607172776Sdarrenr# ifdef USE_INET6 1608172776Sdarrenr ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6); 1609172776Sdarrenr# endif 1610172776Sdarrenr if (ph_inet == NULL 1611172776Sdarrenr# ifdef USE_INET6 1612172776Sdarrenr && ph_inet6 == NULL 1613172776Sdarrenr# endif 1614172776Sdarrenr ) 1615172776Sdarrenr return ENODEV; 1616172776Sdarrenr 1617172776Sdarrenr if (ph_inet != NULL) 1618172776Sdarrenr pfil_add_hook((void *)fr_check_wrapper, NULL, 1619172776Sdarrenr PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet); 1620172776Sdarrenr# else 1621172776Sdarrenr pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK, 1622172776Sdarrenr &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); 1623172776Sdarrenr# endif 1624172776Sdarrenr# else 1625172776Sdarrenr pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK); 1626172776Sdarrenr# endif 1627172776Sdarrenr# ifdef USE_INET6 1628172776Sdarrenr# if __FreeBSD_version >= 501108 1629172776Sdarrenr if (ph_inet6 != NULL) 1630172776Sdarrenr pfil_add_hook((void *)fr_check_wrapper6, NULL, 1631172776Sdarrenr PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet6); 1632172776Sdarrenr# else 1633172776Sdarrenr pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK, 1634172776Sdarrenr &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh); 1635172776Sdarrenr# endif 1636172776Sdarrenr# endif 1637172776Sdarrenr# endif 1638172776Sdarrenr return (0); 1639172776Sdarrenr} 1640172776Sdarrenr 1641172776Sdarrenrvoid 1642172776Sdarrenripf_event_reg(void) 1643172776Sdarrenr{ 1644172776Sdarrenr#if (__FreeBSD_version >= 502103) 1645172776Sdarrenr ipf_arrivetag = EVENTHANDLER_REGISTER(ifnet_arrival_event, \ 1646172776Sdarrenr ipf_ifevent, NULL, \ 1647172776Sdarrenr EVENTHANDLER_PRI_ANY); 1648172776Sdarrenr ipf_departtag = EVENTHANDLER_REGISTER(ifnet_departure_event, \ 1649172776Sdarrenr ipf_ifevent, NULL, \ 1650172776Sdarrenr EVENTHANDLER_PRI_ANY); 1651172776Sdarrenr ipf_clonetag = EVENTHANDLER_REGISTER(if_clone_event, ipf_ifevent, \ 1652172776Sdarrenr NULL, EVENTHANDLER_PRI_ANY); 1653172776Sdarrenr#endif 1654172776Sdarrenr} 1655172776Sdarrenr 1656172776Sdarrenrvoid 1657172776Sdarrenripf_event_dereg(void) 1658172776Sdarrenr{ 1659172776Sdarrenr#if (__FreeBSD_version >= 502103) 1660172776Sdarrenr if (ipf_arrivetag != NULL) { 1661172776Sdarrenr EVENTHANDLER_DEREGISTER(ifnet_arrival_event, ipf_arrivetag); 1662172776Sdarrenr } 1663172776Sdarrenr if (ipf_departtag != NULL) { 1664172776Sdarrenr EVENTHANDLER_DEREGISTER(ifnet_departure_event, ipf_departtag); 1665172776Sdarrenr } 1666172776Sdarrenr if (ipf_clonetag != NULL) { 1667172776Sdarrenr EVENTHANDLER_DEREGISTER(if_clone_event, ipf_clonetag); 1668172776Sdarrenr } 1669172776Sdarrenr#endif 1670172776Sdarrenr} 1671