git: fc6e50699615 - main - pflow: add RFC8158 NAT support
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 16 Jan 2024 08:52:01 UTC
The branch main has been updated by kp: URL: https://cgit.FreeBSD.org/src/commit/?id=fc6e50699615c93f39d008709f87c754d9b6c7d3 commit fc6e50699615c93f39d008709f87c754d9b6c7d3 Author: Kristof Provost <kp@FreeBSD.org> AuthorDate: 2023-12-13 15:55:28 +0000 Commit: Kristof Provost <kp@FreeBSD.org> CommitDate: 2024-01-16 08:45:55 +0000 pflow: add RFC8158 NAT support Extend pflow(4) to send NAT44 Session Create and Delete events. This applies only to IPFIX (i.e. proto version 10), and requires no user configuration. Sponsored by: Rubicon Communications, LLC ("Netgate") Differential Revision: https://reviews.freebsd.org/D43114 --- sbin/pfctl/parse.y | 16 ++++ sys/net/pflow.h | 44 ++++++++++ sys/netpfil/pf/pf.c | 3 +- sys/netpfil/pf/pflow.c | 213 +++++++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 260 insertions(+), 16 deletions(-) diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y index 94b7e241cd25..9ec86f898240 100644 --- a/sbin/pfctl/parse.y +++ b/sbin/pfctl/parse.y @@ -4680,6 +4680,7 @@ natrule : nataction interface af proto fromto tag tagged rtable redirpool pool_opts { struct pfctl_rule r; + struct node_state_opt *o; if (check_rulestate(PFCTL_STATE_NAT)) YYERROR; @@ -4855,6 +4856,21 @@ natrule : nataction interface af proto fromto tag tagged rtable 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 index 4a63f7640629..84fcf1327a17 100644 --- 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 @@ struct pflow_ipfix_tmpl_ipv6 { #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 @@ struct pflow_ipfix_flow6 { /* 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 @@ struct pflow_softc { 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 @@ struct pflow_softc { 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 index 89f6e000f6cf..9bd9828a99d9 100644 --- a/sys/netpfil/pf/pf.c +++ b/sys/netpfil/pf/pf.c @@ -4875,7 +4875,8 @@ pf_create_state(struct pf_krule *r, struct pf_krule *nr, struct pf_krule *a, 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 index 398851bf17d0..ce5e8ec6547c 100644 --- 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 int pflowvalidsockaddr(const struct sockaddr *, int); 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 @@ static int copy_flow_ipfix_4_to_m(struct pflow_ipfix_flow4 *flow, 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 @@ pflow_create(int unit) 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 @@ pflow_create(int unit) 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 @@ pflow_destroy(int unit, bool drain) 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 @@ pflowvalidsockaddr(const struct sockaddr *sa, int ignore_port) 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 @@ copy_flow_ipfix_6_data(struct pflow_ipfix_flow6 *flow1, 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 @@ copy_flow_ipfix_4_to_m(struct pflow_ipfix_flow4 *flow, struct pflow_softc *sc) 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 @@ copy_flow_ipfix_6_to_m(struct pflow_ipfix_flow6 *flow, struct pflow_softc *sc) 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 @@ pflow_pack_flow(const struct pf_kstate *st, struct pf_state_key *sk, 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 @@ pflow_pack_flow_ipfix(const struct pf_kstate *st, struct pf_state_key *sk, 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_timeout(void *v) 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 @@ pflow_timeout6(void *v) return; CURVNET_SET(sc->sc_vnet); - pflow_sendout_ipfix(sc, AF_INET6); + pflow_sendout_ipfix(sc, PFLOW_INET6); CURVNET_RESTORE(); } @@ -911,6 +1068,21 @@ pflow_timeout_tmpl(void *v) 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_flush(struct pflow_softc *sc) 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 @@ pflow_sendout_v5(struct pflow_softc *sc) } 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_sendout_ipfix(struct pflow_softc *sc, sa_family_t af) 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 @@ pflow_sendout_ipfix(struct pflow_softc *sc, sa_family_t af) 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 @@ pflow_sendout_ipfix(struct pflow_softc *sc, sa_family_t af) 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); }