diff --git a/README b/README index 7e56149..41d70d0 100644 --- a/README +++ b/README @@ -1,7 +1,7 @@ Userspace logging daemon for netfilter/iptables -Project Homepage: http://www.gnumonks.org/projects/ulogd -Mailinglist: http://lists.gnumonks.org/mailman/listinfo/ulogd/ +Project Homepage: https://www.netfilter.org/projects/ulogd/ +Mailinglist: https://marc.info/?l=netfilter This is just a short README, pleaes see the more extensive documentation in the doc/ subdirectory. diff --git a/include/ulogd/ipfix_protocol.h b/include/ulogd/ipfix_protocol.h index 01dd96a..941a67a 100644 --- a/include/ulogd/ipfix_protocol.h +++ b/include/ulogd/ipfix_protocol.h @@ -39,10 +39,11 @@ struct ipfix_vendor_field { }; /* Information Element Identifiers as of draft-ietf-ipfix-info-11.txt */ +/* https://www.iana.org/assignments/ipfix/ipfix.xhtml */ enum { IPFIX_octetDeltaCount = 1, IPFIX_packetDeltaCount = 2, - /* reserved */ + /* deltaFlowCount */ IPFIX_protocolIdentifier = 4, IPFIX_classOfServiceIPv4 = 5, IPFIX_tcpControlBits = 6, @@ -73,24 +74,24 @@ enum { IPFIX_flowLabelIPv6 = 31, IPFIX_icmpTypeCodeIPv4 = 32, IPFIX_igmpType = 33, - /* reserved */ - /* reserved */ + /* samplingInterval */ + /* samplingAlgorithm */ IPFIX_flowActiveTimeOut = 36, IPFIX_flowInactiveTimeout = 37, - /* reserved */ - /* reserved */ + /* engineType */ + /* engineId */ IPFIX_exportedOctetTotalCount = 40, IPFIX_exportedMessageTotalCount = 41, IPFIX_exportedFlowTotalCount = 42, - /* reserved */ + /* ipv4RouterSc */ IPFIX_sourceIPv4Prefix = 44, IPFIX_destinationIPv4Prefix = 45, IPFIX_mplsTopLabelType = 46, IPFIX_mplsTopLabelIPv4Address = 47, - /* reserved */ - /* reserved */ - /* reserved */ - /* reserved */ + /* samplerId */ + /* samplerMode */ + /* samplerRandomInterval */ + /* classId */ IPFIX_minimumTtl = 52, IPFIX_maximumTtl = 53, IPFIX_identificationIPv4 = 54, @@ -100,7 +101,7 @@ enum { IPFIX_vlanId = 58, IPFIX_postVlanId = 59, IPFIX_ipVersion = 60, - /* reserved */ + /* flowDirection */ IPFIX_ipNextHopIPv6Address = 62, IPFIX_bgpNexthopIPv6Address = 63, IPFIX_ipv6ExtensionHeaders = 64, @@ -121,15 +122,30 @@ enum { IPFIX_mplsLabelStackEntry10 = 79, IPFIX_destinationMacAddress = 80, IPFIX_postSourceMacAddress = 81, - /* reserved */ - /* reserved */ - /* reserved */ + /* interfaceName */ + /* interfaceDescription */ + /* samplerName */ IPFIX_octetTotalCount = 85, IPFIX_packetTotalCount = 86, - /* reserved */ + /* flagsAndSamplerId */ IPFIX_fragmentOffsetIPv4 = 88, - /* reserved */ + /* forwardingStatus */ + /* mplsVpnRouteDistinguisher + mplsTopLabelPrefixLength + srcTrafficIndex + dstTrafficIndex + applicationDescription */ IPFIX_applicationId = 95, + /* applicationName + Assigned for NetFlow v9 compatibility + postIpDiffServCodePoint + plicationFactor + className + classificationEngineId + layer2packetSectionOffset + layer2packetSectionSize + layer2packetSectionData + 105-127 Assigned for NetFlow v9 compatibility */ IPFIX_bgpNextAdjacentAsNumber = 128, IPFIX_bgpPrevAdjacentAsNumber = 129, IPFIX_exporterIPv4Address = 130, @@ -213,10 +229,54 @@ enum { IPFIX_ipv4Options = 208, IPFIX_tcpOptions = 209, IPFIX_paddingOctets = 210, - /* reserved */ - /* reserved */ + /* collectorIPv4Address */ + /* collectorIPv6Address */ IPFIX_headerLengthIPv4 = 213, IPFIX_mplsPayloadLength = 214, + /* exportTransportProtocol + collectorTransportPort + exporterTransportPort + tcpSynTotalCount + tcpFinTotalCount + tcpRstTotalCount + tcpPshTotalCount + tcpAckTotalCount + tcpUrgTotalCount + ipTotalLength */ + IPFIX_postNATSourceIPv4Address = 225, + IPFIX_postNATDestinationIPv4Address = 226, + IPFIX_postNAPTSourceTransportPort = 227, + IPFIX_postNAPTDestinationTransportPort = 228, + /* natOriginatingAddressRealm + natEvent + initiatorOctets + responderOctets + firewallEvent + ingressVRFID + egressVRFID + VRFname + postMplsTopLabelExp + tcpWindowScale + biflowDirection + ethernetHeaderLength + ethernetPayloadLength + ethernetTotalLength + dot1qVlanId + dot1qPriority + dot1qCustomerVlanId + dot1qCustomerPriority + metroEvcId + metroEvcType + pseudoWireId + pseudoWireType + pseudoWireControlWord + ingressPhysicalInterface + egressPhysicalInterface + postDot1qVlanId + postDot1qCustomerVlanId + ethernetType + postIpPrecedence + collectionTimeMilliseconds */ }; /* Information elements of the netfilter vendor id */ diff --git a/input/flow/ulogd_inpflow_NFCT.c b/input/flow/ulogd_inpflow_NFCT.c index 899b7e3..8ed2210 100644 --- a/input/flow/ulogd_inpflow_NFCT.c +++ b/input/flow/ulogd_inpflow_NFCT.c @@ -262,19 +262,19 @@ static struct ulogd_key nfct_okeys[] = { { .type = ULOGD_RET_IPADDR, .flags = ULOGD_RETF_NONE, - .name = "reply.ip.saddr", + .name = "reply.ip.saddr", /* reply source is supposed to be my after-DNAT destination */ .ipfix = { .vendor = IPFIX_VENDOR_IETF, - .field_id = IPFIX_sourceIPv4Address, + .field_id = IPFIX_postNATDestinationIPv4Address, }, }, { .type = ULOGD_RET_IPADDR, .flags = ULOGD_RETF_NONE, - .name = "reply.ip.daddr", + .name = "reply.ip.daddr", /* reply destination is my after-SNAT source */ .ipfix = { .vendor = IPFIX_VENDOR_IETF, - .field_id = IPFIX_destinationIPv4Address, + .field_id = IPFIX_postNATSourceIPv4Address, }, }, { @@ -292,7 +292,7 @@ static struct ulogd_key nfct_okeys[] = { .name = "reply.l4.sport", .ipfix = { .vendor = IPFIX_VENDOR_IETF, - .field_id = IPFIX_sourceTransportPort, + .field_id = IPFIX_postNAPTDestinationTransportPort, }, }, { @@ -301,7 +301,7 @@ static struct ulogd_key nfct_okeys[] = { .name = "reply.l4.dport", .ipfix = { .vendor = IPFIX_VENDOR_IETF, - .field_id = IPFIX_destinationTransportPort, + .field_id = IPFIX_postNAPTSourceTransportPort, }, }, { @@ -379,10 +379,10 @@ static struct ulogd_key nfct_okeys[] = { .type = ULOGD_RET_UINT32, .flags = ULOGD_RETF_NONE, .name = "flow.start.usec", - .ipfix = { + /* .ipfix = { .vendor = IPFIX_VENDOR_IETF, - .field_id = IPFIX_flowStartMicroSeconds, - }, + .field_id = IPFIX_flowStartMicroSeconds, -- this entry expects absolute total value, not the subsecond remainder + }, */ }, { .type = ULOGD_RET_UINT32, @@ -397,10 +397,10 @@ static struct ulogd_key nfct_okeys[] = { .type = ULOGD_RET_UINT32, .flags = ULOGD_RETF_NONE, .name = "flow.end.usec", - .ipfix = { + /* .ipfix = { .vendor = IPFIX_VENDOR_IETF, - .field_id = IPFIX_flowEndSeconds, - }, + .field_id = IPFIX_flowEndMicroSeconds, -- this entry expects absolute total value, not the subsecond remainder + }, */ }, { .type = ULOGD_RET_UINT8, diff --git a/output/ipfix/ipfix.c b/output/ipfix/ipfix.c index e0b3440..90f8b37 100644 --- a/output/ipfix/ipfix.c +++ b/output/ipfix/ipfix.c @@ -26,7 +26,7 @@ struct ipfix_templ { /* Template fields modeled after vy_ipfix_data */ static const struct ipfix_templ template = { - .num_templ_elements = 10, + .num_templ_elements = 14, .templ_elements = { { .id = IPFIX_sourceIPv4Address, @@ -37,22 +37,30 @@ static const struct ipfix_templ template = { .len = sizeof(uint32_t) }, { - .id = IPFIX_packetTotalCount, + .id = IPFIX_postNATSourceIPv4Address, .len = sizeof(uint32_t) }, { - .id = IPFIX_octetTotalCount, + .id = IPFIX_postNATDestinationIPv4Address, .len = sizeof(uint32_t) }, { - .id = IPFIX_flowStartSeconds, + .id = IPFIX_packetTotalCount, .len = sizeof(uint32_t) }, { - .id = IPFIX_flowEndSeconds, + .id = IPFIX_octetTotalCount, .len = sizeof(uint32_t) }, { + .id = IPFIX_flowStartMilliSeconds, + .len = sizeof(uint64_t) /* better resolution, handled by nfdump */ + }, + { + .id = IPFIX_flowEndMilliSeconds, + .len = sizeof(uint64_t) /* high || low */ + }, + { .id = IPFIX_sourceTransportPort, .len = sizeof(uint16_t) }, @@ -61,13 +69,21 @@ static const struct ipfix_templ template = { .len = sizeof(uint16_t) }, { + .id = IPFIX_postNAPTSourceTransportPort, + .len = sizeof(uint16_t) + }, + { + .id = IPFIX_postNAPTDestinationTransportPort, + .len = sizeof(uint16_t) + }, + { .id = IPFIX_protocolIdentifier, .len = sizeof(uint8_t) }, { .id = IPFIX_applicationId, .len = sizeof(uint32_t) - } + }, } }; diff --git a/output/ipfix/ipfix.h b/output/ipfix/ipfix.h index b0f3ae6..2de9572 100644 --- a/output/ipfix/ipfix.h +++ b/output/ipfix/ipfix.h @@ -59,12 +59,18 @@ struct ipfix_msg { struct vy_ipfix_data { struct in_addr saddr; struct in_addr daddr; + struct in_addr tsaddr; /* translated source address, as read from the reply destination */ + struct in_addr tdaddr; uint32_t packets; uint32_t bytes; - uint32_t start; /* Unix time */ - uint32_t end; /* Unix time */ + uint32_t start_high; /* Unix time * 1000 */ + uint32_t start_low; + uint32_t end_high; + uint32_t end_low; uint16_t sport; uint16_t dport; + uint16_t tsport; + uint16_t tdport; uint8_t l4_proto; uint32_t aid; /* Application ID */ } __attribute__((packed)); diff --git a/output/ipfix/ulogd_output_IPFIX.c b/output/ipfix/ulogd_output_IPFIX.c index 1c0f730..8f1dde3 100644 --- a/output/ipfix/ulogd_output_IPFIX.c +++ b/output/ipfix/ulogd_output_IPFIX.c @@ -97,6 +97,8 @@ struct ipfix_priv { enum { InIpSaddr = 0, InIpDaddr, + InTIpSaddr, + InTIpDaddr, InRawInPktCount, InRawInPktLen, InRawOutPktCount, @@ -107,6 +109,8 @@ enum { InFlowEndUsec, InL4SPort, InL4DPort, + InL4TSPort, + InL4TDPort, InIpProto, InCtMark }; @@ -120,6 +124,14 @@ static struct ulogd_key ipfix_in_keys[] = { .type = ULOGD_RET_IPADDR, .name = "orig.ip.daddr" }, + [InTIpSaddr] = { + .type = ULOGD_RET_IPADDR, + .name = "reply.ip.daddr" + }, + [InTIpDaddr] = { + .type = ULOGD_RET_IPADDR, + .name = "reply.ip.saddr" + }, [InRawInPktCount] = { .type = ULOGD_RET_UINT64, .name = "orig.raw.pktcount" @@ -160,6 +172,14 @@ static struct ulogd_key ipfix_in_keys[] = { .type = ULOGD_RET_UINT16, .name = "orig.l4.dport" }, + [InL4TSPort] = { + .type = ULOGD_RET_UINT16, + .name = "reply.l4.dport" + }, + [InL4TDPort] = { + .type = ULOGD_RET_UINT16, + .name = "reply.l4.sport" + }, [InIpProto] = { .type = ULOGD_RET_UINT8, .name = "orig.ip.protocol" @@ -419,7 +439,8 @@ static int ipfix_stop(struct ulogd_pluginstance *pi) static int ipfix_interp(struct ulogd_pluginstance *pi) { struct ipfix_priv *priv = (struct ipfix_priv *) &pi->private; - char saddr[16], daddr[16], *send_template; + char saddr[16],tsaddr[16], daddr[16],tdaddr[16], *send_template; + uint64_t start, end; struct vy_ipfix_data *data; int oid, mtu, ret; @@ -458,18 +479,27 @@ again: data->saddr.s_addr = ikey_get_u32(&pi->input.keys[InIpSaddr]); data->daddr.s_addr = ikey_get_u32(&pi->input.keys[InIpDaddr]); + data->tsaddr.s_addr = ikey_get_u32(&pi->input.keys[InTIpSaddr]); + data->tdaddr.s_addr = ikey_get_u32(&pi->input.keys[InTIpDaddr]); data->packets = htonl((uint32_t) (ikey_get_u64(&pi->input.keys[InRawInPktCount]) + ikey_get_u64(&pi->input.keys[InRawOutPktCount]))); data->bytes = htonl((uint32_t) (ikey_get_u64(&pi->input.keys[InRawInPktLen]) + ikey_get_u64(&pi->input.keys[InRawOutPktLen]))); - data->start = htonl(ikey_get_u32(&pi->input.keys[InFlowStartSec])); - data->end = htonl(ikey_get_u32(&pi->input.keys[InFlowEndSec])); + start = (uint64_t)ikey_get_u32(&pi->input.keys[InFlowStartSec]) *1000 + ikey_get_u32(&pi->input.keys[InFlowStartUsec])/1000; + end = (uint64_t)ikey_get_u32(&pi->input.keys[InFlowEndSec]) *1000 + ikey_get_u32(&pi->input.keys[InFlowEndUsec])/1000; + data->start_low = htonl((uint32_t)(start & 0xFFFFFFFFUL)); + data->start_high = htonl(start >> 32); + if (!end) end = start; /* nfcapd doesn't record start time without end timestamp... this is a workaround for logging new connections */ + data->end_low = htonl((uint32_t)(end & 0xFFFFFFFFUL)); + data->end_high = htonl(end >> 32); if (GET_FLAGS(pi->input.keys, InL4SPort) & ULOGD_RETF_VALID) { data->sport = htons(ikey_get_u16(&pi->input.keys[InL4SPort])); data->dport = htons(ikey_get_u16(&pi->input.keys[InL4DPort])); + data->tsport = htons(ikey_get_u16(&pi->input.keys[InL4TSPort])); + data->tdport = htons(ikey_get_u16(&pi->input.keys[InL4TDPort])); } data->aid = 0; @@ -478,11 +508,13 @@ again: data->l4_proto = ikey_get_u8(&pi->input.keys[InIpProto]); - ulogd_log(ULOGD_DEBUG, "Got new packet (packets = %u, bytes = %u, flow = (%u, %u), saddr = %s, daddr = %s, sport = %u, dport = %u)\n", - ntohl(data->packets), ntohl(data->bytes), ntohl(data->start), ntohl(data->end), + ulogd_log(ULOGD_DEBUG, "Got new packet (packets = %u, bytes = %u, flow = (%u:%u, %u:%u), saddr = %s/%s, daddr = %s/%s, sport = %u/%u, dport = %u/%u)\n", + ntohl(data->packets), ntohl(data->bytes), ntohl(data->start_high),ntohl(data->start_low), ntohl(data->end_high),ntohl(data->end_low), inet_ntop(AF_INET, &data->saddr.s_addr, saddr, sizeof(saddr)), + inet_ntop(AF_INET, &data->tsaddr.s_addr, tsaddr, sizeof(tsaddr)), inet_ntop(AF_INET, &data->daddr.s_addr, daddr, sizeof(daddr)), - ntohs(data->sport), ntohs(data->dport)); + inet_ntop(AF_INET, &data->tdaddr.s_addr, tdaddr, sizeof(tdaddr)), + ntohs(data->sport),ntohs(data->tsport), ntohs(data->dport),ntohs(data->tdport)); if ((ret = send_msgs(pi)) < 0) return ret;