From 49a3083396a890b3390b5c2a9793ce331da3ef00 Mon Sep 17 00:00:00 2001 From: Florian Obser Date: Tue, 5 Feb 2013 11:58:40 +0000 Subject: netflow v10 omitted the sysUpTime flow set header field from v9. Without it it's not possible to find out at what time a flow started/ended with only flowStartSysUpTime/flowEndSysUpTime. Fix this by using flowStartSeconds/flowEndSeconds for v10. Problem reported by Chris Ivancic and Colin Ligertwood, analyzed by benno@ Tested by benno@ against nprobe (which doesn't care that much one way or the other) Tested by Chris Ivancic against solarwinds collector. OK benno@ --- sys/net/if_pflow.c | 125 ++++++++++++++++++++++++++++++++++++++--------------- sys/net/if_pflow.h | 35 ++++++++------- 2 files changed, 110 insertions(+), 50 deletions(-) (limited to 'sys') diff --git a/sys/net/if_pflow.c b/sys/net/if_pflow.c index e8e94d23d7d..cf137f4ce4a 100644 --- a/sys/net/if_pflow.c +++ b/sys/net/if_pflow.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_pflow.c,v 1.23 2013/01/16 09:53:19 dlg Exp $ */ +/* $OpenBSD: if_pflow.c,v 1.24 2013/02/05 11:58:39 florian Exp $ */ /* * Copyright (c) 2011 Florian Obser @@ -91,9 +91,9 @@ void pflow_timeout_tmpl(void *); void copy_flow_data(struct pflow_flow *, struct pflow_flow *, struct pf_state *, int, int); void copy_flow4_data(struct pflow_flow4 *, struct pflow_flow4 *, - struct pf_state *, int, int); + struct pf_state *, struct pflow_softc *, int, int); void copy_flow6_data(struct pflow_flow6 *, struct pflow_flow6 *, - struct pf_state *, int, int); + struct pf_state *, struct pflow_softc *, int, int); int pflow_pack_flow(struct pf_state *, struct pflow_softc *); int pflow_pack_flow_ipfix(struct pf_state *, struct pflow_softc *); int pflow_get_dynport(void); @@ -162,11 +162,15 @@ pflow_clone_create(struct if_clone *ifc, int unit) pflowif->sc_tmpl.ipv4_tmpl.octets.field_id = htons(PFIX_IE_octetDeltaCount); pflowif->sc_tmpl.ipv4_tmpl.octets.len = htons(8); + /* keep in sync with SIOCSETPFLOW */ pflowif->sc_tmpl.ipv4_tmpl.start.field_id = - htons(PFIX_IE_flowStartSysUpTime); + htons(pflowif->sc_version == PFLOW_PROTO_9? + PFIX_IE_flowStartSysUpTime:PFIX_IE_flowStartSeconds); pflowif->sc_tmpl.ipv4_tmpl.start.len = htons(4); + /* keep in sync with SIOCSETPFLOW */ pflowif->sc_tmpl.ipv4_tmpl.finish.field_id = - htons(PFIX_IE_flowEndSysUpTime); + htons(pflowif->sc_version == PFLOW_PROTO_9? + PFIX_IE_flowEndSysUpTime:PFIX_IE_flowEndSeconds); pflowif->sc_tmpl.ipv4_tmpl.finish.len = htons(4); pflowif->sc_tmpl.ipv4_tmpl.src_port.field_id = htons(PFIX_IE_sourceTransportPort); @@ -197,11 +201,15 @@ pflow_clone_create(struct if_clone *ifc, int unit) pflowif->sc_tmpl.ipv6_tmpl.octets.field_id = htons(PFIX_IE_octetDeltaCount); pflowif->sc_tmpl.ipv6_tmpl.octets.len = htons(8); + /* keep in sync with SIOCSETPFLOW */ pflowif->sc_tmpl.ipv6_tmpl.start.field_id = - htons(PFIX_IE_flowStartSysUpTime); + htons(pflowif->sc_version == PFLOW_PROTO_9? + PFIX_IE_flowStartSysUpTime:PFIX_IE_flowStartSeconds); pflowif->sc_tmpl.ipv6_tmpl.start.len = htons(4); + /* keep in sync with SIOCSETPFLOW */ pflowif->sc_tmpl.ipv6_tmpl.finish.field_id = - htons(PFIX_IE_flowEndSysUpTime); + htons(pflowif->sc_version == PFLOW_PROTO_9? + PFIX_IE_flowEndSysUpTime:PFIX_IE_flowEndSeconds); pflowif->sc_tmpl.ipv6_tmpl.finish.len = htons(4); pflowif->sc_tmpl.ipv6_tmpl.src_port.field_id = htons(PFIX_IE_sourceTransportPort); @@ -374,12 +382,31 @@ pflowioctl(struct ifnet *ifp, u_long cmd, caddr_t data) pflow_setmtu(sc, ETHERMTU); pflow_init_timeouts(sc); - if (sc->sc_version == PFLOW_PROTO_9 - || sc->sc_version == PFLOW_PROTO_10) { + switch (sc->sc_version) { + case PFLOW_PROTO_9: + sc->sc_tmpl.set_header.set_id = + htons(PFLOW_V9_TMPL_SET_ID); + sc->sc_tmpl.ipv4_tmpl.start.field_id = + sc->sc_tmpl.ipv6_tmpl.start.field_id = + htons(PFIX_IE_flowStartSysUpTime); + sc->sc_tmpl.ipv4_tmpl.finish.field_id = + sc->sc_tmpl.ipv6_tmpl.finish.field_id = + htons(PFIX_IE_flowEndSysUpTime); + pflow_sendout_ipfix_tmpl(sc); + break; + case PFLOW_PROTO_10: sc->sc_tmpl.set_header.set_id = - htons(sc->sc_version == PFLOW_PROTO_9? - PFLOW_V9_TMPL_SET_ID:PFLOW_V10_TMPL_SET_ID); + htons(PFLOW_V10_TMPL_SET_ID); + sc->sc_tmpl.ipv4_tmpl.start.field_id = + sc->sc_tmpl.ipv6_tmpl.start.field_id = + htons(PFIX_IE_flowStartSeconds); + sc->sc_tmpl.ipv4_tmpl.finish.field_id = + sc->sc_tmpl.ipv6_tmpl.finish.field_id = + htons(PFIX_IE_flowEndSeconds); pflow_sendout_ipfix_tmpl(sc); + break; + default: + break; } splx(s); @@ -566,7 +593,7 @@ copy_flow_data(struct pflow_flow *flow1, struct pflow_flow *flow2, void copy_flow4_data(struct pflow_flow4 *flow1, struct pflow_flow4 *flow2, - struct pf_state *st, int src, int dst) + struct pf_state *st, struct pflow_softc *sc, int src, int dst) { struct pf_state_key *sk = st->key[PF_SK_WIRE]; @@ -580,15 +607,29 @@ copy_flow4_data(struct pflow_flow4 *flow1, struct pflow_flow4 *flow2, flow1->flow_octets = htobe64(st->bytes[0]); flow2->flow_octets = htobe64(st->bytes[1]); - /* - * Pretend the flow was created or expired when the machine came up - * when creation is in the future of the last time a package was seen - * or was created / expired before this machine came up due to pfsync. - */ - flow1->flow_start = flow2->flow_start = st->creation < 0 || - st->creation > st->expire ? htonl(0) : htonl(st->creation * 1000); - flow1->flow_finish = flow2->flow_finish = st->expire < 0 ? htonl(0) : - htonl(st->expire * 1000); + switch (sc->sc_version) { + case PFLOW_PROTO_9: + /* + * Pretend the flow was created or expired when the machine came + * up when creation is in the future of the last time a package + * was seen or was created / expired before this machine came up + * due to pfsync. + */ + flow1->flow_start = flow2->flow_start = st->creation < 0 || + st->creation > st->expire ? htonl(0) : htonl(st->creation * + 1000); + flow1->flow_finish = flow2->flow_finish = st->expire < 0 ? + htonl(0) : htonl(st->expire * 1000); + break; + case PFLOW_PROTO_10: + flow1->flow_start = flow2->flow_start = htonl(time_second - + (time_uptime - st->creation)); + flow1->flow_finish = flow2->flow_finish = htonl(time_second - + (time_uptime - st->expire)); + break; + default: /* NOTREACHED */ + break; + } flow1->protocol = flow2->protocol = sk->proto; flow1->tos = flow2->tos = st->rule.ptr->tos; @@ -596,7 +637,7 @@ copy_flow4_data(struct pflow_flow4 *flow1, struct pflow_flow4 *flow2, void copy_flow6_data(struct pflow_flow6 *flow1, struct pflow_flow6 *flow2, - struct pf_state *st, int src, int dst) + struct pf_state *st, struct pflow_softc *sc, int src, int dst) { struct pf_state_key *sk = st->key[PF_SK_WIRE]; bcopy(&sk->addr[src].v6, &flow1->src_ip, sizeof(flow1->src_ip)); @@ -611,15 +652,29 @@ copy_flow6_data(struct pflow_flow6 *flow1, struct pflow_flow6 *flow2, flow1->flow_octets = htobe64(st->bytes[0]); flow2->flow_octets = htobe64(st->bytes[1]); - /* - * Pretend the flow was created or expired when the machine came up - * when creation is in the future of the last time a package was seen - * or was created / expired before this machine came up due to pfsync. - */ - flow1->flow_start = flow2->flow_start = st->creation < 0 || - st->creation > st->expire ? htonl(0) : htonl(st->creation * 1000); - flow1->flow_finish = flow2->flow_finish = st->expire < 0 ? htonl(0) : - htonl(st->expire * 1000); + switch (sc->sc_version) { + case PFLOW_PROTO_9: + /* + * Pretend the flow was created or expired when the machine came + * up when creation is in the future of the last time a package + * was seen or was created / expired before this machine came up + * due to pfsync. + */ + flow1->flow_start = flow2->flow_start = st->creation < 0 || + st->creation > st->expire ? htonl(0) : htonl(st->creation * + 1000); + flow1->flow_finish = flow2->flow_finish = st->expire < 0 ? + htonl(0) : htonl(st->expire * 1000); + break; + case PFLOW_PROTO_10: + flow1->flow_start = flow2->flow_start = htonl(time_second - + (time_uptime - st->creation)); + flow1->flow_finish = flow2->flow_finish = htonl(time_second - + (time_uptime - st->expire)); + break; + default: /* NOTREACHED */ + break; + } flow1->protocol = flow2->protocol = sk->proto; flow1->tos = flow2->tos = st->rule.ptr->tos; @@ -826,9 +881,9 @@ pflow_pack_flow_ipfix(struct pf_state *st, struct pflow_softc *sc) bzero(&flow4_2, sizeof(flow4_2)); if (st->direction == PF_OUT) - copy_flow4_data(&flow4_1, &flow4_2, st, 1, 0); + copy_flow4_data(&flow4_1, &flow4_2, st, sc, 1, 0); else - copy_flow4_data(&flow4_1, &flow4_2, st, 0, 1); + copy_flow4_data(&flow4_1, &flow4_2, st, sc, 0, 1); if (st->bytes[0] != 0) /* first flow from state */ ret = copy_flow4_to_m(&flow4_1, sc); @@ -840,9 +895,9 @@ pflow_pack_flow_ipfix(struct pf_state *st, struct pflow_softc *sc) bzero(&flow6_2, sizeof(flow6_2)); if (st->direction == PF_OUT) - copy_flow6_data(&flow6_1, &flow6_2, st, 1, 0); + copy_flow6_data(&flow6_1, &flow6_2, st, sc, 1, 0); else - copy_flow6_data(&flow6_1, &flow6_2, st, 0, 1); + copy_flow6_data(&flow6_1, &flow6_2, st, sc, 0, 1); if (st->bytes[0] != 0) /* first flow from state */ ret = copy_flow6_to_m(&flow6_1, sc); diff --git a/sys/net/if_pflow.h b/sys/net/if_pflow.h index b39e491cecf..0bb0ebbc93c 100644 --- a/sys/net/if_pflow.h +++ b/sys/net/if_pflow.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_pflow.h,v 1.6 2012/02/02 12:34:37 benno Exp $ */ +/* $OpenBSD: if_pflow.h,v 1.7 2013/02/05 11:58:39 florian Exp $ */ /* * Copyright (c) 2008 Henning Brauer @@ -34,18 +34,20 @@ /* RFC 5102 Information Element Identifiers */ -#define PFIX_IE_octetDeltaCount 1 -#define PFIX_IE_packetDeltaCount 2 -#define PFIX_IE_protocolIdentifier 4 -#define PFIX_IE_ipClassOfService 5 -#define PFIX_IE_sourceTransportPort 7 -#define PFIX_IE_sourceIPv4Address 8 -#define PFIX_IE_destinationTransportPort 11 -#define PFIX_IE_destinationIPv4Address 12 -#define PFIX_IE_flowEndSysUpTime 21 -#define PFIX_IE_flowStartSysUpTime 22 -#define PFIX_IE_sourceIPv6Address 27 -#define PFIX_IE_destinationIPv6Address 28 +#define PFIX_IE_octetDeltaCount 1 +#define PFIX_IE_packetDeltaCount 2 +#define PFIX_IE_protocolIdentifier 4 +#define PFIX_IE_ipClassOfService 5 +#define PFIX_IE_sourceTransportPort 7 +#define PFIX_IE_sourceIPv4Address 8 +#define PFIX_IE_destinationTransportPort 11 +#define PFIX_IE_destinationIPv4Address 12 +#define PFIX_IE_flowEndSysUpTime 21 +#define PFIX_IE_flowStartSysUpTime 22 +#define PFIX_IE_sourceIPv6Address 27 +#define PFIX_IE_destinationIPv6Address 28 +#define PFIX_IE_flowStartSeconds 150 +#define PFIX_IE_flowEndSeconds 151 struct pflow_flow { u_int32_t src_ip; @@ -148,8 +150,11 @@ struct pflow_flow6 { struct in6_addr dest_ip; /* destinationIPv6Address */ u_int64_t flow_packets; /* packetDeltaCount */ u_int64_t flow_octets; /* octetDeltaCount */ - u_int32_t flow_start; /* flowStartSysUpTime */ - u_int32_t flow_finish; /* flowEndSysUpTime */ + u_int32_t flow_start; /* + * flowStartSysUpTime / + * flowStartSeconds + */ + u_int32_t flow_finish; /* flowEndSysUpTime / flowEndSeconds */ u_int16_t src_port; /* sourceTransportPort */ u_int16_t dest_port; /* destinationTransportPort */ u_int8_t tos; /* ipClassOfService */ -- cgit v1.2.3