mirror of
https://github.com/safing/portmaster
synced 2025-04-23 04:19:10 +00:00
186 lines
No EOL
4.9 KiB
C
186 lines
No EOL
4.9 KiB
C
#include "vmlinux-x86.h"
|
|
#include "bpf/bpf_helpers.h"
|
|
#include "bpf/bpf_tracing.h"
|
|
|
|
// IP Version
|
|
#define AF_INET 2
|
|
#define AF_INET6 10
|
|
|
|
// Protocols
|
|
#define TCP 6
|
|
#define UDP 17
|
|
#define UDPLite 136
|
|
|
|
#define OUTBOUND 0
|
|
#define INBOUND 1
|
|
|
|
char __license[] SEC("license") = "GPL";
|
|
|
|
// Ring buffer for all connection events
|
|
struct {
|
|
__uint(type, BPF_MAP_TYPE_RINGBUF);
|
|
__uint(max_entries, 1 << 24);
|
|
} pm_connection_events SEC(".maps");
|
|
|
|
// 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;
|
|
u8 direction;
|
|
};
|
|
struct Event *unused __attribute__((unused));
|
|
|
|
// Fentry of tcp_connect will be executed when equivalent kernel function is called.
|
|
// In the kernel all IP address and ports should be set before tcp_connect is called. [this-function] -> tcp_connect
|
|
SEC("fentry/tcp_connect")
|
|
int BPF_PROG(tcp_connect, struct sock *sk) {
|
|
// Alloc space for the event
|
|
struct Event *tcp_info;
|
|
tcp_info = bpf_ringbuf_reserve(&pm_connection_events, sizeof(struct Event), 0);
|
|
if (!tcp_info) {
|
|
return 0;
|
|
}
|
|
|
|
// Read PID (Careful: This is the Thread Group ID in kernel speak!)
|
|
tcp_info->pid = __builtin_bswap32((u32)(bpf_get_current_pid_tgid() >> 32));
|
|
|
|
// Set protocol
|
|
tcp_info->protocol = TCP;
|
|
|
|
// Set direction
|
|
tcp_info->direction = OUTBOUND;
|
|
|
|
// Set src and dist ports
|
|
tcp_info->sport = __builtin_bswap16(sk->__sk_common.skc_num);
|
|
tcp_info->dport = sk->__sk_common.skc_dport;
|
|
|
|
// Set src and dist IPs
|
|
if (sk->__sk_common.skc_family == AF_INET) {
|
|
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;
|
|
} else if (sk->__sk_common.skc_family == AF_INET6) {
|
|
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]);
|
|
}
|
|
// Set IP version
|
|
tcp_info->ipVersion = 6;
|
|
}
|
|
|
|
// Send event
|
|
bpf_ringbuf_submit(tcp_info, 0);
|
|
return 0;
|
|
};
|
|
|
|
// Fexit(function exit) of udp_v4_connect will be executed after the ip4_datagram_connect kernel function is called.
|
|
// ip4_datagram_connect -> udp_v4_connect
|
|
SEC("fexit/ip4_datagram_connect")
|
|
int BPF_PROG(udp_v4_connect, struct sock *sk) {
|
|
// Ignore everything else then IPv4
|
|
if (sk->__sk_common.skc_family != AF_INET) {
|
|
return 0;
|
|
}
|
|
|
|
// ip4_datagram_connect return error
|
|
if (sk->__sk_common.skc_dport == 0) {
|
|
return 0;
|
|
}
|
|
|
|
// Allocate space for the event.
|
|
struct Event *udp_info;
|
|
udp_info = bpf_ringbuf_reserve(&pm_connection_events, sizeof(struct Event), 0);
|
|
if (!udp_info) {
|
|
return 0;
|
|
}
|
|
|
|
// Read PID (Careful: This is the Thread Group ID in kernel speak!)
|
|
udp_info->pid = __builtin_bswap32((u32)(bpf_get_current_pid_tgid() >> 32));
|
|
|
|
// Set src and dst ports
|
|
udp_info->sport = __builtin_bswap16(sk->__sk_common.skc_num);
|
|
udp_info->dport = sk->__sk_common.skc_dport;
|
|
|
|
// Set src and dst 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
|
|
if(sk->sk_protocol == IPPROTO_UDPLITE) {
|
|
udp_info->protocol = UDPLite;
|
|
} else {
|
|
udp_info->protocol = UDP;
|
|
}
|
|
|
|
// Send event
|
|
bpf_ringbuf_submit(udp_info, 0);
|
|
return 0;
|
|
}
|
|
|
|
// Fentry(function enter) of udp_v6_connect will be executed after the ip6_datagram_connect kernel function is called.
|
|
// ip6_datagram_connect -> udp_v6_connect
|
|
SEC("fexit/ip6_datagram_connect")
|
|
int BPF_PROG(udp_v6_connect, struct sock *sk) {
|
|
// Ignore everything else then IPv6
|
|
if (sk->__sk_common.skc_family != AF_INET6) {
|
|
return 0;
|
|
}
|
|
|
|
// ip6_datagram_connect return error
|
|
if (sk->__sk_common.skc_dport == 0) {
|
|
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(&pm_connection_events, sizeof(struct Event), 0);
|
|
if (!udp_info) {
|
|
return 0;
|
|
}
|
|
|
|
// Read PID (Careful: This is the Thread Group ID in kernel speak!)
|
|
udp_info->pid = __builtin_bswap32((u32)(bpf_get_current_pid_tgid() >> 32));
|
|
|
|
// Set src and dst ports
|
|
udp_info->sport = __builtin_bswap16(sk->__sk_common.skc_num);
|
|
udp_info->dport = sk->__sk_common.skc_dport;
|
|
|
|
// Set src and dst 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
|
|
if(sk->sk_protocol == IPPROTO_UDPLITE) {
|
|
udp_info->protocol = UDPLite;
|
|
} else {
|
|
udp_info->protocol = UDP;
|
|
}
|
|
|
|
// Send event
|
|
bpf_ringbuf_submit(udp_info, 0);
|
|
return 0;
|
|
} |