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