ip_fil_freebsd.c revision 161356
1/* $FreeBSD: head/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c 161356 2006-08-16 12:06:35Z guido $ */ 2 3/* 4 * Copyright (C) 1993-2003 by Darren Reed. 5 * 6 * See the IPFILTER.LICENCE file for details on licencing. 7 */ 8#if !defined(lint) 9static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed"; 10static const char rcsid[] = "@(#)$Id: ip_fil_freebsd.c,v 2.53.2.32 2006/03/25 13:03:01 darrenr Exp $"; 11#endif 12 13#if defined(KERNEL) || defined(_KERNEL) 14# undef KERNEL 15# undef _KERNEL 16# define KERNEL 1 17# define _KERNEL 1 18#endif 19#if defined(__FreeBSD_version) && (__FreeBSD_version >= 400000) && \ 20 !defined(KLD_MODULE) && !defined(IPFILTER_LKM) 21# include "opt_inet6.h" 22#endif 23#if defined(__FreeBSD_version) && (__FreeBSD_version >= 440000) && \ 24 !defined(KLD_MODULE) && !defined(IPFILTER_LKM) 25# include "opt_random_ip_id.h" 26#endif 27#include <sys/param.h> 28#if defined(__FreeBSD__) && !defined(__FreeBSD_version) 29# if defined(IPFILTER_LKM) 30# ifndef __FreeBSD_cc_version 31# include <osreldate.h> 32# else 33# if __FreeBSD_cc_version < 430000 34# include <osreldate.h> 35# endif 36# endif 37# endif 38#endif 39#include <sys/errno.h> 40#include <sys/types.h> 41#include <sys/file.h> 42#if __FreeBSD_version >= 220000 43# include <sys/fcntl.h> 44# include <sys/filio.h> 45#else 46# include <sys/ioctl.h> 47#endif 48#include <sys/time.h> 49#include <sys/systm.h> 50#if (__FreeBSD_version >= 300000) 51# include <sys/dirent.h> 52#else 53# include <sys/dir.h> 54#endif 55#if !defined(__hpux) 56# include <sys/mbuf.h> 57#endif 58#include <sys/protosw.h> 59#include <sys/socket.h> 60#include <sys/selinfo.h> 61 62#include <net/if.h> 63#if __FreeBSD_version >= 300000 64# include <net/if_var.h> 65# if !defined(IPFILTER_LKM) 66# include "opt_ipfilter.h" 67# endif 68#endif 69#include <net/route.h> 70#include <netinet/in.h> 71#include <netinet/in_var.h> 72#include <netinet/in_systm.h> 73#include <netinet/ip.h> 74#include <netinet/ip_var.h> 75#include <netinet/tcp.h> 76#if defined(__osf__) 77# include <netinet/tcp_timer.h> 78#endif 79#include <netinet/udp.h> 80#include <netinet/tcpip.h> 81#include <netinet/ip_icmp.h> 82#ifndef _KERNEL 83# include "netinet/ipf.h" 84#endif 85#include "netinet/ip_compat.h" 86#ifdef USE_INET6 87# include <netinet/icmp6.h> 88#endif 89#include "netinet/ip_fil.h" 90#include "netinet/ip_nat.h" 91#include "netinet/ip_frag.h" 92#include "netinet/ip_state.h" 93#include "netinet/ip_proxy.h" 94#include "netinet/ip_auth.h" 95#ifdef IPFILTER_SYNC 96#include "netinet/ip_sync.h" 97#endif 98#ifdef IPFILTER_SCAN 99#include "netinet/ip_scan.h" 100#endif 101#include "netinet/ip_pool.h" 102#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) 103# include <sys/malloc.h> 104#endif 105#include <sys/kernel.h> 106#ifdef CSUM_DATA_VALID 107#include <machine/in_cksum.h> 108#endif 109extern int ip_optcopy __P((struct ip *, struct ip *)); 110 111#if (__FreeBSD_version > 460000) 112extern int path_mtu_discovery; 113#endif 114 115# ifdef IPFILTER_M_IPFILTER 116MALLOC_DEFINE(M_IPFILTER, "ipfilter", "IP Filter packet filter data structures"); 117# endif 118 119 120#if !defined(__osf__) 121extern struct protosw inetsw[]; 122#endif 123 124static int (*fr_savep) __P((ip_t *, int, void *, int, struct mbuf **)); 125static int fr_send_ip __P((fr_info_t *, mb_t *, mb_t **)); 126# ifdef USE_MUTEXES 127ipfmutex_t ipl_mutex, ipf_authmx, ipf_rw, ipf_stinsert; 128ipfmutex_t ipf_nat_new, ipf_natio, ipf_timeoutlock; 129ipfrwlock_t ipf_mutex, ipf_global, ipf_ipidfrag, ipf_frcache; 130ipfrwlock_t ipf_frag, ipf_state, ipf_nat, ipf_natfrag, ipf_auth; 131# endif 132int ipf_locks_done = 0; 133 134#if (__FreeBSD_version >= 300000) 135struct callout_handle fr_slowtimer_ch; 136#endif 137struct selinfo ipfselwait[IPL_LOGSIZE]; 138 139#if (__FreeBSD_version >= 500011) 140# include <sys/conf.h> 141# if defined(NETBSD_PF) 142# include <net/pfil.h> 143# include <netinet/ipprotosw.h> 144/* 145 * We provide the fr_checkp name just to minimize changes later. 146 */ 147int (*fr_checkp) __P((ip_t *ip, int hlen, void *ifp, int out, mb_t **mp)); 148# endif /* NETBSD_PF */ 149#endif /* __FreeBSD_version >= 500011 */ 150 151 152#if (__FreeBSD_version >= 502103) 153static eventhandler_tag ipf_arrivetag, ipf_departtag, ipf_clonetag; 154 155static void ipf_ifevent(void *arg); 156 157static void ipf_ifevent(arg) 158void *arg; 159{ 160 frsync(NULL); 161} 162#endif 163 164 165#if (__FreeBSD_version >= 501108) && defined(_KERNEL) 166 167static int 168fr_check_wrapper(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir) 169{ 170 struct ip *ip = mtod(*mp, struct ip *); 171 return fr_check(ip, ip->ip_hl << 2, ifp, (dir == PFIL_OUT), mp); 172} 173 174# ifdef USE_INET6 175# include <netinet/ip6.h> 176 177static int 178fr_check_wrapper6(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir) 179{ 180 return (fr_check(mtod(*mp, struct ip *), sizeof(struct ip6_hdr), 181 ifp, (dir == PFIL_OUT), mp)); 182} 183# endif 184#endif /* __FreeBSD_version >= 501108 */ 185#if defined(IPFILTER_LKM) 186int iplidentify(s) 187char *s; 188{ 189 if (strcmp(s, "ipl") == 0) 190 return 1; 191 return 0; 192} 193#endif /* IPFILTER_LKM */ 194 195 196int iplattach() 197{ 198#ifdef USE_SPL 199 int s; 200#endif 201#if defined(NETBSD_PF) && (__FreeBSD_version >= 500011) 202 int error = 0; 203# if __FreeBSD_version >= 501108 204 struct pfil_head *ph_inet; 205# ifdef USE_INET6 206 struct pfil_head *ph_inet6; 207# endif 208# endif 209#endif 210 211 SPL_NET(s); 212 if (fr_running > 0) { 213 SPL_X(s); 214 return EBUSY; 215 } 216 217 MUTEX_INIT(&ipf_rw, "ipf rw mutex"); 218 RWLOCK_INIT(&ipf_global, "ipf filter load/unload mutex"); 219 MUTEX_INIT(&ipf_timeoutlock, "ipf timeout queue mutex"); 220 RWLOCK_INIT(&ipf_mutex, "ipf filter rwlock"); 221 RWLOCK_INIT(&ipf_frcache, "ipf cache rwlock"); 222 RWLOCK_INIT(&ipf_ipidfrag, "ipf IP NAT-Frag rwlock"); 223 ipf_locks_done = 1; 224 225 if (fr_initialise() < 0) { 226 SPL_X(s); 227 return EIO; 228 } 229 230 231# ifdef NETBSD_PF 232# if __FreeBSD_version >= 500011 233# if __FreeBSD_version >= 501108 234 ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); 235# ifdef USE_INET6 236 ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6); 237# endif 238 if (ph_inet == NULL 239# ifdef USE_INET6 240 && ph_inet6 == NULL 241# endif 242 ) 243 return ENODEV; 244 245 if (ph_inet != NULL) 246 error = pfil_add_hook((void *)fr_check_wrapper, NULL, 247 PFIL_IN|PFIL_OUT, ph_inet); 248 else 249 error = 0; 250# else 251 error = pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT, 252 &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); 253# endif 254 if (error) { 255# ifdef USE_INET6 256 goto pfil_error; 257# else 258 fr_deinitialise(); 259 SPL_X(s); 260 return error; 261# endif 262 } 263# else 264 pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT); 265# endif 266# ifdef USE_INET6 267# if __FreeBSD_version >= 501108 268 if (ph_inet6 != NULL) 269 error = pfil_add_hook((void *)fr_check_wrapper6, NULL, 270 PFIL_IN|PFIL_OUT, ph_inet6); 271 else 272 error = 0; 273 if (error) { 274 pfil_remove_hook((void *)fr_check_wrapper6, NULL, 275 PFIL_IN|PFIL_OUT, ph_inet6); 276# else 277 error = pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT, 278 &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh); 279 if (error) { 280 pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT, 281 &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); 282# endif 283pfil_error: 284 fr_deinitialise(); 285 SPL_X(s); 286 return error; 287 } 288# endif 289# endif 290 291#if (__FreeBSD_version >= 502103) 292 ipf_arrivetag = EVENTHANDLER_REGISTER(ifnet_arrival_event, \ 293 ipf_ifevent, NULL, \ 294 EVENTHANDLER_PRI_ANY); 295 ipf_departtag = EVENTHANDLER_REGISTER(ifnet_departure_event, \ 296 ipf_ifevent, NULL, \ 297 EVENTHANDLER_PRI_ANY); 298 ipf_clonetag = EVENTHANDLER_REGISTER(if_clone_event, ipf_ifevent, \ 299 NULL, EVENTHANDLER_PRI_ANY); 300#endif 301 302 if (fr_checkp != fr_check) { 303 fr_savep = fr_checkp; 304 fr_checkp = fr_check; 305 } 306 307 bzero((char *)ipfselwait, sizeof(ipfselwait)); 308 bzero((char *)frcache, sizeof(frcache)); 309 fr_running = 1; 310 311 if (fr_control_forwarding & 1) 312 ipforwarding = 1; 313 314 SPL_X(s); 315#if (__FreeBSD_version >= 300000) 316 fr_slowtimer_ch = timeout(fr_slowtimer, NULL, 317 (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT); 318#else 319 timeout(fr_slowtimer, NULL, (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT); 320#endif 321 return 0; 322} 323 324 325/* 326 * Disable the filter by removing the hooks from the IP input/output 327 * stream. 328 */ 329int ipldetach() 330{ 331#ifdef USE_SPL 332 int s; 333#endif 334#if defined(NETBSD_PF) && (__FreeBSD_version >= 500011) 335 int error = 0; 336# if __FreeBSD_version >= 501108 337 struct pfil_head *ph_inet; 338# ifdef USE_INET6 339 struct pfil_head *ph_inet6; 340# endif 341# endif 342#endif 343 344 if (fr_control_forwarding & 2) 345 ipforwarding = 0; 346 347#if (__FreeBSD_version >= 502103) 348 if (ipf_arrivetag != NULL) { 349 EVENTHANDLER_DEREGISTER(ifnet_arrival_event, ipf_arrivetag); 350 } 351 if (ipf_departtag != NULL) { 352 EVENTHANDLER_DEREGISTER(ifnet_departure_event, ipf_departtag); 353 } 354 if (ipf_clonetag != NULL) { 355 EVENTHANDLER_DEREGISTER(if_clone_event, ipf_clonetag); 356 } 357#endif 358 359 SPL_NET(s); 360 361#if (__FreeBSD_version >= 300000) 362 if (fr_slowtimer_ch.callout != NULL) 363 untimeout(fr_slowtimer, NULL, fr_slowtimer_ch); 364 bzero(&fr_slowtimer_ch, sizeof(fr_slowtimer_ch)); 365#else 366 untimeout(fr_slowtimer, NULL); 367#endif /* FreeBSD */ 368 369#ifndef NETBSD_PF 370 if (fr_checkp != NULL) 371 fr_checkp = fr_savep; 372 fr_savep = NULL; 373#endif 374 375#ifdef NETBSD_PF 376# if (__FreeBSD_version >= 500011) 377# if (__FreeBSD_version >= 501108) 378 ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); 379 if (ph_inet != NULL) 380 error = pfil_remove_hook((void *)fr_check_wrapper, NULL, 381 PFIL_IN|PFIL_OUT, ph_inet); 382 else 383 error = 0; 384# else 385 error = pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT, 386 &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); 387# endif 388 if (error) { 389 SPL_X(s); 390 return error; 391 } 392# else 393 pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT); 394# endif 395# ifdef USE_INET6 396# if (__FreeBSD_version >= 501108) 397 ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6); 398 if (ph_inet6 != NULL) 399 error = pfil_remove_hook((void *)fr_check_wrapper6, NULL, 400 PFIL_IN|PFIL_OUT, ph_inet6); 401 else 402 error = 0; 403# else 404 error = pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT, 405 &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh); 406# endif 407 if (error) { 408 SPL_X(s); 409 return error; 410 } 411# endif 412#endif 413 fr_deinitialise(); 414 415 fr_running = -2; 416 417 (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE); 418 (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE); 419 420 if (ipf_locks_done == 1) { 421 MUTEX_DESTROY(&ipf_timeoutlock); 422 MUTEX_DESTROY(&ipf_rw); 423 RW_DESTROY(&ipf_mutex); 424 RW_DESTROY(&ipf_frcache); 425 RW_DESTROY(&ipf_ipidfrag); 426 RW_DESTROY(&ipf_global); 427 ipf_locks_done = 0; 428 } 429 430 SPL_X(s); 431 432 return 0; 433} 434 435 436/* 437 * Filter ioctl interface. 438 */ 439int iplioctl(dev, cmd, data, mode 440# if defined(_KERNEL) && ((BSD >= 199506) || (__FreeBSD_version >= 220000)) 441, p) 442# if (__FreeBSD_version >= 500024) 443struct thread *p; 444# else 445struct proc *p; 446# endif /* __FreeBSD_version >= 500024 */ 447# else 448) 449# endif 450#if defined(_KERNEL) && (__FreeBSD_version >= 502116) 451struct cdev *dev; 452#else 453dev_t dev; 454#endif 455ioctlcmd_t cmd; 456caddr_t data; 457int mode; 458{ 459#ifdef USE_SPL 460 int s; 461#endif 462 int error = 0, unit = 0, tmp; 463 friostat_t fio; 464 465#if (BSD >= 199306) && defined(_KERNEL) 466 if ((securelevel >= 3) && (mode & FWRITE)) 467 return EPERM; 468#endif 469 470 unit = GET_MINOR(dev); 471 if ((IPL_LOGMAX < unit) || (unit < 0)) 472 return ENXIO; 473 474 if (fr_running <= 0) { 475 if (unit != IPL_LOGIPF) 476 return EIO; 477 if (cmd != SIOCIPFGETNEXT && cmd != SIOCIPFGET && 478 cmd != SIOCIPFSET && cmd != SIOCFRENB && 479 cmd != SIOCGETFS && cmd != SIOCGETFF) 480 return EIO; 481 } 482 483 SPL_NET(s); 484 READ_ENTER(&ipf_global); 485 486 error = fr_ioctlswitch(unit, data, cmd, mode); 487 if (error != -1) { 488 RWLOCK_EXIT(&ipf_global); 489 SPL_X(s); 490 return error; 491 } 492 error = 0; 493 494 switch (cmd) 495 { 496 case FIONREAD : 497#ifdef IPFILTER_LOG 498 BCOPYOUT(&iplused[IPL_LOGIPF], (caddr_t)data, 499 sizeof(iplused[IPL_LOGIPF])); 500#endif 501 break; 502 case SIOCFRENB : 503 if (!(mode & FWRITE)) 504 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