Skip to content

Commit 56b2d28

Browse files
ebpf: added support for ipv6 tunnels
In order to intercept UDP tunnels traffic, we use iptunnel_xmit for IPv4 connections. The equivalent of IPv6 would be ip6tunnel_xmit, but unfortunately it's not public. So instead of ip6tunnel_xmit, we'll use udp_tunnel6_xmit_skb. This function receives two parameters besides the struct sock*, in6_addr *saddr and in6_addr *daddr. If these addresses are not set, usually the connection is a localhost connection. On the other hand, this function is defined in the module ip6_udp_tunnel. If this module is not loaded when the daemon starts, we'll fail to intercept the connections. Closes: #1250
1 parent 02da9b7 commit 56b2d28

File tree

3 files changed

+87
-0
lines changed

3 files changed

+87
-0
lines changed

daemon/procmon/ebpf/ebpf.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ type KProbeDefs struct {
3030
KProbeIPtunnelXmit *ebpf.Program `ebpf:"kprobe__iptunnel_xmit"`
3131
KProbeInetDgramConnect *ebpf.Program `ebpf:"kprobe__inet_dgram_connect"`
3232
KretProbeInetDgramConnect *ebpf.Program `ebpf:"kretprobe__inet_dgram_connect"`
33+
34+
KProbeUDPtunnel6Xmit *ebpf.Program `ebpf:"kprobe__udp_tunnel6_xmit_skb"`
3335
}
3436

3537
// MapDefs holds the map definitions of the main module
@@ -187,6 +189,11 @@ func Start(ebpfOpts Config) *Error {
187189
log.Error("opening kretprobe: %s", err)
188190
}
189191
hooks = append(hooks, kp)
192+
kp, err = link.Kprobe("udp_tunnel6_xmit_skb", ebpfMod.KProbeUDPtunnel6Xmit, nil)
193+
if err != nil {
194+
log.Error("opening kprobe: %s", err)
195+
}
196+
hooks = append(hooks, kp)
190197

191198
ebpfMaps = map[string]*ebpfMapsForProto{
192199
"tcp": {bpfMap: ebpfMod.TCPMap},

ebpf_prog/common_defs.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#include <linux/sched.h>
55
#include <linux/ptrace.h>
6+
#include <linux/byteorder/generic.h>
67
#include <uapi/linux/bpf.h>
78
#include "bpf_headers/bpf_helpers.h"
89
#include "bpf_headers/bpf_tracing.h"
@@ -11,6 +12,10 @@
1112
#define BUF_SIZE_MAP_NS 256
1213
#define MAPSIZE 12000
1314

15+
#ifndef htonll
16+
#define htonll(x) cpu_to_be64(x)
17+
#endif
18+
1419
#define debug(fmt, ...) \
1520
( \
1621
{ \

ebpf_prog/opensnitch.c

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,81 @@ int kprobe__udpv6_sendmsg(struct pt_regs *ctx)
342342
return 0;
343343
};
344344

345+
SEC("kprobe/udp_tunnel6_xmit_skb")
346+
int kprobe__udp_tunnel6_xmit_skb(struct pt_regs *ctx)
347+
{
348+
#if defined(__x86_64__)
349+
struct sock *sk = (struct sock *)PT_REGS_PARM2(ctx);
350+
struct in6_addr *saddr = (struct in6_addr *)PT_REGS_PARM5(ctx);
351+
// 6th
352+
struct in6_addr *daddr = (struct in6_addr *)(ctx->r9);
353+
// 10th
354+
void *sport_ptr = (void *)(ctx->sp + 32);
355+
// 11th
356+
void *dport_ptr = (void *)(ctx->sp + 40);
357+
358+
struct udpv6_key_t udpv6_key, udpv6_key2;
359+
__builtin_memset(&udpv6_key, 0, sizeof(udpv6_key));
360+
__builtin_memset(&udpv6_key2, 0, sizeof(udpv6_key2));
361+
u16 dport = 0, sport = 0;
362+
363+
bpf_probe_read(&sport, sizeof(sport), (void *)sport_ptr);
364+
bpf_probe_read(&dport, sizeof(dport), (void *)dport_ptr);
365+
if (dport == 0 || sport == 0){
366+
return 0;
367+
}
368+
369+
udpv6_key.dport = dport;
370+
udpv6_key.sport = (sport >> 8) | ((sport << 8) & 0xff00);
371+
udpv6_key2.sport = udpv6_key.sport;
372+
udpv6_key2.dport = udpv6_key.dport;
373+
374+
// tunnel addrs
375+
bpf_probe_read(&udpv6_key.saddr, sizeof(udpv6_key.saddr), &saddr->in6_u.u6_addr32);
376+
bpf_probe_read(&udpv6_key.daddr, sizeof(udpv6_key.daddr), &daddr->in6_u.u6_addr32);
377+
378+
//bpf_probe_read(&udpv6_key.dport, sizeof(udpv6_key.dport), &sk->__sk_common.skc_dport);
379+
//bpf_probe_read(&udpv6_key.sport, sizeof(udpv6_key.sport), &sk->__sk_common.skc_num);
380+
381+
// internet addrs
382+
bpf_probe_read(&udpv6_key2.daddr, sizeof(udpv6_key2.daddr), &sk->__sk_common.skc_v6_daddr.in6_u.u6_addr32);
383+
bpf_probe_read(&udpv6_key2.saddr, sizeof(udpv6_key2.saddr), &sk->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32);
384+
385+
u64 pid_tgid = bpf_get_current_pid_tgid();
386+
u64 pid = pid_tgid >> 32;
387+
struct udpv6_value_t udpv6_value={0};
388+
__builtin_memset(&udpv6_value, 0, sizeof(udpv6_value));
389+
bpf_get_current_comm(&udpv6_value.comm, sizeof(udpv6_value.comm));
390+
udpv6_value.pid = pid;
391+
udpv6_value.uid = bpf_get_current_uid_gid() & 0xffffffff;
392+
393+
struct udpv6_value_t *lookedupValue = bpf_map_lookup_elem(&udpv6Map, &udpv6_key2);
394+
if (lookedupValue == NULL || lookedupValue->pid != pid) {
395+
bpf_map_update_elem(&udpv6Map, &udpv6_key2, &udpv6_value, BPF_ANY);
396+
}
397+
398+
lookedupValue = bpf_map_lookup_elem(&udpv6Map, &udpv6_key);
399+
if (lookedupValue == NULL || lookedupValue->pid != pid) {
400+
bpf_map_update_elem(&udpv6Map, &udpv6_key, &udpv6_value, BPF_ANY);
401+
}
402+
403+
// when saddr and daddr are empty, usually the connection is from-to localhost.
404+
if (saddr == 0 && daddr == 0){
405+
udpv6_key.saddr.part1 = 0;
406+
udpv6_key.saddr.part2 = htonll(1);
407+
udpv6_key.daddr.part1 = 0;
408+
udpv6_key.daddr.part2 = htonll(1);
409+
bpf_map_update_elem(&udpv6Map, &udpv6_key, &udpv6_value, BPF_ANY);
410+
}
411+
412+
#endif
413+
414+
// TODO: other architectures
415+
416+
return 0;
417+
};
418+
419+
345420
SEC("kprobe/inet_dgram_connect")
346421
int kprobe__inet_dgram_connect(struct pt_regs *ctx)
347422
{

0 commit comments

Comments
 (0)