diff --git a/src/sflow/sfcapd.c b/src/sflow/sfcapd.c index 647f6b30..497362cf 100644 --- a/src/sflow/sfcapd.c +++ b/src/sflow/sfcapd.c @@ -111,7 +111,7 @@ static void IntHandler(int signal); static inline FlowSource_t *GetFlowSource(struct sockaddr_storage *ss); -static void run(packet_function_t receive_packet, int socket, int pfd, int rfd, time_t twin, time_t t_begin, char *time_extension, int compress); +static void run(packet_function_t receive_packet, int socket, int pfd, int rfd, time_t twin, time_t t_begin, char *time_extension, int compress, int parse_gre); /* Functions */ static void usage(char *name) { @@ -155,6 +155,7 @@ static void usage(char *name) { "-X \t',' separated list of extensions (numbers). Default all extensions.\n" "-V\t\tPrint version and exit.\n" "-Z\t\tAdd timezone offset to filename.\n", + "-G\t\tEnable GRE parsing.\n", name); } // End of usage @@ -266,7 +267,7 @@ static int SendRepeaterMessage(int fd, void *in_buff, size_t cnt, struct sockadd return 0; } // End of SendRepeaterMessage -static void run(packet_function_t receive_packet, int socket, int pfd, int rfd, time_t twin, time_t t_begin, char *time_extension, int compress) { +static void run(packet_function_t receive_packet, int socket, int pfd, int rfd, time_t twin, time_t t_begin, char *time_extension, int compress, int parse_gre) { struct sockaddr_storage sf_sender; socklen_t sf_sender_size = sizeof(sf_sender); @@ -424,7 +425,7 @@ static void run(packet_function_t receive_packet, int socket, int pfd, int rfd, fs->received = tv; /* Process data - have a look at the common header */ - Process_sflow(in_buff, cnt, fs); + Process_sflow(in_buff, cnt, fs, parse_gre); // each Process_xx function has to process the entire input buffer, therefore it's empty // now. @@ -452,7 +453,7 @@ int main(int argc, char **argv) { FlowSource_t *fs; int family, bufflen, metricInterval; time_t twin; - int sock, do_daemonize, expire, spec_time_extension; + int sock, do_daemonize, expire, spec_time_extension, parse_gre; int subdir_index, compress, srcSpoofing, workers; #ifdef PCAP char *pcap_file = NULL; @@ -486,9 +487,10 @@ int main(int argc, char **argv) { metricInterval = 60; extensionList = NULL; workers = 0; + parse_gre = 0; int c; - while ((c = getopt(argc, argv, "46AB:b:C:d:DeEf:g:hI:i:jJ:l:m:M:n:p:P:R:S:T:t:u:vVW:w:x:X:yz::Z")) != EOF) { + while ((c = getopt(argc, argv, "46AB:b:C:d:DeEf:g:hI:i:jJ:l:m:M:n:p:P:R:S:T:t:u:vVW:w:x:X:yz::Z:G")) != EOF) { switch (c) { case 'h': usage(argv[0]); @@ -725,6 +727,9 @@ int main(int argc, char **argv) { exit(EXIT_FAILURE); } break; + case 'G': + parse_gre = 1; + break; default: usage(argv[0]); exit(EXIT_FAILURE); @@ -894,7 +899,7 @@ int main(int argc, char **argv) { sigaction(SIGPIPE, &act, NULL); LogInfo("Startup sfcapd."); - run(receive_packet, sock, pfd, rfd, twin, t_start, time_extension, compress); + run(receive_packet, sock, pfd, rfd, twin, t_start, time_extension, compress, parse_gre); // shutdown close(sock); diff --git a/src/sflow/sflow_nfdump.c b/src/sflow/sflow_nfdump.c index d0b408a7..9c603196 100644 --- a/src/sflow/sflow_nfdump.c +++ b/src/sflow/sflow_nfdump.c @@ -147,8 +147,8 @@ int Init_sflow(int verbose, char *extensionList) { } // End of Init_sflow // called by sfcapd for each packet -void Process_sflow(void *in_buff, ssize_t in_buff_cnt, FlowSource_t *fs) { - SFSample sample = {.rawSample = in_buff, .rawSampleLen = in_buff_cnt, .sourceIP.s_addr = fs->sa_family == PF_INET ? htonl(fs->ip.V4) : 0}; +void Process_sflow(void *in_buff, ssize_t in_buff_cnt, FlowSource_t *fs, int parse_gre) { + SFSample sample = {.rawSample = in_buff, .rawSampleLen = in_buff_cnt, .sourceIP.s_addr = fs->sa_family == PF_INET ? htonl(fs->ip.V4) : 0, .parse_gre = parse_gre}; dbg_printf("startDatagram =================================\n"); // catch SFABORT in sflow code diff --git a/src/sflow/sflow_nfdump.h b/src/sflow/sflow_nfdump.h index 4b35b273..cce83ea8 100644 --- a/src/sflow/sflow_nfdump.h +++ b/src/sflow/sflow_nfdump.h @@ -39,7 +39,7 @@ int Init_sflow(int verbose, char *extensionList); -void Process_sflow(void *in_buff, ssize_t in_buff_cnt, FlowSource_t *fs); +void Process_sflow(void *in_buff, ssize_t in_buff_cnt, FlowSource_t *fs, int parse_gre); void StoreSflowRecord(SFSample *sample, FlowSource_t *fs); diff --git a/src/sflow/sflow_process.c b/src/sflow/sflow_process.c index 5099f09f..c82fe610 100644 --- a/src/sflow/sflow_process.c +++ b/src/sflow/sflow_process.c @@ -687,6 +687,38 @@ static void decodeIPLayer4(SFSample *sample, uint8_t *ptr) { dbg_printf("UDPBytes %u\n", sample->udp_pduLen); sample->offsetToPayload = ptr + sizeof(udp) - sample->header; } break; + case 47: { /* GRE */ + dbg_printf("GRE\n"); + if (sample->parse_gre) { + struct mygreheader gre; + memcpy(&gre, ptr, sizeof(gre)); + uint16_t checksum_present = ntohs(gre.flags) >> 15; + uint16_t key_present = (uint16_t)(ntohs(gre.flags) << 2) >> 15; + uint16_t seq_number_present = (uint16_t)(ntohs(gre.flags) << 3) >> 15; + uint32_t gre_header_length = sizeof(gre) + (checksum_present + key_present + seq_number_present) * 4; + switch (ntohs(gre.protocol_type)) { + case 0x6558: { /* Transparent Ethernet bridging */ + sample->headerProtocol = SFLHEADER_ETHERNET_ISO8023; +; } break; + case 0x0800: { /* IPv4 */ + sample->headerProtocol = SFLHEADER_IPv4; + } break; + case 0x86DD: { /* IPv6 */ + sample->headerProtocol = SFLHEADER_IPv6; + } break; + default: { /* some other protocol */ + dbg_printf("GRE: Unsupported encapsulated protocol"); + sample->offsetToPayload = ptr - sample->header; + return; + } + } + dbg_printf("GRE: Header type: %u\n", sample->headerProtocol); + sample->datap = sample->headerDescriptionStart; /* Reset parsing pointer for metadata */ + sample->header = ptr + gre_header_length; /* Set parsing pointer for header to end of GRE header */ + readFlowSample_header(sample); + return; + } + } default: /* some other protocol */ sample->offsetToPayload = ptr - sample->header; break; @@ -729,6 +761,7 @@ static void decodeIPV4(SFSample *sample) { printf("IPProtocol %u\n", sample->dcd_ipProtocol); printf("IPTOS %u\n", sample->dcd_ipTos); printf("IPTTL %u\n", sample->dcd_ipTTL); + #endif /* check for fragments */ sample->ip_fragmentOffset = ntohs(ip.frag_off) & 0x1FFF; @@ -1462,7 +1495,13 @@ static void readExtendedWifiTx(SFSample *sample) { static void readFlowSample_header(SFSample *sample) { dbg_printf("flowSampleType HEADER\n"); - sample->headerProtocol = getData32(sample); + if (!sample->headerDescriptionStart) { + sample->headerDescriptionStart = sample->datap; + } + uint32_t headerProtocol = getData32(sample); + if (!sample->headerProtocol) { + sample->headerProtocol = headerProtocol; + } dbg_printf("headerProtocol %u\n", sample->headerProtocol); sample->sampledPacketSize = getData32(sample); dbg_printf("sampledPacketSize %u\n", sample->sampledPacketSize); @@ -1474,7 +1513,10 @@ static void readFlowSample_header(SFSample *sample) { sample->headerLen = getData32(sample); dbg_printf("headerLen %u\n", sample->headerLen); - sample->header = (uint8_t *)sample->datap; /* just point at the header */ + if (!sample->header) { + sample->header = (uint8_t *)sample->datap; /* just point at the header */ + } + skipBytes(sample, sample->headerLen); { char scratch[2000]; @@ -1482,6 +1524,9 @@ static void readFlowSample_header(SFSample *sample) { dbg_printf("headerBytes %s\n", scratch); } + sample->gotIPV4 = NO; + sample->gotIPV6 = NO; + switch (sample->headerProtocol) { /* the header protocol tells us where to jump into the decode */ case SFLHEADER_ETHERNET_ISO8023: @@ -3597,6 +3642,8 @@ void readSFlowDatagram(SFSample *sample, FlowSource_t *fs, int verbose) { char buf[51]; #endif + int parse_gre = sample->parse_gre; + /* log some datagram info */ dbg_printf("datagramSourceIP %s\n", IP_to_a(sample->sourceIP.s_addr, buf, 51)); dbg_printf("datagramSize %u\n", sample->rawSampleLen); @@ -3632,6 +3679,7 @@ void readSFlowDatagram(SFSample *sample, FlowSource_t *fs, int verbose) { for (samp = 0; samp < samplesInPacket; samp++) { // fix bug sflowtool */ memset(sampleData, 0, sizeof(SFSample) - sampleDataOffset); + sample->parse_gre = parse_gre; if ((uint8_t *)sample->datap >= sample->endp) { LogError("SFLOW: readSFlowDatagram() unexpected end of datagram after sample %d of %d\n", samp, samplesInPacket); diff --git a/src/sflow/sflow_process.h b/src/sflow/sflow_process.h index 2540ec96..3e15dad2 100644 --- a/src/sflow/sflow_process.h +++ b/src/sflow/sflow_process.h @@ -106,6 +106,13 @@ struct myicmphdr { /* ignore the rest */ }; +/* and GRE (RFC 2890) */ +struct mygreheader { /* only relevant fields */ + uint8_t flags; /* presence indicators for checksum, key, and sequence number */ + uint8_t version; /* GRE version */ + uint16_t protocol_type; /* EtherType code for encapsulated protocol */ +}; + typedef struct _SFSample { /* exception handler context */ jmp_buf env; @@ -149,6 +156,7 @@ typedef struct _SFSample { uint8_t *header; uint32_t headerLen; uint32_t stripped; + uint32_t *headerDescriptionStart; /* header decode */ int gotIPV4; @@ -271,6 +279,8 @@ typedef struct _SFSample { #define SF_ABORT_DECODE_ERROR 2 #define SF_ABORT_LENGTH_ERROR 3 + int parse_gre; + } SFSample; #define sampleDataOffset offsetof(SFSample, sampleType)