mirror of
https://github.com/freebsd/freebsd-src
synced 2024-10-15 04:43:53 +00:00
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
This commit is contained in:
parent
85b71dcfc9
commit
fc6e506996
|
@ -4680,6 +4680,7 @@ natrule : nataction interface af proto fromto tag tagged rtable
|
||||||
redirpool pool_opts
|
redirpool pool_opts
|
||||||
{
|
{
|
||||||
struct pfctl_rule r;
|
struct pfctl_rule r;
|
||||||
|
struct node_state_opt *o;
|
||||||
|
|
||||||
if (check_rulestate(PFCTL_STATE_NAT))
|
if (check_rulestate(PFCTL_STATE_NAT))
|
||||||
YYERROR;
|
YYERROR;
|
||||||
|
@ -4855,6 +4856,21 @@ natrule : nataction interface af proto fromto tag tagged rtable
|
||||||
r.rpool.mape = $10.mape;
|
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,
|
expand_rule(&r, $2, $9 == NULL ? NULL : $9->host, $4,
|
||||||
$5.src_os, $5.src.host, $5.src.port, $5.dst.host,
|
$5.src_os, $5.src.host, $5.src.port, $5.dst.host,
|
||||||
$5.dst.port, 0, 0, 0, "");
|
$5.dst.port, 0, 0, 0, "");
|
||||||
|
|
|
@ -68,6 +68,14 @@
|
||||||
#define PFIX_IE_destinationIPv6Address 28
|
#define PFIX_IE_destinationIPv6Address 28
|
||||||
#define PFIX_IE_flowStartMilliseconds 152
|
#define PFIX_IE_flowStartMilliseconds 152
|
||||||
#define PFIX_IE_flowEndMilliseconds 153
|
#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 {
|
struct pflow_flow {
|
||||||
u_int32_t src_ip;
|
u_int32_t src_ip;
|
||||||
|
@ -148,10 +156,28 @@ struct pflow_ipfix_tmpl_ipv6 {
|
||||||
#define PFLOW_IPFIX_TMPL_IPV6_ID 257
|
#define PFLOW_IPFIX_TMPL_IPV6_ID 257
|
||||||
} __packed;
|
} __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_ipfix_tmpl {
|
||||||
struct pflow_set_header set_header;
|
struct pflow_set_header set_header;
|
||||||
struct pflow_ipfix_tmpl_ipv4 ipv4_tmpl;
|
struct pflow_ipfix_tmpl_ipv4 ipv4_tmpl;
|
||||||
struct pflow_ipfix_tmpl_ipv6 ipv6_tmpl;
|
struct pflow_ipfix_tmpl_ipv6 ipv6_tmpl;
|
||||||
|
struct pflow_ipfix_tmpl_nat44 nat44_tmpl;
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
struct pflow_ipfix_flow4 {
|
struct pflow_ipfix_flow4 {
|
||||||
|
@ -186,6 +212,20 @@ struct pflow_ipfix_flow6 {
|
||||||
/* XXX padding needed? */
|
/* XXX padding needed? */
|
||||||
} __packed;
|
} __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
|
#ifdef _KERNEL
|
||||||
|
|
||||||
struct pflow_softc {
|
struct pflow_softc {
|
||||||
|
@ -199,13 +239,16 @@ struct pflow_softc {
|
||||||
unsigned int sc_count;
|
unsigned int sc_count;
|
||||||
unsigned int sc_count4;
|
unsigned int sc_count4;
|
||||||
unsigned int sc_count6;
|
unsigned int sc_count6;
|
||||||
|
unsigned int sc_count_nat4;
|
||||||
unsigned int sc_maxcount;
|
unsigned int sc_maxcount;
|
||||||
unsigned int sc_maxcount4;
|
unsigned int sc_maxcount4;
|
||||||
unsigned int sc_maxcount6;
|
unsigned int sc_maxcount6;
|
||||||
|
unsigned int sc_maxcount_nat4;
|
||||||
u_int64_t sc_gcounter;
|
u_int64_t sc_gcounter;
|
||||||
u_int32_t sc_sequence;
|
u_int32_t sc_sequence;
|
||||||
struct callout sc_tmo;
|
struct callout sc_tmo;
|
||||||
struct callout sc_tmo6;
|
struct callout sc_tmo6;
|
||||||
|
struct callout sc_tmo_nat4;
|
||||||
struct callout sc_tmo_tmpl;
|
struct callout sc_tmo_tmpl;
|
||||||
struct intr_event *sc_swi_ie;
|
struct intr_event *sc_swi_ie;
|
||||||
void *sc_swi_cookie;
|
void *sc_swi_cookie;
|
||||||
|
@ -219,6 +262,7 @@ struct pflow_softc {
|
||||||
u_int32_t sc_observation_dom;
|
u_int32_t sc_observation_dom;
|
||||||
struct mbuf *sc_mbuf; /* current cumulative mbuf */
|
struct mbuf *sc_mbuf; /* current cumulative mbuf */
|
||||||
struct mbuf *sc_mbuf6; /* current cumulative mbuf */
|
struct mbuf *sc_mbuf6; /* current cumulative mbuf */
|
||||||
|
struct mbuf *sc_mbuf_nat4;
|
||||||
CK_LIST_ENTRY(pflow_softc) sc_next;
|
CK_LIST_ENTRY(pflow_softc) sc_next;
|
||||||
struct epoch_context sc_epoch_ctx;
|
struct epoch_context sc_epoch_ctx;
|
||||||
};
|
};
|
||||||
|
|
|
@ -4875,7 +4875,8 @@ pf_create_state(struct pf_krule *r, struct pf_krule *nr, struct pf_krule *a,
|
||||||
s->state_flags |= PFSTATE_SLOPPY;
|
s->state_flags |= PFSTATE_SLOPPY;
|
||||||
if (pd->flags & PFDESC_TCP_NORM) /* Set by old-style scrub rules */
|
if (pd->flags & PFDESC_TCP_NORM) /* Set by old-style scrub rules */
|
||||||
s->state_flags |= PFSTATE_SCRUB_TCP;
|
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->state_flags |= PFSTATE_PFLOW;
|
||||||
|
|
||||||
s->act.log = pd->act.log & PF_LOG_ALL;
|
s->act.log = pd->act.log & PF_LOG_ALL;
|
||||||
|
|
|
@ -70,6 +70,12 @@
|
||||||
#define DPRINTF(x)
|
#define DPRINTF(x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
enum pflow_family_t {
|
||||||
|
PFLOW_INET,
|
||||||
|
PFLOW_INET6,
|
||||||
|
PFLOW_NAT4,
|
||||||
|
};
|
||||||
|
|
||||||
static void pflow_output_process(void *);
|
static void pflow_output_process(void *);
|
||||||
static int pflow_create(int);
|
static int pflow_create(int);
|
||||||
static int pflow_destroy(int, bool);
|
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 struct mbuf *pflow_get_mbuf(struct pflow_softc *, u_int16_t);
|
||||||
static void pflow_flush(struct pflow_softc *);
|
static void pflow_flush(struct pflow_softc *);
|
||||||
static int pflow_sendout_v5(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_ipfix_tmpl(struct pflow_softc *);
|
||||||
static int pflow_sendout_mbuf(struct pflow_softc *, struct mbuf *);
|
static int pflow_sendout_mbuf(struct pflow_softc *, struct mbuf *);
|
||||||
static void pflow_timeout(void *);
|
static void pflow_timeout(void *);
|
||||||
static void pflow_timeout6(void *);
|
static void pflow_timeout6(void *);
|
||||||
static void pflow_timeout_tmpl(void *);
|
static void pflow_timeout_tmpl(void *);
|
||||||
|
static void pflow_timeout_nat4(void *);
|
||||||
static void copy_flow_data(struct pflow_flow *, struct pflow_flow *,
|
static void copy_flow_data(struct pflow_flow *, struct pflow_flow *,
|
||||||
const struct pf_kstate *, struct pf_state_key *, int, int);
|
const struct pf_kstate *, struct pf_state_key *, int, int);
|
||||||
static void copy_flow_ipfix_4_data(struct pflow_ipfix_flow4 *,
|
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);
|
struct pflow_softc *sc);
|
||||||
static int copy_flow_ipfix_6_to_m(struct pflow_ipfix_flow6 *flow,
|
static int copy_flow_ipfix_6_to_m(struct pflow_ipfix_flow6 *flow,
|
||||||
struct pflow_softc *sc);
|
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";
|
static const char pflowname[] = "pflow";
|
||||||
|
|
||||||
|
@ -303,6 +313,53 @@ pflow_create(int unit)
|
||||||
htons(PFIX_IE_protocolIdentifier);
|
htons(PFIX_IE_protocolIdentifier);
|
||||||
pflowif->sc_tmpl_ipfix.ipv6_tmpl.protocol.len = htons(1);
|
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_id = unit;
|
||||||
pflowif->sc_vnet = curvnet;
|
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_tmo, &pflowif->sc_lock, 0);
|
||||||
callout_init_mtx(&pflowif->sc_tmo6, &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);
|
callout_init_mtx(&pflowif->sc_tmo_tmpl, &pflowif->sc_lock, 0);
|
||||||
|
|
||||||
error = swi_add(&pflowif->sc_swi_ie, pflowname, pflow_output_process,
|
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_tmo);
|
||||||
callout_drain(&sc->sc_tmo6);
|
callout_drain(&sc->sc_tmo6);
|
||||||
|
callout_drain(&sc->sc_tmo_nat4);
|
||||||
callout_drain(&sc->sc_tmo_tmpl);
|
callout_drain(&sc->sc_tmo_tmpl);
|
||||||
|
|
||||||
m_freem(sc->sc_mbuf);
|
m_freem(sc->sc_mbuf);
|
||||||
m_freem(sc->sc_mbuf6);
|
m_freem(sc->sc_mbuf6);
|
||||||
|
m_freem(sc->sc_mbuf_nat4);
|
||||||
|
|
||||||
PFLOW_LOCK(sc);
|
PFLOW_LOCK(sc);
|
||||||
mbufq_drain(&sc->sc_outputqueue);
|
mbufq_drain(&sc->sc_outputqueue);
|
||||||
|
@ -425,18 +485,26 @@ pflowvalidsockaddr(const struct sockaddr *sa, int ignore_port)
|
||||||
int
|
int
|
||||||
pflow_calc_mtu(struct pflow_softc *sc, int mtu, int hdrsz)
|
pflow_calc_mtu(struct pflow_softc *sc, int mtu, int hdrsz)
|
||||||
{
|
{
|
||||||
|
size_t min;
|
||||||
|
|
||||||
sc->sc_maxcount4 = (mtu - hdrsz -
|
sc->sc_maxcount4 = (mtu - hdrsz -
|
||||||
sizeof(struct udpiphdr)) / sizeof(struct pflow_ipfix_flow4);
|
sizeof(struct udpiphdr)) / sizeof(struct pflow_ipfix_flow4);
|
||||||
sc->sc_maxcount6 = (mtu - hdrsz -
|
sc->sc_maxcount6 = (mtu - hdrsz -
|
||||||
sizeof(struct udpiphdr)) / sizeof(struct pflow_ipfix_flow6);
|
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)
|
if (sc->sc_maxcount4 > PFLOW_MAXFLOWS)
|
||||||
sc->sc_maxcount4 = PFLOW_MAXFLOWS;
|
sc->sc_maxcount4 = PFLOW_MAXFLOWS;
|
||||||
if (sc->sc_maxcount6 > PFLOW_MAXFLOWS)
|
if (sc->sc_maxcount6 > PFLOW_MAXFLOWS)
|
||||||
sc->sc_maxcount6 = PFLOW_MAXFLOWS;
|
sc->sc_maxcount6 = PFLOW_MAXFLOWS;
|
||||||
return (hdrsz + sizeof(struct udpiphdr) +
|
if (sc->sc_maxcount_nat4 > PFLOW_MAXFLOWS)
|
||||||
MIN(sc->sc_maxcount4 * sizeof(struct pflow_ipfix_flow4),
|
sc->sc_maxcount_nat4 = PFLOW_MAXFLOWS;
|
||||||
sc->sc_maxcount6 * sizeof(struct pflow_ipfix_flow6)));
|
|
||||||
|
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
|
static void
|
||||||
|
@ -628,6 +696,28 @@ copy_flow_ipfix_6_data(struct pflow_ipfix_flow6 *flow1,
|
||||||
flow1->tos = flow2->tos = st->rule.ptr->tos;
|
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
|
static void
|
||||||
export_pflow(const struct pf_kstate *st)
|
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++;
|
sc->sc_count4++;
|
||||||
|
|
||||||
if (sc->sc_count4 >= sc->sc_maxcount4)
|
if (sc->sc_count4 >= sc->sc_maxcount4)
|
||||||
ret = pflow_sendout_ipfix(sc, AF_INET);
|
ret = pflow_sendout_ipfix(sc, PFLOW_INET);
|
||||||
return(ret);
|
return(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -785,11 +875,46 @@ copy_flow_ipfix_6_to_m(struct pflow_ipfix_flow6 *flow, struct pflow_softc *sc)
|
||||||
sc->sc_count6++;
|
sc->sc_count6++;
|
||||||
|
|
||||||
if (sc->sc_count6 >= sc->sc_maxcount6)
|
if (sc->sc_count6 >= sc->sc_maxcount6)
|
||||||
ret = pflow_sendout_ipfix(sc, AF_INET6);
|
ret = pflow_sendout_ipfix(sc, PFLOW_INET6);
|
||||||
|
|
||||||
return(ret);
|
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
|
static int
|
||||||
pflow_pack_flow(const struct pf_kstate *st, struct pf_state_key *sk,
|
pflow_pack_flow(const struct pf_kstate *st, struct pf_state_key *sk,
|
||||||
struct pflow_softc *sc)
|
struct pflow_softc *sc)
|
||||||
|
@ -815,17 +940,30 @@ pflow_pack_flow(const struct pf_kstate *st, struct pf_state_key *sk,
|
||||||
return (ret);
|
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
|
static int
|
||||||
pflow_pack_flow_ipfix(const struct pf_kstate *st, struct pf_state_key *sk,
|
pflow_pack_flow_ipfix(const struct pf_kstate *st, struct pf_state_key *sk,
|
||||||
struct pflow_softc *sc)
|
struct pflow_softc *sc)
|
||||||
{
|
{
|
||||||
struct pflow_ipfix_flow4 flow4_1, flow4_2;
|
struct pflow_ipfix_flow4 flow4_1, flow4_2;
|
||||||
|
struct pflow_ipfix_nat4 nat4_1, nat4_2;
|
||||||
struct pflow_ipfix_flow6 flow6_1, flow6_2;
|
struct pflow_ipfix_flow6 flow6_1, flow6_2;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
bool nat = false;
|
||||||
|
|
||||||
if (sk->af == AF_INET) {
|
if (sk->af == AF_INET) {
|
||||||
bzero(&flow4_1, sizeof(flow4_1));
|
bzero(&flow4_1, sizeof(flow4_1));
|
||||||
bzero(&flow4_2, sizeof(flow4_2));
|
bzero(&flow4_2, sizeof(flow4_2));
|
||||||
|
|
||||||
|
nat = pflow_is_natd(st);
|
||||||
|
|
||||||
if (st->direction == PF_OUT)
|
if (st->direction == PF_OUT)
|
||||||
copy_flow_ipfix_4_data(&flow4_1, &flow4_2, st, sk, sc,
|
copy_flow_ipfix_4_data(&flow4_1, &flow4_2, st, sk, sc,
|
||||||
1, 0);
|
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,
|
copy_flow_ipfix_4_data(&flow4_1, &flow4_2, st, sk, sc,
|
||||||
0, 1);
|
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);
|
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);
|
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) {
|
} else if (sk->af == AF_INET6) {
|
||||||
bzero(&flow6_1, sizeof(flow6_1));
|
bzero(&flow6_1, sizeof(flow6_1));
|
||||||
bzero(&flow6_2, sizeof(flow6_2));
|
bzero(&flow6_2, sizeof(flow6_2));
|
||||||
|
@ -871,7 +1028,7 @@ pflow_timeout(void *v)
|
||||||
pflow_sendout_v5(sc);
|
pflow_sendout_v5(sc);
|
||||||
break;
|
break;
|
||||||
case PFLOW_PROTO_10:
|
case PFLOW_PROTO_10:
|
||||||
pflow_sendout_ipfix(sc, AF_INET);
|
pflow_sendout_ipfix(sc, PFLOW_INET);
|
||||||
break;
|
break;
|
||||||
default: /* NOTREACHED */
|
default: /* NOTREACHED */
|
||||||
panic("Unsupported version %d", sc->sc_version);
|
panic("Unsupported version %d", sc->sc_version);
|
||||||
|
@ -892,7 +1049,7 @@ pflow_timeout6(void *v)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
CURVNET_SET(sc->sc_vnet);
|
CURVNET_SET(sc->sc_vnet);
|
||||||
pflow_sendout_ipfix(sc, AF_INET6);
|
pflow_sendout_ipfix(sc, PFLOW_INET6);
|
||||||
CURVNET_RESTORE();
|
CURVNET_RESTORE();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -911,6 +1068,21 @@ pflow_timeout_tmpl(void *v)
|
||||||
CURVNET_RESTORE();
|
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
|
static void
|
||||||
pflow_flush(struct pflow_softc *sc)
|
pflow_flush(struct pflow_softc *sc)
|
||||||
{
|
{
|
||||||
|
@ -921,8 +1093,9 @@ pflow_flush(struct pflow_softc *sc)
|
||||||
pflow_sendout_v5(sc);
|
pflow_sendout_v5(sc);
|
||||||
break;
|
break;
|
||||||
case PFLOW_PROTO_10:
|
case PFLOW_PROTO_10:
|
||||||
pflow_sendout_ipfix(sc, AF_INET);
|
pflow_sendout_ipfix(sc, PFLOW_INET);
|
||||||
pflow_sendout_ipfix(sc, AF_INET6);
|
pflow_sendout_ipfix(sc, PFLOW_INET6);
|
||||||
|
pflow_sendout_ipfix(sc, PFLOW_NAT4);
|
||||||
break;
|
break;
|
||||||
default: /* NOTREACHED */
|
default: /* NOTREACHED */
|
||||||
break;
|
break;
|
||||||
|
@ -960,7 +1133,7 @@ pflow_sendout_v5(struct pflow_softc *sc)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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 mbuf *m;
|
||||||
struct pflow_v10_header *h10;
|
struct pflow_v10_header *h10;
|
||||||
|
@ -971,7 +1144,7 @@ pflow_sendout_ipfix(struct pflow_softc *sc, sa_family_t af)
|
||||||
PFLOW_ASSERT(sc);
|
PFLOW_ASSERT(sc);
|
||||||
|
|
||||||
switch (af) {
|
switch (af) {
|
||||||
case AF_INET:
|
case PFLOW_INET:
|
||||||
m = sc->sc_mbuf;
|
m = sc->sc_mbuf;
|
||||||
callout_stop(&sc->sc_tmo);
|
callout_stop(&sc->sc_tmo);
|
||||||
if (m == NULL)
|
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)
|
set_length = sizeof(struct pflow_set_header)
|
||||||
+ sc->sc_count4 * sizeof(struct pflow_ipfix_flow4);
|
+ sc->sc_count4 * sizeof(struct pflow_ipfix_flow4);
|
||||||
break;
|
break;
|
||||||
case AF_INET6:
|
case PFLOW_INET6:
|
||||||
m = sc->sc_mbuf6;
|
m = sc->sc_mbuf6;
|
||||||
callout_stop(&sc->sc_tmo6);
|
callout_stop(&sc->sc_tmo6);
|
||||||
if (m == NULL)
|
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)
|
set_length = sizeof(struct pflow_set_header)
|
||||||
+ sc->sc_count6 * sizeof(struct pflow_ipfix_flow6);
|
+ sc->sc_count6 * sizeof(struct pflow_ipfix_flow6);
|
||||||
break;
|
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:
|
default:
|
||||||
panic("Unsupported AF %d", af);
|
panic("Unsupported AF %d", af);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue