Skip to content

Commit

Permalink
Add udp process detection with ebpf
Browse files Browse the repository at this point in the history
  • Loading branch information
vlabo committed Jun 7, 2023
1 parent 26042ac commit 0164463
Show file tree
Hide file tree
Showing 6 changed files with 191 additions and 58 deletions.
9 changes: 8 additions & 1 deletion firewall/interception/ebpf/bpf_bpfeb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 8 additions & 1 deletion firewall/interception/ebpf/bpf_bpfel.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 9 additions & 7 deletions firewall/interception/ebpf/packet.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
package ebpf

import (
"fmt"

pmpacket "github.com/safing/portmaster/network/packet"
)

Expand All @@ -13,19 +15,19 @@ type infoPacket struct {

// LoadPacketData does nothing on Linux, as data is always fully parsed.
func (pkt *infoPacket) LoadPacketData() error {
return nil // fmt.Errorf("can't load data info only packet")
return fmt.Errorf("can't load data in info only packet")
}

func (pkt *infoPacket) Accept() error {
return nil // fmt.Errorf("can't accept info only packet")
return nil
}

func (pkt *infoPacket) Block() error {
return nil // fmt.Errorf("can't block info only packet")
return nil
}

func (pkt *infoPacket) Drop() error {
return nil // fmt.Errorf("can't block info only packet")
return nil
}

func (pkt *infoPacket) PermanentAccept() error {
Expand All @@ -37,13 +39,13 @@ func (pkt *infoPacket) PermanentBlock() error {
}

func (pkt *infoPacket) PermanentDrop() error {
return nil // fmt.Errorf("can't drop info only packet")
return nil
}

func (pkt *infoPacket) RerouteToNameserver() error {
return nil // fmt.Errorf("can't reroute info only packet")
return nil
}

func (pkt *infoPacket) RerouteToTunnel() error {
return nil // fmt.Errorf("can't reroute info only packet")
return nil
}
178 changes: 143 additions & 35 deletions firewall/interception/ebpf/program/monitor.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,105 +2,213 @@
#include "bpf/bpf_helpers.h"
#include "bpf/bpf_tracing.h"

typedef unsigned char u8;
typedef short int s16;
typedef short unsigned int u16;
typedef int s32;
typedef unsigned int u32;
typedef long long int s64;
typedef long long unsigned int u64;
typedef u16 le16;
typedef u16 be16;
typedef u32 be32;
typedef u64 be64;
typedef u32 wsum;


// IP Version
#define AF_INET 2
#define AF_INET6 10
#define TASK_COMM_LEN 16

char __license[] SEC("license") = "Dual MIT/GPL";
// Protocols
#define TCP 6
#define UDP 17
#define UDPLite 136

struct
{
char __license[] SEC("license") = "GPL";

// Ring buffer for all connection events
struct {
__uint(type, BPF_MAP_TYPE_RINGBUF);
__uint(max_entries, 1 << 24);
} events SEC(".maps");

/**
* The sample submitted to userspace over a ring buffer.
* Emit struct event's type info into the ELF's BTF so bpf2go
* can generate a Go type from it.
*/
struct event {
be32 saddr[4];
be32 daddr[4];
// Event struct that will be sent to Go on each new connection. (The name should be the same as the go generate command)
struct Event {
u32 saddr[4];
u32 daddr[4];
u16 sport;
u16 dport;
u32 pid;
u8 ipVersion;
u8 protocol;
};
struct event *unused __attribute__((unused));
struct Event *unused __attribute__((unused));

// Fexit of tcp_v4_connect will be executed when equivalent kernel function returns.
// In the kernel function all IPs and ports are set and then tcp_connect is called. tcp_v4_connect -> tcp_connect -> [this-function]
SEC("fexit/tcp_v4_connect")
int BPF_PROG(tcp_v4_connect, struct sock *sk) {
// Ignore everything else then IPv4
if (sk->__sk_common.skc_family != AF_INET) {
return 0;
}

// Make sure it's tcp sock
struct tcp_sock *ts = bpf_skc_to_tcp_sock(sk);
if (!ts) {
return 0;
}

struct event *tcp_info;
tcp_info = bpf_ringbuf_reserve(&events, sizeof(struct event), 0);
// Alloc space for the event
struct Event *tcp_info;
tcp_info = bpf_ringbuf_reserve(&events, sizeof(struct Event), 0);
if (!tcp_info) {
return 0;
}

// Read PID
tcp_info->pid = __builtin_bswap32((u32)bpf_get_current_pid_tgid());

// Set src and dist ports
tcp_info->dport = sk->__sk_common.skc_dport;
tcp_info->sport = sk->__sk_common.skc_num;

// Set src and dist IPs
tcp_info->saddr[0] = __builtin_bswap32(sk->__sk_common.skc_rcv_saddr);
tcp_info->daddr[0] = __builtin_bswap32(sk->__sk_common.skc_daddr);

// Set IP version
tcp_info->ipVersion = 4;

// Set protocol
tcp_info->protocol = TCP;

// Send event
bpf_ringbuf_submit(tcp_info, 0);
return 0;
};

// Fexit(function exit) of tcp_v6_connect will be executed when equivalent kernel function returns.
// In the kernel function all IPs and ports are set and then tcp_connect is called. tcp_v6_connect -> tcp_connect -> [this-function]
SEC("fexit/tcp_v6_connect")
int BPF_PROG(tcp_v6_connect, struct sock *sk) {
// Ignore everything else then IPv6
if (sk->__sk_common.skc_family != AF_INET6) {
return 0;
}

struct tcp_sock *ts = bpf_skc_to_tcp_sock(sk);
// Make sure its a tcp6 sock
struct tcp6_sock *ts = bpf_skc_to_tcp6_sock(sk);
if (!ts) {
return 0;
}

struct event *tcp_info;
tcp_info = bpf_ringbuf_reserve(&events, sizeof(struct event), 0);
// Alloc space for the event
struct Event *tcp_info;
tcp_info = bpf_ringbuf_reserve(&events, sizeof(struct Event), 0);
if (!tcp_info) {
return 0;
}

// Read PID
tcp_info->pid = __builtin_bswap32((u32)bpf_get_current_pid_tgid());

// Set src and dist ports
tcp_info->dport = sk->__sk_common.skc_dport;
tcp_info->sport = sk->__sk_common.skc_num;

// Set src and dist IPs
for(int i = 0; i < 4; i++) {
tcp_info->saddr[i] = __builtin_bswap32(sk->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32[i]);
}
for(int i = 0; i < 4; i++) {
tcp_info->daddr[i] = __builtin_bswap32(sk->__sk_common.skc_v6_daddr.in6_u.u6_addr32[i]);
}
tcp_info->dport = sk->__sk_common.skc_dport;
tcp_info->sport = sk->__sk_common.skc_num;

// Set IP version
tcp_info->ipVersion = 6;

// Set protocol
tcp_info->protocol = TCP;

// Send event
bpf_ringbuf_submit(tcp_info, 0);
return 0;
};

// SEC("fentry/udp_sendmsg")
// Fentry(function enter) of udp_sendmsg will be executed before equivalent kernel function is called.
// [this-function] -> udp_sendmsg
SEC("fentry/udp_sendmsg")
int BPF_PROG(udp_sendmsg, struct sock *sk) {
// Ignore everything else then IPv4
if (sk->__sk_common.skc_family != AF_INET) {
return 0;
}

// Allocate space for the event.
struct Event *udp_info;
udp_info = bpf_ringbuf_reserve(&events, sizeof(struct Event), 0);
if (!udp_info) {
return 0;
}

// Read PID
udp_info->pid = __builtin_bswap32((u32)bpf_get_current_pid_tgid());

// Set src and dist ports
udp_info->dport = sk->__sk_common.skc_dport;
udp_info->sport = sk->__sk_common.skc_num;

// Set src and dist IPs
udp_info->saddr[0] = __builtin_bswap32(sk->__sk_common.skc_rcv_saddr);
udp_info->daddr[0] = __builtin_bswap32(sk->__sk_common.skc_daddr);

// Set IP version
udp_info->ipVersion = 4;

// Set protocol. No way to detect udplite for ipv4
udp_info->protocol = UDP;

// Send event
bpf_ringbuf_submit(udp_info, 0);
return 0;
}

// Fentry(function enter) of udpv6_sendmsg will be executed before equivalent kernel function is called.
// [this-function] -> udpv6_sendmsg
SEC("fentry/udpv6_sendmsg")
int BPF_PROG(udpv6_sendmsg, struct sock *sk) {
// Ignore everything else then IPv6
if (sk->__sk_common.skc_family != AF_INET6) {
return 0;
}

// Make sure its udp6 socket
struct udp6_sock *us = bpf_skc_to_udp6_sock(sk);
if (!us) {
return 0;
}

// Allocate space for the event.
struct Event *udp_info;
udp_info = bpf_ringbuf_reserve(&events, sizeof(struct Event), 0);
if (!udp_info) {
return 0;
}

// Read PID
udp_info->pid = __builtin_bswap32((u32)bpf_get_current_pid_tgid());

// Set src and dist ports
udp_info->dport = sk->__sk_common.skc_dport;
udp_info->sport = sk->__sk_common.skc_num;

// Set src and dist IPs
for(int i = 0; i < 4; i++) {
udp_info->saddr[i] = __builtin_bswap32(sk->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32[i]);
}
for(int i = 0; i < 4; i++) {
udp_info->daddr[i] = __builtin_bswap32(sk->__sk_common.skc_v6_daddr.in6_u.u6_addr32[i]);
}

// IP version
udp_info->ipVersion = 6;

// Set protocol for UDPLite
if(us->udp.pcflag == 0) {
udp_info->protocol = UDP;
} else {
udp_info->protocol = UDPLite;
}

// Send event
bpf_ringbuf_submit(udp_info, 0);
return 0;
}
Loading

0 comments on commit 0164463

Please sign in to comment.