ip_fil_freebsd.c revision 161356
1190501Smr/* $FreeBSD: head/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c 161356 2006-08-16 12:06:35Z guido $ */ 2190501Smr 3190501Smr/* 4190501Smr * Copyright (C) 1993-2003 by Darren Reed. 5190501Smr * 6190501Smr * See the IPFILTER.LICENCE file for details on licencing. 7190501Smr */ 8190501Smr#if !defined(lint) 9190501Smrstatic const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed"; 10190501Smrstatic const char rcsid[] = "@(#)$Id: ip_fil_freebsd.c,v 2.53.2.32 2006/03/25 13:03:01 darrenr Exp $"; 11190521Smr#endif 12190501Smr 13190501Smr#if defined(KERNEL) || defined(_KERNEL) 14190501Smr# undef KERNEL 15190501Smr# undef _KERNEL 16190501Smr# define KERNEL 1 17190501Smr# define _KERNEL 1 18190501Smr#endif 19190501Smr#if defined(__FreeBSD_version) && (__FreeBSD_version >= 400000) && \ 20190501Smr !defined(KLD_MODULE) && !defined(IPFILTER_LKM) 21190501Smr# include "opt_inet6.h" 22190501Smr#endif 23190501Smr#if defined(__FreeBSD_version) && (__FreeBSD_version >= 440000) && \ 24190501Smr !defined(KLD_MODULE) && !defined(IPFILTER_LKM) 25190501Smr# include "opt_random_ip_id.h" 26190501Smr#endif 27190501Smr#include <sys/param.h> 28190501Smr#if defined(__FreeBSD__) && !defined(__FreeBSD_version) 29190501Smr# if defined(IPFILTER_LKM) 30190501Smr# ifndef __FreeBSD_cc_version 31190501Smr# include <osreldate.h> 32190501Smr# else 33190501Smr# if __FreeBSD_cc_version < 430000 34190501Smr# include <osreldate.h> 35190501Smr# endif 36190501Smr# endif 37190501Smr# endif 38190501Smr#endif 39190501Smr#include <sys/errno.h> 40190501Smr#include <sys/types.h> 41190501Smr#include <sys/file.h> 42190501Smr#if __FreeBSD_version >= 220000 43190501Smr# include <sys/fcntl.h> 44190501Smr# include <sys/filio.h> 45190501Smr#else 46190501Smr# include <sys/ioctl.h> 47190501Smr#endif 48190501Smr#include <sys/time.h> 49190501Smr#include <sys/systm.h> 50190501Smr#if (__FreeBSD_version >= 300000) 51190501Smr# include <sys/dirent.h> 52190501Smr#else 53190501Smr# include <sys/dir.h> 54190501Smr#endif 55190501Smr#if !defined(__hpux) 56190501Smr# include <sys/mbuf.h> 57190501Smr#endif 58190501Smr#include <sys/protosw.h> 59190501Smr#include <sys/socket.h> 60190501Smr#include <sys/selinfo.h> 61190501Smr 62190501Smr#include <net/if.h> 63190501Smr#if __FreeBSD_version >= 300000 64193530Sjkim# include <net/if_var.h> 65193530Sjkim# if !defined(IPFILTER_LKM) 66190501Smr# include "opt_ipfilter.h" 67190501Smr# endif 68190501Smr#endif 69190501Smr#include <net/route.h> 70190501Smr#include <netinet/in.h> 71190501Smr#include <netinet/in_var.h> 72190501Smr#include <netinet/in_systm.h> 73190501Smr#include <netinet/ip.h> 74190501Smr#include <netinet/ip_var.h> 75190501Smr#include <netinet/tcp.h> 76190501Smr#if defined(__osf__) 77190501Smr# include <netinet/tcp_timer.h> 78190501Smr#endif 79190501Smr#include <netinet/udp.h> 80190501Smr#include <netinet/tcpip.h> 81190501Smr#include <netinet/ip_icmp.h> 82190501Smr#ifndef _KERNEL 83190501Smr# include "netinet/ipf.h" 84190501Smr#endif 85190501Smr#include "netinet/ip_compat.h" 86190501Smr#ifdef USE_INET6 87190501Smr# include <netinet/icmp6.h> 88190501Smr#endif 89190501Smr#include "netinet/ip_fil.h" 90190501Smr#include "netinet/ip_nat.h" 91190501Smr#include "netinet/ip_frag.h" 92190501Smr#include "netinet/ip_state.h" 93190501Smr#include "netinet/ip_proxy.h" 94190501Smr#include "netinet/ip_auth.h" 95190501Smr#ifdef IPFILTER_SYNC 96190501Smr#include "netinet/ip_sync.h" 97190501Smr#endif 98190501Smr#ifdef IPFILTER_SCAN 99190501Smr#include "netinet/ip_scan.h" 100190501Smr#endif 101190501Smr#include "netinet/ip_pool.h" 102190501Smr#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) 103190501Smr# include <sys/malloc.h> 104190501Smr#endif 105190501Smr#include <sys/kernel.h> 106190501Smr#ifdef CSUM_DATA_VALID 107190501Smr#include <machine/in_cksum.h> 108190501Smr#endif 109190501Smrextern int ip_optcopy __P((struct ip *, struct ip *)); 110190501Smr 111190501Smr#if (__FreeBSD_version > 460000) 112190501Smrextern int path_mtu_discovery; 113190501Smr#endif 114190501Smr 115190501Smr# ifdef IPFILTER_M_IPFILTER 116190501SmrMALLOC_DEFINE(M_IPFILTER, "ipfilter", "IP Filter packet filter data structures"); 117190501Smr# endif 118190501Smr 119190501Smr 120190501Smr#if !defined(__osf__) 121215131Savgextern struct protosw inetsw[]; 122190501Smr#endif 123215131Savg 124190501Smrstatic int (*fr_savep) __P((ip_t *, int, void *, int, struct mbuf **)); 125190501Smrstatic int fr_send_ip __P((fr_info_t *, mb_t *, mb_t **)); 126190501Smr# ifdef USE_MUTEXES 127190501Smripfmutex_t ipl_mutex, ipf_authmx, ipf_rw, ipf_stinsert; 128190501Smripfmutex_t ipf_nat_new, ipf_natio, ipf_timeoutlock; 129190501Smripfrwlock_t ipf_mutex, ipf_global, ipf_ipidfrag, ipf_frcache; 130190501Smripfrwlock_t ipf_frag, ipf_state, ipf_nat, ipf_natfrag, ipf_auth; 131190501Smr# endif 132190501Smrint ipf_locks_done = 0; 133190501Smr 134190501Smr#if (__FreeBSD_version >= 300000) 135190501Smrstruct callout_handle fr_slowtimer_ch; 136190501Smr#endif 137190501Smrstruct selinfo ipfselwait[IPL_LOGSIZE]; 138190501Smr 139190501Smr#if (__FreeBSD_version >= 500011) 140190501Smr# include <sys/conf.h> 141190501Smr# if defined(NETBSD_PF) 142190501Smr# include <net/pfil.h> 143190501Smr# include <netinet/ipprotosw.h> 144190501Smr/* 145190501Smr * We provide the fr_checkp name just to minimize changes later. 146190501Smr */ 147190501Smrint (*fr_checkp) __P((ip_t *ip, int hlen, void *ifp, int out, mb_t **mp)); 148190501Smr# endif /* NETBSD_PF */ 149190501Smr#endif /* __FreeBSD_version >= 500011 */ 150190501Smr 151190501Smr 152190501Smr#if (__FreeBSD_version >= 502103) 153190501Smrstatic eventhandler_tag ipf_arrivetag, ipf_departtag, ipf_clonetag; 154190501Smr 155190501Smrstatic void ipf_ifevent(void *arg); 156190501Smr 157190501Smrstatic void ipf_ifevent(arg) 158190501Smrvoid *arg; 159190501Smr{ 160190501Smr frsync(NULL); 161190501Smr} 162190501Smr#endif 163190501Smr 164190501Smr 165190501Smr#if (__FreeBSD_version >= 501108) && defined(_KERNEL) 166190501Smr 167190501Smrstatic int 168190501Smrfr_check_wrapper(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir) 169190501Smr{ 170190501Smr struct ip *ip = mtod(*mp, struct ip *); 171190501Smr return fr_check(ip, ip->ip_hl << 2, ifp, (dir == PFIL_OUT), mp); 172190501Smr} 173190501Smr 174190501Smr# ifdef USE_INET6 175215398Savg# include <netinet/ip6.h> 176190501Smr 177215398Savgstatic int 178215398Savgfr_check_wrapper6(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir) 179215398Savg{ 180190501Smr return (fr_check(mtod(*mp, struct ip *), sizeof(struct ip6_hdr), 181215398Savg ifp, (dir == PFIL_OUT), mp)); 182190501Smr} 183190501Smr# endif 184190501Smr#endif /* __FreeBSD_version >= 501108 */ 185190501Smr#if defined(IPFILTER_LKM) 186190501Smrint iplidentify(s) 187190501Smrchar *s; 188190501Smr{ 189190501Smr if (strcmp(s, "ipl") == 0) 190190501Smr return 1; 191190501Smr return 0; 192190501Smr} 193190501Smr#endif /* IPFILTER_LKM */ 194190501Smr 195190501Smr 196190501Smrint iplattach() 197190501Smr{ 198190501Smr#ifdef USE_SPL 199190501Smr int s; 200190501Smr#endif 201190501Smr#if defined(NETBSD_PF) && (__FreeBSD_version >= 500011) 202190501Smr int error = 0; 203190501Smr# if __FreeBSD_version >= 501108 204215398Savg struct pfil_head *ph_inet; 205215398Savg# ifdef USE_INET6 206215398Savg struct pfil_head *ph_inet6; 207190501Smr# endif 208190501Smr# endif 209190501Smr#endif 210190501Smr 211190501Smr SPL_NET(s); 212190501Smr if (fr_running > 0) { 213190501Smr SPL_X(s); 214190501Smr return EBUSY; 215190501Smr } 216190501Smr 217190501Smr MUTEX_INIT(&ipf_rw, "ipf rw mutex"); 218190501Smr RWLOCK_INIT(&ipf_global, "ipf filter load/unload mutex"); 219190501Smr MUTEX_INIT(&ipf_timeoutlock, "ipf timeout queue mutex"); 220190501Smr RWLOCK_INIT(&ipf_mutex, "ipf filter rwlock"); 221190501Smr RWLOCK_INIT(&ipf_frcache, "ipf cache rwlock"); 222190501Smr RWLOCK_INIT(&ipf_ipidfrag, "ipf IP NAT-Frag rwlock"); 223190501Smr ipf_locks_done = 1; 224190501Smr 225190501Smr if (fr_initialise() < 0) { 226190501Smr SPL_X(s); 227190501Smr return EIO; 228190501Smr } 229190501Smr 230190501Smr 231190501Smr# ifdef NETBSD_PF 232190501Smr# if __FreeBSD_version >= 500011 233190501Smr# if __FreeBSD_version >= 501108 234190501Smr ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); 235190501Smr# ifdef USE_INET6 236190501Smr ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6); 237190501Smr# endif 238190501Smr if (ph_inet == NULL 239190501Smr# ifdef USE_INET6 240190501Smr && ph_inet6 == NULL 241190501Smr# endif 242190501Smr ) 243190501Smr return ENODEV; 244190501Smr 245190501Smr if (ph_inet != NULL) 246190501Smr error = pfil_add_hook((void *)fr_check_wrapper, NULL, 247190501Smr PFIL_IN|PFIL_OUT, ph_inet); 248190501Smr else 249190501Smr error = 0; 250190501Smr# else 251190501Smr error = pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT, 252190501Smr &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); 253190501Smr# endif 254190501Smr if (error) { 255190501Smr# ifdef USE_INET6 256190501Smr goto pfil_error; 257190501Smr# else 258190501Smr fr_deinitialise(); 259190501Smr SPL_X(s); 260190501Smr return error; 261190501Smr# endif 262190501Smr } 263190501Smr# else 264190501Smr pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT); 265190501Smr# endif 266190501Smr# ifdef USE_INET6 267190501Smr# if __FreeBSD_version >= 501108 268190501Smr if (ph_inet6 != NULL) 269190501Smr error = pfil_add_hook((void *)fr_check_wrapper6, NULL, 270190501Smr PFIL_IN|PFIL_OUT, ph_inet6); 271190501Smr else 272190501Smr error = 0; 273190501Smr if (error) { 274190501Smr pfil_remove_hook((void *)fr_check_wrapper6, NULL, 275190501Smr PFIL_IN|PFIL_OUT, ph_inet6); 276190501Smr# else 277190501Smr error = pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT, 278190501Smr &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh); 279190501Smr if (error) { 280190501Smr pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT, 281190501Smr &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); 282190501Smr# endif 283190501Smrpfil_error: 284190501Smr fr_deinitialise(); 285190501Smr SPL_X(s); 286190501Smr return error; 287190501Smr } 288190501Smr# endif 289190501Smr# endif 290190501Smr 291190501Smr#if (__FreeBSD_version >= 502103) 292190501Smr ipf_arrivetag = EVENTHANDLER_REGISTER(ifnet_arrival_event, \ 293190501Smr ipf_ifevent, NULL, \ 294190501Smr EVENTHANDLER_PRI_ANY); 295190501Smr ipf_departtag = EVENTHANDLER_REGISTER(ifnet_departure_event, \ 296197070Sjkim ipf_ifevent, NULL, \ 297190501Smr EVENTHANDLER_PRI_ANY); 298190501Smr ipf_clonetag = EVENTHANDLER_REGISTER(if_clone_event, ipf_ifevent, \ 299190501Smr NULL, EVENTHANDLER_PRI_ANY); 300190501Smr#endif 301190501Smr 302190501Smr if (fr_checkp != fr_check) { 303190501Smr fr_savep = fr_checkp; 304190501Smr fr_checkp = fr_check; 305190501Smr } 306190501Smr 307190501Smr bzero((char *)ipfselwait, sizeof(ipfselwait)); 308190501Smr bzero((char *)frcache, sizeof(frcache)); 309190501Smr fr_running = 1; 310192029Sbrueffer 311190501Smr if (fr_control_forwarding & 1) 312190501Smr ipforwarding = 1; 313190501Smr 314190501Smr SPL_X(s); 315190501Smr#if (__FreeBSD_version >= 300000) 316190501Smr fr_slowtimer_ch = timeout(fr_slowtimer, NULL, 317190501Smr (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT); 318190501Smr#else 319190501Smr timeout(fr_slowtimer, NULL, (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT); 320190501Smr#endif 321190501Smr return 0; 322190501Smr} 323190501Smr 324190501Smr 325190501Smr/* 326190501Smr * Disable the filter by removing the hooks from the IP input/output 327190501Smr * stream. 328190501Smr */ 329190501Smrint ipldetach() 330190501Smr{ 331190501Smr#ifdef USE_SPL 332190501Smr int s; 333190501Smr#endif 334190501Smr#if defined(NETBSD_PF) && (__FreeBSD_version >= 500011) 335190501Smr int error = 0; 336190501Smr# if __FreeBSD_version >= 501108 337190501Smr struct pfil_head *ph_inet; 338190501Smr# ifdef USE_INET6 339190501Smr struct pfil_head *ph_inet6; 340190501Smr# endif 341190501Smr# endif 342190501Smr#endif 343190501Smr 344190501Smr if (fr_control_forwarding & 2) 345190501Smr ipforwarding = 0; 346190501Smr 347190501Smr#if (__FreeBSD_version >= 502103) 348190501Smr if (ipf_arrivetag != NULL) { 349190501Smr EVENTHANDLER_DEREGISTER(ifnet_arrival_event, ipf_arrivetag); 350190501Smr } 351190501Smr if (ipf_departtag != NULL) { 352190501Smr EVENTHANDLER_DEREGISTER(ifnet_departure_event, ipf_departtag); 353190501Smr } 354190501Smr if (ipf_clonetag != NULL) { 355190501Smr EVENTHANDLER_DEREGISTER(if_clone_event, ipf_clonetag); 356190501Smr } 357190501Smr#endif 358190501Smr 359190501Smr SPL_NET(s); 360190501Smr 361190501Smr#if (__FreeBSD_version >= 300000) 362190501Smr if (fr_slowtimer_ch.callout != NULL) 363190501Smr untimeout(fr_slowtimer, NULL, fr_slowtimer_ch); 364190501Smr bzero(&fr_slowtimer_ch, sizeof(fr_slowtimer_ch)); 365190501Smr#else 366190501Smr untimeout(fr_slowtimer, NULL); 367190501Smr#endif /* FreeBSD */ 368190501Smr 369190501Smr#ifndef NETBSD_PF 370190501Smr if (fr_checkp != NULL) 371190501Smr fr_checkp = fr_savep; 372190501Smr fr_savep = NULL; 373190501Smr#endif 374190501Smr 375190501Smr#ifdef NETBSD_PF 376190501Smr# if (__FreeBSD_version >= 500011) 377190501Smr# if (__FreeBSD_version >= 501108) 378190501Smr ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); 379190501Smr if (ph_inet != NULL) 380190501Smr error = pfil_remove_hook((void *)fr_check_wrapper, NULL, 381190501Smr PFIL_IN|PFIL_OUT, ph_inet); 382190501Smr else 383190501Smr error = 0; 384190501Smr# else 385190501Smr error = pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT, 386190501Smr &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); 387190501Smr# endif 388190501Smr if (error) { 389190501Smr SPL_X(s); 390190501Smr return error; 391190501Smr } 392190501Smr# else 393190501Smr pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT); 394190501Smr# endif 395190501Smr# ifdef USE_INET6 396190501Smr# if (__FreeBSD_version >= 501108) 397190501Smr ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6); 398190501Smr if (ph_inet6 != NULL) 399197070Sjkim error = pfil_remove_hook((void *)fr_check_wrapper6, NULL, 400190501Smr PFIL_IN|PFIL_OUT, ph_inet6); 401190501Smr else 402190501Smr error = 0; 403190501Smr# else 404190501Smr error = pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT, 405190501Smr &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh); 406190501Smr# endif 407190501Smr if (error) { 408190501Smr SPL_X(s); 409190501Smr return error; 410190501Smr } 411190501Smr# endif 412190501Smr#endif 413190501Smr fr_deinitialise(); 414190501Smr 415190501Smr fr_running = -2; 416190501Smr 417190501Smr (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE); 418190501Smr (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE); 419190501Smr 420190501Smr if (ipf_locks_done == 1) { 421190501Smr MUTEX_DESTROY(&ipf_timeoutlock); 422190501Smr MUTEX_DESTROY(&ipf_rw); 423190501Smr RW_DESTROY(&ipf_mutex); 424190501Smr RW_DESTROY(&ipf_frcache); 425190501Smr RW_DESTROY(&ipf_ipidfrag); 426190501Smr RW_DESTROY(&ipf_global); 427190501Smr ipf_locks_done = 0; 428190501Smr } 429190501Smr 430190501Smr SPL_X(s); 431190501Smr 432190501Smr return 0; 433190501Smr} 434190501Smr 435190501Smr 436190501Smr/* 437190501Smr * Filter ioctl interface. 438190501Smr */ 439190501Smrint iplioctl(dev, cmd, data, mode 440190501Smr# if defined(_KERNEL) && ((BSD >= 199506) || (__FreeBSD_version >= 220000)) 441190501Smr, p) 442190501Smr# if (__FreeBSD_version >= 500024) 443190501Smrstruct thread *p; 444190501Smr# else 445190501Smrstruct proc *p; 446190501Smr# endif /* __FreeBSD_version >= 500024 */ 447190501Smr# else 448190501Smr) 449190501Smr# endif 450190501Smr#if defined(_KERNEL) && (__FreeBSD_version >= 502116) 451190501Smrstruct cdev *dev; 452190501Smr#else 453190501Smrdev_t dev; 454190501Smr#endif 455190501Smrioctlcmd_t cmd; 456190501Smrcaddr_t data; 457190501Smrint mode; 458190501Smr{ 459190501Smr#ifdef USE_SPL 460190501Smr int s; 461190501Smr#endif 462190501Smr int error = 0, unit = 0, tmp; 463190501Smr friostat_t fio; 464190501Smr 465190501Smr#if (BSD >= 199306) && defined(_KERNEL) 466190501Smr if ((securelevel >= 3) && (mode & FWRITE)) 467190501Smr return EPERM; 468190501Smr#endif 469190501Smr 470190501Smr unit = GET_MINOR(dev); 471190501Smr if ((IPL_LOGMAX < unit) || (unit < 0)) 472190501Smr return ENXIO; 473190501Smr 474190501Smr if (fr_running <= 0) { 475190501Smr if (unit != IPL_LOGIPF) 476190501Smr return EIO; 477190501Smr if (cmd != SIOCIPFGETNEXT && cmd != SIOCIPFGET && 478190501Smr cmd != SIOCIPFSET && cmd != SIOCFRENB && 479190501Smr cmd != SIOCGETFS && cmd != SIOCGETFF) 480190501Smr return EIO; 481190501Smr } 482190501Smr 483190501Smr SPL_NET(s); 484190501Smr READ_ENTER(&ipf_global); 485190501Smr 486190501Smr error = fr_ioctlswitch(unit, data, cmd, mode); 487190501Smr if (error != -1) { 488190501Smr RWLOCK_EXIT(&ipf_global); 489190501Smr SPL_X(s); 490190501Smr return error; 491190501Smr } 492190501Smr error = 0; 493190501Smr 494190501Smr switch (cmd) 495190501Smr { 496190501Smr case FIONREAD : 497190501Smr#ifdef IPFILTER_LOG 498190501Smr BCOPYOUT(&iplused[IPL_LOGIPF], (caddr_t)data, 499190501Smr sizeof(iplused[IPL_LOGIPF])); 500190501Smr#endif 501190501Smr break; 502190501Smr case SIOCFRENB : 503190501Smr if (!(mode & FWRITE)) 504190501Smr error = EPERM; 505 else { 506 BCOPYIN(data, &tmp, sizeof(tmp)); 507 if (tmp) { 508 if (fr_running > 0) 509 error = 0; 510 else 511 error = iplattach(); 512 if (error == 0) 513 fr_running = 1; 514 else 515 (void) ipldetach(); 516 } else { 517 error = ipldetach(); 518 if (error == 0) 519 fr_running = -1; 520 } 521 } 522 break; 523 case SIOCIPFSET : 524 if (!(mode & FWRITE)) { 525 error = EPERM; 526 break; 527 } 528 case SIOCIPFGETNEXT : 529 case SIOCIPFGET : 530 error = fr_ipftune(cmd, data); 531 break; 532 case SIOCSETFF : 533 if (!(mode & FWRITE)) 534 error = EPERM; 535 else 536 BCOPYIN(data, &fr_flags, sizeof(fr_flags)); 537 break; 538 case SIOCGETFF : 539 BCOPYOUT(&fr_flags, data, sizeof(fr_flags)); 540 break; 541 case SIOCFUNCL : 542 error = fr_resolvefunc(data); 543 break; 544 case SIOCINAFR : 545 case SIOCRMAFR : 546 case SIOCADAFR : 547 case SIOCZRLST : 548 if (!(mode & FWRITE)) 549 error = EPERM; 550 else 551 error = frrequest(unit, cmd, data, fr_active, 1); 552 break; 553 case SIOCINIFR : 554 case SIOCRMIFR : 555 case SIOCADIFR : 556 if (!(mode & FWRITE)) 557 error = EPERM; 558 else 559 error = frrequest(unit, cmd, data, 1 - fr_active, 1); 560 break; 561 case SIOCSWAPA : 562 if (!(mode & FWRITE)) 563 error = EPERM; 564 else { 565 bzero((char *)frcache, sizeof(frcache[0]) * 2); 566 *(u_int *)data = fr_active; 567 fr_active = 1 - fr_active; 568 } 569 break; 570 case SIOCGETFS : 571 fr_getstat(&fio); 572 error = fr_outobj(data, &fio, IPFOBJ_IPFSTAT); 573 break; 574 case SIOCFRZST : 575 if (!(mode & FWRITE)) 576 error = EPERM; 577 else 578 error = fr_zerostats(data); 579 break; 580 case SIOCIPFFL : 581 if (!(mode & FWRITE)) 582 error = EPERM; 583 else { 584 BCOPYIN(data, &tmp, sizeof(tmp)); 585 tmp = frflush(unit, 4, tmp); 586 BCOPYOUT(&tmp, data, sizeof(tmp)); 587 } 588 break; 589#ifdef USE_INET6 590 case SIOCIPFL6 : 591 if (!(mode & FWRITE)) 592 error = EPERM; 593 else { 594 BCOPYIN(data, &tmp, sizeof(tmp)); 595 tmp = frflush(unit, 6, tmp); 596 BCOPYOUT(&tmp, data, sizeof(tmp)); 597 } 598 break; 599#endif 600 case SIOCSTLCK : 601 BCOPYIN(data, &tmp, sizeof(tmp)); 602 fr_state_lock = tmp; 603 fr_nat_lock = tmp; 604 fr_frag_lock = tmp; 605 fr_auth_lock = tmp; 606 break; 607#ifdef IPFILTER_LOG 608 case SIOCIPFFB : 609 if (!(mode & FWRITE)) 610 error = EPERM; 611 else 612 *(int *)data = ipflog_clear(unit); 613 break; 614#endif /* IPFILTER_LOG */ 615 case SIOCGFRST : 616 error = fr_outobj(data, fr_fragstats(), IPFOBJ_FRAGSTAT); 617 break; 618 case SIOCFRSYN : 619 if (!(mode & FWRITE)) 620 error = EPERM; 621 else { 622 frsync(NULL); 623 } 624 break; 625 default : 626 error = EINVAL; 627 break; 628 } 629 630 RWLOCK_EXIT(&ipf_global); 631 SPL_X(s); 632 633 return error; 634} 635 636 637#if 0 638void fr_forgetifp(ifp) 639void *ifp; 640{ 641 register frentry_t *f; 642 643 WRITE_ENTER(&ipf_mutex); 644 for (f = ipacct[0][fr_active]; (f != NULL); f = f->fr_next) 645 if (f->fr_ifa == ifp) 646 f->fr_ifa = (void *)-1; 647 for (f = ipacct[1][fr_active]; (f != NULL); f = f->fr_next) 648 if (f->fr_ifa == ifp) 649 f->fr_ifa = (void *)-1; 650 for (f = ipfilter[0][fr_active]; (f != NULL); f = f->fr_next) 651 if (f->fr_ifa == ifp) 652 f->fr_ifa = (void *)-1; 653 for (f = ipfilter[1][fr_active]; (f != NULL); f = f->fr_next) 654 if (f->fr_ifa == ifp) 655 f->fr_ifa = (void *)-1; 656#ifdef USE_INET6 657 for (f = ipacct6[0][fr_active]; (f != NULL); f = f->fr_next) 658 if (f->fr_ifa == ifp) 659 f->fr_ifa = (void *)-1; 660 for (f = ipacct6[1][fr_active]; (f != NULL); f = f->fr_next) 661 if (f->fr_ifa == ifp) 662 f->fr_ifa = (void *)-1; 663 for (f = ipfilter6[0][fr_active]; (f != NULL); f = f->fr_next) 664 if (f->fr_ifa == ifp) 665 f->fr_ifa = (void *)-1; 666 for (f = ipfilter6[1][fr_active]; (f != NULL); f = f->fr_next) 667 if (f->fr_ifa == ifp) 668 f->fr_ifa = (void *)-1; 669#endif 670 RWLOCK_EXIT(&ipf_mutex); 671 fr_natsync(ifp); 672} 673#endif 674 675 676/* 677 * routines below for saving IP headers to buffer 678 */ 679int iplopen(dev, flags 680#if ((BSD >= 199506) || (__FreeBSD_version >= 220000)) && defined(_KERNEL) 681, devtype, p) 682int devtype; 683# if (__FreeBSD_version >= 500024) 684struct thread *p; 685# else 686struct proc *p; 687# endif /* __FreeBSD_version >= 500024 */ 688#else 689) 690#endif 691#if defined(_KERNEL) && (__FreeBSD_version >= 502116) 692struct cdev *dev; 693#else 694dev_t dev; 695#endif 696int flags; 697{ 698 u_int min = GET_MINOR(dev); 699 700 if (IPL_LOGMAX < min) 701 min = ENXIO; 702 else 703 min = 0; 704 return min; 705} 706 707 708int iplclose(dev, flags 709#if ((BSD >= 199506) || (__FreeBSD_version >= 220000)) && defined(_KERNEL) 710, devtype, p) 711int devtype; 712# if (__FreeBSD_version >= 500024) 713struct thread *p; 714# else 715struct proc *p; 716# endif /* __FreeBSD_version >= 500024 */ 717#else 718) 719#endif 720#if defined(_KERNEL) && (__FreeBSD_version >= 502116) 721struct cdev *dev; 722#else 723dev_t dev; 724#endif 725int flags; 726{ 727 u_int min = GET_MINOR(dev); 728 729 if (IPL_LOGMAX < min) 730 min = ENXIO; 731 else 732 min = 0; 733 return min; 734} 735 736/* 737 * iplread/ipllog 738 * both of these must operate with at least splnet() lest they be 739 * called during packet processing and cause an inconsistancy to appear in 740 * the filter lists. 741 */ 742#if (BSD >= 199306) 743int iplread(dev, uio, ioflag) 744int ioflag; 745#else 746int iplread(dev, uio) 747#endif 748#if defined(_KERNEL) && (__FreeBSD_version >= 502116) 749struct cdev *dev; 750#else 751dev_t dev; 752#endif 753register struct uio *uio; 754{ 755 u_int xmin = GET_MINOR(dev); 756 757 if (xmin < 0) 758 return ENXIO; 759 760# ifdef IPFILTER_SYNC 761 if (xmin == IPL_LOGSYNC) 762 return ipfsync_read(uio); 763# endif 764 765#ifdef IPFILTER_LOG 766 return ipflog_read(xmin, uio); 767#else 768 return ENXIO; 769#endif 770} 771 772 773/* 774 * iplwrite 775 * both of these must operate with at least splnet() lest they be 776 * called during packet processing and cause an inconsistancy to appear in 777 * the filter lists. 778 */ 779#if (BSD >= 199306) 780int iplwrite(dev, uio, ioflag) 781int ioflag; 782#else 783int iplwrite(dev, uio) 784#endif 785#if defined(_KERNEL) && (__FreeBSD_version >= 502116) 786struct cdev *dev; 787#else 788dev_t dev; 789#endif 790register struct uio *uio; 791{ 792 793#ifdef IPFILTER_SYNC 794 if (GET_MINOR(dev) == IPL_LOGSYNC) 795 return ipfsync_write(uio); 796#endif 797 return ENXIO; 798} 799 800 801/* 802 * fr_send_reset - this could conceivably be a call to tcp_respond(), but that 803 * requires a large amount of setting up and isn't any more efficient. 804 */ 805int fr_send_reset(fin) 806fr_info_t *fin; 807{ 808 struct tcphdr *tcp, *tcp2; 809 int tlen = 0, hlen; 810 struct mbuf *m; 811#ifdef USE_INET6 812 ip6_t *ip6; 813#endif 814 ip_t *ip; 815 816 tcp = fin->fin_dp; 817 if (tcp->th_flags & TH_RST) 818 return -1; /* feedback loop */ 819 820#ifndef IPFILTER_CKSUM 821 if (fr_checkl4sum(fin) == -1) 822 return -1; 823#endif 824 825 tlen = fin->fin_dlen - (TCP_OFF(tcp) << 2) + 826 ((tcp->th_flags & TH_SYN) ? 1 : 0) + 827 ((tcp->th_flags & TH_FIN) ? 1 : 0); 828 829#ifdef USE_INET6 830 hlen = (fin->fin_v == 6) ? sizeof(ip6_t) : sizeof(ip_t); 831#else 832 hlen = sizeof(ip_t); 833#endif 834#ifdef MGETHDR 835 MGETHDR(m, M_DONTWAIT, MT_HEADER); 836#else 837 MGET(m, M_DONTWAIT, MT_HEADER); 838#endif 839 if (m == NULL) 840 return -1; 841 if (sizeof(*tcp2) + hlen > MLEN) { 842 MCLGET(m, M_DONTWAIT); 843 if ((m->m_flags & M_EXT) == 0) { 844 FREE_MB_T(m); 845 return -1; 846 } 847 } 848 849 m->m_len = sizeof(*tcp2) + hlen; 850#if (BSD >= 199103) 851 m->m_data += max_linkhdr; 852 m->m_pkthdr.len = m->m_len; 853 m->m_pkthdr.rcvif = (struct ifnet *)0; 854#endif 855 ip = mtod(m, struct ip *); 856 bzero((char *)ip, hlen); 857#ifdef USE_INET6 858 ip6 = (ip6_t *)ip; 859#endif 860 tcp2 = (struct tcphdr *)((char *)ip + hlen); 861 tcp2->th_sport = tcp->th_dport; 862 tcp2->th_dport = tcp->th_sport; 863 864 if (tcp->th_flags & TH_ACK) { 865 tcp2->th_seq = tcp->th_ack; 866 tcp2->th_flags = TH_RST; 867 tcp2->th_ack = 0; 868 } else { 869 tcp2->th_seq = 0; 870 tcp2->th_ack = ntohl(tcp->th_seq); 871 tcp2->th_ack += tlen; 872 tcp2->th_ack = htonl(tcp2->th_ack); 873 tcp2->th_flags = TH_RST|TH_ACK; 874 } 875 TCP_X2_A(tcp2, 0); 876 TCP_OFF_A(tcp2, sizeof(*tcp2) >> 2); 877 tcp2->th_win = tcp->th_win; 878 tcp2->th_sum = 0; 879 tcp2->th_urp = 0; 880 881#ifdef USE_INET6 882 if (fin->fin_v == 6) { 883 ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; 884 ip6->ip6_plen = htons(sizeof(struct tcphdr)); 885 ip6->ip6_nxt = IPPROTO_TCP; 886 ip6->ip6_hlim = 0; 887 ip6->ip6_src = fin->fin_dst6; 888 ip6->ip6_dst = fin->fin_src6; 889 tcp2->th_sum = in6_cksum(m, IPPROTO_TCP, 890 sizeof(*ip6), sizeof(*tcp2)); 891 return fr_send_ip(fin, m, &m); 892 } 893#endif 894 ip->ip_p = IPPROTO_TCP; 895 ip->ip_len = htons(sizeof(struct tcphdr)); 896 ip->ip_src.s_addr = fin->fin_daddr; 897 ip->ip_dst.s_addr = fin->fin_saddr; 898 tcp2->th_sum = in_cksum(m, hlen + sizeof(*tcp2)); 899 ip->ip_len = hlen + sizeof(*tcp2); 900 return fr_send_ip(fin, m, &m); 901} 902 903 904static int fr_send_ip(fin, m, mpp) 905fr_info_t *fin; 906mb_t *m, **mpp; 907{ 908 fr_info_t fnew; 909 ip_t *ip, *oip; 910 int hlen; 911 912 ip = mtod(m, ip_t *); 913 bzero((char *)&fnew, sizeof(fnew)); 914 915 IP_V_A(ip, fin->fin_v); 916 switch (fin->fin_v) 917 { 918 case 4 : 919 fnew.fin_v = 4; 920 oip = fin->fin_ip; 921 IP_HL_A(ip, sizeof(*oip) >> 2); 922 ip->ip_tos = oip->ip_tos; 923 ip->ip_id = fin->fin_ip->ip_id; 924#if (__FreeBSD_version > 460000) 925 ip->ip_off = path_mtu_discovery ? IP_DF : 0; 926#else 927 ip->ip_off = 0; 928#endif 929 ip->ip_ttl = ip_defttl; 930 ip->ip_sum = 0; 931 hlen = sizeof(*oip); 932 break; 933#ifdef USE_INET6 934 case 6 : 935 { 936 ip6_t *ip6 = (ip6_t *)ip; 937 938 ip6->ip6_vfc = 0x60; 939 ip6->ip6_hlim = IPDEFTTL; 940 941 fnew.fin_v = 6; 942 hlen = sizeof(*ip6); 943 break; 944 } 945#endif 946 default : 947 return EINVAL; 948 } 949#ifdef IPSEC 950 m->m_pkthdr.rcvif = NULL; 951#endif 952 953 fnew.fin_ifp = fin->fin_ifp; 954 fnew.fin_flx = FI_NOCKSUM; 955 fnew.fin_m = m; 956 fnew.fin_ip = ip; 957 fnew.fin_mp = mpp; 958 fnew.fin_hlen = hlen; 959 fnew.fin_dp = (char *)ip + hlen; 960 (void) fr_makefrip(hlen, ip, &fnew); 961 962 return fr_fastroute(m, mpp, &fnew, NULL); 963} 964 965 966int fr_send_icmp_err(type, fin, dst) 967int type; 968fr_info_t *fin; 969int dst; 970{ 971 int err, hlen, xtra, iclen, ohlen, avail, code; 972 struct in_addr dst4; 973 struct icmp *icmp; 974 struct mbuf *m; 975 void *ifp; 976#ifdef USE_INET6 977 ip6_t *ip6; 978 struct in6_addr dst6; 979#endif 980 ip_t *ip, *ip2; 981 982 if ((type < 0) || (type > ICMP_MAXTYPE)) 983 return -1; 984 985 code = fin->fin_icode; 986#ifdef USE_INET6 987 if ((code < 0) || (code > sizeof(icmptoicmp6unreach)/sizeof(int))) 988 return -1; 989#endif 990 991#ifndef IPFILTER_CKSUM 992 if (fr_checkl4sum(fin) == -1) 993 return -1; 994#endif 995#ifdef MGETHDR 996 MGETHDR(m, M_DONTWAIT, MT_HEADER); 997#else 998 MGET(m, M_DONTWAIT, MT_HEADER); 999#endif 1000 if (m == NULL) 1001 return -1; 1002 avail = MHLEN; 1003 1004 xtra = 0; 1005 hlen = 0; 1006 ohlen = 0; 1007 ifp = fin->fin_ifp; 1008 if (fin->fin_v == 4) { 1009 if ((fin->fin_p == IPPROTO_ICMP) && 1010 !(fin->fin_flx & FI_SHORT)) 1011 switch (ntohs(fin->fin_data[0]) >> 8) 1012 { 1013 case ICMP_ECHO : 1014 case ICMP_TSTAMP : 1015 case ICMP_IREQ : 1016 case ICMP_MASKREQ : 1017 break; 1018 default : 1019 FREE_MB_T(m); 1020 return 0; 1021 } 1022 1023 if (dst == 0) { 1024 if (fr_ifpaddr(4, FRI_NORMAL, ifp, 1025 &dst4, NULL) == -1) { 1026 FREE_MB_T(m); 1027 return -1; 1028 } 1029 } else 1030 dst4.s_addr = fin->fin_daddr; 1031 1032 hlen = sizeof(ip_t); 1033 ohlen = fin->fin_hlen; 1034 if (fin->fin_hlen < fin->fin_plen) 1035 xtra = MIN(fin->fin_dlen, 8); 1036 else 1037 xtra = 0; 1038 } 1039 1040#ifdef USE_INET6 1041 else if (fin->fin_v == 6) { 1042 hlen = sizeof(ip6_t); 1043 ohlen = sizeof(ip6_t); 1044 type = icmptoicmp6types[type]; 1045 if (type == ICMP6_DST_UNREACH) 1046 code = icmptoicmp6unreach[code]; 1047 1048 if (hlen + sizeof(*icmp) + max_linkhdr + 1049 fin->fin_plen > avail) { 1050 MCLGET(m, M_DONTWAIT); 1051 if ((m->m_flags & M_EXT) == 0) { 1052 FREE_MB_T(m); 1053 return -1; 1054 } 1055 avail = MCLBYTES; 1056 } 1057 xtra = MIN(fin->fin_plen, 1058 avail - hlen - sizeof(*icmp) - max_linkhdr); 1059 if (dst == 0) { 1060 if (fr_ifpaddr(6, FRI_NORMAL, ifp, 1061 (struct in_addr *)&dst6, NULL) == -1) { 1062 FREE_MB_T(m); 1063 return -1; 1064 } 1065 } else 1066 dst6 = fin->fin_dst6; 1067 } 1068#endif 1069 else { 1070 FREE_MB_T(m); 1071 return -1; 1072 } 1073 1074 iclen = hlen + sizeof(*icmp); 1075 avail -= (max_linkhdr + iclen); 1076 if (avail < 0) { 1077 FREE_MB_T(m); 1078 return -1; 1079 } 1080 if (xtra > avail) 1081 xtra = avail; 1082 iclen += xtra; 1083 m->m_data += max_linkhdr; 1084 m->m_pkthdr.rcvif = (struct ifnet *)0; 1085 m->m_pkthdr.len = iclen; 1086 m->m_len = iclen; 1087 ip = mtod(m, ip_t *); 1088 icmp = (struct icmp *)((char *)ip + hlen); 1089 ip2 = (ip_t *)&icmp->icmp_ip; 1090 1091 icmp->icmp_type = type; 1092 icmp->icmp_code = fin->fin_icode; 1093 icmp->icmp_cksum = 0; 1094#ifdef icmp_nextmtu 1095 if (type == ICMP_UNREACH && 1096 fin->fin_icode == ICMP_UNREACH_NEEDFRAG && ifp) 1097 icmp->icmp_nextmtu = htons(((struct ifnet *)ifp)->if_mtu); 1098#endif 1099 1100 bcopy((char *)fin->fin_ip, (char *)ip2, ohlen); 1101 1102#ifdef USE_INET6 1103 ip6 = (ip6_t *)ip; 1104 if (fin->fin_v == 6) { 1105 ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; 1106 ip6->ip6_plen = htons(iclen - hlen); 1107 ip6->ip6_nxt = IPPROTO_ICMPV6; 1108 ip6->ip6_hlim = 0; 1109 ip6->ip6_src = dst6; 1110 ip6->ip6_dst = fin->fin_src6; 1111 if (xtra > 0) 1112 bcopy((char *)fin->fin_ip + ohlen, 1113 (char *)&icmp->icmp_ip + ohlen, xtra); 1114 icmp->icmp_cksum = in6_cksum(m, IPPROTO_ICMPV6, 1115 sizeof(*ip6), iclen - hlen); 1116 } else 1117#endif 1118 { 1119 ip2->ip_len = htons(ip2->ip_len); 1120 ip2->ip_off = htons(ip2->ip_off); 1121 ip->ip_p = IPPROTO_ICMP; 1122 ip->ip_src.s_addr = dst4.s_addr; 1123 ip->ip_dst.s_addr = fin->fin_saddr; 1124 1125 if (xtra > 0) 1126 bcopy((char *)fin->fin_ip + ohlen, 1127 (char *)&icmp->icmp_ip + ohlen, xtra); 1128 icmp->icmp_cksum = ipf_cksum((u_short *)icmp, 1129 sizeof(*icmp) + 8); 1130 ip->ip_len = iclen; 1131 ip->ip_p = IPPROTO_ICMP; 1132 } 1133 err = fr_send_ip(fin, m, &m); 1134 return err; 1135} 1136 1137 1138#if !defined(IPFILTER_LKM) && (__FreeBSD_version < 300000) 1139# if (BSD < 199306) 1140int iplinit __P((void)); 1141 1142int 1143# else 1144void iplinit __P((void)); 1145 1146void 1147# endif 1148iplinit() 1149{ 1150 if (iplattach() != 0) 1151 printf("IP Filter failed to attach\n"); 1152 ip_init(); 1153} 1154#endif /* __FreeBSD_version < 300000 */ 1155 1156 1157int fr_fastroute(m0, mpp, fin, fdp) 1158mb_t *m0, **mpp; 1159fr_info_t *fin; 1160frdest_t *fdp; 1161{ 1162 register struct ip *ip, *mhip; 1163 register struct mbuf *m = m0; 1164 register struct route *ro; 1165 int len, off, error = 0, hlen, code; 1166 struct ifnet *ifp, *sifp; 1167 struct sockaddr_in *dst; 1168 struct route iproute; 1169 u_short ip_off; 1170 frentry_t *fr; 1171 1172 ro = NULL; 1173 1174#ifdef M_WRITABLE 1175 /* 1176 * HOT FIX/KLUDGE: 1177 * 1178 * If the mbuf we're about to send is not writable (because of 1179 * a cluster reference, for example) we'll need to make a copy 1180 * of it since this routine modifies the contents. 1181 * 1182 * If you have non-crappy network hardware that can transmit data 1183 * from the mbuf, rather than making a copy, this is gonna be a 1184 * problem. 1185 */ 1186 if (M_WRITABLE(m) == 0) { 1187 m0 = m_dup(m, M_DONTWAIT); 1188 if (m0 != 0) { 1189 FREE_MB_T(m); 1190 m = m0; 1191 *mpp = m; 1192 } else { 1193 error = ENOBUFS; 1194 FREE_MB_T(m); 1195 goto done; 1196 } 1197 } 1198#endif 1199 1200#ifdef USE_INET6 1201 if (fin->fin_v == 6) { 1202 /* 1203 * currently "to <if>" and "to <if>:ip#" are not supported 1204 * for IPv6 1205 */ 1206#if (__FreeBSD_version >= 490000) 1207 return ip6_output(m0, NULL, NULL, 0, NULL, NULL, NULL); 1208#else 1209 return ip6_output(m0, NULL, NULL, 0, NULL, NULL); 1210#endif 1211 } 1212#endif 1213 1214 hlen = fin->fin_hlen; 1215 ip = mtod(m0, struct ip *); 1216 1217 /* 1218 * Route packet. 1219 */ 1220 ro = &iproute; 1221 bzero((caddr_t)ro, sizeof (*ro)); 1222 dst = (struct sockaddr_in *)&ro->ro_dst; 1223 dst->sin_family = AF_INET; 1224 dst->sin_addr = ip->ip_dst; 1225 1226 fr = fin->fin_fr; 1227 if (fdp != NULL) 1228 ifp = fdp->fd_ifp; 1229 else 1230 ifp = fin->fin_ifp; 1231 1232 if ((ifp == NULL) && (!fr || !(fr->fr_flags & FR_FASTROUTE))) { 1233 error = -2; 1234 goto bad; 1235 } 1236 1237 if ((fdp != NULL) && (fdp->fd_ip.s_addr != 0)) 1238 dst->sin_addr = fdp->fd_ip; 1239 1240 dst->sin_len = sizeof(*dst); 1241 rtalloc(ro); 1242 1243 if ((ifp == NULL) && (ro->ro_rt != NULL)) 1244 ifp = ro->ro_rt->rt_ifp; 1245 1246 if ((ro->ro_rt == NULL) || (ifp == NULL)) { 1247 if (in_localaddr(ip->ip_dst)) 1248 error = EHOSTUNREACH; 1249 else 1250 error = ENETUNREACH; 1251 goto bad; 1252 } 1253 if (ro->ro_rt->rt_flags & RTF_GATEWAY) 1254 dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway; 1255 if (ro->ro_rt) 1256 ro->ro_rt->rt_use++; 1257 1258 /* 1259 * For input packets which are being "fastrouted", they won't 1260 * go back through output filtering and miss their chance to get 1261 * NAT'd and counted. 1262 */ 1263 if (fin->fin_out == 0) { 1264 sifp = fin->fin_ifp; 1265 fin->fin_ifp = ifp; 1266 fin->fin_out = 1; 1267 (void) fr_acctpkt(fin, NULL); 1268 fin->fin_fr = NULL; 1269 if (!fr || !(fr->fr_flags & FR_RETMASK)) { 1270 u_32_t pass; 1271 1272 (void) fr_checkstate(fin, &pass); 1273 } 1274 1275 switch (fr_checknatout(fin, NULL)) 1276 { 1277 case 0 : 1278 break; 1279 case 1 : 1280 ip->ip_sum = 0; 1281 break; 1282 case -1 : 1283 error = -1; 1284 goto done; 1285 break; 1286 } 1287 1288 fin->fin_ifp = sifp; 1289 fin->fin_out = 0; 1290 } else 1291 ip->ip_sum = 0; 1292 /* 1293 * If small enough for interface, can just send directly. 1294 */ 1295 if (ip->ip_len <= ifp->if_mtu) { 1296 ip->ip_len = htons(ip->ip_len); 1297 ip->ip_off = htons(ip->ip_off); 1298 1299 if (!ip->ip_sum) 1300 ip->ip_sum = in_cksum(m, hlen); 1301 error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst, 1302 ro->ro_rt); 1303 goto done; 1304 } 1305 /* 1306 * Too large for interface; fragment if possible. 1307 * Must be able to put at least 8 bytes per fragment. 1308 */ 1309 ip_off = ntohs(ip->ip_off); 1310 if (ip_off & IP_DF) { 1311 error = EMSGSIZE; 1312 goto bad; 1313 } 1314 len = (ifp->if_mtu - hlen) &~ 7; 1315 if (len < 8) { 1316 error = EMSGSIZE; 1317 goto bad; 1318 } 1319 1320 { 1321 int mhlen, firstlen = len; 1322 struct mbuf **mnext = &m->m_act; 1323 1324 /* 1325 * Loop through length of segment after first fragment, 1326 * make new header and copy data of each part and link onto chain. 1327 */ 1328 m0 = m; 1329 mhlen = sizeof (struct ip); 1330 for (off = hlen + len; off < ip->ip_len; off += len) { 1331#ifdef MGETHDR 1332 MGETHDR(m, M_DONTWAIT, MT_HEADER); 1333#else 1334 MGET(m, M_DONTWAIT, MT_HEADER); 1335#endif 1336 if (m == 0) { 1337 m = m0; 1338 error = ENOBUFS; 1339 goto bad; 1340 } 1341 m->m_data += max_linkhdr; 1342 mhip = mtod(m, struct ip *); 1343 bcopy((char *)ip, (char *)mhip, sizeof(*ip)); 1344 if (hlen > sizeof (struct ip)) { 1345 mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip); 1346 IP_HL_A(mhip, mhlen >> 2); 1347 } 1348 m->m_len = mhlen; 1349 mhip->ip_off = ((off - hlen) >> 3) + ip_off; 1350 if (off + len >= ip->ip_len) 1351 len = ip->ip_len - off; 1352 else 1353 mhip->ip_off |= IP_MF; 1354 mhip->ip_len = htons((u_short)(len + mhlen)); 1355 *mnext = m; 1356 m->m_next = m_copy(m0, off, len); 1357 if (m->m_next == 0) { 1358 error = ENOBUFS; /* ??? */ 1359 goto sendorfree; 1360 } 1361 m->m_pkthdr.len = mhlen + len; 1362 m->m_pkthdr.rcvif = NULL; 1363 mhip->ip_off = htons((u_short)mhip->ip_off); 1364 mhip->ip_sum = 0; 1365 mhip->ip_sum = in_cksum(m, mhlen); 1366 mnext = &m->m_act; 1367 } 1368 /* 1369 * Update first fragment by trimming what's been copied out 1370 * and updating header, then send each fragment (in order). 1371 */ 1372 m_adj(m0, hlen + firstlen - ip->ip_len); 1373 ip->ip_len = htons((u_short)(hlen + firstlen)); 1374 ip->ip_off = htons((u_short)IP_MF); 1375 ip->ip_sum = 0; 1376 ip->ip_sum = in_cksum(m0, hlen); 1377sendorfree: 1378 for (m = m0; m; m = m0) { 1379 m0 = m->m_act; 1380 m->m_act = 0; 1381 if (error == 0) 1382 error = (*ifp->if_output)(ifp, m, 1383 (struct sockaddr *)dst, ro->ro_rt); 1384 else 1385 FREE_MB_T(m); 1386 } 1387 } 1388done: 1389 if (!error) 1390 fr_frouteok[0]++; 1391 else 1392 fr_frouteok[1]++; 1393 1394 if ((ro != NULL) && (ro->ro_rt != NULL)) { 1395 RTFREE(ro->ro_rt); 1396 } 1397 *mpp = NULL; 1398 return 0; 1399bad: 1400 if (error == EMSGSIZE) { 1401 sifp = fin->fin_ifp; 1402 code = fin->fin_icode; 1403 fin->fin_icode = ICMP_UNREACH_NEEDFRAG; 1404 fin->fin_ifp = ifp; 1405 (void) fr_send_icmp_err(ICMP_UNREACH, fin, 1); 1406 fin->fin_ifp = sifp; 1407 fin->fin_icode = code; 1408 } 1409 FREE_MB_T(m); 1410 goto done; 1411} 1412 1413 1414int fr_verifysrc(fin) 1415fr_info_t *fin; 1416{ 1417 struct sockaddr_in *dst; 1418 struct route iproute; 1419 1420 bzero((char *)&iproute, sizeof(iproute)); 1421 dst = (struct sockaddr_in *)&iproute.ro_dst; 1422 dst->sin_len = sizeof(*dst); 1423 dst->sin_family = AF_INET; 1424 dst->sin_addr = fin->fin_src; 1425 rtalloc(&iproute); 1426 if (iproute.ro_rt == NULL) 1427 return 0; 1428 return (fin->fin_ifp == iproute.ro_rt->rt_ifp); 1429} 1430 1431 1432/* 1433 * return the first IP Address associated with an interface 1434 */ 1435int fr_ifpaddr(v, atype, ifptr, inp, inpmask) 1436int v, atype; 1437void *ifptr; 1438struct in_addr *inp, *inpmask; 1439{ 1440#ifdef USE_INET6 1441 struct in6_addr *inp6 = NULL; 1442#endif 1443 struct sockaddr *sock, *mask; 1444 struct sockaddr_in *sin; 1445 struct ifaddr *ifa; 1446 struct ifnet *ifp; 1447 1448 if ((ifptr == NULL) || (ifptr == (void *)-1)) 1449 return -1; 1450 1451 sin = NULL; 1452 ifp = ifptr; 1453 1454 if (v == 4) 1455 inp->s_addr = 0; 1456#ifdef USE_INET6 1457 else if (v == 6) 1458 bzero((char *)inp, sizeof(struct in6_addr)); 1459#endif 1460#if (__FreeBSD_version >= 300000) 1461 ifa = TAILQ_FIRST(&ifp->if_addrhead); 1462#else 1463 ifa = ifp->if_addrlist; 1464#endif /* __FreeBSD_version >= 300000 */ 1465 1466 sock = ifa->ifa_addr; 1467 while (sock != NULL && ifa != NULL) { 1468 sin = (struct sockaddr_in *)sock; 1469 if ((v == 4) && (sin->sin_family == AF_INET)) 1470 break; 1471#ifdef USE_INET6 1472 if ((v == 6) && (sin->sin_family == AF_INET6)) { 1473 inp6 = &((struct sockaddr_in6 *)sin)->sin6_addr; 1474 if (!IN6_IS_ADDR_LINKLOCAL(inp6) && 1475 !IN6_IS_ADDR_LOOPBACK(inp6)) 1476 break; 1477 } 1478#endif 1479#if (__FreeBSD_version >= 300000) 1480 ifa = TAILQ_NEXT(ifa, ifa_link); 1481#else 1482 ifa = ifa->ifa_next; 1483#endif /* __FreeBSD_version >= 300000 */ 1484 if (ifa != NULL) 1485 sock = ifa->ifa_addr; 1486 } 1487 1488 if (ifa == NULL || sin == NULL) 1489 return -1; 1490 1491 mask = ifa->ifa_netmask; 1492 if (atype == FRI_BROADCAST) 1493 sock = ifa->ifa_broadaddr; 1494 else if (atype == FRI_PEERADDR) 1495 sock = ifa->ifa_dstaddr; 1496 1497 if (sock == NULL) 1498 return -1; 1499 1500#ifdef USE_INET6 1501 if (v == 6) { 1502 return fr_ifpfillv6addr(atype, (struct sockaddr_in6 *)sock, 1503 (struct sockaddr_in6 *)mask, 1504 inp, inpmask); 1505 } 1506#endif 1507 return fr_ifpfillv4addr(atype, (struct sockaddr_in *)sock, 1508 (struct sockaddr_in *)mask, inp, inpmask); 1509} 1510 1511 1512u_32_t fr_newisn(fin) 1513fr_info_t *fin; 1514{ 1515 u_32_t newiss; 1516#if (__FreeBSD_version >= 400000) 1517 newiss = arc4random(); 1518#else 1519 static iss_seq_off = 0; 1520 u_char hash[16]; 1521 MD5_CTX ctx; 1522 1523 /* 1524 * Compute the base value of the ISS. It is a hash 1525 * of (saddr, sport, daddr, dport, secret). 1526 */ 1527 MD5Init(&ctx); 1528 1529 MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src, 1530 sizeof(fin->fin_fi.fi_src)); 1531 MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst, 1532 sizeof(fin->fin_fi.fi_dst)); 1533 MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat)); 1534 1535 MD5Update(&ctx, ipf_iss_secret, sizeof(ipf_iss_secret)); 1536 1537 MD5Final(hash, &ctx); 1538 1539 memcpy(&newiss, hash, sizeof(newiss)); 1540 1541 /* 1542 * Now increment our "timer", and add it in to 1543 * the computed value. 1544 * 1545 * XXX Use `addin'? 1546 * XXX TCP_ISSINCR too large to use? 1547 */ 1548 iss_seq_off += 0x00010000; 1549 newiss += iss_seq_off; 1550#endif 1551 return newiss; 1552} 1553 1554 1555/* ------------------------------------------------------------------------ */ 1556/* Function: fr_nextipid */ 1557/* Returns: int - 0 == success, -1 == error (packet should be droppped) */ 1558/* Parameters: fin(I) - pointer to packet information */ 1559/* */ 1560/* Returns the next IPv4 ID to use for this packet. */ 1561/* ------------------------------------------------------------------------ */ 1562u_short fr_nextipid(fin) 1563fr_info_t *fin; 1564{ 1565#ifndef RANDOM_IP_ID 1566 static u_short ipid = 0; 1567 u_short id; 1568 1569 MUTEX_ENTER(&ipf_rw); 1570 id = ipid++; 1571 MUTEX_EXIT(&ipf_rw); 1572#else 1573 u_short id; 1574 1575 id = ip_randomid(); 1576#endif 1577 1578 return id; 1579} 1580 1581 1582INLINE void fr_checkv4sum(fin) 1583fr_info_t *fin; 1584{ 1585#ifdef CSUM_DATA_VALID 1586 int manual = 0; 1587 u_short sum; 1588 ip_t *ip; 1589 mb_t *m; 1590 1591 if ((fin->fin_flx & FI_NOCKSUM) != 0) 1592 return; 1593 1594 m = fin->fin_m; 1595 if (m == NULL) { 1596 manual = 1; 1597 goto skipauto; 1598 } 1599 ip = fin->fin_ip; 1600 1601 if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) { 1602 if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) 1603 sum = m->m_pkthdr.csum_data; 1604 else 1605 sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, 1606 htonl(m->m_pkthdr.csum_data + 1607 fin->fin_ip->ip_len + fin->fin_p)); 1608 sum ^= 0xffff; 1609 if (sum != 0) 1610 fin->fin_flx |= FI_BAD; 1611 } else 1612 manual = 1; 1613skipauto: 1614# ifdef IPFILTER_CKSUM 1615 if (manual != 0) 1616 if (fr_checkl4sum(fin) == -1) 1617 fin->fin_flx |= FI_BAD; 1618# else 1619 ; 1620# endif 1621#else 1622# ifdef IPFILTER_CKSUM 1623 if (fr_checkl4sum(fin) == -1) 1624 fin->fin_flx |= FI_BAD; 1625# endif 1626#endif 1627} 1628 1629 1630#ifdef USE_INET6 1631INLINE void fr_checkv6sum(fin) 1632fr_info_t *fin; 1633{ 1634# ifdef IPFILTER_CKSUM 1635 if (fr_checkl4sum(fin) == -1) 1636 fin->fin_flx |= FI_BAD; 1637# endif 1638} 1639#endif /* USE_INET6 */ 1640 1641 1642size_t mbufchainlen(m0) 1643struct mbuf *m0; 1644{ 1645 size_t len; 1646 1647 if ((m0->m_flags & M_PKTHDR) != 0) { 1648 len = m0->m_pkthdr.len; 1649 } else { 1650 struct mbuf *m; 1651 1652 for (m = m0, len = 0; m != NULL; m = m->m_next) 1653 len += m->m_len; 1654 } 1655 return len; 1656} 1657 1658 1659/* ------------------------------------------------------------------------ */ 1660/* Function: fr_pullup */ 1661/* Returns: NULL == pullup failed, else pointer to protocol header */ 1662/* Parameters: m(I) - pointer to buffer where data packet starts */ 1663/* fin(I) - pointer to packet information */ 1664/* len(I) - number of bytes to pullup */ 1665/* */ 1666/* Attempt to move at least len bytes (from the start of the buffer) into a */ 1667/* single buffer for ease of access. Operating system native functions are */ 1668/* used to manage buffers - if necessary. If the entire packet ends up in */ 1669/* a single buffer, set the FI_COALESCE flag even though fr_coalesce() has */ 1670/* not been called. Both fin_ip and fin_dp are updated before exiting _IF_ */ 1671/* and ONLY if the pullup succeeds. */ 1672/* */ 1673/* We assume that 'min' is a pointer to a buffer that is part of the chain */ 1674/* of buffers that starts at *fin->fin_mp. */ 1675/* ------------------------------------------------------------------------ */ 1676void *fr_pullup(min, fin, len) 1677mb_t *min; 1678fr_info_t *fin; 1679int len; 1680{ 1681 int out = fin->fin_out, dpoff, ipoff; 1682 mb_t *m = min; 1683 char *ip; 1684 1685 if (m == NULL) 1686 return NULL; 1687 1688 ip = (char *)fin->fin_ip; 1689 if ((fin->fin_flx & FI_COALESCE) != 0) 1690 return ip; 1691 1692 ipoff = fin->fin_ipoff; 1693 if (fin->fin_dp != NULL) 1694 dpoff = (char *)fin->fin_dp - (char *)ip; 1695 else 1696 dpoff = 0; 1697 1698 if (M_LEN(m) < len) { 1699#ifdef MHLEN 1700 /* 1701 * Assume that M_PKTHDR is set and just work with what is left 1702 * rather than check.. 1703 * Should not make any real difference, anyway. 1704 */ 1705 if (len > MHLEN) 1706#else 1707 if (len > MLEN) 1708#endif 1709 { 1710#ifdef HAVE_M_PULLDOWN 1711 if (m_pulldown(m, 0, len, NULL) == NULL) 1712 m = NULL; 1713#else 1714 FREE_MB_T(*fin->fin_mp); 1715 m = NULL; 1716#endif 1717 } else 1718 { 1719 m = m_pullup(m, len); 1720 } 1721 *fin->fin_mp = m; 1722 fin->fin_m = m; 1723 if (m == NULL) { 1724 ATOMIC_INCL(frstats[out].fr_pull[1]); 1725 return NULL; 1726 } 1727 ip = MTOD(m, char *) + ipoff; 1728 } 1729 1730 ATOMIC_INCL(frstats[out].fr_pull[0]); 1731 fin->fin_ip = (ip_t *)ip; 1732 if (fin->fin_dp != NULL) 1733 fin->fin_dp = (char *)fin->fin_ip + dpoff; 1734 1735 if (len == fin->fin_plen) 1736 fin->fin_flx |= FI_COALESCE; 1737 return ip; 1738} 1739