ip_fil_freebsd.c revision 186436
1145516Sdarrenr/* $FreeBSD: head/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c 186436 2008-12-23 16:49:07Z bz $ */ 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> 95145516Sdarrenr#ifndef _KERNEL 96145516Sdarrenr# include "netinet/ipf.h" 97145516Sdarrenr#endif 98145516Sdarrenr#include "netinet/ip_compat.h" 99145516Sdarrenr#ifdef USE_INET6 100145516Sdarrenr# include <netinet/icmp6.h> 101145516Sdarrenr#endif 102145516Sdarrenr#include "netinet/ip_fil.h" 103145516Sdarrenr#include "netinet/ip_nat.h" 104145516Sdarrenr#include "netinet/ip_frag.h" 105145516Sdarrenr#include "netinet/ip_state.h" 106145516Sdarrenr#include "netinet/ip_proxy.h" 107145516Sdarrenr#include "netinet/ip_auth.h" 108145516Sdarrenr#ifdef IPFILTER_SYNC 109145516Sdarrenr#include "netinet/ip_sync.h" 110145516Sdarrenr#endif 111145516Sdarrenr#ifdef IPFILTER_SCAN 112145516Sdarrenr#include "netinet/ip_scan.h" 113145516Sdarrenr#endif 114145516Sdarrenr#include "netinet/ip_pool.h" 115185571Sbz#if defined(__FreeBSD_version) && (__FreeBSD_version >= 800056) 116185571Sbz# include <netinet/vinet.h> 117185571Sbz#endif 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{ 216145516Sdarrenr#ifdef USE_SPL 217145516Sdarrenr int s; 218145516Sdarrenr#endif 219145516Sdarrenr 220145516Sdarrenr SPL_NET(s); 221145516Sdarrenr if (fr_running > 0) { 222145516Sdarrenr SPL_X(s); 223145516Sdarrenr return EBUSY; 224145516Sdarrenr } 225145516Sdarrenr 226145516Sdarrenr MUTEX_INIT(&ipf_rw, "ipf rw mutex"); 227145516Sdarrenr MUTEX_INIT(&ipf_timeoutlock, "ipf timeout queue mutex"); 228145516Sdarrenr RWLOCK_INIT(&ipf_ipidfrag, "ipf IP NAT-Frag rwlock"); 229170268Sdarrenr RWLOCK_INIT(&ipf_tokens, "ipf token rwlock"); 230145516Sdarrenr ipf_locks_done = 1; 231145516Sdarrenr 232145516Sdarrenr if (fr_initialise() < 0) { 233145516Sdarrenr SPL_X(s); 234145516Sdarrenr return EIO; 235145516Sdarrenr } 236145516Sdarrenr 237145516Sdarrenr 238145516Sdarrenr if (fr_checkp != fr_check) { 239145516Sdarrenr fr_savep = fr_checkp; 240145516Sdarrenr fr_checkp = fr_check; 241145516Sdarrenr } 242145516Sdarrenr 243161356Sguido bzero((char *)ipfselwait, sizeof(ipfselwait)); 244145516Sdarrenr bzero((char *)frcache, sizeof(frcache)); 245145516Sdarrenr fr_running = 1; 246145516Sdarrenr 247145516Sdarrenr if (fr_control_forwarding & 1) 248181803Sbz V_ipforwarding = 1; 249145516Sdarrenr 250145516Sdarrenr SPL_X(s); 251145516Sdarrenr#if (__FreeBSD_version >= 300000) 252145516Sdarrenr fr_slowtimer_ch = timeout(fr_slowtimer, NULL, 253145516Sdarrenr (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT); 254145516Sdarrenr#else 255145516Sdarrenr timeout(fr_slowtimer, NULL, (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT); 256145516Sdarrenr#endif 257145516Sdarrenr return 0; 258145516Sdarrenr} 259145516Sdarrenr 260145516Sdarrenr 261145516Sdarrenr/* 262145516Sdarrenr * Disable the filter by removing the hooks from the IP input/output 263145516Sdarrenr * stream. 264145516Sdarrenr */ 265170268Sdarrenrint ipfdetach() 266145516Sdarrenr{ 267145516Sdarrenr#ifdef USE_SPL 268145516Sdarrenr int s; 269145516Sdarrenr#endif 270145516Sdarrenr if (fr_control_forwarding & 2) 271181803Sbz V_ipforwarding = 0; 272145516Sdarrenr 273145516Sdarrenr SPL_NET(s); 274145516Sdarrenr 275145516Sdarrenr#if (__FreeBSD_version >= 300000) 276145516Sdarrenr if (fr_slowtimer_ch.callout != NULL) 277145516Sdarrenr untimeout(fr_slowtimer, NULL, fr_slowtimer_ch); 278145516Sdarrenr bzero(&fr_slowtimer_ch, sizeof(fr_slowtimer_ch)); 279145516Sdarrenr#else 280145516Sdarrenr untimeout(fr_slowtimer, NULL); 281145516Sdarrenr#endif /* FreeBSD */ 282145516Sdarrenr 283145516Sdarrenr#ifndef NETBSD_PF 284145516Sdarrenr if (fr_checkp != NULL) 285145516Sdarrenr fr_checkp = fr_savep; 286145516Sdarrenr fr_savep = NULL; 287145516Sdarrenr#endif 288145516Sdarrenr 289145516Sdarrenr fr_deinitialise(); 290145516Sdarrenr 291145516Sdarrenr fr_running = -2; 292145516Sdarrenr 293145516Sdarrenr (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE); 294145516Sdarrenr (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE); 295145516Sdarrenr 296145516Sdarrenr if (ipf_locks_done == 1) { 297145516Sdarrenr MUTEX_DESTROY(&ipf_timeoutlock); 298145516Sdarrenr MUTEX_DESTROY(&ipf_rw); 299145516Sdarrenr RW_DESTROY(&ipf_ipidfrag); 300170268Sdarrenr RW_DESTROY(&ipf_tokens); 301145516Sdarrenr ipf_locks_done = 0; 302145516Sdarrenr } 303145516Sdarrenr 304145516Sdarrenr SPL_X(s); 305145516Sdarrenr 306145516Sdarrenr return 0; 307145516Sdarrenr} 308145516Sdarrenr 309145516Sdarrenr 310145516Sdarrenr/* 311145516Sdarrenr * Filter ioctl interface. 312145516Sdarrenr */ 313145516Sdarrenrint iplioctl(dev, cmd, data, mode 314145516Sdarrenr# if defined(_KERNEL) && ((BSD >= 199506) || (__FreeBSD_version >= 220000)) 315145516Sdarrenr, p) 316145516Sdarrenr# if (__FreeBSD_version >= 500024) 317145516Sdarrenrstruct thread *p; 318170268Sdarrenr# if (__FreeBSD_version >= 500043) 319170268Sdarrenr# define p_uid td_ucred->cr_ruid 320170268Sdarrenr# else 321170268Sdarrenr# define p_uid t_proc->p_cred->p_ruid 322170268Sdarrenr# endif 323145516Sdarrenr# else 324145516Sdarrenrstruct proc *p; 325170268Sdarrenr# define p_uid p_cred->p_ruid 326145516Sdarrenr# endif /* __FreeBSD_version >= 500024 */ 327145516Sdarrenr# else 328145516Sdarrenr) 329145516Sdarrenr# endif 330145516Sdarrenr#if defined(_KERNEL) && (__FreeBSD_version >= 502116) 331145516Sdarrenrstruct cdev *dev; 332145516Sdarrenr#else 333145516Sdarrenrdev_t dev; 334145516Sdarrenr#endif 335145516Sdarrenrioctlcmd_t cmd; 336145516Sdarrenrcaddr_t data; 337145516Sdarrenrint mode; 338145516Sdarrenr{ 339170268Sdarrenr int error = 0, unit = 0; 340170268Sdarrenr SPL_INT(s); 341145516Sdarrenr 342145516Sdarrenr#if (BSD >= 199306) && defined(_KERNEL) 343153876Sguido if ((securelevel >= 3) && (mode & FWRITE)) 344145516Sdarrenr return EPERM; 345145516Sdarrenr#endif 346145516Sdarrenr 347145516Sdarrenr unit = GET_MINOR(dev); 348145516Sdarrenr if ((IPL_LOGMAX < unit) || (unit < 0)) 349145516Sdarrenr return ENXIO; 350145516Sdarrenr 351145516Sdarrenr if (fr_running <= 0) { 352145516Sdarrenr if (unit != IPL_LOGIPF) 353145516Sdarrenr return EIO; 354145516Sdarrenr if (cmd != SIOCIPFGETNEXT && cmd != SIOCIPFGET && 355173181Sdarrenr cmd != SIOCIPFSET && cmd != SIOCFRENB && 356145516Sdarrenr cmd != SIOCGETFS && cmd != SIOCGETFF) 357145516Sdarrenr return EIO; 358145516Sdarrenr } 359145516Sdarrenr 360145516Sdarrenr SPL_NET(s); 361145516Sdarrenr 362170268Sdarrenr error = fr_ioctlswitch(unit, data, cmd, mode, p->p_uid, p); 363145516Sdarrenr if (error != -1) { 364145516Sdarrenr SPL_X(s); 365145516Sdarrenr return error; 366145516Sdarrenr } 367145516Sdarrenr 368145516Sdarrenr SPL_X(s); 369161356Sguido 370145516Sdarrenr return error; 371145516Sdarrenr} 372145516Sdarrenr 373145516Sdarrenr 374145516Sdarrenr#if 0 375145516Sdarrenrvoid fr_forgetifp(ifp) 376145516Sdarrenrvoid *ifp; 377145516Sdarrenr{ 378145516Sdarrenr register frentry_t *f; 379145516Sdarrenr 380145516Sdarrenr WRITE_ENTER(&ipf_mutex); 381145516Sdarrenr for (f = ipacct[0][fr_active]; (f != NULL); f = f->fr_next) 382145516Sdarrenr if (f->fr_ifa == ifp) 383145516Sdarrenr f->fr_ifa = (void *)-1; 384145516Sdarrenr for (f = ipacct[1][fr_active]; (f != NULL); f = f->fr_next) 385145516Sdarrenr if (f->fr_ifa == ifp) 386145516Sdarrenr f->fr_ifa = (void *)-1; 387145516Sdarrenr for (f = ipfilter[0][fr_active]; (f != NULL); f = f->fr_next) 388145516Sdarrenr if (f->fr_ifa == ifp) 389145516Sdarrenr f->fr_ifa = (void *)-1; 390145516Sdarrenr for (f = ipfilter[1][fr_active]; (f != NULL); f = f->fr_next) 391145516Sdarrenr if (f->fr_ifa == ifp) 392145516Sdarrenr f->fr_ifa = (void *)-1; 393145516Sdarrenr#ifdef USE_INET6 394145516Sdarrenr for (f = ipacct6[0][fr_active]; (f != NULL); f = f->fr_next) 395145516Sdarrenr if (f->fr_ifa == ifp) 396145516Sdarrenr f->fr_ifa = (void *)-1; 397145516Sdarrenr for (f = ipacct6[1][fr_active]; (f != NULL); f = f->fr_next) 398145516Sdarrenr if (f->fr_ifa == ifp) 399145516Sdarrenr f->fr_ifa = (void *)-1; 400145516Sdarrenr for (f = ipfilter6[0][fr_active]; (f != NULL); f = f->fr_next) 401145516Sdarrenr if (f->fr_ifa == ifp) 402145516Sdarrenr f->fr_ifa = (void *)-1; 403145516Sdarrenr for (f = ipfilter6[1][fr_active]; (f != NULL); f = f->fr_next) 404145516Sdarrenr if (f->fr_ifa == ifp) 405145516Sdarrenr f->fr_ifa = (void *)-1; 406145516Sdarrenr#endif 407145516Sdarrenr RWLOCK_EXIT(&ipf_mutex); 408145516Sdarrenr fr_natsync(ifp); 409145516Sdarrenr} 410145516Sdarrenr#endif 411145516Sdarrenr 412145516Sdarrenr 413145516Sdarrenr/* 414145516Sdarrenr * routines below for saving IP headers to buffer 415145516Sdarrenr */ 416145516Sdarrenrint iplopen(dev, flags 417145516Sdarrenr#if ((BSD >= 199506) || (__FreeBSD_version >= 220000)) && defined(_KERNEL) 418145516Sdarrenr, devtype, p) 419145516Sdarrenrint devtype; 420145516Sdarrenr# if (__FreeBSD_version >= 500024) 421145516Sdarrenrstruct thread *p; 422145516Sdarrenr# else 423145516Sdarrenrstruct proc *p; 424145516Sdarrenr# endif /* __FreeBSD_version >= 500024 */ 425145516Sdarrenr#else 426145516Sdarrenr) 427145516Sdarrenr#endif 428145516Sdarrenr#if defined(_KERNEL) && (__FreeBSD_version >= 502116) 429145516Sdarrenrstruct cdev *dev; 430145516Sdarrenr#else 431145516Sdarrenrdev_t dev; 432145516Sdarrenr#endif 433145516Sdarrenrint flags; 434145516Sdarrenr{ 435145516Sdarrenr u_int min = GET_MINOR(dev); 436145516Sdarrenr 437145516Sdarrenr if (IPL_LOGMAX < min) 438145516Sdarrenr min = ENXIO; 439145516Sdarrenr else 440145516Sdarrenr min = 0; 441145516Sdarrenr return min; 442145516Sdarrenr} 443145516Sdarrenr 444145516Sdarrenr 445145516Sdarrenrint iplclose(dev, flags 446145516Sdarrenr#if ((BSD >= 199506) || (__FreeBSD_version >= 220000)) && defined(_KERNEL) 447145516Sdarrenr, devtype, p) 448145516Sdarrenrint devtype; 449145516Sdarrenr# if (__FreeBSD_version >= 500024) 450145516Sdarrenrstruct thread *p; 451145516Sdarrenr# else 452145516Sdarrenrstruct proc *p; 453145516Sdarrenr# endif /* __FreeBSD_version >= 500024 */ 454145516Sdarrenr#else 455145516Sdarrenr) 456145516Sdarrenr#endif 457145516Sdarrenr#if defined(_KERNEL) && (__FreeBSD_version >= 502116) 458145516Sdarrenrstruct cdev *dev; 459145516Sdarrenr#else 460145516Sdarrenrdev_t dev; 461145516Sdarrenr#endif 462145516Sdarrenrint flags; 463145516Sdarrenr{ 464145516Sdarrenr u_int min = GET_MINOR(dev); 465145516Sdarrenr 466145516Sdarrenr if (IPL_LOGMAX < min) 467145516Sdarrenr min = ENXIO; 468145516Sdarrenr else 469145516Sdarrenr min = 0; 470145516Sdarrenr return min; 471145516Sdarrenr} 472145516Sdarrenr 473145516Sdarrenr/* 474145516Sdarrenr * iplread/ipllog 475145516Sdarrenr * both of these must operate with at least splnet() lest they be 476145516Sdarrenr * called during packet processing and cause an inconsistancy to appear in 477145516Sdarrenr * the filter lists. 478145516Sdarrenr */ 479145516Sdarrenr#if (BSD >= 199306) 480145516Sdarrenrint iplread(dev, uio, ioflag) 481145516Sdarrenrint ioflag; 482145516Sdarrenr#else 483145516Sdarrenrint iplread(dev, uio) 484145516Sdarrenr#endif 485145516Sdarrenr#if defined(_KERNEL) && (__FreeBSD_version >= 502116) 486145516Sdarrenrstruct cdev *dev; 487145516Sdarrenr#else 488145516Sdarrenrdev_t dev; 489145516Sdarrenr#endif 490145516Sdarrenrregister struct uio *uio; 491145516Sdarrenr{ 492161356Sguido u_int xmin = GET_MINOR(dev); 493145516Sdarrenr 494170268Sdarrenr if (fr_running < 1) 495170268Sdarrenr return EIO; 496170268Sdarrenr 497161356Sguido if (xmin < 0) 498161356Sguido return ENXIO; 499161356Sguido 500145516Sdarrenr# ifdef IPFILTER_SYNC 501161356Sguido if (xmin == IPL_LOGSYNC) 502145516Sdarrenr return ipfsync_read(uio); 503145516Sdarrenr# endif 504145516Sdarrenr 505145516Sdarrenr#ifdef IPFILTER_LOG 506161356Sguido return ipflog_read(xmin, uio); 507145516Sdarrenr#else 508145516Sdarrenr return ENXIO; 509145516Sdarrenr#endif 510145516Sdarrenr} 511145516Sdarrenr 512145516Sdarrenr 513145516Sdarrenr/* 514145516Sdarrenr * iplwrite 515145516Sdarrenr * both of these must operate with at least splnet() lest they be 516145516Sdarrenr * called during packet processing and cause an inconsistancy to appear in 517145516Sdarrenr * the filter lists. 518145516Sdarrenr */ 519145516Sdarrenr#if (BSD >= 199306) 520145516Sdarrenrint iplwrite(dev, uio, ioflag) 521145516Sdarrenrint ioflag; 522145516Sdarrenr#else 523145516Sdarrenrint iplwrite(dev, uio) 524145516Sdarrenr#endif 525145516Sdarrenr#if defined(_KERNEL) && (__FreeBSD_version >= 502116) 526145516Sdarrenrstruct cdev *dev; 527145516Sdarrenr#else 528145516Sdarrenrdev_t dev; 529145516Sdarrenr#endif 530145516Sdarrenrregister struct uio *uio; 531145516Sdarrenr{ 532145516Sdarrenr 533170268Sdarrenr if (fr_running < 1) 534170268Sdarrenr return EIO; 535170268Sdarrenr 536145516Sdarrenr#ifdef IPFILTER_SYNC 537145516Sdarrenr if (GET_MINOR(dev) == IPL_LOGSYNC) 538145516Sdarrenr return ipfsync_write(uio); 539145516Sdarrenr#endif 540145516Sdarrenr return ENXIO; 541145516Sdarrenr} 542145516Sdarrenr 543145516Sdarrenr 544145516Sdarrenr/* 545145516Sdarrenr * fr_send_reset - this could conceivably be a call to tcp_respond(), but that 546145516Sdarrenr * requires a large amount of setting up and isn't any more efficient. 547145516Sdarrenr */ 548145516Sdarrenrint fr_send_reset(fin) 549145516Sdarrenrfr_info_t *fin; 550145516Sdarrenr{ 551145516Sdarrenr struct tcphdr *tcp, *tcp2; 552145516Sdarrenr int tlen = 0, hlen; 553145516Sdarrenr struct mbuf *m; 554145516Sdarrenr#ifdef USE_INET6 555145516Sdarrenr ip6_t *ip6; 556145516Sdarrenr#endif 557145516Sdarrenr ip_t *ip; 558145516Sdarrenr 559145516Sdarrenr tcp = fin->fin_dp; 560145516Sdarrenr if (tcp->th_flags & TH_RST) 561145516Sdarrenr return -1; /* feedback loop */ 562145516Sdarrenr 563145516Sdarrenr if (fr_checkl4sum(fin) == -1) 564145516Sdarrenr return -1; 565145516Sdarrenr 566145516Sdarrenr tlen = fin->fin_dlen - (TCP_OFF(tcp) << 2) + 567145516Sdarrenr ((tcp->th_flags & TH_SYN) ? 1 : 0) + 568145516Sdarrenr ((tcp->th_flags & TH_FIN) ? 1 : 0); 569145516Sdarrenr 570145516Sdarrenr#ifdef USE_INET6 571145516Sdarrenr hlen = (fin->fin_v == 6) ? sizeof(ip6_t) : sizeof(ip_t); 572145516Sdarrenr#else 573145516Sdarrenr hlen = sizeof(ip_t); 574145516Sdarrenr#endif 575145516Sdarrenr#ifdef MGETHDR 576145516Sdarrenr MGETHDR(m, M_DONTWAIT, MT_HEADER); 577145516Sdarrenr#else 578145516Sdarrenr MGET(m, M_DONTWAIT, MT_HEADER); 579145516Sdarrenr#endif 580145516Sdarrenr if (m == NULL) 581145516Sdarrenr return -1; 582145516Sdarrenr if (sizeof(*tcp2) + hlen > MLEN) { 583145516Sdarrenr MCLGET(m, M_DONTWAIT); 584145516Sdarrenr if ((m->m_flags & M_EXT) == 0) { 585145516Sdarrenr FREE_MB_T(m); 586145516Sdarrenr return -1; 587145516Sdarrenr } 588145516Sdarrenr } 589145516Sdarrenr 590145516Sdarrenr m->m_len = sizeof(*tcp2) + hlen; 591145516Sdarrenr#if (BSD >= 199103) 592145516Sdarrenr m->m_data += max_linkhdr; 593145516Sdarrenr m->m_pkthdr.len = m->m_len; 594145516Sdarrenr m->m_pkthdr.rcvif = (struct ifnet *)0; 595145516Sdarrenr#endif 596145516Sdarrenr ip = mtod(m, struct ip *); 597145516Sdarrenr bzero((char *)ip, hlen); 598145516Sdarrenr#ifdef USE_INET6 599145516Sdarrenr ip6 = (ip6_t *)ip; 600145516Sdarrenr#endif 601145516Sdarrenr tcp2 = (struct tcphdr *)((char *)ip + hlen); 602145516Sdarrenr tcp2->th_sport = tcp->th_dport; 603145516Sdarrenr tcp2->th_dport = tcp->th_sport; 604145516Sdarrenr 605145516Sdarrenr if (tcp->th_flags & TH_ACK) { 606145516Sdarrenr tcp2->th_seq = tcp->th_ack; 607145516Sdarrenr tcp2->th_flags = TH_RST; 608145516Sdarrenr tcp2->th_ack = 0; 609145516Sdarrenr } else { 610145516Sdarrenr tcp2->th_seq = 0; 611145516Sdarrenr tcp2->th_ack = ntohl(tcp->th_seq); 612145516Sdarrenr tcp2->th_ack += tlen; 613145516Sdarrenr tcp2->th_ack = htonl(tcp2->th_ack); 614145516Sdarrenr tcp2->th_flags = TH_RST|TH_ACK; 615145516Sdarrenr } 616145516Sdarrenr TCP_X2_A(tcp2, 0); 617145516Sdarrenr TCP_OFF_A(tcp2, sizeof(*tcp2) >> 2); 618145516Sdarrenr tcp2->th_win = tcp->th_win; 619145516Sdarrenr tcp2->th_sum = 0; 620145516Sdarrenr tcp2->th_urp = 0; 621145516Sdarrenr 622145516Sdarrenr#ifdef USE_INET6 623145516Sdarrenr if (fin->fin_v == 6) { 624145516Sdarrenr ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; 625145516Sdarrenr ip6->ip6_plen = htons(sizeof(struct tcphdr)); 626145516Sdarrenr ip6->ip6_nxt = IPPROTO_TCP; 627145516Sdarrenr ip6->ip6_hlim = 0; 628145516Sdarrenr ip6->ip6_src = fin->fin_dst6; 629145516Sdarrenr ip6->ip6_dst = fin->fin_src6; 630145516Sdarrenr tcp2->th_sum = in6_cksum(m, IPPROTO_TCP, 631145516Sdarrenr sizeof(*ip6), sizeof(*tcp2)); 632145516Sdarrenr return fr_send_ip(fin, m, &m); 633145516Sdarrenr } 634145516Sdarrenr#endif 635145516Sdarrenr ip->ip_p = IPPROTO_TCP; 636145516Sdarrenr ip->ip_len = htons(sizeof(struct tcphdr)); 637145516Sdarrenr ip->ip_src.s_addr = fin->fin_daddr; 638145516Sdarrenr ip->ip_dst.s_addr = fin->fin_saddr; 639145516Sdarrenr tcp2->th_sum = in_cksum(m, hlen + sizeof(*tcp2)); 640145516Sdarrenr ip->ip_len = hlen + sizeof(*tcp2); 641145516Sdarrenr return fr_send_ip(fin, m, &m); 642145516Sdarrenr} 643145516Sdarrenr 644145516Sdarrenr 645145516Sdarrenrstatic int fr_send_ip(fin, m, mpp) 646145516Sdarrenrfr_info_t *fin; 647145516Sdarrenrmb_t *m, **mpp; 648145516Sdarrenr{ 649145516Sdarrenr fr_info_t fnew; 650145516Sdarrenr ip_t *ip, *oip; 651145516Sdarrenr int hlen; 652145516Sdarrenr 653145516Sdarrenr ip = mtod(m, ip_t *); 654145516Sdarrenr bzero((char *)&fnew, sizeof(fnew)); 655145516Sdarrenr 656145516Sdarrenr IP_V_A(ip, fin->fin_v); 657145516Sdarrenr switch (fin->fin_v) 658145516Sdarrenr { 659145516Sdarrenr case 4 : 660145516Sdarrenr fnew.fin_v = 4; 661145516Sdarrenr oip = fin->fin_ip; 662145516Sdarrenr IP_HL_A(ip, sizeof(*oip) >> 2); 663145516Sdarrenr ip->ip_tos = oip->ip_tos; 664145516Sdarrenr ip->ip_id = fin->fin_ip->ip_id; 665145516Sdarrenr#if (__FreeBSD_version > 460000) 666181803Sbz ip->ip_off = V_path_mtu_discovery ? IP_DF : 0; 667145516Sdarrenr#else 668145516Sdarrenr ip->ip_off = 0; 669145516Sdarrenr#endif 670181803Sbz ip->ip_ttl = V_ip_defttl; 671145516Sdarrenr ip->ip_sum = 0; 672145516Sdarrenr hlen = sizeof(*oip); 673145516Sdarrenr break; 674145516Sdarrenr#ifdef USE_INET6 675145516Sdarrenr case 6 : 676145516Sdarrenr { 677145516Sdarrenr ip6_t *ip6 = (ip6_t *)ip; 678145516Sdarrenr 679145516Sdarrenr ip6->ip6_vfc = 0x60; 680145516Sdarrenr ip6->ip6_hlim = IPDEFTTL; 681145516Sdarrenr 682145516Sdarrenr fnew.fin_v = 6; 683145516Sdarrenr hlen = sizeof(*ip6); 684145516Sdarrenr break; 685145516Sdarrenr } 686145516Sdarrenr#endif 687145516Sdarrenr default : 688145516Sdarrenr return EINVAL; 689145516Sdarrenr } 690145516Sdarrenr#ifdef IPSEC 691145516Sdarrenr m->m_pkthdr.rcvif = NULL; 692145516Sdarrenr#endif 693145516Sdarrenr 694145516Sdarrenr fnew.fin_ifp = fin->fin_ifp; 695145516Sdarrenr fnew.fin_flx = FI_NOCKSUM; 696145516Sdarrenr fnew.fin_m = m; 697145516Sdarrenr fnew.fin_ip = ip; 698145516Sdarrenr fnew.fin_mp = mpp; 699145516Sdarrenr fnew.fin_hlen = hlen; 700145516Sdarrenr fnew.fin_dp = (char *)ip + hlen; 701145516Sdarrenr (void) fr_makefrip(hlen, ip, &fnew); 702145516Sdarrenr 703145516Sdarrenr return fr_fastroute(m, mpp, &fnew, NULL); 704145516Sdarrenr} 705145516Sdarrenr 706145516Sdarrenr 707145516Sdarrenrint fr_send_icmp_err(type, fin, dst) 708145516Sdarrenrint type; 709145516Sdarrenrfr_info_t *fin; 710145516Sdarrenrint dst; 711145516Sdarrenr{ 712145516Sdarrenr int err, hlen, xtra, iclen, ohlen, avail, code; 713145516Sdarrenr struct in_addr dst4; 714145516Sdarrenr struct icmp *icmp; 715145516Sdarrenr struct mbuf *m; 716145516Sdarrenr void *ifp; 717145516Sdarrenr#ifdef USE_INET6 718145516Sdarrenr ip6_t *ip6; 719145516Sdarrenr struct in6_addr dst6; 720145516Sdarrenr#endif 721145516Sdarrenr ip_t *ip, *ip2; 722145516Sdarrenr 723172776Sdarrenr if ((type < 0) || (type >= ICMP_MAXTYPE)) 724145516Sdarrenr return -1; 725145516Sdarrenr 726145516Sdarrenr code = fin->fin_icode; 727145516Sdarrenr#ifdef USE_INET6 728145516Sdarrenr if ((code < 0) || (code > sizeof(icmptoicmp6unreach)/sizeof(int))) 729145516Sdarrenr return -1; 730145516Sdarrenr#endif 731145516Sdarrenr 732145516Sdarrenr if (fr_checkl4sum(fin) == -1) 733145516Sdarrenr return -1; 734145516Sdarrenr#ifdef MGETHDR 735145516Sdarrenr MGETHDR(m, M_DONTWAIT, MT_HEADER); 736145516Sdarrenr#else 737145516Sdarrenr MGET(m, M_DONTWAIT, MT_HEADER); 738145516Sdarrenr#endif 739145516Sdarrenr if (m == NULL) 740145516Sdarrenr return -1; 741145516Sdarrenr avail = MHLEN; 742145516Sdarrenr 743145516Sdarrenr xtra = 0; 744145516Sdarrenr hlen = 0; 745145516Sdarrenr ohlen = 0; 746145516Sdarrenr ifp = fin->fin_ifp; 747145516Sdarrenr if (fin->fin_v == 4) { 748145516Sdarrenr if ((fin->fin_p == IPPROTO_ICMP) && 749145516Sdarrenr !(fin->fin_flx & FI_SHORT)) 750145516Sdarrenr switch (ntohs(fin->fin_data[0]) >> 8) 751145516Sdarrenr { 752145516Sdarrenr case ICMP_ECHO : 753145516Sdarrenr case ICMP_TSTAMP : 754145516Sdarrenr case ICMP_IREQ : 755145516Sdarrenr case ICMP_MASKREQ : 756145516Sdarrenr break; 757145516Sdarrenr default : 758145516Sdarrenr FREE_MB_T(m); 759145516Sdarrenr return 0; 760145516Sdarrenr } 761145516Sdarrenr 762145516Sdarrenr if (dst == 0) { 763145516Sdarrenr if (fr_ifpaddr(4, FRI_NORMAL, ifp, 764145516Sdarrenr &dst4, NULL) == -1) { 765145516Sdarrenr FREE_MB_T(m); 766145516Sdarrenr return -1; 767145516Sdarrenr } 768145516Sdarrenr } else 769145516Sdarrenr dst4.s_addr = fin->fin_daddr; 770145516Sdarrenr 771145516Sdarrenr hlen = sizeof(ip_t); 772145516Sdarrenr ohlen = fin->fin_hlen; 773145516Sdarrenr if (fin->fin_hlen < fin->fin_plen) 774145516Sdarrenr xtra = MIN(fin->fin_dlen, 8); 775145516Sdarrenr else 776145516Sdarrenr xtra = 0; 777145516Sdarrenr } 778145516Sdarrenr 779145516Sdarrenr#ifdef USE_INET6 780145516Sdarrenr else if (fin->fin_v == 6) { 781145516Sdarrenr hlen = sizeof(ip6_t); 782145516Sdarrenr ohlen = sizeof(ip6_t); 783145516Sdarrenr type = icmptoicmp6types[type]; 784145516Sdarrenr if (type == ICMP6_DST_UNREACH) 785145516Sdarrenr code = icmptoicmp6unreach[code]; 786145516Sdarrenr 787145516Sdarrenr if (hlen + sizeof(*icmp) + max_linkhdr + 788145516Sdarrenr fin->fin_plen > avail) { 789145516Sdarrenr MCLGET(m, M_DONTWAIT); 790145516Sdarrenr if ((m->m_flags & M_EXT) == 0) { 791145516Sdarrenr FREE_MB_T(m); 792145516Sdarrenr return -1; 793145516Sdarrenr } 794145516Sdarrenr avail = MCLBYTES; 795145516Sdarrenr } 796145516Sdarrenr xtra = MIN(fin->fin_plen, 797145516Sdarrenr avail - hlen - sizeof(*icmp) - max_linkhdr); 798145516Sdarrenr if (dst == 0) { 799145516Sdarrenr if (fr_ifpaddr(6, FRI_NORMAL, ifp, 800145516Sdarrenr (struct in_addr *)&dst6, NULL) == -1) { 801145516Sdarrenr FREE_MB_T(m); 802145516Sdarrenr return -1; 803145516Sdarrenr } 804145516Sdarrenr } else 805145516Sdarrenr dst6 = fin->fin_dst6; 806145516Sdarrenr } 807145516Sdarrenr#endif 808145516Sdarrenr else { 809145516Sdarrenr FREE_MB_T(m); 810145516Sdarrenr return -1; 811145516Sdarrenr } 812145516Sdarrenr 813145516Sdarrenr iclen = hlen + sizeof(*icmp); 814145516Sdarrenr avail -= (max_linkhdr + iclen); 815145516Sdarrenr if (avail < 0) { 816145516Sdarrenr FREE_MB_T(m); 817145516Sdarrenr return -1; 818145516Sdarrenr } 819145516Sdarrenr if (xtra > avail) 820145516Sdarrenr xtra = avail; 821145516Sdarrenr iclen += xtra; 822145516Sdarrenr m->m_data += max_linkhdr; 823145516Sdarrenr m->m_pkthdr.rcvif = (struct ifnet *)0; 824145516Sdarrenr m->m_pkthdr.len = iclen; 825145516Sdarrenr m->m_len = iclen; 826145516Sdarrenr ip = mtod(m, ip_t *); 827145516Sdarrenr icmp = (struct icmp *)((char *)ip + hlen); 828145516Sdarrenr ip2 = (ip_t *)&icmp->icmp_ip; 829145516Sdarrenr 830145516Sdarrenr icmp->icmp_type = type; 831145516Sdarrenr icmp->icmp_code = fin->fin_icode; 832145516Sdarrenr icmp->icmp_cksum = 0; 833145516Sdarrenr#ifdef icmp_nextmtu 834145516Sdarrenr if (type == ICMP_UNREACH && 835145516Sdarrenr fin->fin_icode == ICMP_UNREACH_NEEDFRAG && ifp) 836145516Sdarrenr icmp->icmp_nextmtu = htons(((struct ifnet *)ifp)->if_mtu); 837145516Sdarrenr#endif 838145516Sdarrenr 839145516Sdarrenr bcopy((char *)fin->fin_ip, (char *)ip2, ohlen); 840145516Sdarrenr 841145516Sdarrenr#ifdef USE_INET6 842145516Sdarrenr ip6 = (ip6_t *)ip; 843145516Sdarrenr if (fin->fin_v == 6) { 844145516Sdarrenr ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; 845145516Sdarrenr ip6->ip6_plen = htons(iclen - hlen); 846145516Sdarrenr ip6->ip6_nxt = IPPROTO_ICMPV6; 847145516Sdarrenr ip6->ip6_hlim = 0; 848145516Sdarrenr ip6->ip6_src = dst6; 849145516Sdarrenr ip6->ip6_dst = fin->fin_src6; 850145516Sdarrenr if (xtra > 0) 851145516Sdarrenr bcopy((char *)fin->fin_ip + ohlen, 852145516Sdarrenr (char *)&icmp->icmp_ip + ohlen, xtra); 853145516Sdarrenr icmp->icmp_cksum = in6_cksum(m, IPPROTO_ICMPV6, 854145516Sdarrenr sizeof(*ip6), iclen - hlen); 855145516Sdarrenr } else 856145516Sdarrenr#endif 857145516Sdarrenr { 858145516Sdarrenr ip2->ip_len = htons(ip2->ip_len); 859145516Sdarrenr ip2->ip_off = htons(ip2->ip_off); 860145516Sdarrenr ip->ip_p = IPPROTO_ICMP; 861145516Sdarrenr ip->ip_src.s_addr = dst4.s_addr; 862145516Sdarrenr ip->ip_dst.s_addr = fin->fin_saddr; 863145516Sdarrenr 864145516Sdarrenr if (xtra > 0) 865145516Sdarrenr bcopy((char *)fin->fin_ip + ohlen, 866145516Sdarrenr (char *)&icmp->icmp_ip + ohlen, xtra); 867145516Sdarrenr icmp->icmp_cksum = ipf_cksum((u_short *)icmp, 868145516Sdarrenr sizeof(*icmp) + 8); 869145516Sdarrenr ip->ip_len = iclen; 870145516Sdarrenr ip->ip_p = IPPROTO_ICMP; 871145516Sdarrenr } 872145516Sdarrenr err = fr_send_ip(fin, m, &m); 873145516Sdarrenr return err; 874145516Sdarrenr} 875145516Sdarrenr 876145516Sdarrenr 877145516Sdarrenr#if !defined(IPFILTER_LKM) && (__FreeBSD_version < 300000) 878145516Sdarrenr# if (BSD < 199306) 879145516Sdarrenrint iplinit __P((void)); 880145516Sdarrenr 881145516Sdarrenrint 882145516Sdarrenr# else 883145516Sdarrenrvoid iplinit __P((void)); 884145516Sdarrenr 885145516Sdarrenrvoid 886145516Sdarrenr# endif 887145516Sdarrenriplinit() 888145516Sdarrenr{ 889170268Sdarrenr if (ipfattach() != 0) 890145516Sdarrenr printf("IP Filter failed to attach\n"); 891145516Sdarrenr ip_init(); 892145516Sdarrenr} 893145516Sdarrenr#endif /* __FreeBSD_version < 300000 */ 894145516Sdarrenr 895145516Sdarrenr 896173181Sdarrenr/* 897173181Sdarrenr * m0 - pointer to mbuf where the IP packet starts 898173181Sdarrenr * mpp - pointer to the mbuf pointer that is the start of the mbuf chain 899173181Sdarrenr */ 900145516Sdarrenrint fr_fastroute(m0, mpp, fin, fdp) 901145516Sdarrenrmb_t *m0, **mpp; 902145516Sdarrenrfr_info_t *fin; 903145516Sdarrenrfrdest_t *fdp; 904145516Sdarrenr{ 905145516Sdarrenr register struct ip *ip, *mhip; 906173181Sdarrenr register struct mbuf *m = *mpp; 907145516Sdarrenr register struct route *ro; 908145516Sdarrenr int len, off, error = 0, hlen, code; 909145516Sdarrenr struct ifnet *ifp, *sifp; 910145516Sdarrenr struct sockaddr_in *dst; 911145516Sdarrenr struct route iproute; 912145516Sdarrenr u_short ip_off; 913145516Sdarrenr frentry_t *fr; 914145516Sdarrenr 915161356Sguido ro = NULL; 916161356Sguido 917145516Sdarrenr#ifdef M_WRITABLE 918145516Sdarrenr /* 919145516Sdarrenr * HOT FIX/KLUDGE: 920145516Sdarrenr * 921145516Sdarrenr * If the mbuf we're about to send is not writable (because of 922145516Sdarrenr * a cluster reference, for example) we'll need to make a copy 923145516Sdarrenr * of it since this routine modifies the contents. 924145516Sdarrenr * 925145516Sdarrenr * If you have non-crappy network hardware that can transmit data 926145516Sdarrenr * from the mbuf, rather than making a copy, this is gonna be a 927145516Sdarrenr * problem. 928145516Sdarrenr */ 929145516Sdarrenr if (M_WRITABLE(m) == 0) { 930161356Sguido m0 = m_dup(m, M_DONTWAIT); 931161356Sguido if (m0 != 0) { 932145516Sdarrenr FREE_MB_T(m); 933145516Sdarrenr m = m0; 934145516Sdarrenr *mpp = m; 935145516Sdarrenr } else { 936145516Sdarrenr error = ENOBUFS; 937145516Sdarrenr FREE_MB_T(m); 938161356Sguido goto done; 939145516Sdarrenr } 940145516Sdarrenr } 941145516Sdarrenr#endif 942145516Sdarrenr 943145516Sdarrenr#ifdef USE_INET6 944145516Sdarrenr if (fin->fin_v == 6) { 945145516Sdarrenr /* 946145516Sdarrenr * currently "to <if>" and "to <if>:ip#" are not supported 947145516Sdarrenr * for IPv6 948145516Sdarrenr */ 949145516Sdarrenr#if (__FreeBSD_version >= 490000) 950145516Sdarrenr return ip6_output(m0, NULL, NULL, 0, NULL, NULL, NULL); 951145516Sdarrenr#else 952145516Sdarrenr return ip6_output(m0, NULL, NULL, 0, NULL, NULL); 953145516Sdarrenr#endif 954145516Sdarrenr } 955145516Sdarrenr#endif 956145516Sdarrenr 957145516Sdarrenr hlen = fin->fin_hlen; 958145516Sdarrenr ip = mtod(m0, struct ip *); 959145516Sdarrenr 960145516Sdarrenr /* 961145516Sdarrenr * Route packet. 962145516Sdarrenr */ 963145516Sdarrenr ro = &iproute; 964145516Sdarrenr bzero((caddr_t)ro, sizeof (*ro)); 965145516Sdarrenr dst = (struct sockaddr_in *)&ro->ro_dst; 966145516Sdarrenr dst->sin_family = AF_INET; 967145516Sdarrenr dst->sin_addr = ip->ip_dst; 968145516Sdarrenr 969145516Sdarrenr fr = fin->fin_fr; 970145516Sdarrenr if (fdp != NULL) 971145516Sdarrenr ifp = fdp->fd_ifp; 972145516Sdarrenr else 973145516Sdarrenr ifp = fin->fin_ifp; 974145516Sdarrenr 975145516Sdarrenr if ((ifp == NULL) && (!fr || !(fr->fr_flags & FR_FASTROUTE))) { 976145516Sdarrenr error = -2; 977145516Sdarrenr goto bad; 978145516Sdarrenr } 979145516Sdarrenr 980161356Sguido if ((fdp != NULL) && (fdp->fd_ip.s_addr != 0)) 981161356Sguido dst->sin_addr = fdp->fd_ip; 982145516Sdarrenr 983145516Sdarrenr dst->sin_len = sizeof(*dst); 984178888Sjulian in_rtalloc(ro, 0); 985145516Sdarrenr 986145516Sdarrenr if ((ifp == NULL) && (ro->ro_rt != NULL)) 987145516Sdarrenr ifp = ro->ro_rt->rt_ifp; 988145516Sdarrenr 989145516Sdarrenr if ((ro->ro_rt == NULL) || (ifp == NULL)) { 990145516Sdarrenr if (in_localaddr(ip->ip_dst)) 991145516Sdarrenr error = EHOSTUNREACH; 992145516Sdarrenr else 993145516Sdarrenr error = ENETUNREACH; 994145516Sdarrenr goto bad; 995145516Sdarrenr } 996145516Sdarrenr if (ro->ro_rt->rt_flags & RTF_GATEWAY) 997145516Sdarrenr dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway; 998145516Sdarrenr if (ro->ro_rt) 999145516Sdarrenr ro->ro_rt->rt_use++; 1000145516Sdarrenr 1001145516Sdarrenr /* 1002145516Sdarrenr * For input packets which are being "fastrouted", they won't 1003145516Sdarrenr * go back through output filtering and miss their chance to get 1004170268Sdarrenr * NAT'd and counted. Duplicated packets aren't considered to be 1005170268Sdarrenr * part of the normal packet stream, so do not NAT them or pass 1006170268Sdarrenr * them through stateful checking, etc. 1007145516Sdarrenr */ 1008170268Sdarrenr if ((fdp != &fr->fr_dif) && (fin->fin_out == 0)) { 1009145516Sdarrenr sifp = fin->fin_ifp; 1010145516Sdarrenr fin->fin_ifp = ifp; 1011145516Sdarrenr fin->fin_out = 1; 1012145516Sdarrenr (void) fr_acctpkt(fin, NULL); 1013145516Sdarrenr fin->fin_fr = NULL; 1014145516Sdarrenr if (!fr || !(fr->fr_flags & FR_RETMASK)) { 1015145516Sdarrenr u_32_t pass; 1016145516Sdarrenr 1017170268Sdarrenr if (fr_checkstate(fin, &pass) != NULL) 1018170268Sdarrenr fr_statederef((ipstate_t **)&fin->fin_state); 1019145516Sdarrenr } 1020145516Sdarrenr 1021145516Sdarrenr switch (fr_checknatout(fin, NULL)) 1022145516Sdarrenr { 1023145516Sdarrenr case 0 : 1024145516Sdarrenr break; 1025145516Sdarrenr case 1 : 1026170268Sdarrenr fr_natderef((nat_t **)&fin->fin_nat); 1027145516Sdarrenr ip->ip_sum = 0; 1028145516Sdarrenr break; 1029145516Sdarrenr case -1 : 1030145516Sdarrenr error = -1; 1031173181Sdarrenr goto bad; 1032145516Sdarrenr break; 1033145516Sdarrenr } 1034145516Sdarrenr 1035145516Sdarrenr fin->fin_ifp = sifp; 1036145516Sdarrenr fin->fin_out = 0; 1037145516Sdarrenr } else 1038145516Sdarrenr ip->ip_sum = 0; 1039145516Sdarrenr /* 1040145516Sdarrenr * If small enough for interface, can just send directly. 1041145516Sdarrenr */ 1042145516Sdarrenr if (ip->ip_len <= ifp->if_mtu) { 1043145516Sdarrenr ip->ip_len = htons(ip->ip_len); 1044145516Sdarrenr ip->ip_off = htons(ip->ip_off); 1045145516Sdarrenr 1046145516Sdarrenr if (!ip->ip_sum) 1047145516Sdarrenr ip->ip_sum = in_cksum(m, hlen); 1048145516Sdarrenr error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst, 1049145516Sdarrenr ro->ro_rt); 1050145516Sdarrenr goto done; 1051145516Sdarrenr } 1052145516Sdarrenr /* 1053145516Sdarrenr * Too large for interface; fragment if possible. 1054145516Sdarrenr * Must be able to put at least 8 bytes per fragment. 1055145516Sdarrenr */ 1056145516Sdarrenr ip_off = ntohs(ip->ip_off); 1057145516Sdarrenr if (ip_off & IP_DF) { 1058145516Sdarrenr error = EMSGSIZE; 1059145516Sdarrenr goto bad; 1060145516Sdarrenr } 1061145516Sdarrenr len = (ifp->if_mtu - hlen) &~ 7; 1062145516Sdarrenr if (len < 8) { 1063145516Sdarrenr error = EMSGSIZE; 1064145516Sdarrenr goto bad; 1065145516Sdarrenr } 1066145516Sdarrenr 1067145516Sdarrenr { 1068145516Sdarrenr int mhlen, firstlen = len; 1069145516Sdarrenr struct mbuf **mnext = &m->m_act; 1070145516Sdarrenr 1071145516Sdarrenr /* 1072145516Sdarrenr * Loop through length of segment after first fragment, 1073145516Sdarrenr * make new header and copy data of each part and link onto chain. 1074145516Sdarrenr */ 1075145516Sdarrenr m0 = m; 1076145516Sdarrenr mhlen = sizeof (struct ip); 1077145516Sdarrenr for (off = hlen + len; off < ip->ip_len; off += len) { 1078145516Sdarrenr#ifdef MGETHDR 1079145516Sdarrenr MGETHDR(m, M_DONTWAIT, MT_HEADER); 1080145516Sdarrenr#else 1081145516Sdarrenr MGET(m, M_DONTWAIT, MT_HEADER); 1082145516Sdarrenr#endif 1083145516Sdarrenr if (m == 0) { 1084145516Sdarrenr m = m0; 1085145516Sdarrenr error = ENOBUFS; 1086145516Sdarrenr goto bad; 1087145516Sdarrenr } 1088145516Sdarrenr m->m_data += max_linkhdr; 1089145516Sdarrenr mhip = mtod(m, struct ip *); 1090145516Sdarrenr bcopy((char *)ip, (char *)mhip, sizeof(*ip)); 1091145516Sdarrenr if (hlen > sizeof (struct ip)) { 1092145516Sdarrenr mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip); 1093145516Sdarrenr IP_HL_A(mhip, mhlen >> 2); 1094145516Sdarrenr } 1095145516Sdarrenr m->m_len = mhlen; 1096145516Sdarrenr mhip->ip_off = ((off - hlen) >> 3) + ip_off; 1097145516Sdarrenr if (off + len >= ip->ip_len) 1098145516Sdarrenr len = ip->ip_len - off; 1099145516Sdarrenr else 1100145516Sdarrenr mhip->ip_off |= IP_MF; 1101145516Sdarrenr mhip->ip_len = htons((u_short)(len + mhlen)); 1102161356Sguido *mnext = m; 1103145516Sdarrenr m->m_next = m_copy(m0, off, len); 1104145516Sdarrenr if (m->m_next == 0) { 1105145516Sdarrenr error = ENOBUFS; /* ??? */ 1106145516Sdarrenr goto sendorfree; 1107145516Sdarrenr } 1108145516Sdarrenr m->m_pkthdr.len = mhlen + len; 1109145516Sdarrenr m->m_pkthdr.rcvif = NULL; 1110145516Sdarrenr mhip->ip_off = htons((u_short)mhip->ip_off); 1111145516Sdarrenr mhip->ip_sum = 0; 1112145516Sdarrenr mhip->ip_sum = in_cksum(m, mhlen); 1113145516Sdarrenr mnext = &m->m_act; 1114145516Sdarrenr } 1115145516Sdarrenr /* 1116145516Sdarrenr * Update first fragment by trimming what's been copied out 1117145516Sdarrenr * and updating header, then send each fragment (in order). 1118145516Sdarrenr */ 1119145516Sdarrenr m_adj(m0, hlen + firstlen - ip->ip_len); 1120145516Sdarrenr ip->ip_len = htons((u_short)(hlen + firstlen)); 1121145516Sdarrenr ip->ip_off = htons((u_short)IP_MF); 1122145516Sdarrenr ip->ip_sum = 0; 1123145516Sdarrenr ip->ip_sum = in_cksum(m0, hlen); 1124145516Sdarrenrsendorfree: 1125145516Sdarrenr for (m = m0; m; m = m0) { 1126145516Sdarrenr m0 = m->m_act; 1127145516Sdarrenr m->m_act = 0; 1128145516Sdarrenr if (error == 0) 1129145516Sdarrenr error = (*ifp->if_output)(ifp, m, 1130145516Sdarrenr (struct sockaddr *)dst, ro->ro_rt); 1131145516Sdarrenr else 1132145516Sdarrenr FREE_MB_T(m); 1133145516Sdarrenr } 1134145516Sdarrenr } 1135145516Sdarrenrdone: 1136145516Sdarrenr if (!error) 1137145516Sdarrenr fr_frouteok[0]++; 1138145516Sdarrenr else 1139145516Sdarrenr fr_frouteok[1]++; 1140145516Sdarrenr 1141161356Sguido if ((ro != NULL) && (ro->ro_rt != NULL)) { 1142145516Sdarrenr RTFREE(ro->ro_rt); 1143145516Sdarrenr } 1144145516Sdarrenr *mpp = NULL; 1145145516Sdarrenr return 0; 1146145516Sdarrenrbad: 1147145516Sdarrenr if (error == EMSGSIZE) { 1148145516Sdarrenr sifp = fin->fin_ifp; 1149145516Sdarrenr code = fin->fin_icode; 1150145516Sdarrenr fin->fin_icode = ICMP_UNREACH_NEEDFRAG; 1151145516Sdarrenr fin->fin_ifp = ifp; 1152145516Sdarrenr (void) fr_send_icmp_err(ICMP_UNREACH, fin, 1); 1153145516Sdarrenr fin->fin_ifp = sifp; 1154145516Sdarrenr fin->fin_icode = code; 1155145516Sdarrenr } 1156145516Sdarrenr FREE_MB_T(m); 1157145516Sdarrenr goto done; 1158145516Sdarrenr} 1159145516Sdarrenr 1160145516Sdarrenr 1161145516Sdarrenrint fr_verifysrc(fin) 1162145516Sdarrenrfr_info_t *fin; 1163145516Sdarrenr{ 1164145516Sdarrenr struct sockaddr_in *dst; 1165145516Sdarrenr struct route iproute; 1166145516Sdarrenr 1167145516Sdarrenr bzero((char *)&iproute, sizeof(iproute)); 1168145516Sdarrenr dst = (struct sockaddr_in *)&iproute.ro_dst; 1169145516Sdarrenr dst->sin_len = sizeof(*dst); 1170145516Sdarrenr dst->sin_family = AF_INET; 1171145516Sdarrenr dst->sin_addr = fin->fin_src; 1172178888Sjulian in_rtalloc(&iproute, 0); 1173145516Sdarrenr if (iproute.ro_rt == NULL) 1174145516Sdarrenr return 0; 1175145516Sdarrenr return (fin->fin_ifp == iproute.ro_rt->rt_ifp); 1176145516Sdarrenr} 1177145516Sdarrenr 1178145516Sdarrenr 1179145516Sdarrenr/* 1180145516Sdarrenr * return the first IP Address associated with an interface 1181145516Sdarrenr */ 1182145516Sdarrenrint fr_ifpaddr(v, atype, ifptr, inp, inpmask) 1183145516Sdarrenrint v, atype; 1184145516Sdarrenrvoid *ifptr; 1185145516Sdarrenrstruct in_addr *inp, *inpmask; 1186145516Sdarrenr{ 1187145516Sdarrenr#ifdef USE_INET6 1188145516Sdarrenr struct in6_addr *inp6 = NULL; 1189145516Sdarrenr#endif 1190145516Sdarrenr struct sockaddr *sock, *mask; 1191145516Sdarrenr struct sockaddr_in *sin; 1192145516Sdarrenr struct ifaddr *ifa; 1193145516Sdarrenr struct ifnet *ifp; 1194145516Sdarrenr 1195145516Sdarrenr if ((ifptr == NULL) || (ifptr == (void *)-1)) 1196145516Sdarrenr return -1; 1197145516Sdarrenr 1198145516Sdarrenr sin = NULL; 1199145516Sdarrenr ifp = ifptr; 1200145516Sdarrenr 1201145516Sdarrenr if (v == 4) 1202145516Sdarrenr inp->s_addr = 0; 1203145516Sdarrenr#ifdef USE_INET6 1204145516Sdarrenr else if (v == 6) 1205145516Sdarrenr bzero((char *)inp, sizeof(struct in6_addr)); 1206145516Sdarrenr#endif 1207145516Sdarrenr#if (__FreeBSD_version >= 300000) 1208145516Sdarrenr ifa = TAILQ_FIRST(&ifp->if_addrhead); 1209145516Sdarrenr#else 1210145516Sdarrenr ifa = ifp->if_addrlist; 1211145516Sdarrenr#endif /* __FreeBSD_version >= 300000 */ 1212145516Sdarrenr 1213145516Sdarrenr sock = ifa->ifa_addr; 1214145516Sdarrenr while (sock != NULL && ifa != NULL) { 1215145516Sdarrenr sin = (struct sockaddr_in *)sock; 1216145516Sdarrenr if ((v == 4) && (sin->sin_family == AF_INET)) 1217145516Sdarrenr break; 1218145516Sdarrenr#ifdef USE_INET6 1219145516Sdarrenr if ((v == 6) && (sin->sin_family == AF_INET6)) { 1220145516Sdarrenr inp6 = &((struct sockaddr_in6 *)sin)->sin6_addr; 1221145516Sdarrenr if (!IN6_IS_ADDR_LINKLOCAL(inp6) && 1222145516Sdarrenr !IN6_IS_ADDR_LOOPBACK(inp6)) 1223145516Sdarrenr break; 1224145516Sdarrenr } 1225145516Sdarrenr#endif 1226145516Sdarrenr#if (__FreeBSD_version >= 300000) 1227145516Sdarrenr ifa = TAILQ_NEXT(ifa, ifa_link); 1228145516Sdarrenr#else 1229145516Sdarrenr ifa = ifa->ifa_next; 1230145516Sdarrenr#endif /* __FreeBSD_version >= 300000 */ 1231145516Sdarrenr if (ifa != NULL) 1232145516Sdarrenr sock = ifa->ifa_addr; 1233145516Sdarrenr } 1234145516Sdarrenr 1235145516Sdarrenr if (ifa == NULL || sin == NULL) 1236145516Sdarrenr return -1; 1237145516Sdarrenr 1238145516Sdarrenr mask = ifa->ifa_netmask; 1239145516Sdarrenr if (atype == FRI_BROADCAST) 1240145516Sdarrenr sock = ifa->ifa_broadaddr; 1241145516Sdarrenr else if (atype == FRI_PEERADDR) 1242145516Sdarrenr sock = ifa->ifa_dstaddr; 1243145516Sdarrenr 1244161356Sguido if (sock == NULL) 1245161356Sguido return -1; 1246161356Sguido 1247145516Sdarrenr#ifdef USE_INET6 1248145516Sdarrenr if (v == 6) { 1249145516Sdarrenr return fr_ifpfillv6addr(atype, (struct sockaddr_in6 *)sock, 1250145516Sdarrenr (struct sockaddr_in6 *)mask, 1251145516Sdarrenr inp, inpmask); 1252145516Sdarrenr } 1253145516Sdarrenr#endif 1254145516Sdarrenr return fr_ifpfillv4addr(atype, (struct sockaddr_in *)sock, 1255145516Sdarrenr (struct sockaddr_in *)mask, inp, inpmask); 1256145516Sdarrenr} 1257145516Sdarrenr 1258145516Sdarrenr 1259145516Sdarrenru_32_t fr_newisn(fin) 1260145516Sdarrenrfr_info_t *fin; 1261145516Sdarrenr{ 1262145516Sdarrenr u_32_t newiss; 1263145516Sdarrenr#if (__FreeBSD_version >= 400000) 1264145516Sdarrenr newiss = arc4random(); 1265145516Sdarrenr#else 1266145516Sdarrenr static iss_seq_off = 0; 1267145516Sdarrenr u_char hash[16]; 1268145516Sdarrenr MD5_CTX ctx; 1269145516Sdarrenr 1270145516Sdarrenr /* 1271145516Sdarrenr * Compute the base value of the ISS. It is a hash 1272145516Sdarrenr * of (saddr, sport, daddr, dport, secret). 1273145516Sdarrenr */ 1274145516Sdarrenr MD5Init(&ctx); 1275145516Sdarrenr 1276145516Sdarrenr MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src, 1277145516Sdarrenr sizeof(fin->fin_fi.fi_src)); 1278145516Sdarrenr MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst, 1279145516Sdarrenr sizeof(fin->fin_fi.fi_dst)); 1280145516Sdarrenr MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat)); 1281145516Sdarrenr 1282145516Sdarrenr MD5Update(&ctx, ipf_iss_secret, sizeof(ipf_iss_secret)); 1283145516Sdarrenr 1284145516Sdarrenr MD5Final(hash, &ctx); 1285145516Sdarrenr 1286145516Sdarrenr memcpy(&newiss, hash, sizeof(newiss)); 1287145516Sdarrenr 1288145516Sdarrenr /* 1289145516Sdarrenr * Now increment our "timer", and add it in to 1290145516Sdarrenr * the computed value. 1291145516Sdarrenr * 1292145516Sdarrenr * XXX Use `addin'? 1293145516Sdarrenr * XXX TCP_ISSINCR too large to use? 1294145516Sdarrenr */ 1295145516Sdarrenr iss_seq_off += 0x00010000; 1296145516Sdarrenr newiss += iss_seq_off; 1297145516Sdarrenr#endif 1298145516Sdarrenr return newiss; 1299145516Sdarrenr} 1300145516Sdarrenr 1301145516Sdarrenr 1302145516Sdarrenr/* ------------------------------------------------------------------------ */ 1303145516Sdarrenr/* Function: fr_nextipid */ 1304145516Sdarrenr/* Returns: int - 0 == success, -1 == error (packet should be droppped) */ 1305145516Sdarrenr/* Parameters: fin(I) - pointer to packet information */ 1306145516Sdarrenr/* */ 1307145516Sdarrenr/* Returns the next IPv4 ID to use for this packet. */ 1308145516Sdarrenr/* ------------------------------------------------------------------------ */ 1309145516Sdarrenru_short fr_nextipid(fin) 1310145516Sdarrenrfr_info_t *fin; 1311145516Sdarrenr{ 1312145516Sdarrenr#ifndef RANDOM_IP_ID 1313145516Sdarrenr static u_short ipid = 0; 1314145516Sdarrenr u_short id; 1315145516Sdarrenr 1316145516Sdarrenr MUTEX_ENTER(&ipf_rw); 1317145516Sdarrenr id = ipid++; 1318145516Sdarrenr MUTEX_EXIT(&ipf_rw); 1319145516Sdarrenr#else 1320145516Sdarrenr u_short id; 1321145516Sdarrenr 1322145516Sdarrenr id = ip_randomid(); 1323145516Sdarrenr#endif 1324145516Sdarrenr 1325145516Sdarrenr return id; 1326145516Sdarrenr} 1327145516Sdarrenr 1328145516Sdarrenr 1329145516SdarrenrINLINE void fr_checkv4sum(fin) 1330145516Sdarrenrfr_info_t *fin; 1331145516Sdarrenr{ 1332145516Sdarrenr#ifdef CSUM_DATA_VALID 1333145516Sdarrenr int manual = 0; 1334145516Sdarrenr u_short sum; 1335145516Sdarrenr ip_t *ip; 1336145516Sdarrenr mb_t *m; 1337145516Sdarrenr 1338145516Sdarrenr if ((fin->fin_flx & FI_NOCKSUM) != 0) 1339145516Sdarrenr return; 1340145516Sdarrenr 1341172776Sdarrenr if (fin->fin_cksum != 0) 1342172776Sdarrenr return; 1343172776Sdarrenr 1344145516Sdarrenr m = fin->fin_m; 1345145516Sdarrenr if (m == NULL) { 1346145516Sdarrenr manual = 1; 1347145516Sdarrenr goto skipauto; 1348145516Sdarrenr } 1349145516Sdarrenr ip = fin->fin_ip; 1350145516Sdarrenr 1351145516Sdarrenr if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) { 1352145516Sdarrenr if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) 1353145516Sdarrenr sum = m->m_pkthdr.csum_data; 1354145516Sdarrenr else 1355145516Sdarrenr sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, 1356145516Sdarrenr htonl(m->m_pkthdr.csum_data + 1357145516Sdarrenr fin->fin_ip->ip_len + fin->fin_p)); 1358145516Sdarrenr sum ^= 0xffff; 1359172776Sdarrenr if (sum != 0) { 1360145516Sdarrenr fin->fin_flx |= FI_BAD; 1361172776Sdarrenr fin->fin_cksum = -1; 1362172776Sdarrenr } else { 1363172776Sdarrenr fin->fin_cksum = 1; 1364172776Sdarrenr } 1365145516Sdarrenr } else 1366145516Sdarrenr manual = 1; 1367145516Sdarrenrskipauto: 1368145516Sdarrenr# ifdef IPFILTER_CKSUM 1369145516Sdarrenr if (manual != 0) 1370145516Sdarrenr if (fr_checkl4sum(fin) == -1) 1371145516Sdarrenr fin->fin_flx |= FI_BAD; 1372145516Sdarrenr# else 1373145516Sdarrenr ; 1374145516Sdarrenr# endif 1375145516Sdarrenr#else 1376145516Sdarrenr# ifdef IPFILTER_CKSUM 1377145516Sdarrenr if (fr_checkl4sum(fin) == -1) 1378145516Sdarrenr fin->fin_flx |= FI_BAD; 1379145516Sdarrenr# endif 1380145516Sdarrenr#endif 1381145516Sdarrenr} 1382145516Sdarrenr 1383145516Sdarrenr 1384145516Sdarrenr#ifdef USE_INET6 1385145516SdarrenrINLINE void fr_checkv6sum(fin) 1386145516Sdarrenrfr_info_t *fin; 1387145516Sdarrenr{ 1388145516Sdarrenr# ifdef IPFILTER_CKSUM 1389145516Sdarrenr if (fr_checkl4sum(fin) == -1) 1390145516Sdarrenr fin->fin_flx |= FI_BAD; 1391145516Sdarrenr# endif 1392145516Sdarrenr} 1393145516Sdarrenr#endif /* USE_INET6 */ 1394145516Sdarrenr 1395145516Sdarrenr 1396145516Sdarrenrsize_t mbufchainlen(m0) 1397145516Sdarrenrstruct mbuf *m0; 1398145516Sdarrenr{ 1399145516Sdarrenr size_t len; 1400145516Sdarrenr 1401145516Sdarrenr if ((m0->m_flags & M_PKTHDR) != 0) { 1402145516Sdarrenr len = m0->m_pkthdr.len; 1403145516Sdarrenr } else { 1404145516Sdarrenr struct mbuf *m; 1405145516Sdarrenr 1406145516Sdarrenr for (m = m0, len = 0; m != NULL; m = m->m_next) 1407145516Sdarrenr len += m->m_len; 1408145516Sdarrenr } 1409145516Sdarrenr return len; 1410145516Sdarrenr} 1411145516Sdarrenr 1412145516Sdarrenr 1413145516Sdarrenr/* ------------------------------------------------------------------------ */ 1414145516Sdarrenr/* Function: fr_pullup */ 1415145516Sdarrenr/* Returns: NULL == pullup failed, else pointer to protocol header */ 1416145516Sdarrenr/* Parameters: m(I) - pointer to buffer where data packet starts */ 1417145516Sdarrenr/* fin(I) - pointer to packet information */ 1418145516Sdarrenr/* len(I) - number of bytes to pullup */ 1419145516Sdarrenr/* */ 1420145516Sdarrenr/* Attempt to move at least len bytes (from the start of the buffer) into a */ 1421145516Sdarrenr/* single buffer for ease of access. Operating system native functions are */ 1422145516Sdarrenr/* used to manage buffers - if necessary. If the entire packet ends up in */ 1423145516Sdarrenr/* a single buffer, set the FI_COALESCE flag even though fr_coalesce() has */ 1424145516Sdarrenr/* not been called. Both fin_ip and fin_dp are updated before exiting _IF_ */ 1425145516Sdarrenr/* and ONLY if the pullup succeeds. */ 1426145516Sdarrenr/* */ 1427145516Sdarrenr/* We assume that 'min' is a pointer to a buffer that is part of the chain */ 1428145516Sdarrenr/* of buffers that starts at *fin->fin_mp. */ 1429145516Sdarrenr/* ------------------------------------------------------------------------ */ 1430145516Sdarrenrvoid *fr_pullup(min, fin, len) 1431145516Sdarrenrmb_t *min; 1432145516Sdarrenrfr_info_t *fin; 1433145516Sdarrenrint len; 1434145516Sdarrenr{ 1435145516Sdarrenr int out = fin->fin_out, dpoff, ipoff; 1436145516Sdarrenr mb_t *m = min; 1437145516Sdarrenr char *ip; 1438145516Sdarrenr 1439145516Sdarrenr if (m == NULL) 1440145516Sdarrenr return NULL; 1441145516Sdarrenr 1442145516Sdarrenr ip = (char *)fin->fin_ip; 1443145516Sdarrenr if ((fin->fin_flx & FI_COALESCE) != 0) 1444145516Sdarrenr return ip; 1445145516Sdarrenr 1446145516Sdarrenr ipoff = fin->fin_ipoff; 1447145516Sdarrenr if (fin->fin_dp != NULL) 1448145516Sdarrenr dpoff = (char *)fin->fin_dp - (char *)ip; 1449145516Sdarrenr else 1450145516Sdarrenr dpoff = 0; 1451145516Sdarrenr 1452145516Sdarrenr if (M_LEN(m) < len) { 1453145516Sdarrenr#ifdef MHLEN 1454145516Sdarrenr /* 1455145516Sdarrenr * Assume that M_PKTHDR is set and just work with what is left 1456145516Sdarrenr * rather than check.. 1457145516Sdarrenr * Should not make any real difference, anyway. 1458145516Sdarrenr */ 1459145516Sdarrenr if (len > MHLEN) 1460145516Sdarrenr#else 1461145516Sdarrenr if (len > MLEN) 1462145516Sdarrenr#endif 1463145516Sdarrenr { 1464145516Sdarrenr#ifdef HAVE_M_PULLDOWN 1465145516Sdarrenr if (m_pulldown(m, 0, len, NULL) == NULL) 1466145516Sdarrenr m = NULL; 1467145516Sdarrenr#else 1468145516Sdarrenr FREE_MB_T(*fin->fin_mp); 1469145516Sdarrenr m = NULL; 1470145516Sdarrenr#endif 1471145516Sdarrenr } else 1472145516Sdarrenr { 1473145516Sdarrenr m = m_pullup(m, len); 1474145516Sdarrenr } 1475145516Sdarrenr *fin->fin_mp = m; 1476145516Sdarrenr if (m == NULL) { 1477172776Sdarrenr fin->fin_m = NULL; 1478145516Sdarrenr ATOMIC_INCL(frstats[out].fr_pull[1]); 1479145516Sdarrenr return NULL; 1480145516Sdarrenr } 1481172776Sdarrenr 1482172776Sdarrenr while (M_LEN(m) == 0) { 1483172776Sdarrenr m = m->m_next; 1484172776Sdarrenr } 1485172776Sdarrenr fin->fin_m = m; 1486145516Sdarrenr ip = MTOD(m, char *) + ipoff; 1487145516Sdarrenr } 1488145516Sdarrenr 1489145516Sdarrenr ATOMIC_INCL(frstats[out].fr_pull[0]); 1490145516Sdarrenr fin->fin_ip = (ip_t *)ip; 1491145516Sdarrenr if (fin->fin_dp != NULL) 1492145516Sdarrenr fin->fin_dp = (char *)fin->fin_ip + dpoff; 1493145516Sdarrenr 1494145516Sdarrenr if (len == fin->fin_plen) 1495145516Sdarrenr fin->fin_flx |= FI_COALESCE; 1496145516Sdarrenr return ip; 1497145516Sdarrenr} 1498170268Sdarrenr 1499170268Sdarrenr 1500170268Sdarrenrint ipf_inject(fin, m) 1501170268Sdarrenrfr_info_t *fin; 1502170268Sdarrenrmb_t *m; 1503170268Sdarrenr{ 1504170268Sdarrenr int error = 0; 1505170268Sdarrenr 1506170268Sdarrenr if (fin->fin_out == 0) { 1507170268Sdarrenr#if (__FreeBSD_version >= 501000) 1508170268Sdarrenr netisr_dispatch(NETISR_IP, m); 1509170268Sdarrenr#else 1510170268Sdarrenr struct ifqueue *ifq; 1511170268Sdarrenr 1512170268Sdarrenr ifq = &ipintrq; 1513170268Sdarrenr 1514170268Sdarrenr# ifdef _IF_QFULL 1515170268Sdarrenr if (_IF_QFULL(ifq)) 1516170268Sdarrenr# else 1517170268Sdarrenr if (IF_QFULL(ifq)) 1518170268Sdarrenr# endif 1519170268Sdarrenr { 1520170268Sdarrenr# ifdef _IF_DROP 1521170268Sdarrenr _IF_DROP(ifq); 1522170268Sdarrenr# else 1523170268Sdarrenr IF_DROP(ifq); 1524170268Sdarrenr# endif 1525170268Sdarrenr FREE_MB_T(m); 1526170268Sdarrenr error = ENOBUFS; 1527170268Sdarrenr } else { 1528170268Sdarrenr IF_ENQUEUE(ifq, m); 1529170268Sdarrenr } 1530170268Sdarrenr#endif 1531170268Sdarrenr } else { 1532173931Sdarrenr fin->fin_ip->ip_len = ntohs(fin->fin_ip->ip_len); 1533173931Sdarrenr fin->fin_ip->ip_off = ntohs(fin->fin_ip->ip_off); 1534170268Sdarrenr#if (__FreeBSD_version >= 470102) 1535170268Sdarrenr error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL); 1536170268Sdarrenr#else 1537170268Sdarrenr error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL); 1538170268Sdarrenr#endif 1539170268Sdarrenr } 1540170268Sdarrenr 1541170268Sdarrenr return error; 1542170268Sdarrenr} 1543172776Sdarrenr 1544172776Sdarrenrint ipf_pfil_unhook(void) { 1545172776Sdarrenr#if defined(NETBSD_PF) && (__FreeBSD_version >= 500011) 1546172776Sdarrenr# if __FreeBSD_version >= 501108 1547172776Sdarrenr struct pfil_head *ph_inet; 1548172776Sdarrenr# ifdef USE_INET6 1549172776Sdarrenr struct pfil_head *ph_inet6; 1550172776Sdarrenr# endif 1551172776Sdarrenr# endif 1552172776Sdarrenr#endif 1553172776Sdarrenr 1554172776Sdarrenr#ifdef NETBSD_PF 1555172776Sdarrenr# if (__FreeBSD_version >= 500011) 1556172776Sdarrenr# if (__FreeBSD_version >= 501108) 1557172776Sdarrenr ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); 1558172776Sdarrenr if (ph_inet != NULL) 1559172776Sdarrenr pfil_remove_hook((void *)fr_check_wrapper, NULL, 1560172776Sdarrenr PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet); 1561172776Sdarrenr# else 1562172776Sdarrenr pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK, 1563172776Sdarrenr &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); 1564172776Sdarrenr# endif 1565172776Sdarrenr# else 1566172776Sdarrenr pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK); 1567172776Sdarrenr# endif 1568172776Sdarrenr# ifdef USE_INET6 1569172776Sdarrenr# if (__FreeBSD_version >= 501108) 1570172776Sdarrenr ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6); 1571172776Sdarrenr if (ph_inet6 != NULL) 1572172776Sdarrenr pfil_remove_hook((void *)fr_check_wrapper6, NULL, 1573172776Sdarrenr PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet6); 1574172776Sdarrenr# else 1575172776Sdarrenr pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK, 1576172776Sdarrenr &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh); 1577172776Sdarrenr# endif 1578172776Sdarrenr# endif 1579172776Sdarrenr#endif 1580172776Sdarrenr 1581172776Sdarrenr return (0); 1582172776Sdarrenr} 1583172776Sdarrenr 1584172776Sdarrenrint ipf_pfil_hook(void) { 1585172776Sdarrenr#if defined(NETBSD_PF) && (__FreeBSD_version >= 500011) 1586172776Sdarrenr# if __FreeBSD_version >= 501108 1587172776Sdarrenr struct pfil_head *ph_inet; 1588172776Sdarrenr# ifdef USE_INET6 1589172776Sdarrenr struct pfil_head *ph_inet6; 1590172776Sdarrenr# endif 1591172776Sdarrenr# endif 1592172776Sdarrenr#endif 1593172776Sdarrenr 1594172776Sdarrenr# ifdef NETBSD_PF 1595172776Sdarrenr# if __FreeBSD_version >= 500011 1596172776Sdarrenr# if __FreeBSD_version >= 501108 1597172776Sdarrenr ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); 1598172776Sdarrenr# ifdef USE_INET6 1599172776Sdarrenr ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6); 1600172776Sdarrenr# endif 1601172776Sdarrenr if (ph_inet == NULL 1602172776Sdarrenr# ifdef USE_INET6 1603172776Sdarrenr && ph_inet6 == NULL 1604172776Sdarrenr# endif 1605172776Sdarrenr ) 1606172776Sdarrenr return ENODEV; 1607172776Sdarrenr 1608172776Sdarrenr if (ph_inet != NULL) 1609172776Sdarrenr pfil_add_hook((void *)fr_check_wrapper, NULL, 1610172776Sdarrenr PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet); 1611172776Sdarrenr# else 1612172776Sdarrenr pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK, 1613172776Sdarrenr &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); 1614172776Sdarrenr# endif 1615172776Sdarrenr# else 1616172776Sdarrenr pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK); 1617172776Sdarrenr# endif 1618172776Sdarrenr# ifdef USE_INET6 1619172776Sdarrenr# if __FreeBSD_version >= 501108 1620172776Sdarrenr if (ph_inet6 != NULL) 1621172776Sdarrenr pfil_add_hook((void *)fr_check_wrapper6, NULL, 1622172776Sdarrenr PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet6); 1623172776Sdarrenr# else 1624172776Sdarrenr pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK, 1625172776Sdarrenr &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh); 1626172776Sdarrenr# endif 1627172776Sdarrenr# endif 1628172776Sdarrenr# endif 1629172776Sdarrenr return (0); 1630172776Sdarrenr} 1631172776Sdarrenr 1632172776Sdarrenrvoid 1633172776Sdarrenripf_event_reg(void) 1634172776Sdarrenr{ 1635172776Sdarrenr#if (__FreeBSD_version >= 502103) 1636172776Sdarrenr ipf_arrivetag = EVENTHANDLER_REGISTER(ifnet_arrival_event, \ 1637172776Sdarrenr ipf_ifevent, NULL, \ 1638172776Sdarrenr EVENTHANDLER_PRI_ANY); 1639172776Sdarrenr ipf_departtag = EVENTHANDLER_REGISTER(ifnet_departure_event, \ 1640172776Sdarrenr ipf_ifevent, NULL, \ 1641172776Sdarrenr EVENTHANDLER_PRI_ANY); 1642172776Sdarrenr ipf_clonetag = EVENTHANDLER_REGISTER(if_clone_event, ipf_ifevent, \ 1643172776Sdarrenr NULL, EVENTHANDLER_PRI_ANY); 1644172776Sdarrenr#endif 1645172776Sdarrenr} 1646172776Sdarrenr 1647172776Sdarrenrvoid 1648172776Sdarrenripf_event_dereg(void) 1649172776Sdarrenr{ 1650172776Sdarrenr#if (__FreeBSD_version >= 502103) 1651172776Sdarrenr if (ipf_arrivetag != NULL) { 1652172776Sdarrenr EVENTHANDLER_DEREGISTER(ifnet_arrival_event, ipf_arrivetag); 1653172776Sdarrenr } 1654172776Sdarrenr if (ipf_departtag != NULL) { 1655172776Sdarrenr EVENTHANDLER_DEREGISTER(ifnet_departure_event, ipf_departtag); 1656172776Sdarrenr } 1657172776Sdarrenr if (ipf_clonetag != NULL) { 1658172776Sdarrenr EVENTHANDLER_DEREGISTER(if_clone_event, ipf_clonetag); 1659172776Sdarrenr } 1660172776Sdarrenr#endif 1661172776Sdarrenr} 1662