Page MenuHomeFreeBSD

D43114.id132462.diff
No OneTemporary

D43114.id132462.diff

diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
--- a/sbin/pfctl/parse.y
+++ b/sbin/pfctl/parse.y
@@ -4680,6 +4680,7 @@
redirpool pool_opts
{
struct pfctl_rule r;
+ struct node_state_opt *o;
if (check_rulestate(PFCTL_STATE_NAT))
YYERROR;
@@ -4855,6 +4856,21 @@
r.rpool.mape = $10.mape;
}
+ o = keep_state_defaults;
+ while (o) {
+ switch (o->type) {
+ case PF_STATE_OPT_PFLOW:
+ if (r.rule_flag & PFRULE_PFLOW) {
+ yyerror("state pflow option: "
+ "multiple definitions");
+ YYERROR;
+ }
+ r.rule_flag |= PFRULE_PFLOW;
+ break;
+ }
+ o = o->next;
+ }
+
expand_rule(&r, $2, $9 == NULL ? NULL : $9->host, $4,
$5.src_os, $5.src.host, $5.src.port, $5.dst.host,
$5.dst.port, 0, 0, 0, "");
diff --git a/sys/net/pflow.h b/sys/net/pflow.h
--- a/sys/net/pflow.h
+++ b/sys/net/pflow.h
@@ -68,6 +68,14 @@
#define PFIX_IE_destinationIPv6Address 28
#define PFIX_IE_flowStartMilliseconds 152
#define PFIX_IE_flowEndMilliseconds 153
+#define PFIX_IE_postNATSourceIPv4Address 225
+#define PFIX_IE_postNATDestinationIPv4Address 226
+#define PFIX_IE_postNAPTSourceTransportPort 227
+#define PFIX_IE_postNAPTDestinationTransportPort 228
+#define PFIX_IE_natEvent 230
+#define PFIX_NAT_EVENT_SESSION_CREATE 4
+#define PFIX_NAT_EVENT_SESSION_DELETE 5
+#define PFIX_IE_timeStamp 323
struct pflow_flow {
u_int32_t src_ip;
@@ -148,10 +156,28 @@
#define PFLOW_IPFIX_TMPL_IPV6_ID 257
} __packed;
+struct pflow_ipfix_tmpl_nat44 {
+ struct pflow_tmpl_hdr h;
+ struct pflow_tmpl_fspec timestamp;
+ struct pflow_tmpl_fspec nat_event;
+ struct pflow_tmpl_fspec protocol;
+ struct pflow_tmpl_fspec src_ip;
+ struct pflow_tmpl_fspec src_port;
+ struct pflow_tmpl_fspec postnat_src_ip;
+ struct pflow_tmpl_fspec postnat_src_port;
+ struct pflow_tmpl_fspec dst_ip;
+ struct pflow_tmpl_fspec dst_port;
+ struct pflow_tmpl_fspec postnat_dst_ip;
+ struct pflow_tmpl_fspec postnat_dst_port;
+#define PFLOW_IPFIX_TMPL_NAT44_FIELD_COUNT 11
+#define PFLOW_IPFIX_TMPL_NAT44_ID 258
+};
+
struct pflow_ipfix_tmpl {
struct pflow_set_header set_header;
struct pflow_ipfix_tmpl_ipv4 ipv4_tmpl;
struct pflow_ipfix_tmpl_ipv6 ipv6_tmpl;
+ struct pflow_ipfix_tmpl_nat44 nat44_tmpl;
} __packed;
struct pflow_ipfix_flow4 {
@@ -186,6 +212,20 @@
/* XXX padding needed? */
} __packed;
+struct pflow_ipfix_nat4 {
+ u_int64_t timestamp; /* timeStamp */
+ u_int8_t nat_event; /* natEvent */
+ u_int8_t protocol; /* protocolIdentifier */
+ u_int32_t src_ip; /* sourceIPv4Address */
+ u_int16_t src_port; /* sourceTransportPort */
+ u_int32_t postnat_src_ip; /* postNATSourceIPv4Address */
+ u_int16_t postnat_src_port;/* postNAPTSourceTransportPort */
+ u_int32_t dest_ip; /* destinationIPv4Address */
+ u_int16_t dest_port; /* destinationTransportPort */
+ u_int32_t postnat_dest_ip;/* postNATDestinationIPv4Address */
+ u_int16_t postnat_dest_port;/* postNAPTDestinationTransportPort */
+} __packed;
+
#ifdef _KERNEL
struct pflow_softc {
@@ -199,13 +239,16 @@
unsigned int sc_count;
unsigned int sc_count4;
unsigned int sc_count6;
+ unsigned int sc_count_nat4;
unsigned int sc_maxcount;
unsigned int sc_maxcount4;
unsigned int sc_maxcount6;
+ unsigned int sc_maxcount_nat4;
u_int64_t sc_gcounter;
u_int32_t sc_sequence;
struct callout sc_tmo;
struct callout sc_tmo6;
+ struct callout sc_tmo_nat4;
struct callout sc_tmo_tmpl;
struct intr_event *sc_swi_ie;
void *sc_swi_cookie;
@@ -219,6 +262,7 @@
u_int32_t sc_observation_dom;
struct mbuf *sc_mbuf; /* current cumulative mbuf */
struct mbuf *sc_mbuf6; /* current cumulative mbuf */
+ struct mbuf *sc_mbuf_nat4;
CK_LIST_ENTRY(pflow_softc) sc_next;
struct epoch_context sc_epoch_ctx;
};
diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c
--- a/sys/netpfil/pf/pf.c
+++ b/sys/netpfil/pf/pf.c
@@ -4875,7 +4875,8 @@
s->state_flags |= PFSTATE_SLOPPY;
if (pd->flags & PFDESC_TCP_NORM) /* Set by old-style scrub rules */
s->state_flags |= PFSTATE_SCRUB_TCP;
- if (r->rule_flag & PFRULE_PFLOW)
+ if ((r->rule_flag & PFRULE_PFLOW) ||
+ (nr != NULL && nr->rule_flag & PFRULE_PFLOW))
s->state_flags |= PFSTATE_PFLOW;
s->act.log = pd->act.log & PF_LOG_ALL;
diff --git a/sys/netpfil/pf/pflow.c b/sys/netpfil/pf/pflow.c
--- a/sys/netpfil/pf/pflow.c
+++ b/sys/netpfil/pf/pflow.c
@@ -70,6 +70,12 @@
#define DPRINTF(x)
#endif
+enum pflow_family_t {
+ PFLOW_INET,
+ PFLOW_INET6,
+ PFLOW_NAT4,
+};
+
static void pflow_output_process(void *);
static int pflow_create(int);
static int pflow_destroy(int, bool);
@@ -80,12 +86,13 @@
static struct mbuf *pflow_get_mbuf(struct pflow_softc *, u_int16_t);
static void pflow_flush(struct pflow_softc *);
static int pflow_sendout_v5(struct pflow_softc *);
-static int pflow_sendout_ipfix(struct pflow_softc *, sa_family_t);
+static int pflow_sendout_ipfix(struct pflow_softc *, enum pflow_family_t);
static int pflow_sendout_ipfix_tmpl(struct pflow_softc *);
static int pflow_sendout_mbuf(struct pflow_softc *, struct mbuf *);
static void pflow_timeout(void *);
static void pflow_timeout6(void *);
static void pflow_timeout_tmpl(void *);
+static void pflow_timeout_nat4(void *);
static void copy_flow_data(struct pflow_flow *, struct pflow_flow *,
const struct pf_kstate *, struct pf_state_key *, int, int);
static void copy_flow_ipfix_4_data(struct pflow_ipfix_flow4 *,
@@ -106,6 +113,9 @@
struct pflow_softc *sc);
static int copy_flow_ipfix_6_to_m(struct pflow_ipfix_flow6 *flow,
struct pflow_softc *sc);
+static int copy_nat_ipfix_4_to_m(struct pflow_ipfix_nat4 *,
+ const struct pf_kstate *, struct pflow_softc *,
+ uint8_t, uint64_t);
static const char pflowname[] = "pflow";
@@ -303,6 +313,53 @@
htons(PFIX_IE_protocolIdentifier);
pflowif->sc_tmpl_ipfix.ipv6_tmpl.protocol.len = htons(1);
+ /* NAT44 create template */
+ pflowif->sc_tmpl_ipfix.nat44_tmpl.h.tmpl_id =
+ htons(PFLOW_IPFIX_TMPL_NAT44_ID);
+ pflowif->sc_tmpl_ipfix.nat44_tmpl.h.field_count =
+ htons(PFLOW_IPFIX_TMPL_NAT44_FIELD_COUNT);
+ pflowif->sc_tmpl_ipfix.nat44_tmpl.timestamp.field_id =
+ htons(PFIX_IE_timeStamp);
+ pflowif->sc_tmpl_ipfix.nat44_tmpl.timestamp.len =
+ htons(8);
+ pflowif->sc_tmpl_ipfix.nat44_tmpl.nat_event.field_id =
+ htons(PFIX_IE_natEvent);
+ pflowif->sc_tmpl_ipfix.nat44_tmpl.nat_event.len =
+ htons(1);
+ pflowif->sc_tmpl_ipfix.nat44_tmpl.protocol.field_id =
+ htons(PFIX_IE_protocolIdentifier);
+ pflowif->sc_tmpl_ipfix.nat44_tmpl.protocol.len = htons(1);
+ pflowif->sc_tmpl_ipfix.nat44_tmpl.src_ip.field_id =
+ htons(PFIX_IE_sourceIPv4Address);
+ pflowif->sc_tmpl_ipfix.nat44_tmpl.src_ip.len =
+ htons(4);
+ pflowif->sc_tmpl_ipfix.nat44_tmpl.src_port.field_id =
+ htons(PFIX_IE_sourceTransportPort);
+ pflowif->sc_tmpl_ipfix.nat44_tmpl.src_port.len = htons(2);
+ pflowif->sc_tmpl_ipfix.nat44_tmpl.postnat_src_ip.field_id =
+ htons(PFIX_IE_postNATSourceIPv4Address);
+ pflowif->sc_tmpl_ipfix.nat44_tmpl.postnat_src_ip.len =
+ htons(4);
+ pflowif->sc_tmpl_ipfix.nat44_tmpl.postnat_src_port.field_id =
+ htons(PFIX_IE_postNAPTSourceTransportPort);
+ pflowif->sc_tmpl_ipfix.nat44_tmpl.postnat_src_port.len =
+ htons(2);
+ pflowif->sc_tmpl_ipfix.nat44_tmpl.dst_ip.field_id =
+ htons(PFIX_IE_destinationIPv4Address);
+ pflowif->sc_tmpl_ipfix.nat44_tmpl.dst_ip.len =
+ htons(4);
+ pflowif->sc_tmpl_ipfix.nat44_tmpl.dst_port.field_id =
+ htons(PFIX_IE_destinationTransportPort);
+ pflowif->sc_tmpl_ipfix.nat44_tmpl.dst_port.len = htons(2);
+ pflowif->sc_tmpl_ipfix.nat44_tmpl.postnat_dst_ip.field_id =
+ htons(PFIX_IE_postNATDestinationIPv4Address);
+ pflowif->sc_tmpl_ipfix.nat44_tmpl.postnat_dst_ip.len =
+ htons(4);
+ pflowif->sc_tmpl_ipfix.nat44_tmpl.postnat_dst_port.field_id =
+ htons(PFIX_IE_postNAPTDestinationTransportPort);
+ pflowif->sc_tmpl_ipfix.nat44_tmpl.postnat_dst_port.len =
+ htons(2);
+
pflowif->sc_id = unit;
pflowif->sc_vnet = curvnet;
@@ -311,6 +368,7 @@
callout_init_mtx(&pflowif->sc_tmo, &pflowif->sc_lock, 0);
callout_init_mtx(&pflowif->sc_tmo6, &pflowif->sc_lock, 0);
+ callout_init_mtx(&pflowif->sc_tmo_nat4, &pflowif->sc_lock, 0);
callout_init_mtx(&pflowif->sc_tmo_tmpl, &pflowif->sc_lock, 0);
error = swi_add(&pflowif->sc_swi_ie, pflowname, pflow_output_process,
@@ -374,10 +432,12 @@
callout_drain(&sc->sc_tmo);
callout_drain(&sc->sc_tmo6);
+ callout_drain(&sc->sc_tmo_nat4);
callout_drain(&sc->sc_tmo_tmpl);
m_freem(sc->sc_mbuf);
m_freem(sc->sc_mbuf6);
+ m_freem(sc->sc_mbuf_nat4);
PFLOW_LOCK(sc);
mbufq_drain(&sc->sc_outputqueue);
@@ -425,18 +485,26 @@
int
pflow_calc_mtu(struct pflow_softc *sc, int mtu, int hdrsz)
{
+ size_t min;
sc->sc_maxcount4 = (mtu - hdrsz -
sizeof(struct udpiphdr)) / sizeof(struct pflow_ipfix_flow4);
sc->sc_maxcount6 = (mtu - hdrsz -
sizeof(struct udpiphdr)) / sizeof(struct pflow_ipfix_flow6);
+ sc->sc_maxcount_nat4 = (mtu - hdrsz -
+ sizeof(struct udpiphdr)) / sizeof(struct pflow_ipfix_nat4);
if (sc->sc_maxcount4 > PFLOW_MAXFLOWS)
sc->sc_maxcount4 = PFLOW_MAXFLOWS;
if (sc->sc_maxcount6 > PFLOW_MAXFLOWS)
sc->sc_maxcount6 = PFLOW_MAXFLOWS;
- return (hdrsz + sizeof(struct udpiphdr) +
- MIN(sc->sc_maxcount4 * sizeof(struct pflow_ipfix_flow4),
- sc->sc_maxcount6 * sizeof(struct pflow_ipfix_flow6)));
+ if (sc->sc_maxcount_nat4 > PFLOW_MAXFLOWS)
+ sc->sc_maxcount_nat4 = PFLOW_MAXFLOWS;
+
+ min = MIN(sc->sc_maxcount4 * sizeof(struct pflow_ipfix_flow4),
+ sc->sc_maxcount6 * sizeof(struct pflow_ipfix_flow6));
+ min = MIN(min, sc->sc_maxcount_nat4 * sizeof(struct pflow_ipfix_nat4));
+
+ return (hdrsz + sizeof(struct udpiphdr) + min);
}
static void
@@ -628,6 +696,28 @@
flow1->tos = flow2->tos = st->rule.ptr->tos;
}
+static void
+copy_nat_ipfix_4_data(struct pflow_ipfix_nat4 *nat1,
+ struct pflow_ipfix_nat4 *nat2, const struct pf_kstate *st,
+ struct pf_state_key *sk, struct pflow_softc *sc, int src, int dst)
+{
+ nat1->src_ip = nat2->dest_ip = st->key[PF_SK_STACK]->addr[src].v4.s_addr;
+ nat1->src_port = nat2->dest_port = st->key[PF_SK_STACK]->port[src];
+ nat1->dest_ip = nat2->src_ip = st->key[PF_SK_STACK]->addr[dst].v4.s_addr;
+ nat1->dest_port = nat2->src_port = st->key[PF_SK_STACK]->port[dst];
+ nat1->postnat_src_ip = nat2->postnat_dest_ip = st->key[PF_SK_WIRE]->addr[src].v4.s_addr;
+ nat1->postnat_src_port = nat2->postnat_dest_port = st->key[PF_SK_WIRE]->port[src];
+ nat1->postnat_dest_ip = nat2->postnat_src_ip = st->key[PF_SK_WIRE]->addr[dst].v4.s_addr;
+ nat1->postnat_dest_port = nat2->postnat_src_port = st->key[PF_SK_WIRE]->port[dst];
+ nat1->protocol = nat2->protocol = sk->proto;
+
+ /*
+ * Because we have to generate a create and delete event we'll fill out the
+ * timestamp and nat_event fields when we transmit. As opposed to doing this
+ * work a second time.
+ */
+}
+
static void
export_pflow(const struct pf_kstate *st)
{
@@ -755,7 +845,7 @@
sc->sc_count4++;
if (sc->sc_count4 >= sc->sc_maxcount4)
- ret = pflow_sendout_ipfix(sc, AF_INET);
+ ret = pflow_sendout_ipfix(sc, PFLOW_INET);
return(ret);
}
@@ -785,11 +875,46 @@
sc->sc_count6++;
if (sc->sc_count6 >= sc->sc_maxcount6)
- ret = pflow_sendout_ipfix(sc, AF_INET6);
+ ret = pflow_sendout_ipfix(sc, PFLOW_INET6);
return(ret);
}
+int
+copy_nat_ipfix_4_to_m(struct pflow_ipfix_nat4 *nat, const struct pf_kstate *st,
+ struct pflow_softc *sc, uint8_t event, uint64_t timestamp)
+{
+ int ret = 0;
+
+ PFLOW_ASSERT(sc);
+
+ if (sc->sc_mbuf_nat4 == NULL) {
+ if ((sc->sc_mbuf_nat4 =
+ pflow_get_mbuf(sc, PFLOW_IPFIX_TMPL_NAT44_ID)) == NULL) {
+ return (ENOBUFS);
+ }
+ sc->sc_count_nat4 = 0;
+ callout_reset(&sc->sc_tmo, PFLOW_TIMEOUT * hz,
+ pflow_timeout_nat4, sc);
+ }
+
+ nat->nat_event = event;
+ nat->timestamp = htobe64(pf_get_time() - (pf_get_uptime() - timestamp));
+ m_copyback(sc->sc_mbuf_nat4, PFLOW_SET_HDRLEN +
+ (sc->sc_count_nat4 * sizeof(struct pflow_ipfix_nat4)),
+ sizeof(struct pflow_ipfix_nat4), (caddr_t)nat);
+ sc->sc_count_nat4++;
+
+ if (V_pflowstats.pflow_flows == sc->sc_gcounter)
+ V_pflowstats.pflow_flows++;
+
+ sc->sc_gcounter++;
+ if (sc->sc_count_nat4 >= sc->sc_maxcount_nat4)
+ ret = pflow_sendout_ipfix(sc, PFLOW_NAT4);
+
+ return (ret);
+}
+
static int
pflow_pack_flow(const struct pf_kstate *st, struct pf_state_key *sk,
struct pflow_softc *sc)
@@ -815,17 +940,30 @@
return (ret);
}
+static bool
+pflow_is_natd(const struct pf_kstate *st)
+{
+ /* If ports or addresses are different we've been NAT-ed. */
+ return (memcmp(st->key[PF_SK_WIRE], st->key[PF_SK_STACK],
+ sizeof(struct pf_addr) * 2 + sizeof(uint16_t) * 2) != 0);
+}
+
static int
pflow_pack_flow_ipfix(const struct pf_kstate *st, struct pf_state_key *sk,
struct pflow_softc *sc)
{
struct pflow_ipfix_flow4 flow4_1, flow4_2;
+ struct pflow_ipfix_nat4 nat4_1, nat4_2;
struct pflow_ipfix_flow6 flow6_1, flow6_2;
int ret = 0;
+ bool nat = false;
+
if (sk->af == AF_INET) {
bzero(&flow4_1, sizeof(flow4_1));
bzero(&flow4_2, sizeof(flow4_2));
+ nat = pflow_is_natd(st);
+
if (st->direction == PF_OUT)
copy_flow_ipfix_4_data(&flow4_1, &flow4_2, st, sk, sc,
1, 0);
@@ -833,11 +971,30 @@
copy_flow_ipfix_4_data(&flow4_1, &flow4_2, st, sk, sc,
0, 1);
- if (st->bytes[0] != 0) /* first flow from state */
+ if (nat)
+ copy_nat_ipfix_4_data(&nat4_1, &nat4_2, st, sk, sc, 1, 0);
+
+ if (st->bytes[0] != 0) /* first flow from state */ {
ret = copy_flow_ipfix_4_to_m(&flow4_1, sc);
- if (st->bytes[1] != 0) /* second flow from state */
+ if (ret == 0 && nat) {
+ ret = copy_nat_ipfix_4_to_m(&nat4_1, st, sc,
+ PFIX_NAT_EVENT_SESSION_CREATE, st->creation);
+ ret |= copy_nat_ipfix_4_to_m(&nat4_1, st, sc,
+ PFIX_NAT_EVENT_SESSION_DELETE, st->expire);
+ }
+ }
+
+ if (st->bytes[1] != 0) /* second flow from state */ {
ret = copy_flow_ipfix_4_to_m(&flow4_2, sc);
+
+ if (ret == 0 && nat) {
+ ret = copy_nat_ipfix_4_to_m(&nat4_2, st, sc,
+ PFIX_NAT_EVENT_SESSION_CREATE, st->creation);
+ ret |= copy_nat_ipfix_4_to_m(&nat4_2, st, sc,
+ PFIX_NAT_EVENT_SESSION_DELETE, st->expire);
+ }
+ }
} else if (sk->af == AF_INET6) {
bzero(&flow6_1, sizeof(flow6_1));
bzero(&flow6_2, sizeof(flow6_2));
@@ -871,7 +1028,7 @@
pflow_sendout_v5(sc);
break;
case PFLOW_PROTO_10:
- pflow_sendout_ipfix(sc, AF_INET);
+ pflow_sendout_ipfix(sc, PFLOW_INET);
break;
default: /* NOTREACHED */
panic("Unsupported version %d", sc->sc_version);
@@ -892,7 +1049,7 @@
return;
CURVNET_SET(sc->sc_vnet);
- pflow_sendout_ipfix(sc, AF_INET6);
+ pflow_sendout_ipfix(sc, PFLOW_INET6);
CURVNET_RESTORE();
}
@@ -911,6 +1068,21 @@
CURVNET_RESTORE();
}
+static void
+pflow_timeout_nat4(void *v)
+{
+ struct pflow_softc *sc = v;
+
+ PFLOW_ASSERT(sc);
+
+ if (sc->sc_version != PFLOW_PROTO_10)
+ return;
+
+ CURVNET_SET(sc->sc_vnet);
+ pflow_sendout_ipfix(sc, PFLOW_NAT4);
+ CURVNET_RESTORE();
+}
+
static void
pflow_flush(struct pflow_softc *sc)
{
@@ -921,8 +1093,9 @@
pflow_sendout_v5(sc);
break;
case PFLOW_PROTO_10:
- pflow_sendout_ipfix(sc, AF_INET);
- pflow_sendout_ipfix(sc, AF_INET6);
+ pflow_sendout_ipfix(sc, PFLOW_INET);
+ pflow_sendout_ipfix(sc, PFLOW_INET6);
+ pflow_sendout_ipfix(sc, PFLOW_NAT4);
break;
default: /* NOTREACHED */
break;
@@ -960,7 +1133,7 @@
}
static int
-pflow_sendout_ipfix(struct pflow_softc *sc, sa_family_t af)
+pflow_sendout_ipfix(struct pflow_softc *sc, enum pflow_family_t af)
{
struct mbuf *m;
struct pflow_v10_header *h10;
@@ -971,7 +1144,7 @@
PFLOW_ASSERT(sc);
switch (af) {
- case AF_INET:
+ case PFLOW_INET:
m = sc->sc_mbuf;
callout_stop(&sc->sc_tmo);
if (m == NULL)
@@ -981,7 +1154,7 @@
set_length = sizeof(struct pflow_set_header)
+ sc->sc_count4 * sizeof(struct pflow_ipfix_flow4);
break;
- case AF_INET6:
+ case PFLOW_INET6:
m = sc->sc_mbuf6;
callout_stop(&sc->sc_tmo6);
if (m == NULL)
@@ -991,6 +1164,16 @@
set_length = sizeof(struct pflow_set_header)
+ sc->sc_count6 * sizeof(struct pflow_ipfix_flow6);
break;
+ case PFLOW_NAT4:
+ m = sc->sc_mbuf_nat4;
+ callout_stop(&sc->sc_tmo_nat4);
+ if (m == NULL)
+ return (0);
+ sc->sc_mbuf_nat4 = NULL;
+ count = sc->sc_count_nat4;
+ set_length = sizeof(struct pflow_set_header)
+ + sc->sc_count_nat4 * sizeof(struct pflow_ipfix_nat4);
+ break;
default:
panic("Unsupported AF %d", af);
}

File Metadata

Mime Type
text/plain
Expires
Mon, Jan 27, 6:09 PM (3 h, 17 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
16186021
Default Alt Text
D43114.id132462.diff (16 KB)

Event Timeline