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

Fixing L4 offset for IP packets with Options field #54

Open
wants to merge 1 commit into
base: main
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
28 changes: 20 additions & 8 deletions connection-limit/connection_limit_kern.c
Original file line number Diff line number Diff line change
Expand Up @@ -269,22 +269,34 @@ int _xdp_limit_conn(struct xdp_md *ctx)
void *data_end = (void *)(long)ctx->data_end;
void *data = (void *)(long)ctx->data;

/* Check if its valid ethernet packet */
if (data + sizeof(struct ethhdr)+ 1 > data_end)
struct ethhdr *eth = data;

/* Check if it is a valid ethernet packet */
if (data + sizeof(*eth)+ 1 > data_end)
return XDP_PASS;

uint16_t eth_type = eth->h_proto;

/* Check if its valid ip packet */
struct iphdr *iph = (struct iphdr *)(data + sizeof(struct ethhdr));
if (iph + 1 > data_end)
/* Ignore other than IPV4 packets */
if (ntohs(eth_type) != ETH_P_IP)
return XDP_PASS;

struct iphdr *iph = (struct iphdr *)(data + sizeof(*eth));
__u8 l4_offset = iph->ihl * 4; // ipv4 header length

/* Check if it is a valid IPV4 packet */
if (iph->ihl < 5 || ((unsigned char *)iph + l4_offset) > data_end)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Range of IHL is 5 to 15, with boundary values included. Please add check explicitly for this.

return XDP_PASS;

/* Ignore other than TCP packets */
if (iph->protocol != IPPROTO_TCP)
return XDP_PASS;

/* Check if its valid tcp packet */
struct tcphdr *tcph = (struct tcphdr *)(iph + 1);
if (tcph + 1 > data_end)
struct tcphdr *tcph = (struct tcphdr *)((unsigned char *)iph + l4_offset);
__u16 data_offset = tcph->doff * 4; // tcp header length

/* Check if it is a valid TCP packet */
if (tcph->doff < 5 || ((unsigned char *)tcph + data_offset) > data_end)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as the range comment for IHL.

return XDP_PASS;

/* Ignore other than TCP-SYN packets */
Expand Down
28 changes: 18 additions & 10 deletions ipfix-flow-exporter/bpf_ipfix_egress_kern.c
Original file line number Diff line number Diff line change
Expand Up @@ -180,8 +180,8 @@ static void parse_icmp_type(void *icmp_data,void *data_end, u16 *icmp_type){
static void parse_port(void *trans_data, void *data_end, u8 proto,
u32 *dport, u32 *sport, u16 *control_bit)
{
struct udphdr *udph;
struct tcphdr *tcph;
struct udphdr *udph; // size = 8 bytes
struct tcphdr *tcph; // size = 20-60 bytes

u32 dstport = 0;
u32 srcport = 0;
Expand All @@ -190,17 +190,20 @@ static void parse_port(void *trans_data, void *data_end, u8 proto,
switch (proto) {
case IPPROTO_UDP:
udph = trans_data;
if (udph + 1 > data_end) {

if (udph + 1 > data_end)
return;
}

dstport = ntohs(udph->dest);
srcport = ntohs(udph->source);
break;
case IPPROTO_TCP:
tcph = trans_data;
if (tcph + 1 > data_end) {
u16 data_offset = tcph->doff * 4;

if (tcph->doff < 5 || ((unsigned char *)tcph + data_offset) > data_end)
return;
}

dstport = ntohs(tcph->dest);
srcport = ntohs(tcph->source);
if (tcph->syn & TCP_FLAGS) { controlbit = controlbit | TH_SYN; }
Expand Down Expand Up @@ -249,13 +252,18 @@ void parse_ipv4(struct __sk_buff *skb, u64 l3_offset)
u16 control_bit = 0;
u16 icmp_type = 0;

if (iph + 1 > data_end)
return;
u8 l4_offset = iph->ihl * 4; // ipv4 header length

/* Check if it's a valid IPv4 packet */
if (iph->ihl < 5 || ((unsigned char *)iph + l4_offset) > data_end)
return;

void *thdr = ((unsigned char *)iph + l4_offset); // transport layer header

if(iph->protocol == ICMP)
parse_icmp_type(iph+1, data_end, &icmp_type);
parse_icmp_type(thdr, data_end, &icmp_type);

parse_port(iph+1, data_end, iph->protocol, &dport, &sport, &control_bit);
parse_port(thdr, data_end, iph->protocol, &dport, &sport, &control_bit);

memset(&flow_key, 0, sizeof(flow_key));
flow_key.sa = iph->saddr;
Expand Down
28 changes: 18 additions & 10 deletions ipfix-flow-exporter/bpf_ipfix_ingress_kern.c
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,8 @@ static void parse_icmp_type(void *icmp_data,void *data_end, u16 *icmp_type){
static void parse_port(void *trans_data, void *data_end, u8 proto,
u32 *dport, u32 *sport, u16 *control_bit)
{
struct udphdr *udph;
struct tcphdr *tcph;
struct udphdr *udph; // size = 8 bytes
struct tcphdr *tcph; // size = 20-60 bytes

u32 dstport = 0;
u32 srcport = 0;
Expand All @@ -188,17 +188,20 @@ static void parse_port(void *trans_data, void *data_end, u8 proto,
switch (proto) {
case IPPROTO_UDP:
udph = trans_data;
if (udph + 1 > data_end) {

if (udph + 1 > data_end)
return;
}

dstport = ntohs(udph->dest);
srcport = ntohs(udph->source);
break;
case IPPROTO_TCP:
tcph = trans_data;
if (tcph + 1 > data_end) {
u16 data_offset = tcph->doff * 4;

if (tcph->doff < 5 || ((unsigned char *)tcph + data_offset) > data_end)
return;
}

dstport = ntohs(tcph->dest);
srcport = ntohs(tcph->source);
if (tcph->syn & TCP_FLAGS) { controlbit = controlbit | TH_SYN; }
Expand Down Expand Up @@ -247,13 +250,18 @@ void parse_ipv4(struct __sk_buff *skb, u64 l3_offset)
u16 control_bit = 0;
u16 icmp_type = 0;

if (iph + 1 > data_end)
return;
u8 l4_offset = iph->ihl * 4; // ipv4 header length

/* Check if it is a valid IPv4 packet */
if (iph->ihl < 5 || ((unsigned char *)iph + l4_offset) > data_end)
return;

void *thdr = ((unsigned char *)iph + l4_offset); // transport layer header

if(iph->protocol == ICMP)
parse_icmp_type(iph+1, data_end, &icmp_type);
parse_icmp_type(thdr, data_end, &icmp_type);

parse_port(iph+1, data_end, iph->protocol, &dport, &sport, &control_bit);
parse_port(thdr, data_end, iph->protocol, &dport, &sport, &control_bit);

memset(&flow_key, 0, sizeof(flow_key));
flow_key.sa = iph->saddr;
Expand Down
18 changes: 12 additions & 6 deletions ratelimiting/ratelimiting_kern.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,22 +93,28 @@ static __always_inline int _xdp_ratelimit(struct xdp_md *ctx)

/* Ignore other than ethernet packets */
uint16_t eth_type = eth->h_proto;

/* Ignore other than IPV4 packets */
if (ntohs(eth_type) != ETH_P_IP) {
return XDP_PASS;
}

/* Ignore other than IP packets */
struct iphdr *iph = data + sizeof(struct ethhdr);
if (iph + 1 > data_end)
struct iphdr *iph = (struct iphdr *)(data + sizeof(*eth));
__u8 l4_offset = iph->ihl * 4; // ipv4 header length

/* Check if it is a valid IPV4 packet */
if (iph->ihl < 5 || ((unsigned char *)iph + l4_offset) > data_end)
return XDP_PASS;

/* Ignore other than TCP packets */
if (iph->protocol != IPPROTO_TCP)
return XDP_PASS;

/* Check if its valid tcp packet */
struct tcphdr *tcph = (struct tcphdr *)(iph + 1);
if (tcph + 1 > data_end)
struct tcphdr *tcph = (struct tcphdr *)((unsigned char *)iph + l4_offset);
__u16 data_offset = tcph->doff * 4; // tcp header length

/* Check if it is a valid TCP packet */
if (tcph->doff < 5 || ((unsigned char *)tcph + data_offset) > data_end)
return XDP_PASS;

/* Ignore other than TCP-SYN packets */
Expand Down