Skip to content

Commit

Permalink
Adding custom memcpy and memset functions to pass verifier checks
Browse files Browse the repository at this point in the history
Built-in memcpy and memset functions cause verifier to complain about
misaligned stack access. To get around that (and be able to copy a
dynamic number of bytes via memcpy), two custom functions are added.
This version of the relay uses interface name + VLAN identifiers in
option 82 circuit ID (left-aligned, length IF_NAMESIZE with trailing
null bytes).
  • Loading branch information
Yoel Caspersen committed Oct 24, 2021
1 parent a9003fa commit b7d2d94
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 41 deletions.
1 change: 1 addition & 0 deletions dhcp-relay/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ USER_TARGETS := dhcp_user_xdp
BPF_TARGETS :=dhcp_kern_xdp
EXTRA_DEPS := dhcp-relay.h
#EXTRA_CFLAGS := $(if $(IPV6),-DIPV6)
EXTRA_CFLAGS := -fno-builtin

LIB_DIR = ../lib

Expand Down
4 changes: 2 additions & 2 deletions dhcp-relay/dhcp-relay.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#define DHO_DHCP_AGENT_OPTIONS 82
#define RAI_CIRCUIT_ID 1
#define RAI_REMOTE_ID 2
#define RAI_OPTION_LEN 40
#define RAI_OPTION_LEN IF_NAMESIZE
#define VLAN_ASCII_MAX 4 /* Max bytes needed to store VLAN in ASCII format */

#define DHCP_SERVER_PORT 67
Expand All @@ -22,7 +22,7 @@
struct sub_option {
__u8 option_id;
__u8 len;
char val[IF_NAMESIZE];
char val[RAI_OPTION_LEN];
};

/*structure for dhcp option 82 */
Expand Down
101 changes: 62 additions & 39 deletions dhcp-relay/dhcp_kern_xdp.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@
#include <xdp/context_helpers.h>
#include "dhcp-relay.h"

#define bpf_printk(fmt, ...) \
({ \
char ____fmt[] = fmt; \
bpf_trace_printk(____fmt, sizeof(____fmt), \
##__VA_ARGS__); \
})

/*
* This map is for storing the DHCP relay configuration, including:
*
Expand Down Expand Up @@ -49,77 +56,100 @@ struct {
__uint(max_entries, 16384);
} client_vlans SEC(".maps");

void memcpy_var(void *to, void *from, __u64 len) {
__u8 *t8 = to, *f8 = from;
int i;

for (i = 0; i < len; i++) {
*t8++ = *f8++;
}

}

void memset_var(void *d, __u8 c, __u64 len) {
__u8 *d8 = d;
int i;

for (i = 0; i < len; i++) {
*d8++ = c;
}

}

/* Inserts DHCP option 82 into the received DHCP packet
* at the specified offset.
*/
static __always_inline int write_dhcp_option_82(void *ctx, int offset,
struct collect_vlans *vlans, char *dev) {

struct dhcp_option_82 option;

option.t = DHO_DHCP_AGENT_OPTIONS;
option.len = sizeof (struct sub_option) + sizeof (struct sub_option);
option.circuit_id.option_id = RAI_CIRCUIT_ID;
option.circuit_id.len = sizeof(option.circuit_id.val);
option.circuit_id.len = sizeof (option.circuit_id.val);
option.remote_id.option_id = RAI_REMOTE_ID;
option.remote_id.len = sizeof (option.remote_id.val);

/* Initialize val arrays */
memset_var(option.circuit_id.val, 0, sizeof (option.circuit_id.val));
memset_var(option.remote_id.val, '*', sizeof (option.remote_id.val));
//memset(option.circuit_id.val, 0, sizeof (option.circuit_id.val));
//memset(option.remote_id.val, '*', sizeof (option.remote_id.val));

/* Reconstruct VLAN device name
* Convert VLAN tags to ASCII from right to left, starting with
* inner VLAN tag.
* Device name is 16 characters long and prepended with dash, e.g.:
* ----ens6f0.83.20
* We avoid null bytes to ensure compatibility with DHCP servers that
* interpret null as a string terminator.
* Device name is up to 16 characters long - remaining buffer space
* contains null bytes.
*/
char buf[IF_NAMESIZE];
memset(buf, '-', sizeof (buf));

char buf[RAI_OPTION_LEN];
memset(buf, 0, sizeof (buf));

int c = VLAN_ASCII_MAX; /* We will need 4 bytes at most */
int i = IF_NAMESIZE - 1;
int c = VLAN_ASCII_MAX; /* We will need 4 bytes at most */
int i = RAI_OPTION_LEN - 1;
__u16 inner_vlan = vlans->id[1];
__u16 outer_vlan = vlans->id[0];


/* Convert inner VLAN to ASCII */
for (c = VLAN_ASCII_MAX; c > 0; c--) {
buf[i--] = (inner_vlan % 10) + '0';
inner_vlan /= 10;
if (inner_vlan == 0) {
break;
}
}

buf[i--] = '.';


/* Convert outer VLAN to ASCII */
for (c = VLAN_ASCII_MAX; c > 0; c--) {
buf[i--] = (outer_vlan % 10) + '0';
outer_vlan /= 10;
if (outer_vlan == 0) {
break;
}
}


buf[i--] = '.';

for (c = IF_NAMESIZE - 1; c >= 0; c--) {

if (dev[c] != 0) {
/* Append interface name */
for (c = RAI_OPTION_LEN - 1; c >= 0; c--) {
if (dev[c] != 0)
buf[i--] = dev[c];
}

if (i < 0) {
break;
}

}

if(sizeof(option.circuit_id.val) == sizeof(buf)) {
memcpy(option.circuit_id.val, buf, sizeof(buf));
if (i < 0)
break;
}

/* Initialize remote ID */
memset(option.remote_id.val, 0, sizeof(option.remote_id.val));
option.remote_id.option_id = RAI_REMOTE_ID;
option.remote_id.len = sizeof(option.remote_id.val);
i++;

/* Copy resulting interface name to circuit_id */
if (sizeof (option.circuit_id.val) == sizeof (buf)) {
memcpy_var(option.circuit_id.val, buf + i, sizeof (buf) - i);
}

return xdp_store_bytes(ctx, offset, &option, sizeof (option), 0);
}

Expand Down Expand Up @@ -166,13 +196,6 @@ static __always_inline int calc_ip_csum(struct iphdr *oldip, struct iphdr *ip,
*/
//static __u8 buf[static_offset + VLAN_MAX_DEPTH * sizeof (struct vlan_hdr)];

#define bpf_printk(fmt, ...) \
({ \
char ____fmt[] = fmt; \
bpf_trace_printk(____fmt, sizeof(____fmt), \
##__VA_ARGS__); \
})

/* XDP program for parsing the DHCP packet and inserting the option 82*/
SEC(XDP_PROG_SEC)
int xdp_dhcp_relay(struct xdp_md *ctx) {
Expand Down

0 comments on commit b7d2d94

Please sign in to comment.