Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GRE tunnel introspection for sFlow #559

Merged
merged 2 commits into from
Aug 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading