Index: sys/contrib/ipfilter/netinet/ip_fil_freebsd.c =================================================================== --- sys/contrib/ipfilter/netinet/ip_fil_freebsd.c +++ sys/contrib/ipfilter/netinet/ip_fil_freebsd.c @@ -149,6 +149,9 @@ struct ip *ip = mtod(*mp, struct ip *); int rv; + if (dir == PFIL_FWD) + dir = PFIL_OUT; + /* * IPFilter expects evreything in network byte order */ @@ -178,6 +181,9 @@ { int error; + if (dir == PFIL_FWD) + dir = PFIL_OUT; + CURVNET_SET(ifp->if_vnet); error = ipf_check(&V_ipfmain, mtod(*mp, struct ip *), sizeof(struct ip6_hdr), ifp, (dir == PFIL_OUT), mp); @@ -1371,12 +1377,12 @@ ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); if (ph_inet != NULL) pfil_remove_hook((void *)ipf_check_wrapper, NULL, - PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet); + PFIL_IN|PFIL_OUT|PFIL_FWD|PFIL_WAITOK, ph_inet); # ifdef USE_INET6 ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6); if (ph_inet6 != NULL) pfil_remove_hook((void *)ipf_check_wrapper6, NULL, - PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet6); + PFIL_IN|PFIL_OUT|PFIL_FWD|PFIL_WAITOK, ph_inet6); # endif #endif @@ -1406,11 +1412,11 @@ if (ph_inet != NULL) pfil_add_hook((void *)ipf_check_wrapper, NULL, - PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet); + PFIL_IN|PFIL_OUT|PFIL_FWD|PFIL_WAITOK, ph_inet); # ifdef USE_INET6 if (ph_inet6 != NULL) pfil_add_hook((void *)ipf_check_wrapper6, NULL, - PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet6); + PFIL_IN|PFIL_OUT|PFIL_FWD|PFIL_WAITOK, ph_inet6); # endif # endif return (0); Index: sys/net/pfil.h =================================================================== --- sys/net/pfil.h +++ sys/net/pfil.h @@ -62,8 +62,9 @@ #define PFIL_IN 0x00000001 #define PFIL_OUT 0x00000002 -#define PFIL_WAITOK 0x00000004 -#define PFIL_ALL (PFIL_IN|PFIL_OUT) +#define PFIL_FWD 0x00000004 +#define PFIL_WAITOK 0x00000008 +#define PFIL_ALL (PFIL_IN|PFIL_OUT|PFIL_FWD) typedef TAILQ_HEAD(pfil_chain, packet_filter_hook) pfil_chain_t; @@ -79,6 +80,7 @@ struct pfil_head { pfil_chain_t ph_in; pfil_chain_t ph_out; + pfil_chain_t ph_fwd; int ph_type; int ph_nhooks; #if defined( __linux__ ) || defined( _WIN32 ) Index: sys/net/pfil.c =================================================================== --- sys/net/pfil.c +++ sys/net/pfil.c @@ -126,6 +126,8 @@ return (TAILQ_FIRST(&ph->ph_in)); else if (dir == PFIL_OUT) return (TAILQ_FIRST(&ph->ph_out)); + else if (dir == PFIL_FWD) + return (TAILQ_FIRST(&ph->ph_fwd)); else return (NULL); } @@ -213,6 +215,7 @@ ph->ph_nhooks = 0; TAILQ_INIT(&ph->ph_in); TAILQ_INIT(&ph->ph_out); + TAILQ_INIT(&ph->ph_fwd); LIST_INSERT_HEAD(&V_pfil_head_list, ph, ph_list); PFIL_HEADLIST_UNLOCK(); return (0); @@ -235,6 +238,8 @@ free(pfh, M_IFADDR); TAILQ_FOREACH_SAFE(pfh, &ph->ph_out, pfil_chain, pfnext) free(pfh, M_IFADDR); + TAILQ_FOREACH_SAFE(pfh, &ph->ph_fwd, pfil_chain, pfnext) + free(pfh, M_IFADDR); PFIL_LOCK_DESTROY(ph); return (0); } @@ -260,6 +265,7 @@ * flags are: * PFIL_IN call me on incoming packets * PFIL_OUT call me on outgoing packets + * PFIL_FWD call me in the forwarding path * PFIL_ALL call me on all of the above * PFIL_WAITOK OK to call malloc with M_WAITOK. */ @@ -268,6 +274,7 @@ { struct packet_filter_hook *pfh1 = NULL; struct packet_filter_hook *pfh2 = NULL; + struct packet_filter_hook *pfh3 = NULL; int err; if (flags & PFIL_IN) { @@ -286,11 +293,19 @@ goto error; } } + if (flags & PFIL_FWD) { + pfh3 = (struct packet_filter_hook *)malloc(sizeof(*pfh1), + M_IFADDR, (flags & PFIL_WAITOK) ? M_WAITOK : M_NOWAIT); + if (pfh3 == NULL) { + err = ENOMEM; + goto error; + } + } PFIL_WLOCK(ph); if (flags & PFIL_IN) { pfh1->pfil_func = func; pfh1->pfil_arg = arg; - err = pfil_chain_add(&ph->ph_in, pfh1, flags & ~PFIL_OUT); + err = pfil_chain_add(&ph->ph_in, pfh1, flags & ~(PFIL_OUT | PFIL_FWD)); if (err) goto locked_error; ph->ph_nhooks++; @@ -298,10 +313,23 @@ if (flags & PFIL_OUT) { pfh2->pfil_func = func; pfh2->pfil_arg = arg; - err = pfil_chain_add(&ph->ph_out, pfh2, flags & ~PFIL_IN); + err = pfil_chain_add(&ph->ph_out, pfh2, flags & ~(PFIL_IN | PFIL_FWD)); + if (err) { + if (flags & PFIL_IN) + pfil_chain_remove(&ph->ph_in, func, arg); + goto locked_error; + } + ph->ph_nhooks++; + } + if (flags & PFIL_FWD) { + pfh3->pfil_func = func; + pfh3->pfil_arg = arg; + err = pfil_chain_add(&ph->ph_fwd, pfh3, flags & ~(PFIL_IN | PFIL_OUT)); if (err) { if (flags & PFIL_IN) pfil_chain_remove(&ph->ph_in, func, arg); + if (flags & PFIL_OUT) + pfil_chain_remove(&ph->ph_out, func, arg); goto locked_error; } ph->ph_nhooks++; @@ -315,6 +343,8 @@ free(pfh1, M_IFADDR); if (pfh2 != NULL) free(pfh2, M_IFADDR); + if (pfh3 != NULL) + free(pfh3, M_IFADDR); return (err); } @@ -338,6 +368,11 @@ if (err == 0) ph->ph_nhooks--; } + if ((err == 0) && (flags & PFIL_FWD)) { + err = pfil_chain_remove(&ph->ph_fwd, func, arg); + if (err == 0) + ph->ph_nhooks--; + } PFIL_WUNLOCK(ph); return (err); } Index: sys/netinet/ip_fastfwd.c =================================================================== --- sys/netinet/ip_fastfwd.c +++ sys/netinet/ip_fastfwd.c @@ -300,12 +300,12 @@ return (NULL); /* icmp unreach already sent */ /* - * Step 5: outgoing firewall packet processing + * Step 5: forwarding firewall packet processing */ if (!PFIL_HOOKED(&V_inet_pfil_hook)) goto passout; - if (pfil_run_hooks(&V_inet_pfil_hook, &m, nh.nh_ifp, PFIL_OUT, NULL) || + if (pfil_run_hooks(&V_inet_pfil_hook, &m, nh.nh_ifp, PFIL_FWD, NULL) || m == NULL) { goto drop; } Index: sys/netinet/siftr.c =================================================================== --- sys/netinet/siftr.c +++ sys/netinet/siftr.c @@ -843,6 +843,9 @@ inp_locally_locked = 0; ss = DPCPU_PTR(ss); + if (dir == PFIL_FWD) + dir = PFIL_OUT; + /* * m_pullup is not required here because ip_{input|output} * already do the heavy lifting for us. @@ -1135,17 +1138,21 @@ if (action == HOOK) { pfil_add_hook(siftr_chkpkt, NULL, - PFIL_IN | PFIL_OUT | PFIL_WAITOK, pfh_inet); + PFIL_IN | PFIL_FWD| PFIL_OUT | PFIL_WAITOK, + pfh_inet); #ifdef SIFTR_IPV6 pfil_add_hook(siftr_chkpkt6, NULL, - PFIL_IN | PFIL_OUT | PFIL_WAITOK, pfh_inet6); + PFIL_IN | PFIL_FWD | PFIL_OUT | PFIL_WAITOK, + pfh_inet6); #endif } else if (action == UNHOOK) { pfil_remove_hook(siftr_chkpkt, NULL, - PFIL_IN | PFIL_OUT | PFIL_WAITOK, pfh_inet); + PFIL_IN | PFIL_FWD | PFIL_OUT | PFIL_WAITOK, + pfh_inet); #ifdef SIFTR_IPV6 pfil_remove_hook(siftr_chkpkt6, NULL, - PFIL_IN | PFIL_OUT | PFIL_WAITOK, pfh_inet6); + PFIL_IN | PFIL_FWD | PFIL_OUT | PFIL_WAITOK, + pfh_inet6); #endif } CURVNET_RESTORE(); Index: sys/netinet6/ip6_fastfwd.c =================================================================== --- sys/netinet6/ip6_fastfwd.c +++ sys/netinet6/ip6_fastfwd.c @@ -196,11 +196,11 @@ } /* - * Outgoing packet firewall processing. + * Forwarded packet firewall processing. */ if (!PFIL_HOOKED(&V_inet6_pfil_hook)) goto passout; - if (pfil_run_hooks(&V_inet6_pfil_hook, &m, nh.nh_ifp, PFIL_OUT, + if (pfil_run_hooks(&V_inet6_pfil_hook, &m, nh.nh_ifp, PFIL_FWD, NULL) != 0 || m == NULL) goto dropout; Index: sys/netinet6/ip6_forward.c =================================================================== --- sys/netinet6/ip6_forward.c +++ sys/netinet6/ip6_forward.c @@ -324,8 +324,8 @@ goto pass; odst = ip6->ip6_dst; - /* Run through list of hooks for output packets. */ - error = pfil_run_hooks(&V_inet6_pfil_hook, &m, rt->rt_ifp, PFIL_OUT, NULL); + /* Run through list of hooks for forwarded packets. */ + error = pfil_run_hooks(&V_inet6_pfil_hook, &m, rt->rt_ifp, PFIL_FWD, NULL); if (error != 0 || m == NULL) goto freecopy; /* consumed by filter */ ip6 = mtod(m, struct ip6_hdr *); Index: sys/netpfil/ipfw/ip_fw_pfil.c =================================================================== --- sys/netpfil/ipfw/ip_fw_pfil.c +++ sys/netpfil/ipfw/ip_fw_pfil.c @@ -317,6 +317,9 @@ struct ip_fw_args args; struct m_tag *mtag; + if (dir == PFIL_FWD) + dir = PFIL_OUT; + /* fetch start point from rule, if any. remove the tag if present. */ mtag = m_tag_locate(*m0, MTAG_IPFW_RULE, 0, NULL); if (mtag == NULL) { @@ -508,7 +511,7 @@ hook_func = (pf == AF_LINK) ? ipfw_check_frame : ipfw_check_packet; (void) (onoff ? pfil_add_hook : pfil_remove_hook) - (hook_func, NULL, PFIL_IN | PFIL_OUT | PFIL_WAITOK, pfh); + (hook_func, NULL, PFIL_IN | PFIL_OUT | PFIL_FWD | PFIL_WAITOK, pfh); return 0; } Index: sys/netpfil/pf/pf.c =================================================================== --- sys/netpfil/pf/pf.c +++ sys/netpfil/pf/pf.c @@ -6246,21 +6246,6 @@ M_ASSERTPKTHDR(m); - /* Detect packet forwarding. - * If the input interface is different from the output interface we're - * forwarding. - * We do need to be careful about bridges. If the - * net.link.bridge.pfil_bridge sysctl is set we can be filtering on a - * bridge, so if the input interface is a bridge member and the output - * interface is its bridge or a member of the same bridge we're not - * actually forwarding but bridging. - */ - if (dir == PF_OUT && m->m_pkthdr.rcvif && ifp != m->m_pkthdr.rcvif && - (m->m_pkthdr.rcvif->if_bridge == NULL || - (m->m_pkthdr.rcvif->if_bridge != ifp->if_softc && - m->m_pkthdr.rcvif->if_bridge != ifp->if_bridge))) - fwdir = PF_FWD; - if (dir == PF_FWD) dir = PF_OUT; Index: sys/netpfil/pf/pf_ioctl.c =================================================================== --- sys/netpfil/pf/pf_ioctl.c +++ sys/netpfil/pf/pf_ioctl.c @@ -3624,7 +3624,7 @@ int chk; CURVNET_SET(ifp->if_vnet); - chk = pf_test6(PF_OUT, ifp, m, inp); + chk = pf_test6(dir == PFIL_OUT ? PF_OUT : PF_FWD, ifp, m, inp); CURVNET_RESTORE(); if (chk && *m) { m_freem(*m); @@ -3654,7 +3654,7 @@ if (pfh_inet == NULL) return (ESRCH); /* XXX */ pfil_add_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet); - pfil_add_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet); + pfil_add_hook(pf_check_out, NULL, PFIL_OUT | PFIL_FWD | PFIL_WAITOK, pfh_inet); #endif #ifdef INET6 pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6); @@ -3662,13 +3662,14 @@ #ifdef INET pfil_remove_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet); - pfil_remove_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK, + pfil_remove_hook(pf_check_out, NULL, PFIL_OUT | PFIL_FWD | PFIL_WAITOK, pfh_inet); #endif return (ESRCH); /* XXX */ } pfil_add_hook(pf_check6_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet6); - pfil_add_hook(pf_check6_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet6); + pfil_add_hook(pf_check6_out, NULL, PFIL_OUT | PFIL_FWD | PFIL_WAITOK, + pfh_inet6); #endif V_pf_pfil_hooked = 1; @@ -3694,7 +3695,7 @@ return (ESRCH); /* XXX */ pfil_remove_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet); - pfil_remove_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK, + pfil_remove_hook(pf_check_out, NULL, PFIL_OUT | PFIL_FWD | PFIL_WAITOK, pfh_inet); #endif #ifdef INET6 @@ -3703,7 +3704,7 @@ return (ESRCH); /* XXX */ pfil_remove_hook(pf_check6_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet6); - pfil_remove_hook(pf_check6_out, NULL, PFIL_OUT | PFIL_WAITOK, + pfil_remove_hook(pf_check6_out, NULL, PFIL_OUT | PFIL_FWD | PFIL_WAITOK, pfh_inet6); #endif