svn commit: r198045 - in user/eri/pf45/head/sys: contrib/pf/net
netinet netinet/ipfw
Ermal Luçi
eri at FreeBSD.org
Tue Oct 13 19:49:33 UTC 2009
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,
More information about the svn-src-user
mailing list