Skip to content

Commit

Permalink
Merge pull request #559 from simonschdev/parse-gre
Browse files Browse the repository at this point in the history
GRE tunnel introspection for sFlow
  • Loading branch information
phaag authored Aug 31, 2024
2 parents 5c67031 fb344fb commit 99db1cd
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 11 deletions.
17 changes: 11 additions & 6 deletions src/sflow/sfcapd.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -155,6 155,7 @@ static void usage(char *name) {
"-X <extlist>\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

Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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]);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions src/sflow/sflow_nfdump.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/sflow/sflow_nfdump.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
52 changes: 50 additions & 2 deletions src/sflow/sflow_process.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -1474,14 1513,20 @@ 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];
printHex(sample->header, sample->headerLen, scratch, 2000, 0, 2000);
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:
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
10 changes: 10 additions & 0 deletions src/sflow/sflow_process.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -149,6 156,7 @@ typedef struct _SFSample {
uint8_t *header;
uint32_t headerLen;
uint32_t stripped;
uint32_t *headerDescriptionStart;

/* header decode */
int gotIPV4;
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit 99db1cd

Please sign in to comment.