Fix ebpf source port, add event validation and simpify tcp monitoring
This commit is contained in:
@@ -21,7 +21,8 @@ type bpfEvent struct {
|
|||||||
Pid uint32
|
Pid uint32
|
||||||
IpVersion uint8
|
IpVersion uint8
|
||||||
Protocol uint8
|
Protocol uint8
|
||||||
_ [2]byte
|
Direction uint8
|
||||||
|
_ [1]byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// loadBpf returns the embedded CollectionSpec for bpf.
|
// loadBpf returns the embedded CollectionSpec for bpf.
|
||||||
@@ -65,8 +66,7 @@ type bpfSpecs struct {
|
|||||||
//
|
//
|
||||||
// It can be passed ebpf.CollectionSpec.Assign.
|
// It can be passed ebpf.CollectionSpec.Assign.
|
||||||
type bpfProgramSpecs struct {
|
type bpfProgramSpecs struct {
|
||||||
TcpV4Connect *ebpf.ProgramSpec `ebpf:"tcp_v4_connect"`
|
TcpConnect *ebpf.ProgramSpec `ebpf:"tcp_connect"`
|
||||||
TcpV6Connect *ebpf.ProgramSpec `ebpf:"tcp_v6_connect"`
|
|
||||||
UdpV4Connect *ebpf.ProgramSpec `ebpf:"udp_v4_connect"`
|
UdpV4Connect *ebpf.ProgramSpec `ebpf:"udp_v4_connect"`
|
||||||
UdpV6Connect *ebpf.ProgramSpec `ebpf:"udp_v6_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.
|
// It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign.
|
||||||
type bpfPrograms struct {
|
type bpfPrograms struct {
|
||||||
TcpV4Connect *ebpf.Program `ebpf:"tcp_v4_connect"`
|
TcpConnect *ebpf.Program `ebpf:"tcp_connect"`
|
||||||
TcpV6Connect *ebpf.Program `ebpf:"tcp_v6_connect"`
|
|
||||||
UdpV4Connect *ebpf.Program `ebpf:"udp_v4_connect"`
|
UdpV4Connect *ebpf.Program `ebpf:"udp_v4_connect"`
|
||||||
UdpV6Connect *ebpf.Program `ebpf:"udp_v6_connect"`
|
UdpV6Connect *ebpf.Program `ebpf:"udp_v6_connect"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *bpfPrograms) Close() error {
|
func (p *bpfPrograms) Close() error {
|
||||||
return _BpfClose(
|
return _BpfClose(
|
||||||
p.TcpV4Connect,
|
p.TcpConnect,
|
||||||
p.TcpV6Connect,
|
|
||||||
p.UdpV4Connect,
|
p.UdpV4Connect,
|
||||||
p.UdpV6Connect,
|
p.UdpV6Connect,
|
||||||
)
|
)
|
||||||
|
|||||||
Binary file not shown.
@@ -21,7 +21,8 @@ type bpfEvent struct {
|
|||||||
Pid uint32
|
Pid uint32
|
||||||
IpVersion uint8
|
IpVersion uint8
|
||||||
Protocol uint8
|
Protocol uint8
|
||||||
_ [2]byte
|
Direction uint8
|
||||||
|
_ [1]byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// loadBpf returns the embedded CollectionSpec for bpf.
|
// loadBpf returns the embedded CollectionSpec for bpf.
|
||||||
@@ -65,8 +66,7 @@ type bpfSpecs struct {
|
|||||||
//
|
//
|
||||||
// It can be passed ebpf.CollectionSpec.Assign.
|
// It can be passed ebpf.CollectionSpec.Assign.
|
||||||
type bpfProgramSpecs struct {
|
type bpfProgramSpecs struct {
|
||||||
TcpV4Connect *ebpf.ProgramSpec `ebpf:"tcp_v4_connect"`
|
TcpConnect *ebpf.ProgramSpec `ebpf:"tcp_connect"`
|
||||||
TcpV6Connect *ebpf.ProgramSpec `ebpf:"tcp_v6_connect"`
|
|
||||||
UdpV4Connect *ebpf.ProgramSpec `ebpf:"udp_v4_connect"`
|
UdpV4Connect *ebpf.ProgramSpec `ebpf:"udp_v4_connect"`
|
||||||
UdpV6Connect *ebpf.ProgramSpec `ebpf:"udp_v6_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.
|
// It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign.
|
||||||
type bpfPrograms struct {
|
type bpfPrograms struct {
|
||||||
TcpV4Connect *ebpf.Program `ebpf:"tcp_v4_connect"`
|
TcpConnect *ebpf.Program `ebpf:"tcp_connect"`
|
||||||
TcpV6Connect *ebpf.Program `ebpf:"tcp_v6_connect"`
|
|
||||||
UdpV4Connect *ebpf.Program `ebpf:"udp_v4_connect"`
|
UdpV4Connect *ebpf.Program `ebpf:"udp_v4_connect"`
|
||||||
UdpV6Connect *ebpf.Program `ebpf:"udp_v6_connect"`
|
UdpV6Connect *ebpf.Program `ebpf:"udp_v6_connect"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *bpfPrograms) Close() error {
|
func (p *bpfPrograms) Close() error {
|
||||||
return _BpfClose(
|
return _BpfClose(
|
||||||
p.TcpV4Connect,
|
p.TcpConnect,
|
||||||
p.TcpV6Connect,
|
|
||||||
p.UdpV4Connect,
|
p.UdpV4Connect,
|
||||||
p.UdpV6Connect,
|
p.UdpV6Connect,
|
||||||
)
|
)
|
||||||
|
|||||||
Binary file not shown.
@@ -11,6 +11,9 @@
|
|||||||
#define UDP 17
|
#define UDP 17
|
||||||
#define UDPLite 136
|
#define UDPLite 136
|
||||||
|
|
||||||
|
#define OUTBOUND 0
|
||||||
|
#define INBOUND 1
|
||||||
|
|
||||||
char __license[] SEC("license") = "GPL";
|
char __license[] SEC("license") = "GPL";
|
||||||
|
|
||||||
// Ring buffer for all connection events
|
// Ring buffer for all connection events
|
||||||
@@ -28,24 +31,14 @@ struct Event {
|
|||||||
u32 pid;
|
u32 pid;
|
||||||
u8 ipVersion;
|
u8 ipVersion;
|
||||||
u8 protocol;
|
u8 protocol;
|
||||||
|
u8 direction;
|
||||||
};
|
};
|
||||||
struct Event *unused __attribute__((unused));
|
struct Event *unused __attribute__((unused));
|
||||||
|
|
||||||
// Fexit of tcp_v4_connect will be executed when equivalent kernel function returns.
|
// Fentry of tcp_connect will be executed when equivalent kernel function is called.
|
||||||
// In the kernel function all IPs and ports are set and then tcp_connect is called. tcp_v4_connect -> tcp_connect -> [this-function]
|
// In the kernel all IP address and ports should be set before tcp_connect is called. [this-function] -> tcp_connect
|
||||||
SEC("fexit/tcp_v4_connect")
|
SEC("fentry/tcp_connect")
|
||||||
int BPF_PROG(tcp_v4_connect, struct sock *sk) {
|
int BPF_PROG(tcp_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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Alloc space for the event
|
// Alloc space for the event
|
||||||
struct Event *tcp_info;
|
struct Event *tcp_info;
|
||||||
tcp_info = bpf_ringbuf_reserve(&events, sizeof(struct Event), 0);
|
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
|
// Read PID
|
||||||
tcp_info->pid = __builtin_bswap32((u32)bpf_get_current_pid_tgid());
|
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
|
// Set protocol
|
||||||
tcp_info->protocol = TCP;
|
tcp_info->protocol = TCP;
|
||||||
|
|
||||||
// Send event
|
// Set direction
|
||||||
bpf_ringbuf_submit(tcp_info, 0);
|
tcp_info->direction = OUTBOUND;
|
||||||
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 src and dist ports
|
// 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;
|
tcp_info->dport = sk->__sk_common.skc_dport;
|
||||||
|
|
||||||
// Set src and dist IPs
|
// Set src and dist IPs
|
||||||
for(int i = 0; i < 4; i++) {
|
if (sk->__sk_common.skc_family == AF_INET) {
|
||||||
tcp_info->saddr[i] = __builtin_bswap32(sk->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32[i]);
|
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
|
// Send event
|
||||||
bpf_ringbuf_submit(tcp_info, 0);
|
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());
|
udp_info->pid = __builtin_bswap32((u32)bpf_get_current_pid_tgid());
|
||||||
|
|
||||||
// Set src and dist ports
|
// 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;
|
udp_info->dport = sk->__sk_common.skc_dport;
|
||||||
|
|
||||||
// Set src and dist IPs
|
// 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());
|
udp_info->pid = __builtin_bswap32((u32)bpf_get_current_pid_tgid());
|
||||||
|
|
||||||
// Set src and dist ports
|
// 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;
|
udp_info->dport = sk->__sk_common.skc_dport;
|
||||||
|
|
||||||
// Set src and dist IPs
|
// Set src and dist IPs
|
||||||
|
|||||||
@@ -32,23 +32,14 @@ func StartEBPFWorker(ch chan packet.Packet) {
|
|||||||
}
|
}
|
||||||
defer objs.Close()
|
defer objs.Close()
|
||||||
|
|
||||||
// Create a link to the tcp_v4_connect program.
|
// Create a link to the tcp_connect program.
|
||||||
linkTCPIPv4, err := link.AttachTracing(link.TracingOptions{
|
linkTCPConnect, err := link.AttachTracing(link.TracingOptions{
|
||||||
Program: objs.bpfPrograms.TcpV4Connect,
|
Program: objs.bpfPrograms.TcpConnect,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("ebpf: failed to attach to tcp_v4_connect: %s ", err)
|
log.Errorf("ebpf: failed to attach to tcp_v4_connect: %s ", err)
|
||||||
}
|
}
|
||||||
defer linkTCPIPv4.Close()
|
defer linkTCPConnect.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()
|
|
||||||
|
|
||||||
// Create a link to the udp_v4_connect program.
|
// Create a link to the udp_v4_connect program.
|
||||||
linkUDPV4, err := link.AttachTracing(link.TracingOptions{
|
linkUDPV4, err := link.AttachTracing(link.TracingOptions{
|
||||||
@@ -102,7 +93,7 @@ func StartEBPFWorker(ch chan packet.Packet) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
info := packet.Info{
|
info := packet.Info{
|
||||||
Inbound: false,
|
Inbound: event.Direction == 1,
|
||||||
InTunnel: false,
|
InTunnel: false,
|
||||||
Version: packet.IPVersion(event.IpVersion),
|
Version: packet.IPVersion(event.IpVersion),
|
||||||
Protocol: packet.IPProtocol(event.Protocol),
|
Protocol: packet.IPProtocol(event.Protocol),
|
||||||
@@ -112,11 +103,16 @@ func StartEBPFWorker(ch chan packet.Packet) {
|
|||||||
Dst: arrayToIP(event.Daddr, packet.IPVersion(event.IpVersion)),
|
Dst: arrayToIP(event.Daddr, packet.IPVersion(event.IpVersion)),
|
||||||
PID: event.Pid,
|
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)
|
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 {
|
func arrayToIP(ipNum [4]uint32, ipVersion packet.IPVersion) net.IP {
|
||||||
if ipVersion == packet.IPv4 {
|
if ipVersion == packet.IPv4 {
|
||||||
return unsafe.Slice((*byte)(unsafe.Pointer(&ipNum)), 4)
|
return unsafe.Slice((*byte)(unsafe.Pointer(&ipNum)), 4)
|
||||||
|
|||||||
Reference in New Issue
Block a user