diff --git a/firewall/interception/ebpf/bpf_bpfeb.go b/firewall/interception/ebpf/bpf_bpfeb.go index f7fe5544..be2d6d56 100644 --- a/firewall/interception/ebpf/bpf_bpfeb.go +++ b/firewall/interception/ebpf/bpf_bpfeb.go @@ -21,7 +21,8 @@ type bpfEvent struct { Pid uint32 IpVersion uint8 Protocol uint8 - _ [2]byte + Direction uint8 + _ [1]byte } // loadBpf returns the embedded CollectionSpec for bpf. @@ -65,8 +66,7 @@ type bpfSpecs struct { // // It can be passed ebpf.CollectionSpec.Assign. type bpfProgramSpecs struct { - TcpV4Connect *ebpf.ProgramSpec `ebpf:"tcp_v4_connect"` - TcpV6Connect *ebpf.ProgramSpec `ebpf:"tcp_v6_connect"` + TcpConnect *ebpf.ProgramSpec `ebpf:"tcp_connect"` UdpV4Connect *ebpf.ProgramSpec `ebpf:"udp_v4_connect"` UdpV6Connect *ebpf.ProgramSpec `ebpf:"udp_v6_connect"` } @@ -110,16 +110,14 @@ func (m *bpfMaps) Close() error { // // It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign. type bpfPrograms struct { - TcpV4Connect *ebpf.Program `ebpf:"tcp_v4_connect"` - TcpV6Connect *ebpf.Program `ebpf:"tcp_v6_connect"` + TcpConnect *ebpf.Program `ebpf:"tcp_connect"` UdpV4Connect *ebpf.Program `ebpf:"udp_v4_connect"` UdpV6Connect *ebpf.Program `ebpf:"udp_v6_connect"` } func (p *bpfPrograms) Close() error { return _BpfClose( - p.TcpV4Connect, - p.TcpV6Connect, + p.TcpConnect, p.UdpV4Connect, p.UdpV6Connect, ) diff --git a/firewall/interception/ebpf/bpf_bpfeb.o b/firewall/interception/ebpf/bpf_bpfeb.o index 643b21ba..a2bc593d 100644 Binary files a/firewall/interception/ebpf/bpf_bpfeb.o and b/firewall/interception/ebpf/bpf_bpfeb.o differ diff --git a/firewall/interception/ebpf/bpf_bpfel.go b/firewall/interception/ebpf/bpf_bpfel.go index 9b0acf67..a72d9e29 100644 --- a/firewall/interception/ebpf/bpf_bpfel.go +++ b/firewall/interception/ebpf/bpf_bpfel.go @@ -21,7 +21,8 @@ type bpfEvent struct { Pid uint32 IpVersion uint8 Protocol uint8 - _ [2]byte + Direction uint8 + _ [1]byte } // loadBpf returns the embedded CollectionSpec for bpf. @@ -65,8 +66,7 @@ type bpfSpecs struct { // // It can be passed ebpf.CollectionSpec.Assign. type bpfProgramSpecs struct { - TcpV4Connect *ebpf.ProgramSpec `ebpf:"tcp_v4_connect"` - TcpV6Connect *ebpf.ProgramSpec `ebpf:"tcp_v6_connect"` + TcpConnect *ebpf.ProgramSpec `ebpf:"tcp_connect"` UdpV4Connect *ebpf.ProgramSpec `ebpf:"udp_v4_connect"` UdpV6Connect *ebpf.ProgramSpec `ebpf:"udp_v6_connect"` } @@ -110,16 +110,14 @@ func (m *bpfMaps) Close() error { // // It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign. type bpfPrograms struct { - TcpV4Connect *ebpf.Program `ebpf:"tcp_v4_connect"` - TcpV6Connect *ebpf.Program `ebpf:"tcp_v6_connect"` + TcpConnect *ebpf.Program `ebpf:"tcp_connect"` UdpV4Connect *ebpf.Program `ebpf:"udp_v4_connect"` UdpV6Connect *ebpf.Program `ebpf:"udp_v6_connect"` } func (p *bpfPrograms) Close() error { return _BpfClose( - p.TcpV4Connect, - p.TcpV6Connect, + p.TcpConnect, p.UdpV4Connect, p.UdpV6Connect, ) diff --git a/firewall/interception/ebpf/bpf_bpfel.o b/firewall/interception/ebpf/bpf_bpfel.o index 7f876973..1d5d5449 100644 Binary files a/firewall/interception/ebpf/bpf_bpfel.o and b/firewall/interception/ebpf/bpf_bpfel.o differ diff --git a/firewall/interception/ebpf/program/monitor.c b/firewall/interception/ebpf/program/monitor.c index 341aaa8c..66177495 100644 --- a/firewall/interception/ebpf/program/monitor.c +++ b/firewall/interception/ebpf/program/monitor.c @@ -11,6 +11,9 @@ #define UDP 17 #define UDPLite 136 +#define OUTBOUND 0 +#define INBOUND 1 + char __license[] SEC("license") = "GPL"; // Ring buffer for all connection events @@ -28,24 +31,14 @@ struct Event { u32 pid; u8 ipVersion; u8 protocol; + u8 direction; }; 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; - } - +// 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(&events, sizeof(struct Event), 0); @@ -56,67 +49,32 @@ int BPF_PROG(tcp_v4_connect, struct sock *sk) { // Read PID tcp_info->pid = __builtin_bswap32((u32)bpf_get_current_pid_tgid()); - // Set src and dist ports - tcp_info->sport = sk->__sk_common.skc_num; - tcp_info->dport = sk->__sk_common.skc_dport; - - // 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; - } - - // Make sure its a tcp6 sock - struct tcp6_sock *ts = bpf_skc_to_tcp6_sock(sk); - if (!ts) { - return 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 direction + tcp_info->direction = OUTBOUND; // Set src and dist ports - tcp_info->sport = sk->__sk_common.skc_num; + tcp_info->sport = __builtin_bswap16(sk->__sk_common.skc_num); tcp_info->dport = sk->__sk_common.skc_dport; // 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]); + 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; } - 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; - - // Set protocol - tcp_info->protocol = TCP; // Send event bpf_ringbuf_submit(tcp_info, 0); @@ -143,7 +101,7 @@ int BPF_PROG(udp_v4_connect, struct sock *sk) { udp_info->pid = __builtin_bswap32((u32)bpf_get_current_pid_tgid()); // Set src and dist ports - udp_info->sport = sk->__sk_common.skc_num; + udp_info->sport = __builtin_bswap16(sk->__sk_common.skc_num); udp_info->dport = sk->__sk_common.skc_dport; // Set src and dist IPs @@ -187,7 +145,7 @@ int BPF_PROG(udp_v6_connect, struct sock *sk) { udp_info->pid = __builtin_bswap32((u32)bpf_get_current_pid_tgid()); // Set src and dist ports - udp_info->sport = sk->__sk_common.skc_num; + udp_info->sport = __builtin_bswap16(sk->__sk_common.skc_num); udp_info->dport = sk->__sk_common.skc_dport; // Set src and dist IPs diff --git a/firewall/interception/ebpf/worker.go b/firewall/interception/ebpf/worker.go index b1798315..ecd7eddb 100644 --- a/firewall/interception/ebpf/worker.go +++ b/firewall/interception/ebpf/worker.go @@ -32,23 +32,14 @@ func StartEBPFWorker(ch chan packet.Packet) { } defer objs.Close() - // Create a link to the tcp_v4_connect program. - linkTCPIPv4, err := link.AttachTracing(link.TracingOptions{ - Program: objs.bpfPrograms.TcpV4Connect, + // Create a link to the tcp_connect program. + linkTCPConnect, err := link.AttachTracing(link.TracingOptions{ + Program: objs.bpfPrograms.TcpConnect, }) if err != nil { log.Errorf("ebpf: failed to attach to tcp_v4_connect: %s ", err) } - defer linkTCPIPv4.Close() - - // Create a link to the tcp_v6_connect program. - linkTCPIPv6, err := link.AttachTracing(link.TracingOptions{ - Program: objs.bpfPrograms.TcpV6Connect, - }) - if err != nil { - log.Errorf("ebpf: failed to attach to tcp_v6_connect: %s ", err) - } - defer linkTCPIPv6.Close() + defer linkTCPConnect.Close() // Create a link to the udp_v4_connect program. linkUDPV4, err := link.AttachTracing(link.TracingOptions{ @@ -102,7 +93,7 @@ func StartEBPFWorker(ch chan packet.Packet) { } info := packet.Info{ - Inbound: false, + Inbound: event.Direction == 1, InTunnel: false, Version: packet.IPVersion(event.IpVersion), Protocol: packet.IPProtocol(event.Protocol), @@ -112,11 +103,16 @@ func StartEBPFWorker(ch chan packet.Packet) { Dst: arrayToIP(event.Daddr, packet.IPVersion(event.IpVersion)), PID: event.Pid, } - log.Debugf("ebpf: PID: %d conn: %s:%d -> %s:%d %s %s", info.PID, info.LocalIP(), info.LocalPort(), info.RemoteIP(), info.RemotePort(), info.Version.String(), info.Protocol.String()) + if isEventValid(event) { + log.Debugf("ebpf: PID: %d conn: %s:%d -> %s:%d %s %s", info.PID, info.LocalIP(), info.LocalPort(), info.RemoteIP(), info.RemotePort(), info.Version.String(), info.Protocol.String()) + + p := &infoPacket{} + p.SetPacketInfo(info) + ch <- p + } else { + log.Debugf("ebpf: invalid event PID: %d conn: %s:%d -> %s:%d %s %s", info.PID, info.LocalIP(), info.LocalPort(), info.RemoteIP(), info.RemotePort(), info.Version.String(), info.Protocol.String()) + } - p := &infoPacket{} - p.SetPacketInfo(info) - ch <- p } }() } @@ -125,7 +121,28 @@ func StopEBPFWorker() { close(stopper) } -// arrayToIP converts IPv4 number to net.IP +func isEventValid(event bpfEvent) bool { + if event.Dport == 0 { + return false + } + + if event.Sport == 0 { + return false + } + + if event.IpVersion == 4 { + if event.Saddr[0] == 0 { + return false + } + + if event.Daddr[0] == 0 { + return false + } + } + return true +} + +// arrayToIP converts IP number array to net.IP func arrayToIP(ipNum [4]uint32, ipVersion packet.IPVersion) net.IP { if ipVersion == packet.IPv4 { return unsafe.Slice((*byte)(unsafe.Pointer(&ipNum)), 4)