Skip to content

Commit

Permalink
Renames & cleanups
Browse files Browse the repository at this point in the history
  • Loading branch information
hack3ric committed Mar 31, 2024
1 parent b0b80ef commit bde2a9e
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 94 deletions.
4 changes: 2 additions & 2 deletions src/bpf/egress.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ int egress_handler(struct __sk_buff* skb) {
__u32 log_verbosity = *(__u32*)try_p_shot(bpf_map_lookup_elem(&mimic_settings, &vkey));

struct conn_tuple conn_key = gen_conn_key(QUARTET_UDP, false);
log_quartet(log_verbosity, LOG_LEVEL_DEBUG, false, LOG_TYPE_MATCHED, conn_key);
log_conn(log_verbosity, LOG_LEVEL_DEBUG, false, LOG_TYPE_MATCHED, &conn_key);
struct connection* conn = try_p_shot(get_conn(&conn_key));

struct udphdr old_udphdr = *udp;
Expand Down Expand Up @@ -97,7 +97,7 @@ int egress_handler(struct __sk_buff* skb) {
break;
}
bpf_spin_unlock(&conn->lock);
send_ctrl_packet(conn_key, true, false, false, seq, ack_seq);
send_ctrl_packet(&conn_key, SYN, seq, ack_seq);
// TODO: store packet in userspace buffer and send them after establishing
return TC_ACT_STOLEN;
}
Expand Down
12 changes: 7 additions & 5 deletions src/bpf/ingress.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ int ingress_handler(struct xdp_md* xdp) {
__u32 log_verbosity = *(__u32*)try_p_drop(bpf_map_lookup_elem(&mimic_settings, &vkey));

struct conn_tuple conn_key = gen_conn_key(QUARTET_TCP, true);
log_quartet(log_verbosity, LOG_LEVEL_DEBUG, true, LOG_TYPE_MATCHED, conn_key);
log_conn(log_verbosity, LOG_LEVEL_DEBUG, true, LOG_TYPE_MATCHED, &conn_key);
struct connection* conn = bpf_map_lookup_elem(&mimic_conns, &conn_key);

// TODO: verify checksum
Expand All @@ -99,9 +99,9 @@ int ingress_handler(struct xdp_md* xdp) {
}
// Drop the RST packet no matter if it is generated from Mimic or the peer's OS, since there are
// no good ways to tell them apart.
log_quartet(log_verbosity, LOG_LEVEL_WARN, true, LOG_TYPE_RST, conn_key);
log_conn(log_verbosity, LOG_LEVEL_WARN, true, LOG_TYPE_RST, &conn_key);
if (rst_result == RST_DESTROYED) {
log_quartet(log_verbosity, LOG_LEVEL_WARN, true, LOG_TYPE_CONN_DESTROY, conn_key);
log_conn(log_verbosity, LOG_LEVEL_WARN, true, LOG_TYPE_CONN_DESTROY, &conn_key);
}
return XDP_DROP;
}
Expand Down Expand Up @@ -170,13 +170,15 @@ int ingress_handler(struct xdp_md* xdp) {
bpf_spin_unlock(&conn->lock);

if (newly_estab) {
log_quartet(log_verbosity, LOG_LEVEL_INFO, true, LOG_TYPE_CONN_ESTABLISH, conn_key);
log_conn(log_verbosity, LOG_LEVEL_INFO, true, LOG_TYPE_CONN_ESTABLISH, &conn_key);
}
log_tcp(log_verbosity, LOG_LEVEL_TRACE, true, LOG_TYPE_TCP_PKT, 0, ntohl(tcp->seq), ntohl(tcp->ack_seq));
log_tcp(log_verbosity, LOG_LEVEL_TRACE, true, LOG_TYPE_STATE, state, seq, ack_seq);

if (rst) bpf_map_delete_elem(&mimic_conns, &conn_key);
if (will_send_ctrl_packet) send_ctrl_packet(conn_key, syn, ack, rst, seq, ack_seq);
if (will_send_ctrl_packet) {
send_ctrl_packet(&conn_key, (syn ? SYN : 0) | (ack ? ACK : 0) | (rst ? RST : 0), seq, ack_seq);
}
if (will_drop) return XDP_DROP;

__be32 ipv4_saddr = 0, ipv4_daddr = 0;
Expand Down
58 changes: 58 additions & 0 deletions src/bpf/mimic.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,62 @@ struct mimic_conns_map mimic_conns SEC(".maps");
struct mimic_settings_map mimic_settings SEC(".maps");
struct mimic_rb_map mimic_rb SEC(".maps");

bool matches_whitelist(QUARTET_DEF, bool ingress) {
struct pkt_filter local = {.origin = ORIGIN_LOCAL}, remote = {.origin = ORIGIN_REMOTE};
if (udp) {
local.port = udp->source;
remote.port = udp->dest;
} else if (tcp) {
local.port = tcp->source;
remote.port = tcp->dest;
}
if (ipv4) {
local.protocol = remote.protocol = PROTO_IPV4;
local.ip.v4 = ipv4->saddr;
remote.ip.v4 = ipv4->daddr;
} else if (ipv6) {
local.protocol = remote.protocol = PROTO_IPV6;
local.ip.v6 = ipv6->saddr;
remote.ip.v6 = ipv6->daddr;
}
if (ingress) {
struct pkt_filter t = local;
local = remote;
remote = t;
local.origin = ORIGIN_LOCAL;
remote.origin = ORIGIN_REMOTE;
}
return bpf_map_lookup_elem(&mimic_whitelist, &local) || bpf_map_lookup_elem(&mimic_whitelist, &remote);
}

int log_any(__u32 log_verbosity, enum log_level level, bool ingress, enum log_type type, union log_info* info) {
if (log_verbosity < level || !info) return -1;
struct rb_item* item = bpf_ringbuf_reserve(&mimic_rb, sizeof(*item), 0);
if (!item) return -1;
item->type = RB_ITEM_LOG_EVENT;
item->log_event.level = level;
item->log_event.type = type;
item->log_event.ingress = ingress;
item->log_event.info = *info;
bpf_ringbuf_submit(item, 0);
return 0;
}

int send_ctrl_packet(struct conn_tuple* conn, __u32 flags, __u32 seq, __u32 ack_seq) {
if (!conn) return -1;
struct rb_item* item = bpf_ringbuf_reserve(&mimic_rb, sizeof(*item), 0);
if (!item) return -1;
item->type = RB_ITEM_SEND_OPTIONS;
item->send_options = (struct send_options){
.conn = *conn,
.syn = flags & SYN,
.ack = flags & ACK,
.rst = flags & RST,
.seq = seq,
.ack_seq = ack_seq,
};
bpf_ringbuf_submit(item, 0);
return 0;
}

char _license[] SEC("license") = "GPL";
96 changes: 25 additions & 71 deletions src/bpf/mimic.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,42 +49,16 @@ struct ipv6_ph_part {
__u8 nexthdr;
} __attribute__((packed));

struct sk_buff* mimic_inspect_skb(struct __sk_buff*) __ksym;
int mimic_change_csum_offset(struct __sk_buff*, __u16) __ksym;
struct sk_buff* mimic_inspect_skb(struct __sk_buff* skb) __ksym;
int mimic_change_csum_offset(struct __sk_buff* skb, __u16 protocol) __ksym;

// clang-format off
#define QUARTET_DEF struct iphdr* ipv4, struct ipv6hdr* ipv6, struct udphdr* udp, struct tcphdr* tcp
#define QUARTET_UDP ipv4, ipv6, udp, NULL
#define QUARTET_TCP ipv4, ipv6, NULL, tcp
// clang-format on

static inline bool matches_whitelist(QUARTET_DEF, bool ingress) {
struct pkt_filter local = {.origin = ORIGIN_LOCAL}, remote = {.origin = ORIGIN_REMOTE};
if (udp) {
local.port = udp->source;
remote.port = udp->dest;
} else if (tcp) {
local.port = tcp->source;
remote.port = tcp->dest;
}
if (ipv4) {
local.protocol = remote.protocol = PROTO_IPV4;
local.ip.v4 = ipv4->saddr;
remote.ip.v4 = ipv4->daddr;
} else if (ipv6) {
local.protocol = remote.protocol = PROTO_IPV6;
local.ip.v6 = ipv6->saddr;
remote.ip.v6 = ipv6->daddr;
}
if (ingress) {
struct pkt_filter t = local;
local = remote;
remote = t;
local.origin = ORIGIN_LOCAL;
remote.origin = ORIGIN_REMOTE;
}
return bpf_map_lookup_elem(&mimic_whitelist, &local) || bpf_map_lookup_elem(&mimic_whitelist, &remote);
}
bool matches_whitelist(QUARTET_DEF, bool ingress);

static inline struct conn_tuple gen_conn_key(QUARTET_DEF, bool ingress) {
struct conn_tuple key = {};
Expand Down Expand Up @@ -115,62 +89,42 @@ static inline struct conn_tuple gen_conn_key(QUARTET_DEF, bool ingress) {
return key;
}

static inline struct connection* get_conn(struct conn_tuple* conn_key) {
struct connection* conn = bpf_map_lookup_elem(&mimic_conns, conn_key);
static inline struct connection* get_conn(struct conn_tuple* key) {
struct connection* conn = bpf_map_lookup_elem(&mimic_conns, key);
if (!conn) {
struct connection conn_value = {};
if (bpf_map_update_elem(&mimic_conns, conn_key, &conn_value, BPF_ANY)) return NULL;
conn = bpf_map_lookup_elem(&mimic_conns, conn_key);
if (bpf_map_update_elem(&mimic_conns, key, &conn_value, BPF_ANY)) return NULL;
conn = bpf_map_lookup_elem(&mimic_conns, key);
if (!conn) return NULL;
}
return conn;
}

static inline void log_any(__u32 log_verbosity, enum log_level level, bool ingress, enum log_type type,
union log_info info) {
if (log_verbosity < level) return;
struct rb_item* item = bpf_ringbuf_reserve(&mimic_rb, sizeof(*item), 0);
if (!item) return;
item->type = RB_ITEM_LOG_EVENT;
item->log_event.level = level;
item->log_event.type = type;
item->log_event.ingress = ingress;
item->log_event.info = info;
bpf_ringbuf_submit(item, 0);
}
int log_any(__u32 log_verbosity, enum log_level level, bool ingress, enum log_type type, union log_info* info);

static inline void log_quartet(__u32 log_verbosity, enum log_level level, bool ingress, enum log_type type,
struct conn_tuple quartet) {
log_any(log_verbosity, level, ingress, type, (union log_info){.quartet = quartet});
static inline int log_conn(__u32 log_verbosity, enum log_level level, bool ingress, enum log_type type,
struct conn_tuple* conn) {
if (!conn) return -1;
return log_any(log_verbosity, level, ingress, type, &(union log_info){.conn = *conn});
}

static __always_inline void log_tcp(__u32 log_verbosity, enum log_level level, bool ingress, enum log_type type,
enum conn_state state, __u32 seq, __u32 ack_seq) {
log_any(log_verbosity, level, ingress, type,
(union log_info){.tcp = {.state = state, .seq = seq, .ack_seq = ack_seq}});
static inline int log_tcp(__u32 log_verbosity, enum log_level level, bool ingress, enum log_type type,
enum conn_state state, __u32 seq, __u32 ack_seq) {
return log_any(log_verbosity, level, ingress, type,
&(union log_info){.tcp = {.state = state, .seq = seq, .ack_seq = ack_seq}});
}

static __always_inline void send_ctrl_packet(struct conn_tuple c, bool syn, bool ack, bool rst, __u32 seq,
__u32 ack_seq) {
struct rb_item* item = bpf_ringbuf_reserve(&mimic_rb, sizeof(*item), 0);
if (!item) return;
item->type = RB_ITEM_SEND_OPTIONS;
item->send_options = (struct send_options){
.c = c,
.syn = syn,
.ack = ack,
.rst = rst,
.seq = seq,
.ack_seq = ack_seq,
};
bpf_ringbuf_submit(item, 0);
}
#define SYN 1
#define ACK 1 << 1
#define RST 1 << 2

int send_ctrl_packet(struct conn_tuple* conn, __u32 flags, __u32 seq, __u32 ack_seq);

#define _log_a(_0, _1, _2, _3, N, ...) _##N
#define _log_b_0() (u64[0]){}, 0
#define _log_b_1(_a) (u64[1]){(u64)(_a)}, sizeof(u64)
#define _log_b_2(_a, _b) (u64[2]){(u64)(_a), (u64)(_b)}, 2 * sizeof(u64)
#define _log_b_3(_a, _b, _c) (u64[2]){(u64)(_a), (u64)(_b), (u64)(_c)}, 3 * sizeof(u64)
#define _log_b_0() (__u64[0]){}, 0
#define _log_b_1(_a) (__u64[1]){(__u64)(_a)}, sizeof(__u64)
#define _log_b_2(_a, _b) (__u64[2]){(__u64)(_a), (__u64)(_b)}, 2 * sizeof(__u64)
#define _log_b_3(_a, _b, _c) (__u64[2]){(__u64)(_a), (__u64)(_b), (__u64)(_c)}, 3 * sizeof(__u64)
#define _log_c(...) _log_a(__VA_ARGS__, 3, 2, 1, 0)
#define _log_d(_x, _y) _x##_y
#define _log_e(_x, _y) _log_d(_x, _y)
Expand Down
20 changes: 10 additions & 10 deletions src/run.c
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ static int handle_log_event(struct log_event* e) {
break;
default: {
char from[IP_PORT_MAX_LEN], to[IP_PORT_MAX_LEN];
struct conn_tuple* pkt = &e->info.quartet;
struct conn_tuple* pkt = &e->info.conn;
// invert again, since conn_tuple passed to it is already inverted
if (e->ingress) {
ip_port_fmt(pkt->protocol, pkt->local, pkt->local_port, to);
Expand All @@ -174,32 +174,32 @@ static int handle_log_event(struct log_event* e) {
}

static inline int send_ctrl_packet(struct send_options* s) {
_cleanup_fd int sk = try(socket(s->c.protocol, SOCK_RAW | SOCK_NONBLOCK, IPPROTO_TCP));
_cleanup_fd int sk = try(socket(s->conn.protocol, SOCK_RAW | SOCK_NONBLOCK, IPPROTO_TCP));
__u32 csum = 0;
struct sockaddr_storage saddr = {}, daddr = {};
if (s->c.protocol == AF_INET) {
__u32 local = s->c.local.v4, remote = s->c.remote.v4;
if (s->conn.protocol == AF_INET) {
__u32 local = s->conn.local.v4, remote = s->conn.remote.v4;
*(struct sockaddr_in*)&saddr = (struct sockaddr_in){.sin_family = AF_INET, .sin_addr = local, .sin_port = 0};
*(struct sockaddr_in*)&daddr = (struct sockaddr_in){.sin_family = AF_INET, .sin_addr = remote, .sin_port = 0};
update_csum_ul(&csum, ntohl(local));
update_csum_ul(&csum, ntohl(remote));
} else {
*(struct sockaddr_in6*)&saddr =
(struct sockaddr_in6){.sin6_family = AF_INET6, .sin6_addr = s->c.local.v6, .sin6_port = 0};
(struct sockaddr_in6){.sin6_family = AF_INET6, .sin6_addr = s->conn.local.v6, .sin6_port = 0};
*(struct sockaddr_in6*)&daddr =
(struct sockaddr_in6){.sin6_family = AF_INET6, .sin6_addr = s->c.remote.v6, .sin6_port = 0};
(struct sockaddr_in6){.sin6_family = AF_INET6, .sin6_addr = s->conn.remote.v6, .sin6_port = 0};
for (int i = 0; i < 8; i++) {
update_csum(&csum, ntohs(s->c.local.v6.s6_addr16[i]));
update_csum(&csum, ntohs(s->c.remote.v6.s6_addr16[i]));
update_csum(&csum, ntohs(s->conn.local.v6.s6_addr16[i]));
update_csum(&csum, ntohs(s->conn.remote.v6.s6_addr16[i]));
}
}
update_csum(&csum, IPPROTO_TCP);
update_csum(&csum, sizeof(struct tcphdr));
try(bind(sk, (struct sockaddr*)&saddr, sizeof(saddr)), _("failed to bind: %s"), strerror(-_ret));

struct tcphdr tcp = {
.source = s->c.local_port,
.dest = s->c.remote_port,
.source = s->conn.local_port,
.dest = s->conn.remote_port,
.seq = htonl(s->seq),
.ack_seq = htonl(s->ack_seq),
.doff = 5,
Expand Down
12 changes: 6 additions & 6 deletions src/shared/misc.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ enum rst_result {
};

struct send_options {
struct conn_tuple c;
struct conn_tuple conn;
bool syn, ack, rst;
__u32 seq, ack_seq;
};
Expand All @@ -134,20 +134,20 @@ struct log_event {
} level;
bool ingress;
enum log_type {
LOG_TYPE_MATCHED, // quartet
LOG_TYPE_CONN_ESTABLISH, // quartet
LOG_TYPE_MATCHED, // conn
LOG_TYPE_CONN_ESTABLISH, // conn
LOG_TYPE_TCP_PKT, // tcp (ignore state)
LOG_TYPE_STATE, // tcp
LOG_TYPE_RST, // quartet
LOG_TYPE_CONN_DESTROY, // quartet
LOG_TYPE_RST, // conn
LOG_TYPE_CONN_DESTROY, // conn
LOG_TYPE_QUICK_MSG, // msg
} type;
union log_info {
struct fake_tcp_info {
enum conn_state state;
__u32 seq, ack_seq;
} tcp;
struct conn_tuple quartet;
struct conn_tuple conn;
char msg[40];
} info;
};
Expand Down

0 comments on commit bde2a9e

Please sign in to comment.