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

libpacket: Decode Geneve encapsulation #5

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions include/packet/protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ typedef enum
PROTO_SCTP,
PROTO_ICMP,
PROTO_ICMP6,
PROTO_GENEVE,
PROTO_MAX
} PROTOCOL;

Expand Down
2 changes: 2 additions & 0 deletions include/packet/stats.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ struct packet_stats {
uint32_t sctps_badsum; /* checksum errors */
uint32_t sctps_badtype; /* bad chunk type */ // XXX UNUSED
uint32_t sctps_tooshort; /* not enough data */

uint32_t geneve_packets; /* total geneve packets */
};

#ifdef __cplusplus
Expand Down
10 changes: 6 additions & 4 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ target_sources(
crc32.h
eth.c
eth.h
geneve.c
geneve.h
icmp4.c
icmp4.h
icmp6.c
icmp6.h
ip4.c
ip4.h
ip6.c
Expand All @@ -45,10 +51,6 @@ target_sources(
tcp.h
udp.c
udp.h
icmp4.c
icmp4.h
icmp6.c
icmp6.h
vlan.c
vlan.h
)
Expand Down
69 changes: 69 additions & 0 deletions src/geneve.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// https://datatracker.ietf.org/doc/html/rfc8926

#include <stdint.h>
#include <stdbool.h>

#include "packet_private.h"
#include "eth.h"

extern struct packet_stats s_stats;

#define ETHERTYPE_ETH 0x6558

struct geneve_header {
uint8_t opt_len;
uint8_t flags;
uint16_t proto;
uint32_t vni;
} __attribute__((packed));

#define GENEVE_VERSION(optlen) (((optlen) & 0xC0) >> 6)
#define GENEVE_OPTLEN(optlen) (((optlen) & 0x3F) * 4)

#define IS_CONTROL_PACKET(flags) (((flags) & 0x80) >> 7)
#define HAS_CRITICAL_OPTIONS(flags) (((flags) & 0x40) >> 6)
#define FLAGS_RESERVED(flags) ((flags) & 0x3F)

#define VNI(vni) (((vni) & 0xFFFFFF00) >> 8)
#define VNI_RESERVED(vni) ((vni) & 0x000000FF)


static bool inline
_is_valid(struct geneve_header *hdr)
{
if (GENEVE_VERSION(hdr->opt_len) != 0)
return false;

if (FLAGS_RESERVED(hdr->flags) != 0)
return false;

if (VNI_RESERVED(hdr->vni) != 0)
return false;

return true;
}

int
decode_geneve(const uint8_t *pkt, unsigned len, Packet* packet)
{
struct geneve_header *hdr = (struct geneve_header*)pkt;

if (len < sizeof(*hdr))
return -1;

unsigned hlen = GENEVE_OPTLEN(hdr->opt_len) + sizeof(*hdr);
if (len < hlen)
return -1;

s_stats.geneve_packets++;

packet->payload += hlen;
packet->paysize -= hlen;
packet_layer_ins(packet, pkt, hlen, PROTO_GENEVE);

uint16_t proto = ntohs(hdr->proto);
if (proto == ETHERTYPE_ETH)
return decode_dlt_eth(pkt + hlen, len - hlen, packet);

return bind_eth(proto, pkt + hlen, len - hlen, packet);
}
7 changes: 7 additions & 0 deletions src/geneve.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#ifndef DECODE_GENEVE_H
#define DECODE_GENEVE_H

int decode_geneve(const uint8_t *pkt, unsigned len, Packet*);

#endif /* DECODE_GENEVE_H */

3 changes: 2 additions & 1 deletion src/packet.c
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,8 @@ static const char *proto_map[PROTO_MAX] = {
"udp",
"sctp",
"icmp",
"icmp6"
"icmp6",
"geneve"
};

#define ENUM2STR(num, map) \
Expand Down
15 changes: 8 additions & 7 deletions src/udp.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@
#define __FAVOR_BSD
#include <netinet/udp.h>

#include "packet_private.h"

#include "checksum.h"
#include "packet_private.h"
#include "geneve.h"

extern struct packet_stats s_stats;

Expand Down Expand Up @@ -78,16 +78,17 @@ decode_udp(const uint8_t *pkt, const uint32_t len, Packet *p)
if (udp->uh_sum == 0 && p->version == 6)
{
s_stats.udps_badsum++;
//return -1;
}
else if (udp->uh_sum == 0)

if (udp->uh_sum != 0)
{
return 0;
if (checksum((uint16_t *)udp, &pseudo, ntohs(pseudo.len)) != 0)
s_stats.udps_badsum++;
}

if (checksum((uint16_t *)udp, &pseudo, ntohs(pseudo.len)) != 0)
if (p->dstport == 6081)
{
s_stats.udps_badsum++;
return decode_geneve(pkt + sizeof(*udp), len - sizeof(*udp), p);
}

return 0;
Expand Down
Binary file added tests/pcaps/geneve.pcap
Binary file not shown.
92 changes: 92 additions & 0 deletions tests/print_packet.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
#include <stdio.h>
#include <stdint.h>
#include <ctype.h>
#include <packet.h>

// Taken from Pcapstats BSD License
void print_data(const uint8_t *data, int length)
{
int i, x, j, c;
int w = 0;

for( i=0; length>0; length -= 16 )
{
c = length >= 16 ? 16 : length;
printf("%06X ", w);
w+=16;

for( j=0; j<c; j++ )
printf("%2.02X ", data[i+j]);

for( x = length; x<16; x++ )
printf(" ");

for( j=0; j<c; j++ )
printf("%c", (isprint(data[i+j]) ? data[i+j] : '.'));

printf("\n");
i+=c;
}
}

void
print_packet(const uint8_t *data, const size_t len)
{
Packet packet = {};
packet_clear(&packet);

printf("\n");
//#define DLT_RAW 12
// packet_set_datalink(DLT_RAW);
int error = packet_decode(&packet, data, len);

struct ipaddr src = packet_srcaddr(&packet);
struct ipaddr dst = packet_dstaddr(&packet);
struct ipaddr *a = &src;
struct ipaddr *b = &dst;
uint32_t sport = packet_srcport(&packet);
uint32_t dport = packet_dstport(&packet);
uint32_t proto = packet_protocol(&packet);

unsigned it;
for (Protocol *_p = packet_proto_first(&packet, &it);
_p; _p = packet_proto_next(&packet, &it))
{
printf("%s:", packet_proto_name(_p));
}
printf("\n");

printf("[src: %d.%d.%d.%d, ",
a->addr8[0],
a->addr8[1],
a->addr8[2],
a->addr8[3]);

printf("dst: %d.%d.%d.%d, ",
b->addr8[0],
b->addr8[1],
b->addr8[2],
b->addr8[3]);

printf("proto: %d, id: %d, sp: %d, dp: %d, dlen: %u]\n",
proto,
packet_id(&packet),
sport,
dport,
packet_paysize(&packet));

if (packet_is_fragment(&packet))
{
printf(" |ip off: %u %s\n",
packet_frag_offset(&packet),
packet_frag_mf(&packet) ? "mf" : "");
}


size_t max = packet_paysize(&packet);
const uint8_t *payload = packet_payload(&packet);
max = max > 128 ? 128 : max;

print_data(payload, max);
}

21 changes: 14 additions & 7 deletions tests/testme.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

int s_error = 0;

extern void print_packet(const uint8_t *data, const size_t len);

#define PERLINE 10
void print_cbuf(const uint8_t *data, int length)
{
Expand All @@ -26,14 +28,16 @@ void print_cbuf(const uint8_t *data, int length)
}
}



static void
packet_callback(uint8_t *unused, const struct pcap_pkthdr *ph,
const uint8_t *pkt)
{
static int count = 0;
count++;

Packet *packet = packet_create( );
//Packet *packet = packet_create( );

/* cute way of collecting packet data for unit tests */
#if 0
Expand All @@ -42,12 +46,14 @@ packet_callback(uint8_t *unused, const struct pcap_pkthdr *ph,
printf("};\n");
#endif

int error = packet_decode(packet, pkt, ph->caplen);
print_packet(pkt, ph->caplen);
//int error = packet_decode(packet, pkt, ph->caplen);

if (error)
{
s_error = error;
}
//if (error)
//{
// s_error = error;
//}


/* not cute */
#if 0
Expand All @@ -63,7 +69,7 @@ packet_callback(uint8_t *unused, const struct pcap_pkthdr *ph,
printf("\n");
#endif

packet_destroy(packet);
//packet_destroy(packet);
}

int main(int argc, char *argv[])
Expand Down Expand Up @@ -96,6 +102,7 @@ int main(int argc, char *argv[])
printf("Processed %u packets\n", ps->total_packets);
printf("Rejected %u packets\n", ps->total_errors);

printf("Analyzed %u geneve packets\n", ps->geneve_packets);
printf("Analyzed %u pppoe packets\n", ps->pppoes_packets);
printf("Analyzed %u ppp packets\n", ps->ppps_packets);
printf("Analyzed %u ip packets\n", ps->ips_packets);
Expand Down