mirror of
https://github.com/netbirdio/netbird.git
synced 2024-11-24 00:54:01 +01:00
b0364da67c
EBPF proxy between TURN (relay) and WireGuard to reduce number of used ports used by the NetBird agent. - Separate the wg configuration from the proxy logic - In case if eBPF type proxy has only one single proxy instance - In case if the eBPF is not supported fallback to the original proxy Implementation Between the signature of eBPF type proxy and original proxy has differences so this is why the factory structure exists
90 lines
2.3 KiB
C
90 lines
2.3 KiB
C
#include <stdbool.h>
|
|
#include <linux/if_ether.h> // ETH_P_IP
|
|
#include <linux/udp.h>
|
|
#include <linux/ip.h>
|
|
#include <netinet/in.h>
|
|
#include <linux/bpf.h>
|
|
#include <bpf/bpf_helpers.h>
|
|
|
|
#define bpf_printk(fmt, ...) \
|
|
({ \
|
|
char ____fmt[] = fmt; \
|
|
bpf_trace_printk(____fmt, sizeof(____fmt), ##__VA_ARGS__); \
|
|
})
|
|
|
|
const __u32 map_key_proxy_port = 0;
|
|
const __u32 map_key_wg_port = 1;
|
|
|
|
struct bpf_map_def SEC("maps") xdp_port_map = {
|
|
.type = BPF_MAP_TYPE_ARRAY,
|
|
.key_size = sizeof(__u32),
|
|
.value_size = sizeof(__u16),
|
|
.max_entries = 10,
|
|
};
|
|
|
|
__u16 proxy_port = 0;
|
|
__u16 wg_port = 0;
|
|
|
|
bool read_port_settings() {
|
|
__u16 *value;
|
|
value = bpf_map_lookup_elem(&xdp_port_map, &map_key_proxy_port);
|
|
if(!value) {
|
|
return false;
|
|
}
|
|
|
|
proxy_port = *value;
|
|
|
|
value = bpf_map_lookup_elem(&xdp_port_map, &map_key_wg_port);
|
|
if(!value) {
|
|
return false;
|
|
}
|
|
wg_port = *value;
|
|
|
|
return true;
|
|
}
|
|
|
|
SEC("xdp")
|
|
int xdp_prog_func(struct xdp_md *ctx) {
|
|
if(proxy_port == 0 || wg_port == 0) {
|
|
if(!read_port_settings()){
|
|
return XDP_PASS;
|
|
}
|
|
bpf_printk("proxy port: %d, wg port: %d", proxy_port, wg_port);
|
|
}
|
|
|
|
void *data = (void *)(long)ctx->data;
|
|
void *data_end = (void *)(long)ctx->data_end;
|
|
struct ethhdr *eth = data;
|
|
struct iphdr *ip = (data + sizeof(struct ethhdr));
|
|
struct udphdr *udp = (data + sizeof(struct ethhdr) + sizeof(struct iphdr));
|
|
|
|
// return early if not enough data
|
|
if (data + sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr) > data_end){
|
|
return XDP_PASS;
|
|
}
|
|
|
|
// skip non IPv4 packages
|
|
if (eth->h_proto != htons(ETH_P_IP)) {
|
|
return XDP_PASS;
|
|
}
|
|
|
|
if (ip->protocol != IPPROTO_UDP) {
|
|
return XDP_PASS;
|
|
}
|
|
|
|
// 2130706433 = 127.0.0.1
|
|
if (ip->daddr != htonl(2130706433)) {
|
|
return XDP_PASS;
|
|
}
|
|
|
|
if (udp->source != htons(wg_port)){
|
|
return XDP_PASS;
|
|
}
|
|
|
|
__be16 new_src_port = udp->dest;
|
|
__be16 new_dst_port = htons(proxy_port);
|
|
udp->dest = new_dst_port;
|
|
udp->source = new_src_port;
|
|
return XDP_PASS;
|
|
}
|
|
char _license[] SEC("license") = "GPL"; |