Date: Tue, 13 Oct 2009 19:49:33 +0000 (UTC) From: Ermal Luçi <eri@FreeBSD.org> To: src-committers@freebsd.org, svn-src-user@freebsd.org Subject: svn commit: r198045 - in user/eri/pf45/head/sys: contrib/pf/net netinet netinet/ipfw Message-ID: <200910131949.n9DJnXsp014720@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: eri Date: Tue Oct 13 19:49:33 2009 New Revision: 198045 URL: http://svn.freebsd.org/changeset/base/198045 Log: Make pf(4) divert target usable with FreeBSD divert(4). The AF_INET only divert(4) limitation is inherited. The divert(4) for pf(4) implementation has been tested/used on pfSense.org since long time and is belived to be stable. As a side not the divert(4) module is not anymore dependent on ipfw(4). TODO: Update the man page of divert(4). Modified: user/eri/pf45/head/sys/contrib/pf/net/pf.c user/eri/pf45/head/sys/netinet/ip_divert.c user/eri/pf45/head/sys/netinet/ip_divert.h user/eri/pf45/head/sys/netinet/ip_input.c user/eri/pf45/head/sys/netinet/ipfw/ip_fw_pfil.c Modified: user/eri/pf45/head/sys/contrib/pf/net/pf.c ============================================================================== --- user/eri/pf45/head/sys/contrib/pf/net/pf.c Tue Oct 13 19:04:01 2009 (r198044) +++ user/eri/pf45/head/sys/contrib/pf/net/pf.c Tue Oct 13 19:49:33 2009 (r198045) @@ -136,6 +136,9 @@ __FBSDID("$FreeBSD$"); #include <netinet/udp_var.h> #include <netinet/icmp_var.h> #include <netinet/if_ether.h> +#ifdef __FreeBSD__ +#include <netinet/ip_divert.h> +#endif #ifndef __FreeBSD__ #include <dev/rndvar.h> @@ -371,6 +374,13 @@ struct pf_pool_limit pf_pool_limits[PF_L #endif #ifdef __FreeBSD__ +#define PF_FREEBSD_DIVERT() \ + do { \ + r = (*state)->rule.ptr; \ + if (r->divert.port && !(pd->pf_mtag->flags & PF_TAG_DIVERTED)) \ + return (PF_PASS); \ + } while (0) + #define STATE_LOOKUP(i, k, d, s, m, pt) \ do { \ s = pf_find_state(i, k, d, m, pt); \ @@ -4342,6 +4352,9 @@ pf_test_state_tcp(struct pf_state **stat int copyback = 0; struct pf_state_peer *src, *dst; struct pf_state_key *sk; +#ifdef __FreeBSD__ + struct pf_rule *r; +#endif key.af = pd->af; key.proto = IPPROTO_TCP; @@ -4359,6 +4372,8 @@ pf_test_state_tcp(struct pf_state **stat #ifdef __FreeBSD__ STATE_LOOKUP(kif, &key, direction, *state, m, pd->pf_mtag); + + PF_FREEBSD_DIVERT(); #else STATE_LOOKUP(kif, &key, direction, *state, m); #endif @@ -4371,6 +4386,19 @@ pf_test_state_tcp(struct pf_state **stat dst = &(*state)->src; } +#ifdef __FreeBSD__ + /* + * The inital state is created when searching in the ruleset when + * the packet reloops the state checking will drop it. + * We take measure here for this special case. + */ + if ((th->th_flags & TH_SYN) && src->state == TCPS_SYN_SENT && + dst->state == TCPS_CLOSED) { + if (pd->pf_mtag->flags & PF_TAG_DIVERTED) + return (PF_PASS); + } +#endif + sk = (*state)->key[pd->didx]; if ((*state)->src.state == PF_TCPS_PROXY_SRC) { @@ -4536,6 +4564,9 @@ pf_test_state_udp(struct pf_state **stat struct pf_state_peer *src, *dst; struct pf_state_key_cmp key; struct udphdr *uh = pd->hdr.udp; +#ifdef __FreeBSD__ + struct pf_rule *r; +#endif key.af = pd->af; key.proto = IPPROTO_UDP; @@ -4553,6 +4584,8 @@ pf_test_state_udp(struct pf_state **stat #ifdef __FreeBSD__ STATE_LOOKUP(kif, &key, direction, *state, m, pd->pf_mtag); + + PF_FREEBSD_DIVERT(); #else STATE_LOOKUP(kif, &key, direction, *state, m); #endif @@ -4609,6 +4642,7 @@ pf_test_state_icmp(struct pf_state **sta { struct pf_addr *saddr = pd->src, *daddr = pd->dst; #ifdef __FreeBSD__ + struct pf_rule *r; u_int16_t icmpid = 0, *icmpsum; #else u_int16_t icmpid, *icmpsum; @@ -4666,6 +4700,8 @@ pf_test_state_icmp(struct pf_state **sta #ifdef __FreeBSD__ STATE_LOOKUP(kif, &key, direction, *state, m, pd->pf_mtag); + + PF_FREEBSD_DIVERT(); #else STATE_LOOKUP(kif, &key, direction, *state, m); #endif @@ -4881,6 +4917,8 @@ pf_test_state_icmp(struct pf_state **sta #ifdef __FreeBSD__ STATE_LOOKUP(kif, &key, direction, *state, m, pd->pf_mtag); + + PF_FREEBSD_DIVERT(); #else STATE_LOOKUP(kif, &key, direction, *state, m); #endif @@ -5031,6 +5069,8 @@ pf_test_state_icmp(struct pf_state **sta #ifdef __FreeBSD__ STATE_LOOKUP(kif, &key, direction, *state, m, pd->pf_mtag); + + PF_FREEBSD_DIVERT(); #else STATE_LOOKUP(kif, &key, direction, *state, m); #endif @@ -5120,6 +5160,8 @@ pf_test_state_icmp(struct pf_state **sta #ifdef __FreeBSD__ STATE_LOOKUP(kif, &key, direction, *state, m, pd->pf_mtag); + + PF_FREEBSD_DIVERT(); #else STATE_LOOKUP(kif, &key, direction, *state, m); #endif @@ -5183,6 +5225,8 @@ pf_test_state_icmp(struct pf_state **sta #ifdef __FreeBSD__ STATE_LOOKUP(kif, &key, direction, *state, m, pd->pf_mtag); + + PF_FREEBSD_DIVERT(); #else STATE_LOOKUP(kif, &key, direction, *state, m); #endif @@ -5239,6 +5283,8 @@ pf_test_state_icmp(struct pf_state **sta #ifdef __FreeBSD__ STATE_LOOKUP(kif, &key, direction, *state, m, pd->pf_mtag); + + PF_FREEBSD_DIVERT(); #else STATE_LOOKUP(kif, &key, direction, *state, m); #endif @@ -5308,6 +5354,9 @@ pf_test_state_other(struct pf_state **st { struct pf_state_peer *src, *dst; struct pf_state_key_cmp key; +#ifdef __FreeBSD__ + struct pf_rule *r; +#endif key.af = pd->af; key.proto = pd->proto; @@ -5323,6 +5372,8 @@ pf_test_state_other(struct pf_state **st #ifdef __FreeBSD__ STATE_LOOKUP(kif, &key, direction, *state, m, pd->pf_mtag); + + PF_FREEBSD_DIVERT(); #else STATE_LOOKUP(kif, &key, direction, *state, m); #endif @@ -6351,6 +6402,7 @@ pf_test(int dir, struct ifnet *ifp, stru struct mbuf *m = *m0; #ifdef __FreeBSD__ struct ip *h = NULL; + struct m_tag *dvtag; #else struct ip *h; #endif @@ -6431,7 +6483,14 @@ pf_test(int dir, struct ifnet *ifp, stru if (m->m_pkthdr.pf.flags & PF_TAG_GENERATED) return (PF_PASS); #endif - + +#ifdef __FreeBSD__ + if (ip_divert_ptr != NULL && + ((dvtag = m_tag_find(m, PACKET_TAG_DIVERT, NULL)) != NULL)) { + pd.pf_mtag->flags |= PF_TAG_DIVERTED; + m_tag_delete(m, dvtag); + } else +#endif /* We do IP header normalization and packet reassembly here */ if (pf_normalize_ip(m0, dir, kif, &reason, &pd) != PF_PASS) { action = PF_DROP; @@ -6670,19 +6729,48 @@ done: m->m_pkthdr.pf.flags |= PF_TAG_TRANSLATE_LOCALHOST; #endif +#ifdef __FreeBSD__ + if (action == PF_PASS && r->divert.port && + ip_divert_ptr != NULL && !(pd.pf_mtag->flags & PF_TAG_DIVERTED)) { + struct divert_tag *dt; + + dvtag = m_tag_get(PACKET_TAG_DIVERT, + sizeof(struct divert_tag), M_NOWAIT); + if (dvtag != NULL) { + dt = (struct divert_tag *)(dvtag+1); + dt->cookie = 0; + dt->info = r->divert.port; + m_tag_prepend(m, dvtag); + + pd.pf_mtag->flags |= PF_TAG_DIVERTED; + + PF_UNLOCK(); + + ip_divert_ptr(*m0, + dir == PF_IN ? DIV_DIR_IN : DIV_DIR_OUT); + + *m0 = NULL; + return (action); + } else { + /* XXX: ipfw has the same behaviour! */ + action = PF_DROP; + REASON_SET(&reason, PFRES_MEMORY); + log = 1; + DPFPRINTF(PF_DEBUG_MISC, + ("pf: failed to allocate divert tag\n")); + } + } +#else if (dir == PF_IN && action == PF_PASS && r->divert.port) { struct pf_divert *divert; if ((divert = pf_get_divert(m))) { -#ifdef __FreeBSD__ - pd.pf_mtag->flags |= PF_TAG_DIVERTED; -#else m->m_pkthdr.pf.flags |= PF_TAG_DIVERTED; -#endif divert->port = r->divert.port; divert->addr.ipv4 = r->divert.addr.v4; } } +#endif if (log) { struct pf_rule *lr; @@ -7156,19 +7244,21 @@ done: m->m_pkthdr.pf.flags |= PF_TAG_TRANSLATE_LOCALHOST; #endif +#ifdef __FreeBSD__ + /* XXX: Anybody working on it?! */ + if (r->divert.port) + printf("pf: divert(9) is not supported for IPv6\n"); +#else if (dir == PF_IN && action == PF_PASS && r->divert.port) { struct pf_divert *divert; if ((divert = pf_get_divert(m))) { -#ifdef __FreeBSD__ - pd.pf_mtag->flags |= PF_TAG_DIVERTED; -#else m->m_pkthdr.pf.flags |= PF_TAG_DIVERTED; -#endif divert->port = r->divert.port; divert->addr.ipv6 = r->divert.addr.v6; } } +#endif if (log) { struct pf_rule *lr; Modified: user/eri/pf45/head/sys/netinet/ip_divert.c ============================================================================== --- user/eri/pf45/head/sys/netinet/ip_divert.c Tue Oct 13 19:04:01 2009 (r198044) +++ user/eri/pf45/head/sys/netinet/ip_divert.c Tue Oct 13 19:49:33 2009 (r198045) @@ -800,5 +800,4 @@ static moduledata_t ipdivertmod = { }; DECLARE_MODULE(ipdivert, ipdivertmod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY); -MODULE_DEPEND(dummynet, ipfw, 2, 2, 2); MODULE_VERSION(ipdivert, 1); Modified: user/eri/pf45/head/sys/netinet/ip_divert.h ============================================================================== --- user/eri/pf45/head/sys/netinet/ip_divert.h Tue Oct 13 19:04:01 2009 (r198044) +++ user/eri/pf45/head/sys/netinet/ip_divert.h Tue Oct 13 19:49:33 2009 (r198045) @@ -50,6 +50,9 @@ struct divert_tag { u_int16_t cookie; /* ipfw rule number */ }; +#define DIV_DIR_IN 1 +#define DIV_DIR_OUT 0 + /* * Return the divert cookie associated with the mbuf; if any. */ Modified: user/eri/pf45/head/sys/netinet/ip_input.c ============================================================================== --- user/eri/pf45/head/sys/netinet/ip_input.c Tue Oct 13 19:04:01 2009 (r198044) +++ user/eri/pf45/head/sys/netinet/ip_input.c Tue Oct 13 19:49:33 2009 (r198045) @@ -80,6 +80,7 @@ __FBSDID("$FreeBSD$"); #ifdef IPSEC #include <netinet/ip_ipsec.h> #endif /* IPSEC */ +#include <netinet/ip_divert.h> #include <sys/socketvar.h> @@ -183,6 +184,9 @@ extern struct domain inetdomain; extern struct protosw inetsw[]; u_char ip_protox[IPPROTO_MAX]; +/* Divert hooks. */ +ip_divert_packet_t *ip_divert_ptr = NULL; + SYSCTL_VNET_STRUCT(_net_inet_ip, IPCTL_STATS, stats, CTLFLAG_RW, &VNET_NAME(ipstat), ipstat, "IP statistics (struct ipstat, netinet/ip_var.h)"); Modified: user/eri/pf45/head/sys/netinet/ipfw/ip_fw_pfil.c ============================================================================== --- user/eri/pf45/head/sys/netinet/ipfw/ip_fw_pfil.c Tue Oct 13 19:04:01 2009 (r198044) +++ user/eri/pf45/head/sys/netinet/ipfw/ip_fw_pfil.c Tue Oct 13 19:49:33 2009 (r198045) @@ -74,16 +74,11 @@ VNET_DEFINE(int, fw6_enable) = 1; int ipfw_chg_hook(SYSCTL_HANDLER_ARGS); -/* Divert hooks. */ -ip_divert_packet_t *ip_divert_ptr = NULL; - /* ng_ipfw hooks. */ ng_ipfw_input_t *ng_ipfw_input_p = NULL; /* Forward declarations. */ static int ipfw_divert(struct mbuf **, int, int); -#define DIV_DIR_IN 1 -#define DIV_DIR_OUT 0 int ipfw_check_in(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200910131949.n9DJnXsp014720>