ip_fil_freebsd.c revision 172776
1/* $FreeBSD: head/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c 172776 2007-10-18 21:52:14Z darrenr $ */ 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.50 2007/09/20 12:51:50 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#if __FreeBSD_version >= 500043 61# include <sys/selinfo.h> 62#else 63# include <sys/select.h> 64#endif 65 66#include <net/if.h> 67#if __FreeBSD_version >= 300000 68# include <net/if_var.h> 69# if __FreeBSD_version >= 500043 70# include <net/netisr.h> 71# endif 72# if !defined(IPFILTER_LKM) 73# include "opt_ipfilter.h" 74# endif 75#endif 76#include <net/route.h> 77#include <netinet/in.h> 78#include <netinet/in_var.h> 79#include <netinet/in_systm.h> 80#include <netinet/ip.h> 81#include <netinet/ip_var.h> 82#include <netinet/tcp.h> 83#if defined(__osf__) 84# include <netinet/tcp_timer.h> 85#endif 86#include <netinet/udp.h> 87#include <netinet/tcpip.h> 88#include <netinet/ip_icmp.h> 89#ifndef _KERNEL 90# include "netinet/ipf.h" 91#endif 92#include "netinet/ip_compat.h" 93#ifdef USE_INET6 94# include <netinet/icmp6.h> 95#endif 96#include "netinet/ip_fil.h" 97#include "netinet/ip_nat.h" 98#include "netinet/ip_frag.h" 99#include "netinet/ip_state.h" 100#include "netinet/ip_proxy.h" 101#include "netinet/ip_auth.h" 102#ifdef IPFILTER_SYNC 103#include "netinet/ip_sync.h" 104#endif 105#ifdef IPFILTER_SCAN 106#include "netinet/ip_scan.h" 107#endif 108#include "netinet/ip_pool.h" 109#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) 110# include <sys/malloc.h> 111#endif 112#include <sys/kernel.h> 113#ifdef CSUM_DATA_VALID 114#include <machine/in_cksum.h> 115#endif 116extern int ip_optcopy __P((struct ip *, struct ip *)); 117 118#if (__FreeBSD_version > 460000) 119extern int path_mtu_discovery; 120#endif 121 122# ifdef IPFILTER_M_IPFILTER 123MALLOC_DEFINE(M_IPFILTER, "ipfilter", "IP Filter packet filter data structures"); 124# endif 125 126 127#if !defined(__osf__) 128extern struct protosw inetsw[]; 129#endif 130 131static int (*fr_savep) __P((ip_t *, int, void *, int, struct mbuf **)); 132static int fr_send_ip __P((fr_info_t *, mb_t *, mb_t **)); 133# ifdef USE_MUTEXES 134ipfmutex_t ipl_mutex, ipf_authmx, ipf_rw, ipf_stinsert; 135ipfmutex_t ipf_nat_new, ipf_natio, ipf_timeoutlock; 136ipfrwlock_t ipf_mutex, ipf_global, ipf_ipidfrag, ipf_frcache, ipf_tokens; 137ipfrwlock_t ipf_frag, ipf_state, ipf_nat, ipf_natfrag, ipf_auth; 138# endif 139int ipf_locks_done = 0; 140 141#if (__FreeBSD_version >= 300000) 142struct callout_handle fr_slowtimer_ch; 143#endif 144struct selinfo ipfselwait[IPL_LOGSIZE]; 145 146#if (__FreeBSD_version >= 500011) 147# include <sys/conf.h> 148# if defined(NETBSD_PF) 149# include <net/pfil.h> 150# include <netinet/ipprotosw.h> 151/* 152 * We provide the fr_checkp name just to minimize changes later. 153 */ 154int (*fr_checkp) __P((ip_t *ip, int hlen, void *ifp, int out, mb_t **mp)); 155# endif /* NETBSD_PF */ 156#endif /* __FreeBSD_version >= 500011 */ 157 158 159#if (__FreeBSD_version >= 502103) 160static eventhandler_tag ipf_arrivetag, ipf_departtag, ipf_clonetag; 161 162static void ipf_ifevent(void *arg); 163 164static void ipf_ifevent(arg) 165void *arg; 166{ 167 frsync(NULL); 168} 169#endif 170 171 172#if (__FreeBSD_version >= 501108) && defined(_KERNEL) 173 174static int 175fr_check_wrapper(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir) 176{ 177 struct ip *ip = mtod(*mp, struct ip *); 178 return fr_check(ip, ip->ip_hl << 2, ifp, (dir == PFIL_OUT), mp); 179} 180 181# ifdef USE_INET6 182# include <netinet/ip6.h> 183 184static int 185fr_check_wrapper6(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir) 186{ 187 return (fr_check(mtod(*mp, struct ip *), sizeof(struct ip6_hdr), 188 ifp, (dir == PFIL_OUT), mp)); 189} 190# endif 191#endif /* __FreeBSD_version >= 501108 */ 192#if defined(IPFILTER_LKM) 193int iplidentify(s) 194char *s; 195{ 196 if (strcmp(s, "ipl") == 0) 197 return 1; 198 return 0; 199} 200#endif /* IPFILTER_LKM */ 201 202 203int ipfattach() 204{ 205#ifdef USE_SPL 206 int s; 207#endif 208 209 SPL_NET(s); 210 if (fr_running > 0) { 211 SPL_X(s); 212 return EBUSY; 213 } 214 215 MUTEX_INIT(&ipf_rw, "ipf rw mutex"); 216 MUTEX_INIT(&ipf_timeoutlock, "ipf timeout queue mutex"); 217 RWLOCK_INIT(&ipf_ipidfrag, "ipf IP NAT-Frag rwlock"); 218 RWLOCK_INIT(&ipf_tokens, "ipf token rwlock"); 219 ipf_locks_done = 1; 220 221 if (fr_initialise() < 0) { 222 SPL_X(s); 223 return EIO; 224 } 225 226 227 if (fr_checkp != fr_check) { 228 fr_savep = fr_checkp; 229 fr_checkp = fr_check; 230 } 231 232 bzero((char *)ipfselwait, sizeof(ipfselwait)); 233 bzero((char *)frcache, sizeof(frcache)); 234 fr_running = 1; 235 236 if (fr_control_forwarding & 1) 237 ipforwarding = 1; 238 239 SPL_X(s); 240#if (__FreeBSD_version >= 300000) 241 fr_slowtimer_ch = timeout(fr_slowtimer, NULL, 242 (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT); 243#else 244 timeout(fr_slowtimer, NULL, (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT); 245#endif 246 return 0; 247} 248 249 250/* 251 * Disable the filter by removing the hooks from the IP input/output 252 * stream. 253 */ 254int ipfdetach() 255{ 256#ifdef USE_SPL 257 int s; 258#endif 259 if (fr_control_forwarding & 2) 260 ipforwarding = 0; 261 262 SPL_NET(s); 263 264#if (__FreeBSD_version >= 300000) 265 if (fr_slowtimer_ch.callout != NULL) 266 untimeout(fr_slowtimer, NULL, fr_slowtimer_ch); 267 bzero(&fr_slowtimer_ch, sizeof(fr_slowtimer_ch)); 268#else 269 untimeout(fr_slowtimer, NULL); 270#endif /* FreeBSD */ 271 272#ifndef NETBSD_PF 273 if (fr_checkp != NULL) 274 fr_checkp = fr_savep; 275 fr_savep = NULL; 276#endif 277 278 fr_deinitialise(); 279 280 fr_running = -2; 281 282 (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE); 283 (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE); 284 285 if (ipf_locks_done == 1) { 286 MUTEX_DESTROY(&ipf_timeoutlock); 287 MUTEX_DESTROY(&ipf_rw); 288 RW_DESTROY(&ipf_ipidfrag); 289 RW_DESTROY(&ipf_tokens); 290 ipf_locks_done = 0; 291 } 292 293 SPL_X(s); 294 295 return 0; 296} 297 298 299/* 300 * Filter ioctl interface. 301 */ 302int iplioctl(dev, cmd, data, mode 303# if defined(_KERNEL) && ((BSD >= 199506) || (__FreeBSD_version >= 220000)) 304, p) 305# if (__FreeBSD_version >= 500024) 306struct thread *p; 307# if (__FreeBSD_version >= 500043) 308# define p_uid td_ucred->cr_ruid 309# else 310# define p_uid t_proc->p_cred->p_ruid 311# endif 312# else 313struct proc *p; 314# define p_uid p_cred->p_ruid 315# endif /* __FreeBSD_version >= 500024 */ 316# else 317) 318# endif 319#if defined(_KERNEL) && (__FreeBSD_version >= 502116) 320struct cdev *dev; 321#else 322dev_t dev; 323#endif 324ioctlcmd_t cmd; 325caddr_t data; 326int mode; 327{ 328 int error = 0, unit = 0; 329 SPL_INT(s); 330 331#if (BSD >= 199306) && defined(_KERNEL) 332 if ((securelevel >= 3) && (mode & FWRITE)) 333 return EPERM; 334#endif 335 336 unit = GET_MINOR(dev); 337 if ((IPL_LOGMAX < unit) || (unit < 0)) 338 return ENXIO; 339 340 if (fr_running <= 0) { 341 if (unit != IPL_LOGIPF) 342 return EIO; 343 if (cmd != SIOCIPFGETNEXT && cmd != SIOCIPFGET && 344 cmd != SIOCIPFSET && cmd != SIOCFRENB && 345 cmd != SIOCGETFS && cmd != SIOCGETFF) 346 return EIO; 347 } 348 349 SPL_NET(s); 350 READ_ENTER(&ipf_global); 351 352 error = fr_ioctlswitch(unit, data, cmd, mode, p->p_uid, p); 353 if (error != -1) { 354 RWLOCK_EXIT(&ipf_global); 355 SPL_X(s); 356 return error; 357 } 358 359 RWLOCK_EXIT(&ipf_global); 360 SPL_X(s); 361 362 return error; 363} 364 365 366#if 0 367void fr_forgetifp(ifp) 368void *ifp; 369{ 370 register frentry_t *f; 371 372 WRITE_ENTER(&ipf_mutex); 373 for (f = ipacct[0][fr_active]; (f != NULL); f = f->fr_next) 374 if (f->fr_ifa == ifp) 375 f->fr_ifa = (void *)-1; 376 for (f = ipacct[1][fr_active]; (f != NULL); f = f->fr_next) 377 if (f->fr_ifa == ifp) 378 f->fr_ifa = (void *)-1; 379 for (f = ipfilter[0][fr_active]; (f != NULL); f = f->fr_next) 380 if (f->fr_ifa == ifp) 381 f->fr_ifa = (void *)-1; 382 for (f = ipfilter[1][fr_active]; (f != NULL); f = f->fr_next) 383 if (f->fr_ifa == ifp) 384 f->fr_ifa = (void *)-1; 385#ifdef USE_INET6 386 for (f = ipacct6[0][fr_active]; (f != NULL); f = f->fr_next) 387 if (f->fr_ifa == ifp) 388 f->fr_ifa = (void *)-1; 389 for (f = ipacct6[1][fr_active]; (f != NULL); f = f->fr_next) 390 if (f->fr_ifa == ifp) 391 f->fr_ifa = (void *)-1; 392 for (f = ipfilter6[0][fr_active]; (f != NULL); f = f->fr_next) 393 if (f->fr_ifa == ifp) 394 f->fr_ifa = (void *)-1; 395 for (f = ipfilter6[1][fr_active]; (f != NULL); f = f->fr_next) 396 if (f->fr_ifa == ifp) 397 f->fr_ifa = (void *)-1; 398#endif 399 RWLOCK_EXIT(&ipf_mutex); 400 fr_natsync(ifp); 401} 402#endif 403 404 405/* 406 * routines below for saving IP headers to buffer 407 */ 408int iplopen(dev, flags 409#if ((BSD >= 199506) || (__FreeBSD_version >= 220000)) && defined(_KERNEL) 410, devtype, p) 411int devtype; 412# if (__FreeBSD_version >= 500024) 413struct thread *p; 414# else 415struct proc *p; 416# endif /* __FreeBSD_version >= 500024 */ 417#else 418) 419#endif 420#if defined(_KERNEL) && (__FreeBSD_version >= 502116) 421struct cdev *dev; 422#else 423dev_t dev; 424#endif 425int flags; 426{ 427 u_int min = GET_MINOR(dev); 428 429 if (IPL_LOGMAX < min) 430 min = ENXIO; 431 else 432 min = 0; 433 return min; 434} 435 436 437int iplclose(dev, flags 438#if ((BSD >= 199506) || (__FreeBSD_version >= 220000)) && defined(_KERNEL) 439, devtype, p) 440int devtype; 441# if (__FreeBSD_version >= 500024) 442struct thread *p; 443# else 444struct proc *p; 445# endif /* __FreeBSD_version >= 500024 */ 446#else 447) 448#endif 449#if defined(_KERNEL) && (__FreeBSD_version >= 502116) 450struct cdev *dev; 451#else 452dev_t dev; 453#endif 454int flags; 455{ 456 u_int min = GET_MINOR(dev); 457 458 if (IPL_LOGMAX < min) 459 min = ENXIO; 460 else 461 min = 0; 462 return min; 463} 464 465/* 466 * iplread/ipllog 467 * both of these must operate with at least splnet() lest they be 468 * called during packet processing and cause an inconsistancy to appear in 469 * the filter lists. 470 */ 471#if (BSD >= 199306) 472int iplread(dev, uio, ioflag) 473int ioflag; 474#else 475int iplread(dev, uio) 476#endif 477#if defined(_KERNEL) && (__FreeBSD_version >= 502116) 478struct cdev *dev; 479#else 480dev_t dev; 481#endif 482register struct uio *uio; 483{ 484 u_int xmin = GET_MINOR(dev); 485 486 if (fr_running < 1) 487 return EIO; 488 489 if (xmin < 0) 490 return ENXIO; 491 492# ifdef IPFILTER_SYNC 493 if (xmin == IPL_LOGSYNC) 494 return ipfsync_read(uio); 495# endif 496 497#ifdef IPFILTER_LOG 498 return ipflog_read(xmin, uio); 499#else 500 return ENXIO; 501#endif 502} 503 504 505/* 506 * iplwrite 507 * both of these must operate with at least splnet() lest they be 508 * called during packet processing and cause an inconsistancy to appear in 509 * the filter lists. 510 */ 511#if (BSD >= 199306) 512int iplwrite(dev, uio, ioflag) 513int ioflag; 514#else 515int iplwrite(dev, uio) 516#endif 517#if defined(_KERNEL) && (__FreeBSD_version >= 502116) 518struct cdev *dev; 519#else 520dev_t dev; 521#endif 522register struct uio *uio; 523{ 524 525 if (fr_running < 1) 526 return EIO; 527 528#ifdef IPFILTER_SYNC 529 if (GET_MINOR(dev) == IPL_LOGSYNC) 530 return ipfsync_write(uio); 531#endif 532 return ENXIO; 533} 534 535 536/* 537 * fr_send_reset - this could conceivably be a call to tcp_respond(), but that 538 * requires a large amount of setting up and isn't any more efficient. 539 */ 540int fr_send_reset(fin) 541fr_info_t *fin; 542{ 543 struct tcphdr *tcp, *tcp2; 544 int tlen = 0, hlen; 545 struct mbuf *m; 546#ifdef USE_INET6 547 ip6_t *ip6; 548#endif 549 ip_t *ip; 550 551 tcp = fin->fin_dp; 552 if (tcp->th_flags & TH_RST) 553 return -1; /* feedback loop */ 554 555 if (fr_checkl4sum(fin) == -1) 556 return -1; 557 558 tlen = fin->fin_dlen - (TCP_OFF(tcp) << 2) + 559 ((tcp->th_flags & TH_SYN) ? 1 : 0) + 560 ((tcp->th_flags & TH_FIN) ? 1 : 0); 561 562#ifdef USE_INET6 563 hlen = (fin->fin_v == 6) ? sizeof(ip6_t) : sizeof(ip_t); 564#else 565 hlen = sizeof(ip_t); 566#endif 567#ifdef MGETHDR 568 MGETHDR(m, M_DONTWAIT, MT_HEADER); 569#else 570 MGET(m, M_DONTWAIT, MT_HEADER); 571#endif 572 if (m == NULL) 573 return -1; 574 if (sizeof(*tcp2) + hlen > MLEN) { 575 MCLGET(m, M_DONTWAIT); 576 if ((m->m_flags & M_EXT) == 0) { 577 FREE_MB_T(m); 578 return -1; 579 } 580 } 581 582 m->m_len = sizeof(*tcp2) + hlen; 583#if (BSD >= 199103) 584 m->m_data += max_linkhdr; 585 m->m_pkthdr.len = m->m_len; 586 m->m_pkthdr.rcvif = (struct ifnet *)0; 587#endif 588 ip = mtod(m, struct ip *); 589 bzero((char *)ip, hlen); 590#ifdef USE_INET6 591 ip6 = (ip6_t *)ip; 592#endif 593 tcp2 = (struct tcphdr *)((char *)ip + hlen); 594 tcp2->th_sport = tcp->th_dport; 595 tcp2->th_dport = tcp->th_sport; 596 597 if (tcp->th_flags & TH_ACK) { 598 tcp2->th_seq = tcp->th_ack; 599 tcp2->th_flags = TH_RST; 600 tcp2->th_ack = 0; 601 } else { 602 tcp2->th_seq = 0; 603 tcp2->th_ack = ntohl(tcp->th_seq); 604 tcp2->th_ack += tlen; 605 tcp2->th_ack = htonl(tcp2->th_ack); 606 tcp2->th_flags = TH_RST|TH_ACK; 607 } 608 TCP_X2_A(tcp2, 0); 609 TCP_OFF_A(tcp2, sizeof(*tcp2) >> 2); 610 tcp2->th_win = tcp->th_win; 611 tcp2->th_sum = 0; 612 tcp2->th_urp = 0; 613 614#ifdef USE_INET6 615 if (fin->fin_v == 6) { 616 ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; 617 ip6->ip6_plen = htons(sizeof(struct tcphdr)); 618 ip6->ip6_nxt = IPPROTO_TCP; 619 ip6->ip6_hlim = 0; 620 ip6->ip6_src = fin->fin_dst6; 621 ip6->ip6_dst = fin->fin_src6; 622 tcp2->th_sum = in6_cksum(m, IPPROTO_TCP, 623 sizeof(*ip6), sizeof(*tcp2)); 624 return fr_send_ip(fin, m, &m); 625 } 626#endif 627 ip->ip_p = IPPROTO_TCP; 628 ip->ip_len = htons(sizeof(struct tcphdr)); 629 ip->ip_src.s_addr = fin->fin_daddr; 630 ip->ip_dst.s_addr = fin->fin_saddr; 631 tcp2->th_sum = in_cksum(m, hlen + sizeof(*tcp2)); 632 ip->ip_len = hlen + sizeof(*tcp2); 633 return fr_send_ip(fin, m, &m); 634} 635 636 637static int fr_send_ip(fin, m, mpp) 638fr_info_t *fin; 639mb_t *m, **mpp; 640{ 641 fr_info_t fnew; 642 ip_t *ip, *oip; 643 int hlen; 644 645 ip = mtod(m, ip_t *); 646 bzero((char *)&fnew, sizeof(fnew)); 647 648 IP_V_A(ip, fin->fin_v); 649 switch (fin->fin_v) 650 { 651 case 4 : 652 fnew.fin_v = 4; 653 oip = fin->fin_ip; 654 IP_HL_A(ip, sizeof(*oip) >> 2); 655 ip->ip_tos = oip->ip_tos; 656 ip->ip_id = fin->fin_ip->ip_id; 657#if (__FreeBSD_version > 460000) 658 ip->ip_off = path_mtu_discovery ? IP_DF : 0; 659#else 660 ip->ip_off = 0; 661#endif 662 ip->ip_ttl = ip_defttl; 663 ip->ip_sum = 0; 664 hlen = sizeof(*oip); 665 break; 666#ifdef USE_INET6 667 case 6 : 668 { 669 ip6_t *ip6 = (ip6_t *)ip; 670 671 ip6->ip6_vfc = 0x60; 672 ip6->ip6_hlim = IPDEFTTL; 673 674 fnew.fin_v = 6; 675 hlen = sizeof(*ip6); 676 break; 677 } 678#endif 679 default : 680 return EINVAL; 681 } 682#ifdef IPSEC 683 m->m_pkthdr.rcvif = NULL; 684#endif 685 686 fnew.fin_ifp = fin->fin_ifp; 687 fnew.fin_flx = FI_NOCKSUM; 688 fnew.fin_m = m; 689 fnew.fin_ip = ip; 690 fnew.fin_mp = mpp; 691 fnew.fin_hlen = hlen; 692 fnew.fin_dp = (char *)ip + hlen; 693 (void) fr_makefrip(hlen, ip, &fnew); 694 695 return fr_fastroute(m, mpp, &fnew, NULL); 696} 697 698 699int fr_send_icmp_err(type, fin, dst) 700int type; 701fr_info_t *fin; 702int dst; 703{ 704 int err, hlen, xtra, iclen, ohlen, avail, code; 705 struct in_addr dst4; 706 struct icmp *icmp; 707 struct mbuf *m; 708 void *ifp; 709#ifdef USE_INET6 710 ip6_t *ip6; 711 struct in6_addr dst6; 712#endif 713 ip_t *ip, *ip2; 714 715 if ((type < 0) || (type >= ICMP_MAXTYPE)) 716 return -1; 717 718 code = fin->fin_icode; 719#ifdef USE_INET6 720 if ((code < 0) || (code > sizeof(icmptoicmp6unreach)/sizeof(int))) 721 return -1; 722#endif 723 724 if (fr_checkl4sum(fin) == -1) 725 return -1; 726#ifdef MGETHDR 727 MGETHDR(m, M_DONTWAIT, MT_HEADER); 728#else 729 MGET(m, M_DONTWAIT, MT_HEADER); 730#endif 731 if (m == NULL) 732 return -1; 733 avail = MHLEN; 734 735 xtra = 0; 736 hlen = 0; 737 ohlen = 0; 738 ifp = fin->fin_ifp; 739 if (fin->fin_v == 4) { 740 if ((fin->fin_p == IPPROTO_ICMP) && 741 !(fin->fin_flx & FI_SHORT)) 742 switch (ntohs(fin->fin_data[0]) >> 8) 743 { 744 case ICMP_ECHO : 745 case ICMP_TSTAMP : 746 case ICMP_IREQ : 747 case ICMP_MASKREQ : 748 break; 749 default : 750 FREE_MB_T(m); 751 return 0; 752 } 753 754 if (dst == 0) { 755 if (fr_ifpaddr(4, FRI_NORMAL, ifp, 756 &dst4, NULL) == -1) { 757 FREE_MB_T(m); 758 return -1; 759 } 760 } else 761 dst4.s_addr = fin->fin_daddr; 762 763 hlen = sizeof(ip_t); 764 ohlen = fin->fin_hlen; 765 if (fin->fin_hlen < fin->fin_plen) 766 xtra = MIN(fin->fin_dlen, 8); 767 else 768 xtra = 0; 769 } 770 771#ifdef USE_INET6 772 else if (fin->fin_v == 6) { 773 hlen = sizeof(ip6_t); 774 ohlen = sizeof(ip6_t); 775 type = icmptoicmp6types[type]; 776 if (type == ICMP6_DST_UNREACH) 777 code = icmptoicmp6unreach[code]; 778 779 if (hlen + sizeof(*icmp) + max_linkhdr + 780 fin->fin_plen > avail) { 781 MCLGET(m, M_DONTWAIT); 782 if ((m->m_flags & M_EXT) == 0) { 783 FREE_MB_T(m); 784 return -1; 785 } 786 avail = MCLBYTES; 787 } 788 xtra = MIN(fin->fin_plen, 789 avail - hlen - sizeof(*icmp) - max_linkhdr); 790 if (dst == 0) { 791 if (fr_ifpaddr(6, FRI_NORMAL, ifp, 792 (struct in_addr *)&dst6, NULL) == -1) { 793 FREE_MB_T(m); 794 return -1; 795 } 796 } else 797 dst6 = fin->fin_dst6; 798 } 799#endif 800 else { 801 FREE_MB_T(m); 802 return -1; 803 } 804 805 iclen = hlen + sizeof(*icmp); 806 avail -= (max_linkhdr + iclen); 807 if (avail < 0) { 808 FREE_MB_T(m); 809 return -1; 810 } 811 if (xtra > avail) 812 xtra = avail; 813 iclen += xtra; 814 m->m_data += max_linkhdr; 815 m->m_pkthdr.rcvif = (struct ifnet *)0; 816 m->m_pkthdr.len = iclen; 817 m->m_len = iclen; 818 ip = mtod(m, ip_t *); 819 icmp = (struct icmp *)((char *)ip + hlen); 820 ip2 = (ip_t *)&icmp->icmp_ip; 821 822 icmp->icmp_type = type; 823 icmp->icmp_code = fin->fin_icode; 824 icmp->icmp_cksum = 0; 825#ifdef icmp_nextmtu 826 if (type == ICMP_UNREACH && 827 fin->fin_icode == ICMP_UNREACH_NEEDFRAG && ifp) 828 icmp->icmp_nextmtu = htons(((struct ifnet *)ifp)->if_mtu); 829#endif 830 831 bcopy((char *)fin->fin_ip, (char *)ip2, ohlen); 832 833#ifdef USE_INET6 834 ip6 = (ip6_t *)ip; 835 if (fin->fin_v == 6) { 836 ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; 837 ip6->ip6_plen = htons(iclen - hlen); 838 ip6->ip6_nxt = IPPROTO_ICMPV6; 839 ip6->ip6_hlim = 0; 840 ip6->ip6_src = dst6; 841 ip6->ip6_dst = fin->fin_src6; 842 if (xtra > 0) 843 bcopy((char *)fin->fin_ip + ohlen, 844 (char *)&icmp->icmp_ip + ohlen, xtra); 845 icmp->icmp_cksum = in6_cksum(m, IPPROTO_ICMPV6, 846 sizeof(*ip6), iclen - hlen); 847 } else 848#endif 849 { 850 ip2->ip_len = htons(ip2->ip_len); 851 ip2->ip_off = htons(ip2->ip_off); 852 ip->ip_p = IPPROTO_ICMP; 853 ip->ip_src.s_addr = dst4.s_addr; 854 ip->ip_dst.s_addr = fin->fin_saddr; 855 856 if (xtra > 0) 857 bcopy((char *)fin->fin_ip + ohlen, 858 (char *)&icmp->icmp_ip + ohlen, xtra); 859 icmp->icmp_cksum = ipf_cksum((u_short *)icmp, 860 sizeof(*icmp) + 8); 861 ip->ip_len = iclen; 862 ip->ip_p = IPPROTO_ICMP; 863 } 864 err = fr_send_ip(fin, m, &m); 865 return err; 866} 867 868 869#if !defined(IPFILTER_LKM) && (__FreeBSD_version < 300000) 870# if (BSD < 199306) 871int iplinit __P((void)); 872 873int 874# else 875void iplinit __P((void)); 876 877void 878# endif 879iplinit() 880{ 881 if (ipfattach() != 0) 882 printf("IP Filter failed to attach\n"); 883 ip_init(); 884} 885#endif /* __FreeBSD_version < 300000 */ 886 887 888int fr_fastroute(m0, mpp, fin, fdp) 889mb_t *m0, **mpp; 890fr_info_t *fin; 891frdest_t *fdp; 892{ 893 register struct ip *ip, *mhip; 894 register struct mbuf *m = m0; 895 register struct route *ro; 896 int len, off, error = 0, hlen, code; 897 struct ifnet *ifp, *sifp; 898 struct sockaddr_in *dst; 899 struct route iproute; 900 u_short ip_off; 901 frentry_t *fr; 902 903 ro = NULL; 904 905#ifdef M_WRITABLE 906 /* 907 * HOT FIX/KLUDGE: 908 * 909 * If the mbuf we're about to send is not writable (because of 910 * a cluster reference, for example) we'll need to make a copy 911 * of it since this routine modifies the contents. 912 * 913 * If you have non-crappy network hardware that can transmit data 914 * from the mbuf, rather than making a copy, this is gonna be a 915 * problem. 916 */ 917 if (M_WRITABLE(m) == 0) { 918 m0 = m_dup(m, M_DONTWAIT); 919 if (m0 != 0) { 920 FREE_MB_T(m); 921 m = m0; 922 *mpp = m; 923 } else { 924 error = ENOBUFS; 925 FREE_MB_T(m); 926 goto done; 927 } 928 } 929#endif 930 931#ifdef USE_INET6 932 if (fin->fin_v == 6) { 933 /* 934 * currently "to <if>" and "to <if>:ip#" are not supported 935 * for IPv6 936 */ 937#if (__FreeBSD_version >= 490000) 938 return ip6_output(m0, NULL, NULL, 0, NULL, NULL, NULL); 939#else 940 return ip6_output(m0, NULL, NULL, 0, NULL, NULL); 941#endif 942 } 943#endif 944 945 hlen = fin->fin_hlen; 946 ip = mtod(m0, struct ip *); 947 948 /* 949 * Route packet. 950 */ 951 ro = &iproute; 952 bzero((caddr_t)ro, sizeof (*ro)); 953 dst = (struct sockaddr_in *)&ro->ro_dst; 954 dst->sin_family = AF_INET; 955 dst->sin_addr = ip->ip_dst; 956 957 fr = fin->fin_fr; 958 if (fdp != NULL) 959 ifp = fdp->fd_ifp; 960 else 961 ifp = fin->fin_ifp; 962 963 if ((ifp == NULL) && (!fr || !(fr->fr_flags & FR_FASTROUTE))) { 964 error = -2; 965 goto bad; 966 } 967 968 if ((fdp != NULL) && (fdp->fd_ip.s_addr != 0)) 969 dst->sin_addr = fdp->fd_ip; 970 971 dst->sin_len = sizeof(*dst); 972 rtalloc(ro); 973 974 if ((ifp == NULL) && (ro->ro_rt != NULL)) 975 ifp = ro->ro_rt->rt_ifp; 976 977 if ((ro->ro_rt == NULL) || (ifp == NULL)) { 978 if (in_localaddr(ip->ip_dst)) 979 error = EHOSTUNREACH; 980 else 981 error = ENETUNREACH; 982 goto bad; 983 } 984 if (ro->ro_rt->rt_flags & RTF_GATEWAY) 985 dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway; 986 if (ro->ro_rt) 987 ro->ro_rt->rt_use++; 988 989 /* 990 * For input packets which are being "fastrouted", they won't 991 * go back through output filtering and miss their chance to get 992 * NAT'd and counted. Duplicated packets aren't considered to be 993 * part of the normal packet stream, so do not NAT them or pass 994 * them through stateful checking, etc. 995 */ 996 if ((fdp != &fr->fr_dif) && (fin->fin_out == 0)) { 997 sifp = fin->fin_ifp; 998 fin->fin_ifp = ifp; 999 fin->fin_out = 1; 1000 (void) fr_acctpkt(fin, NULL); 1001 fin->fin_fr = NULL; 1002 if (!fr || !(fr->fr_flags & FR_RETMASK)) { 1003 u_32_t pass; 1004 1005 if (fr_checkstate(fin, &pass) != NULL) 1006 fr_statederef((ipstate_t **)&fin->fin_state); 1007 } 1008 1009 switch (fr_checknatout(fin, NULL)) 1010 { 1011 case 0 : 1012 break; 1013 case 1 : 1014 fr_natderef((nat_t **)&fin->fin_nat); 1015 ip->ip_sum = 0; 1016 break; 1017 case -1 : 1018 error = -1; 1019 goto done; 1020 break; 1021 } 1022 1023 fin->fin_ifp = sifp; 1024 fin->fin_out = 0; 1025 } else 1026 ip->ip_sum = 0; 1027 /* 1028 * If small enough for interface, can just send directly. 1029 */ 1030 if (ip->ip_len <= ifp->if_mtu) { 1031 ip->ip_len = htons(ip->ip_len); 1032 ip->ip_off = htons(ip->ip_off); 1033 1034 if (!ip->ip_sum) 1035 ip->ip_sum = in_cksum(m, hlen); 1036 error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst, 1037 ro->ro_rt); 1038 goto done; 1039 } 1040 /* 1041 * Too large for interface; fragment if possible. 1042 * Must be able to put at least 8 bytes per fragment. 1043 */ 1044 ip_off = ntohs(ip->ip_off); 1045 if (ip_off & IP_DF) { 1046 error = EMSGSIZE; 1047 goto bad; 1048 } 1049 len = (ifp->if_mtu - hlen) &~ 7; 1050 if (len < 8) { 1051 error = EMSGSIZE; 1052 goto bad; 1053 } 1054 1055 { 1056 int mhlen, firstlen = len; 1057 struct mbuf **mnext = &m->m_act; 1058 1059 /* 1060 * Loop through length of segment after first fragment, 1061 * make new header and copy data of each part and link onto chain. 1062 */ 1063 m0 = m; 1064 mhlen = sizeof (struct ip); 1065 for (off = hlen + len; off < ip->ip_len; off += len) { 1066#ifdef MGETHDR 1067 MGETHDR(m, M_DONTWAIT, MT_HEADER); 1068#else 1069 MGET(m, M_DONTWAIT, MT_HEADER); 1070#endif 1071 if (m == 0) { 1072 m = m0; 1073 error = ENOBUFS; 1074 goto bad; 1075 } 1076 m->m_data += max_linkhdr; 1077 mhip = mtod(m, struct ip *); 1078 bcopy((char *)ip, (char *)mhip, sizeof(*ip)); 1079 if (hlen > sizeof (struct ip)) { 1080 mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip); 1081 IP_HL_A(mhip, mhlen >> 2); 1082 } 1083 m->m_len = mhlen; 1084 mhip->ip_off = ((off - hlen) >> 3) + ip_off; 1085 if (off + len >= ip->ip_len) 1086 len = ip->ip_len - off; 1087 else 1088 mhip->ip_off |= IP_MF; 1089 mhip->ip_len = htons((u_short)(len + mhlen)); 1090 *mnext = m; 1091 m->m_next = m_copy(m0, off, len); 1092 if (m->m_next == 0) { 1093 error = ENOBUFS; /* ??? */ 1094 goto sendorfree; 1095 } 1096 m->m_pkthdr.len = mhlen + len; 1097 m->m_pkthdr.rcvif = NULL; 1098 mhip->ip_off = htons((u_short)mhip->ip_off); 1099 mhip->ip_sum = 0; 1100 mhip->ip_sum = in_cksum(m, mhlen); 1101 mnext = &m->m_act; 1102 } 1103 /* 1104 * Update first fragment by trimming what's been copied out 1105 * and updating header, then send each fragment (in order). 1106 */ 1107 m_adj(m0, hlen + firstlen - ip->ip_len); 1108 ip->ip_len = htons((u_short)(hlen + firstlen)); 1109 ip->ip_off = htons((u_short)IP_MF); 1110 ip->ip_sum = 0; 1111 ip->ip_sum = in_cksum(m0, hlen); 1112sendorfree: 1113 for (m = m0; m; m = m0) { 1114 m0 = m->m_act; 1115 m->m_act = 0; 1116 if (error == 0) 1117 error = (*ifp->if_output)(ifp, m, 1118 (struct sockaddr *)dst, ro->ro_rt); 1119 else 1120 FREE_MB_T(m); 1121 } 1122 } 1123done: 1124 if (!error) 1125 fr_frouteok[0]++; 1126 else 1127 fr_frouteok[1]++; 1128 1129 if ((ro != NULL) && (ro->ro_rt != NULL)) { 1130 RTFREE(ro->ro_rt); 1131 } 1132 *mpp = NULL; 1133 return 0; 1134bad: 1135 if (error == EMSGSIZE) { 1136 sifp = fin->fin_ifp; 1137 code = fin->fin_icode; 1138 fin->fin_icode = ICMP_UNREACH_NEEDFRAG; 1139 fin->fin_ifp = ifp; 1140 (void) fr_send_icmp_err(ICMP_UNREACH, fin, 1); 1141 fin->fin_ifp = sifp; 1142 fin->fin_icode = code; 1143 } 1144 FREE_MB_T(m); 1145 goto done; 1146} 1147 1148 1149int fr_verifysrc(fin) 1150fr_info_t *fin; 1151{ 1152 struct sockaddr_in *dst; 1153 struct route iproute; 1154 1155 bzero((char *)&iproute, sizeof(iproute)); 1156 dst = (struct sockaddr_in *)&iproute.ro_dst; 1157 dst->sin_len = sizeof(*dst); 1158 dst->sin_family = AF_INET; 1159 dst->sin_addr = fin->fin_src; 1160 rtalloc(&iproute); 1161 if (iproute.ro_rt == NULL) 1162 return 0; 1163 return (fin->fin_ifp == iproute.ro_rt->rt_ifp); 1164} 1165 1166 1167/* 1168 * return the first IP Address associated with an interface 1169 */ 1170int fr_ifpaddr(v, atype, ifptr, inp, inpmask) 1171int v, atype; 1172void *ifptr; 1173struct in_addr *inp, *inpmask; 1174{ 1175#ifdef USE_INET6 1176 struct in6_addr *inp6 = NULL; 1177#endif 1178 struct sockaddr *sock, *mask; 1179 struct sockaddr_in *sin; 1180 struct ifaddr *ifa; 1181 struct ifnet *ifp; 1182 1183 if ((ifptr == NULL) || (ifptr == (void *)-1)) 1184 return -1; 1185 1186 sin = NULL; 1187 ifp = ifptr; 1188 1189 if (v == 4) 1190 inp->s_addr = 0; 1191#ifdef USE_INET6 1192 else if (v == 6) 1193 bzero((char *)inp, sizeof(struct in6_addr)); 1194#endif 1195#if (__FreeBSD_version >= 300000) 1196 ifa = TAILQ_FIRST(&ifp->if_addrhead); 1197#else 1198 ifa = ifp->if_addrlist; 1199#endif /* __FreeBSD_version >= 300000 */ 1200 1201 sock = ifa->ifa_addr; 1202 while (sock != NULL && ifa != NULL) { 1203 sin = (struct sockaddr_in *)sock; 1204 if ((v == 4) && (sin->sin_family == AF_INET)) 1205 break; 1206#ifdef USE_INET6 1207 if ((v == 6) && (sin->sin_family == AF_INET6)) { 1208 inp6 = &((struct sockaddr_in6 *)sin)->sin6_addr; 1209 if (!IN6_IS_ADDR_LINKLOCAL(inp6) && 1210 !IN6_IS_ADDR_LOOPBACK(inp6)) 1211 break; 1212 } 1213#endif 1214#if (__FreeBSD_version >= 300000) 1215 ifa = TAILQ_NEXT(ifa, ifa_link); 1216#else 1217 ifa = ifa->ifa_next; 1218#endif /* __FreeBSD_version >= 300000 */ 1219 if (ifa != NULL) 1220 sock = ifa->ifa_addr; 1221 } 1222 1223 if (ifa == NULL || sin == NULL) 1224 return -1; 1225 1226 mask = ifa->ifa_netmask; 1227 if (atype == FRI_BROADCAST) 1228 sock = ifa->ifa_broadaddr; 1229 else if (atype == FRI_PEERADDR) 1230 sock = ifa->ifa_dstaddr; 1231 1232 if (sock == NULL) 1233 return -1; 1234 1235#ifdef USE_INET6 1236 if (v == 6) { 1237 return fr_ifpfillv6addr(atype, (struct sockaddr_in6 *)sock, 1238 (struct sockaddr_in6 *)mask, 1239 inp, inpmask); 1240 } 1241#endif 1242 return fr_ifpfillv4addr(atype, (struct sockaddr_in *)sock, 1243 (struct sockaddr_in *)mask, inp, inpmask); 1244} 1245 1246 1247u_32_t fr_newisn(fin) 1248fr_info_t *fin; 1249{ 1250 u_32_t newiss; 1251#if (__FreeBSD_version >= 400000) 1252 newiss = arc4random(); 1253#else 1254 static iss_seq_off = 0; 1255 u_char hash[16]; 1256 MD5_CTX ctx; 1257 1258 /* 1259 * Compute the base value of the ISS. It is a hash 1260 * of (saddr, sport, daddr, dport, secret). 1261 */ 1262 MD5Init(&ctx); 1263 1264 MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src, 1265 sizeof(fin->fin_fi.fi_src)); 1266 MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst, 1267 sizeof(fin->fin_fi.fi_dst)); 1268 MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat)); 1269 1270 MD5Update(&ctx, ipf_iss_secret, sizeof(ipf_iss_secret)); 1271 1272 MD5Final(hash, &ctx); 1273 1274 memcpy(&newiss, hash, sizeof(newiss)); 1275 1276 /* 1277 * Now increment our "timer", and add it in to 1278 * the computed value. 1279 * 1280 * XXX Use `addin'? 1281 * XXX TCP_ISSINCR too large to use? 1282 */ 1283 iss_seq_off += 0x00010000; 1284 newiss += iss_seq_off; 1285#endif 1286 return newiss; 1287} 1288 1289 1290/* ------------------------------------------------------------------------ */ 1291/* Function: fr_nextipid */ 1292/* Returns: int - 0 == success, -1 == error (packet should be droppped) */ 1293/* Parameters: fin(I) - pointer to packet information */ 1294/* */ 1295/* Returns the next IPv4 ID to use for this packet. */ 1296/* ------------------------------------------------------------------------ */ 1297u_short fr_nextipid(fin) 1298fr_info_t *fin; 1299{ 1300#ifndef RANDOM_IP_ID 1301 static u_short ipid = 0; 1302 u_short id; 1303 1304 MUTEX_ENTER(&ipf_rw); 1305 id = ipid++; 1306 MUTEX_EXIT(&ipf_rw); 1307#else 1308 u_short id; 1309 1310 id = ip_randomid(); 1311#endif 1312 1313 return id; 1314} 1315 1316 1317INLINE void fr_checkv4sum(fin) 1318fr_info_t *fin; 1319{ 1320#ifdef CSUM_DATA_VALID 1321 int manual = 0; 1322 u_short sum; 1323 ip_t *ip; 1324 mb_t *m; 1325 1326 if ((fin->fin_flx & FI_NOCKSUM) != 0) 1327 return; 1328 1329 if (fin->fin_cksum != 0) 1330 return; 1331 1332 m = fin->fin_m; 1333 if (m == NULL) { 1334 manual = 1; 1335 goto skipauto; 1336 } 1337 ip = fin->fin_ip; 1338 1339 if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) { 1340 if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) 1341 sum = m->m_pkthdr.csum_data; 1342 else 1343 sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, 1344 htonl(m->m_pkthdr.csum_data + 1345 fin->fin_ip->ip_len + fin->fin_p)); 1346 sum ^= 0xffff; 1347 if (sum != 0) { 1348 fin->fin_flx |= FI_BAD; 1349 fin->fin_cksum = -1; 1350 } else { 1351 fin->fin_cksum = 1; 1352 } 1353 } else 1354 manual = 1; 1355skipauto: 1356# ifdef IPFILTER_CKSUM 1357 if (manual != 0) 1358 if (fr_checkl4sum(fin) == -1) 1359 fin->fin_flx |= FI_BAD; 1360# else 1361 ; 1362# endif 1363#else 1364# ifdef IPFILTER_CKSUM 1365 if (fr_checkl4sum(fin) == -1) 1366 fin->fin_flx |= FI_BAD; 1367# endif 1368#endif 1369} 1370 1371 1372#ifdef USE_INET6 1373INLINE void fr_checkv6sum(fin) 1374fr_info_t *fin; 1375{ 1376# ifdef IPFILTER_CKSUM 1377 if (fr_checkl4sum(fin) == -1) 1378 fin->fin_flx |= FI_BAD; 1379# endif 1380} 1381#endif /* USE_INET6 */ 1382 1383 1384size_t mbufchainlen(m0) 1385struct mbuf *m0; 1386{ 1387 size_t len; 1388 1389 if ((m0->m_flags & M_PKTHDR) != 0) { 1390 len = m0->m_pkthdr.len; 1391 } else { 1392 struct mbuf *m; 1393 1394 for (m = m0, len = 0; m != NULL; m = m->m_next) 1395 len += m->m_len; 1396 } 1397 return len; 1398} 1399 1400 1401/* ------------------------------------------------------------------------ */ 1402/* Function: fr_pullup */ 1403/* Returns: NULL == pullup failed, else pointer to protocol header */ 1404/* Parameters: m(I) - pointer to buffer where data packet starts */ 1405/* fin(I) - pointer to packet information */ 1406/* len(I) - number of bytes to pullup */ 1407/* */ 1408/* Attempt to move at least len bytes (from the start of the buffer) into a */ 1409/* single buffer for ease of access. Operating system native functions are */ 1410/* used to manage buffers - if necessary. If the entire packet ends up in */ 1411/* a single buffer, set the FI_COALESCE flag even though fr_coalesce() has */ 1412/* not been called. Both fin_ip and fin_dp are updated before exiting _IF_ */ 1413/* and ONLY if the pullup succeeds. */ 1414/* */ 1415/* We assume that 'min' is a pointer to a buffer that is part of the chain */ 1416/* of buffers that starts at *fin->fin_mp. */ 1417/* ------------------------------------------------------------------------ */ 1418void *fr_pullup(min, fin, len) 1419mb_t *min; 1420fr_info_t *fin; 1421int len; 1422{ 1423 int out = fin->fin_out, dpoff, ipoff; 1424 mb_t *m = min; 1425 char *ip; 1426 1427 if (m == NULL) 1428 return NULL; 1429 1430 ip = (char *)fin->fin_ip; 1431 if ((fin->fin_flx & FI_COALESCE) != 0) 1432 return ip; 1433 1434 ipoff = fin->fin_ipoff; 1435 if (fin->fin_dp != NULL) 1436 dpoff = (char *)fin->fin_dp - (char *)ip; 1437 else 1438 dpoff = 0; 1439 1440 if (M_LEN(m) < len) { 1441#ifdef MHLEN 1442 /* 1443 * Assume that M_PKTHDR is set and just work with what is left 1444 * rather than check.. 1445 * Should not make any real difference, anyway. 1446 */ 1447 if (len > MHLEN) 1448#else 1449 if (len > MLEN) 1450#endif 1451 { 1452#ifdef HAVE_M_PULLDOWN 1453 if (m_pulldown(m, 0, len, NULL) == NULL) 1454 m = NULL; 1455#else 1456 FREE_MB_T(*fin->fin_mp); 1457 m = NULL; 1458#endif 1459 } else 1460 { 1461 m = m_pullup(m, len); 1462 } 1463 *fin->fin_mp = m; 1464 if (m == NULL) { 1465 fin->fin_m = NULL; 1466 ATOMIC_INCL(frstats[out].fr_pull[1]); 1467 return NULL; 1468 } 1469 1470 while (M_LEN(m) == 0) { 1471 m = m->m_next; 1472 } 1473 fin->fin_m = m; 1474 ip = MTOD(m, char *) + ipoff; 1475 } 1476 1477 ATOMIC_INCL(frstats[out].fr_pull[0]); 1478 fin->fin_ip = (ip_t *)ip; 1479 if (fin->fin_dp != NULL) 1480 fin->fin_dp = (char *)fin->fin_ip + dpoff; 1481 1482 if (len == fin->fin_plen) 1483 fin->fin_flx |= FI_COALESCE; 1484 return ip; 1485} 1486 1487 1488int ipf_inject(fin, m) 1489fr_info_t *fin; 1490mb_t *m; 1491{ 1492 int error = 0; 1493 1494 if (fin->fin_out == 0) { 1495#if (__FreeBSD_version >= 501000) 1496 netisr_dispatch(NETISR_IP, m); 1497#else 1498 struct ifqueue *ifq; 1499 1500 ifq = &ipintrq; 1501 1502# ifdef _IF_QFULL 1503 if (_IF_QFULL(ifq)) 1504# else 1505 if (IF_QFULL(ifq)) 1506# endif 1507 { 1508# ifdef _IF_DROP 1509 _IF_DROP(ifq); 1510# else 1511 IF_DROP(ifq); 1512# endif 1513 FREE_MB_T(m); 1514 error = ENOBUFS; 1515 } else { 1516 IF_ENQUEUE(ifq, m); 1517 } 1518#endif 1519 } else { 1520#if (__FreeBSD_version >= 470102) 1521 error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL); 1522#else 1523 error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL); 1524#endif 1525 } 1526 1527 return error; 1528} 1529 1530int ipf_pfil_unhook(void) { 1531#if defined(NETBSD_PF) && (__FreeBSD_version >= 500011) 1532# if __FreeBSD_version >= 501108 1533 struct pfil_head *ph_inet; 1534# ifdef USE_INET6 1535 struct pfil_head *ph_inet6; 1536# endif 1537# endif 1538#endif 1539 1540#ifdef NETBSD_PF 1541# if (__FreeBSD_version >= 500011) 1542# if (__FreeBSD_version >= 501108) 1543 ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); 1544 if (ph_inet != NULL) 1545 pfil_remove_hook((void *)fr_check_wrapper, NULL, 1546 PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet); 1547# else 1548 pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK, 1549 &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); 1550# endif 1551# else 1552 pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK); 1553# endif 1554# ifdef USE_INET6 1555# if (__FreeBSD_version >= 501108) 1556 ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6); 1557 if (ph_inet6 != NULL) 1558 pfil_remove_hook((void *)fr_check_wrapper6, NULL, 1559 PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet6); 1560# else 1561 pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK, 1562 &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh); 1563# endif 1564# endif 1565#endif 1566 1567 return (0); 1568} 1569 1570int ipf_pfil_hook(void) { 1571#if defined(NETBSD_PF) && (__FreeBSD_version >= 500011) 1572# if __FreeBSD_version >= 501108 1573 struct pfil_head *ph_inet; 1574# ifdef USE_INET6 1575 struct pfil_head *ph_inet6; 1576# endif 1577# endif 1578#endif 1579 1580# ifdef NETBSD_PF 1581# if __FreeBSD_version >= 500011 1582# if __FreeBSD_version >= 501108 1583 ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); 1584# ifdef USE_INET6 1585 ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6); 1586# endif 1587 if (ph_inet == NULL 1588# ifdef USE_INET6 1589 && ph_inet6 == NULL 1590# endif 1591 ) 1592 return ENODEV; 1593 1594 if (ph_inet != NULL) 1595 pfil_add_hook((void *)fr_check_wrapper, NULL, 1596 PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet); 1597# else 1598 pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK, 1599 &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); 1600# endif 1601# else 1602 pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK); 1603# endif 1604# ifdef USE_INET6 1605# if __FreeBSD_version >= 501108 1606 if (ph_inet6 != NULL) 1607 pfil_add_hook((void *)fr_check_wrapper6, NULL, 1608 PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet6); 1609# else 1610 pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK, 1611 &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh); 1612# endif 1613# endif 1614# endif 1615 return (0); 1616} 1617 1618void 1619ipf_event_reg(void) 1620{ 1621#if (__FreeBSD_version >= 502103) 1622 ipf_arrivetag = EVENTHANDLER_REGISTER(ifnet_arrival_event, \ 1623 ipf_ifevent, NULL, \ 1624 EVENTHANDLER_PRI_ANY); 1625 ipf_departtag = EVENTHANDLER_REGISTER(ifnet_departure_event, \ 1626 ipf_ifevent, NULL, \ 1627 EVENTHANDLER_PRI_ANY); 1628 ipf_clonetag = EVENTHANDLER_REGISTER(if_clone_event, ipf_ifevent, \ 1629 NULL, EVENTHANDLER_PRI_ANY); 1630#endif 1631} 1632 1633void 1634ipf_event_dereg(void) 1635{ 1636#if (__FreeBSD_version >= 502103) 1637 if (ipf_arrivetag != NULL) { 1638 EVENTHANDLER_DEREGISTER(ifnet_arrival_event, ipf_arrivetag); 1639 } 1640 if (ipf_departtag != NULL) { 1641 EVENTHANDLER_DEREGISTER(ifnet_departure_event, ipf_departtag); 1642 } 1643 if (ipf_clonetag != NULL) { 1644 EVENTHANDLER_DEREGISTER(if_clone_event, ipf_clonetag); 1645 } 1646#endif 1647} 1648