Skip to content

Commit

Permalink
Merge pull request #2 from mrtc0/IPv6_support
Browse files Browse the repository at this point in the history
IPv6 support
  • Loading branch information
mrtc0 authored Feb 21, 2022
2 parents ffa2f34 + b0fd285 commit 87295bf
Show file tree
Hide file tree
Showing 17 changed files with 540 additions and 89 deletions.
3 changes: 3 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
BasedOnStyle: LLVM
IndentWidth: 2
AllowShortEnumsOnASingleLine: false
11 changes: 11 additions & 0 deletions Vagrantfile
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,16 @@ Vagrant.configure("2") do |config|
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
apt-get update
apt-get install -y docker-ce docker-ce-cli containerd.io
# Setup IPv6
cat <<EOF >/etc/docker/daemon.json
{
"ipv6": true,
"fixed-cidr-v6": "fc00:deed:beef::/24"
}
EOF
systemctl restart docker
curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
SHELL
end
18 changes: 9 additions & 9 deletions cmd/bouheki/bouheki.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
package main

import (
"os"
"os"

"github.com/mrtc0/bouheki/pkg/commands"
log "github.com/sirupsen/logrus"
"github.com/mrtc0/bouheki/pkg/commands"
log "github.com/sirupsen/logrus"
)

var (
version = "dev"
version = "dev"
)

func main() {
app := commands.NewApp(version)
err := app.Run(os.Args)
if err != nil {
log.Fatal(err)
}
app := commands.NewApp(version)
err := app.Run(os.Args)
if err != nil {
log.Fatal(err)
}
}
40 changes: 35 additions & 5 deletions pkg/bpf/c/common.h
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
#include <linux/errno.h>
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_core_read.h>
#include <bpf/bpf_tracing.h>

#define ALLOW_ACCESS 0
#define AF_INET 2
#define AF_INET6 10
#define AUDIT_EVENTS_RING_SIZE (4 * 4096)
#define TASK_COMM_LEN 16
#define NEW_UTS_LEN 64
Expand Down Expand Up @@ -50,10 +50,9 @@ enum action
ACTION_BLOCK
};

enum audit_event_type
{
enum audit_event_type {
BLOCKED_IPV4,
BLOCKED_IPV6 // Not implemented yet.
BLOCKED_IPV6
};

struct audit_event_header
Expand All @@ -77,6 +76,17 @@ struct audit_event_ipv4
u8 sock_type;
};

struct audit_event_ipv6
{
struct audit_event_header hdr;
struct in6_addr src;
struct in6_addr dst;
u16 dport;
u8 operation;
u8 action;
u8 sock_type;
};

struct bouheki_config
{
enum mode mode;
Expand All @@ -91,6 +101,17 @@ struct ipv4_trie_key
struct in_addr addr;
};

struct ipv6_trie_key
{
u32 prefixlen;
struct in6_addr addr;
};

union ip_trie_key {
struct ipv4_trie_key v4;
struct ipv6_trie_key v6;
};

struct allowed_command_key
{
char comm[TASK_COMM_LEN];
Expand Down Expand Up @@ -130,6 +151,15 @@ static inline struct in_addr src_addr4(const struct socket *sock)
return addr;
}

static inline struct in6_addr src_addr6(const struct socket *sock)
{
struct in6_addr addr;
__builtin_memset(&addr, 0, sizeof(addr));

addr = BPF_CORE_READ(sock, sk, __sk_common.skc_v6_rcv_saddr);
return addr;
}

static inline int _is_host_mntns()
{
struct task_struct *current_task;
Expand All @@ -153,4 +183,4 @@ static inline int _is_host_mntns()
static inline int is_container()
{
return !_is_host_mntns();
}
}
126 changes: 103 additions & 23 deletions pkg/bpf/c/restricted-network.bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,16 @@ struct
__type(key, struct ipv4_trie_key);
__type(value, char);
__uint(map_flags, BPF_F_NO_PREALLOC);
} denied_cidr_list SEC(".maps");
} denied_v4_cidr_list SEC(".maps");

struct
{
__uint(type, BPF_MAP_TYPE_LPM_TRIE);
__uint(max_entries, 256);
__type(key, struct ipv6_trie_key);
__type(value, char);
__uint(map_flags, BPF_F_NO_PREALLOC);
} denied_v6_cidr_list SEC(".maps");

struct
{
Expand All @@ -35,7 +44,16 @@ struct
__type(key, struct ipv4_trie_key);
__type(value, char);
__uint(map_flags, BPF_F_NO_PREALLOC);
} allowed_cidr_list SEC(".maps");
} allowed_v4_cidr_list SEC(".maps");

struct
{
__uint(type, BPF_MAP_TYPE_LPM_TRIE);
__uint(max_entries, 256);
__type(key, struct ipv6_trie_key);
__type(value, char);
__uint(map_flags, BPF_F_NO_PREALLOC);
} allowed_v6_cidr_list SEC(".maps");

static inline void report_ipv4_event(void *ctx, u64 cg, enum action action, enum lsm_hook_point point, struct socket *sock, const struct sockaddr_in *daddr)
{
Expand Down Expand Up @@ -70,13 +88,51 @@ static inline void report_ipv4_event(void *ctx, u64 cg, enum action action, enum
bpf_ringbuf_output(&audit_events, &ev, sizeof(ev), 0);
}

static inline void report_ipv6_event(void *ctx, u64 cg, enum action action, enum lsm_hook_point point, struct socket *sock, const struct sockaddr_in6 *daddr)
{
struct audit_event_ipv6 ev;

struct task_struct *current_task;
struct uts_namespace *uts_ns;
struct nsproxy *nsproxy;
current_task = (struct task_struct *)bpf_get_current_task();

bpf_core_read(&nsproxy, sizeof(nsproxy), &current_task->nsproxy);
bpf_core_read(&uts_ns, sizeof(uts_ns), &nsproxy->uts_ns);

__builtin_memset(&ev, 0, sizeof(ev));
bpf_core_read(&ev.hdr.nodename, sizeof(ev.hdr.nodename), &uts_ns->name.nodename);

ev.hdr.cgroup = cg;
ev.hdr.pid = (u32)(bpf_get_current_pid_tgid() >> 32);
ev.hdr.type = BLOCKED_IPV6;
bpf_get_current_comm(&ev.hdr.task, sizeof(ev.hdr.task));

struct task_struct *parent_task = BPF_CORE_READ(current_task, real_parent);
bpf_probe_read_kernel_str(&ev.hdr.parent_task, sizeof(ev.hdr.parent_task), &parent_task->comm);

ev.dport = __builtin_bswap16(daddr->sin6_port);
ev.src = src_addr6(sock);
ev.dst = BPF_CORE_READ(daddr, sin6_addr);
ev.operation = (u8)point;
ev.action = (u8)action;
ev.sock_type = (u8)sock->type;

bpf_ringbuf_output(&audit_events, &ev, sizeof(ev), 0);
}


// In some cases, such as getaddrinfo(), sin_port is set to 0.
// Not audited because no communication actually occurs.
static inline bool is_destination_port_zero(struct sockaddr_in *inet_addr)
static inline bool is_destination_port_zero_v4(struct sockaddr_in *inet_addr)
{
return __builtin_bswap16(inet_addr->sin_port) == 0;
}

static inline bool is_destination_port_zero_v6(struct sockaddr_in6 *inet_addr) {
return __builtin_bswap16(inet_addr->sin6_port) == 0;
}

// TODO: lsm/send_msg
SEC("lsm/socket_connect")
int BPF_PROG(socket_connect, struct socket *sock, struct sockaddr *address, int addrlen)
Expand All @@ -85,23 +141,35 @@ int BPF_PROG(socket_connect, struct socket *sock, struct sockaddr *address, int
int allow_command = -EPERM;
int allow_uid = -EPERM;
int allow_gid = -EPERM;
bool is_ipv6 = (address->sa_family == AF_INET6);
bool is_ipv4 = (address->sa_family == AF_INET);

// TODO: support IPv6
if (address->sa_family != AF_INET)
if (!(is_ipv4 || is_ipv6))
return 0;

u64 cg = bpf_get_current_cgroup_id();

struct sockaddr_in *inet_addr = (struct sockaddr_in *)address;
struct sockaddr_in *inet_addr4;
struct sockaddr_in6 *inet_addr6;

if (is_ipv6) {
inet_addr6 = (struct sockaddr_in6 *)address;
} else {
inet_addr4 = (struct sockaddr_in *)address;
}

if (is_destination_port_zero(inet_addr))
if ((is_ipv6 && is_destination_port_zero_v6(inet_addr6)) ||
(is_ipv4 && is_destination_port_zero_v4(inet_addr4)))
{
return 0;
}

struct ipv4_trie_key key = {
.prefixlen = 32,
.addr = inet_addr->sin_addr};
union ip_trie_key key = {.v4.prefixlen = 32, .v4.addr = inet_addr4->sin_addr};

if (is_ipv6) {
key.v6.prefixlen = 128;
key.v6.addr = BPF_CORE_READ(inet_addr6, sin6_addr);
}

struct allowed_command_key allowed_command;
struct denied_command_key denied_command;
Expand All @@ -127,6 +195,7 @@ int BPF_PROG(socket_connect, struct socket *sock, struct sockaddr *address, int
int has_allow_uid = 0;
int has_allow_gid = 0;


if (c && c->has_allow_command)
{
has_allow_command = c->has_allow_command;
Expand All @@ -144,8 +213,8 @@ int BPF_PROG(socket_connect, struct socket *sock, struct sockaddr *address, int
}
}

if (bpf_map_lookup_elem(&allowed_cidr_list, &key))
{
if ((is_ipv4 && bpf_map_lookup_elem(&allowed_v4_cidr_list, &key.v4)) ||
(is_ipv6 && bpf_map_lookup_elem(&allowed_v6_cidr_list, &key.v6))) {
allow_connect = 0;
}

Expand Down Expand Up @@ -179,23 +248,26 @@ int BPF_PROG(socket_connect, struct socket *sock, struct sockaddr *address, int
allow_gid = -EPERM;
}

if (bpf_map_lookup_elem(&denied_cidr_list, &key))
{
if ((is_ipv4 && bpf_map_lookup_elem(&denied_v4_cidr_list, &key.v4)) ||
(is_ipv6 && bpf_map_lookup_elem(&denied_v6_cidr_list, &key.v6))) {
allow_connect = -EPERM;
}

if (bpf_map_lookup_elem(&denied_cidr_list, &key) && bpf_map_lookup_elem(&allowed_command_list, &allowed_command))
{
if (((is_ipv4 && bpf_map_lookup_elem(&denied_v4_cidr_list, &key.v4)) ||
(is_ipv6 && bpf_map_lookup_elem(&denied_v6_cidr_list, &key.v6))) &&
bpf_map_lookup_elem(&allowed_command_list, &allowed_command)) {
allow_connect = 0;
}

if (bpf_map_lookup_elem(&denied_cidr_list, &key) && bpf_map_lookup_elem(&allowed_uid_list, &allowed_uid))
{
if (((is_ipv4 && bpf_map_lookup_elem(&denied_v4_cidr_list, &key.v4)) ||
(is_ipv6 && bpf_map_lookup_elem(&denied_v6_cidr_list, &key.v6))) &&
bpf_map_lookup_elem(&allowed_uid_list, &allowed_uid)) {
allow_connect = 0;
}

if (bpf_map_lookup_elem(&denied_cidr_list, &key) && bpf_map_lookup_elem(&allowed_gid_list, &allowed_gid))
{
if (((is_ipv4 && bpf_map_lookup_elem(&denied_v4_cidr_list, &key.v4)) ||
(is_ipv6 && bpf_map_lookup_elem(&denied_v6_cidr_list, &key.v6))) &&
bpf_map_lookup_elem(&allowed_gid_list, &allowed_gid)) {
allow_connect = 0;
}

Expand All @@ -207,14 +279,22 @@ int BPF_PROG(socket_connect, struct socket *sock, struct sockaddr *address, int

if (can_access != 0 && c && c->mode == MODE_BLOCK)
{
report_ipv4_event((void *)ctx, cg, ACTION_BLOCK, CONNECT, sock, inet_addr);
if (is_ipv4) {
report_ipv4_event((void *)ctx, cg, ACTION_BLOCK, CONNECT, sock, inet_addr4);
} else {
report_ipv6_event((void *)ctx, cg, ACTION_BLOCK, CONNECT, sock, inet_addr6);
}
}

if (c && c->mode == MODE_MONITOR)
{
report_ipv4_event((void *)ctx, cg, ACTION_MONITOR, CONNECT, sock, inet_addr);
if (is_ipv4) {
report_ipv4_event((void *)ctx, cg, ACTION_MONITOR, CONNECT, sock, inet_addr4);
} else {
report_ipv6_event((void *)ctx, cg, ACTION_MONITOR, CONNECT, sock, inet_addr6);
}
return 0;
}

return can_access;
}
}
Loading

0 comments on commit 87295bf

Please sign in to comment.