Skip to content

Commit

Permalink
Add sending raw UDP packet for eBPF to process
Browse files Browse the repository at this point in the history
  • Loading branch information
hack3ric committed Mar 27, 2024
1 parent f5931f0 commit 1cbe058
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 9 deletions.
48 changes: 47 additions & 1 deletion src/run.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,27 @@
#include <errno.h>
#include <fcntl.h>
#include <linux/bpf.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/types.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/udp.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/epoll.h>
#include <sys/signalfd.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <unistd.h>

#include "bpf_skel.h"
#include "log.h"
#include "mimic.h"
#include "shared/checksum.h"
#include "shared/conn.h"
#include "shared/filter.h"
#include "shared/gettext.h"
Expand Down Expand Up @@ -162,8 +168,48 @@ static int handle_log_event(void* ctx, void* data, size_t data_sz) {
return 0;
}

static inline int send_packet(struct conn_tuple* c) {
_cleanup_fd int sk = try(socket(c->protocol, SOCK_RAW | SOCK_NONBLOCK, IPPROTO_UDP));
__u32 partial_csum = 0;
struct sockaddr_storage saddr = {}, daddr = {};
if (c->protocol == AF_INET) {
__u32 local = ntohl(c->local.v4), remote = ntohl(c->remote.v4);
*(struct sockaddr_in*)&saddr = (struct sockaddr_in){.sin_family = AF_INET, .sin_addr = local, .sin_port = 0};
*(struct sockaddr_in*)&daddr = (struct sockaddr_in){.sin_family = AF_INET, .sin_addr = remote, .sin_port = 0};
update_csum_ul(&partial_csum, local);
update_csum_ul(&partial_csum, remote);
} else {
*(struct sockaddr_in6*)&saddr =
(struct sockaddr_in6){.sin6_family = AF_INET6, .sin6_addr = c->local.v6, .sin6_port = 0};
*(struct sockaddr_in6*)&daddr =
(struct sockaddr_in6){.sin6_family = AF_INET6, .sin6_addr = c->remote.v6, .sin6_port = 0};
for (int i = 0; i < 8; i++) {
update_csum(&partial_csum, ntohs(c->local.v6.in6_u.u6_addr16[i]));
update_csum(&partial_csum, ntohs(c->remote.v6.in6_u.u6_addr16[i]));
}
}
update_csum(&partial_csum, IPPROTO_UDP);
update_csum(&partial_csum, sizeof(struct udphdr));
try(bind(sk, (struct sockaddr*)&saddr, sizeof(saddr)));

// It is intentional to set length to 0 to get a bogus UDP packet. eBPF egress handler will detect this and treat the
// packet specially.
struct udphdr udp = {
.source = c->local_port,
.dest = c->remote_port,
.len = 0,
.check = htons(~csum_fold(partial_csum)),
};
__u16 csum = calc_csum(&udp, sizeof(udp));
udp.check = htons(csum);

try(sendto(sk, &udp, sizeof(udp), 0, (struct sockaddr*)&daddr, sizeof(daddr)));
return 0;
}

static int handle_send_event(void* ctx, void* data, size_t data_sz) {
// TODO
struct conn_tuple* c = data;
try(send_packet(c), _("error sending packet: %s"), strerror(-_ret));
return 0;
}

Expand Down
31 changes: 23 additions & 8 deletions src/shared/checksum.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#include "../bpf/vmlinux.h"
#else
#include <linux/types.h>
#include <netinet/in.h>
#include <stddef.h>
#endif

static inline __u16 csum_fold(__u32 csum) {
Expand All @@ -29,18 +31,31 @@ static inline void update_csum_ul_neg(__u32* csum, __u32 new) { update_csum(csum
// __u32* csum, __u32 off)`.
//
// void update_csum_data(void* ctx, __u32* csum, __u32 off)
#define update_csum_data(_x, csum, off) \
({ \
__u16* data = (void*)(__u64)_x->data + off; \
int i = 0; \
for (; i < ETH_DATA_LEN / sizeof(__u16); i++) { \
#define update_csum_data(_x, csum, off) \
({ \
__u16* data = (void*)(__u64)_x->data + off; \
int i = 0; \
for (; i < ETH_DATA_LEN / sizeof(__u16); i++) { \
if ((__u64)(data + i + 1) > (__u64)_x->data_end) break; \
*csum += bpf_ntohs(data[i]); \
} \
__u8* remainder = (__u8*)data + i * sizeof(__u16); \
*csum += bpf_ntohs(data[i]); \
} \
__u8* remainder = (__u8*)data + i * sizeof(__u16); \
if ((__u64)(remainder + 1) <= (__u64)_x->data_end) *csum += (__u16)(*remainder << 8); \
})

#else

__u16 calc_csum(void* data, size_t data_len) {
__u32 result = 0;
for (int i = 0; i < data_len / 2; i++) {
result += ntohs(*((__u16*)data + i));
}
if (data_len % 2 == 1) {
result += (__u16)((__u8*)data)[data_len - 1] << 8;
}
return csum_fold(result);
}

#endif // _MIMIC_BPF

#endif // _MIMIC_SHARED_CHECKSUM_H

0 comments on commit 1cbe058

Please sign in to comment.