Created
March 12, 2021 20:59
-
-
Save nithu0115/198d5849fcf5e5dbbf90132b98a02bf4 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <bcc/proto.h> | |
#include <uapi/linux/ip.h> | |
#include <uapi/linux/ipv6.h> | |
#include <net/inet_sock.h> | |
//Newer kernel bug so need to #define before including ip_fib.h | |
#define KBUILD_MODNAME "foo" | |
#include <net/ip_fib.h> | |
#include <linux/netfilter/x_tables.h> | |
#define ROUTE_EVT_IF 1 | |
#define ROUTE_EVT_IPTABLE 2 | |
#define ROUTE_EVT_RTTABLE 4 | |
/* | |
* Cache per event data | |
* interface name, SIP, DIP, FIB result, IP table hook/verdict | |
*/ | |
struct route_evt_t { | |
u64 flags; | |
char ifname[IFNAMSIZ]; | |
u64 netns; | |
u64 ip_version; | |
u64 saddr[2]; | |
u64 daddr[2]; | |
u64 fib_res_addr[2]; | |
unsigned char fib_res_prefixlen; | |
unsigned char fib_res_type; | |
u32 pid; | |
u64 hook; | |
u64 verdict; | |
char tablename[XT_TABLE_MAXNAMELEN]; | |
}; | |
BPF_PERF_OUTPUT(route_evt); | |
/* | |
* This is to cache ip tables input for now | |
*/ | |
struct ipt_do_table_args | |
{ | |
struct sk_buff *skb; | |
const struct nf_hook_state *state; | |
struct xt_table *table; | |
}; | |
BPF_HASH(cur_ipt_do_table_args, u32, struct ipt_do_table_args); | |
/* | |
* This is to cache route tables input for now | |
*/ | |
struct ip_route_table_args | |
{ | |
struct sk_buff *skb; | |
u32 src; | |
u32 dst; | |
struct net_device *dev; | |
struct fib_result *res; | |
}; | |
BPF_HASH(cur_ip_route_table_args, u32, struct ip_route_table_args); | |
#define MAC_HEADER_SIZE 14; | |
#define GET_ADDRESS(buffer, member) (void*) (((char*)buffer) + offsetof(typeof(*buffer), member)) | |
/* | |
* Trace SK buffer | |
*/ | |
static inline int do_trace_skb(struct route_evt_t *evt, void *ctx, struct sk_buff *skb) | |
{ | |
evt->flags |= ROUTE_EVT_IF; | |
char* head; | |
u16 mac_header; | |
u16 network_header; | |
bpf_probe_read(&head, sizeof(skb->head), GET_ADDRESS(skb, head)); | |
bpf_probe_read(&mac_header, sizeof(skb->mac_header), GET_ADDRESS(skb, mac_header)); | |
bpf_probe_read(&network_header, sizeof(skb->network_header), GET_ADDRESS(skb,network_header)); | |
if(network_header == 0) { | |
network_header = mac_header + MAC_HEADER_SIZE; | |
} | |
char *ip_header_address = head + network_header; | |
u8 l4proto; | |
bpf_probe_read(&evt->ip_version, sizeof(u8), ip_header_address); | |
evt->ip_version = evt->ip_version >> 4 & 0xf; | |
if (evt->ip_version == 4) { | |
struct iphdr iphdr; | |
bpf_probe_read(&iphdr, sizeof(iphdr), ip_header_address); | |
l4proto = iphdr.protocol; | |
evt->saddr[0] = iphdr.saddr; | |
evt->daddr[0] = iphdr.daddr; | |
} else if (evt->ip_version == 6) { | |
struct ipv6hdr* ipv6hdr = (struct ipv6hdr*)ip_header_address; | |
bpf_probe_read(&l4proto, sizeof(ipv6hdr->nexthdr), (char*)ipv6hdr + offsetof(struct ipv6hdr, nexthdr)); | |
bpf_probe_read(evt->saddr, sizeof(ipv6hdr->saddr), (char*)ipv6hdr + offsetof(struct ipv6hdr, saddr)); | |
bpf_probe_read(evt->daddr, sizeof(ipv6hdr->daddr), (char*)ipv6hdr + offsetof(struct ipv6hdr, daddr)); | |
} else { | |
return -1; | |
} | |
struct net_device *dev; | |
bpf_probe_read(&dev, sizeof(skb->dev), GET_ADDRESS(skb, dev)); | |
bpf_probe_read(&evt->ifname, IFNAMSIZ, dev->name); | |
#ifdef CONFIG_NET_NS | |
struct net* net; | |
possible_net_t *skc_net = &dev->nd_net; | |
bpf_probe_read(&net, sizeof(skc_net->net), GET_ADDRESS(skc_net,net)); | |
struct ns_common* ns = GET_ADDRESS(net, ns); | |
bpf_probe_read(&evt->netns, sizeof(ns->inum), GET_ADDRESS(ns, inum)); | |
#endif | |
return 0; | |
} | |
static inline int do_trace(void *ctx, struct sk_buff *skb) | |
{ | |
struct route_evt_t evt = {}; | |
int ret = do_trace_skb(&evt, ctx, skb); | |
if(ret == -1) | |
return 0; | |
route_evt.perf_submit(ctx, &evt, sizeof(evt)); | |
return ret; | |
} | |
/** | |
* Kernel probes and tracepoints for capturing packet | |
* on the inner interface(eni/eth) | |
*/ | |
int kprobe__netif_rx(struct pt_regs *ctx, struct sk_buff *skb) | |
{ | |
return do_trace(ctx, skb); | |
} | |
int kprobe__tpacket_rcv(struct pt_regs *ctx, struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) | |
{ | |
return do_trace(ctx, skb); | |
} | |
int kprobe__packet_rcv(struct pt_regs *ctx, struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) | |
{ | |
return do_trace(ctx, skb); | |
} | |
int kprobe__napi_gro_receive(struct pt_regs *ctx, struct napi_struct *napi, struct sk_buff *skb) | |
{ | |
return do_trace(ctx, skb); | |
} | |
TRACEPOINT_PROBE(net, net_dev_queue) { | |
return do_trace(args, (struct sk_buff*)args->skbaddr); | |
} | |
TRACEPOINT_PROBE(net, netif_receive_skb) | |
{ | |
return do_trace(args, (struct sk_buff *)args->skbaddr); | |
} | |
/* | |
* iptables parser | |
*/ | |
static inline int parse_ip_table_input(struct pt_regs *ctx, struct sk_buff *skb, const struct nf_hook_state *state, struct xt_table *table) | |
{ | |
u32 pid = bpf_get_current_pid_tgid(); | |
struct ipt_do_table_args args = { | |
.skb = skb, | |
.state = state, | |
.table = table, | |
}; | |
cur_ipt_do_table_args.update(&pid, &args); | |
return 0; | |
}; | |
static inline int parse_ip_table_output(struct pt_regs * ctx) | |
{ | |
u32 pid = bpf_get_current_pid_tgid(); | |
struct ipt_do_table_args *args; | |
args = cur_ipt_do_table_args.lookup(&pid); | |
if (args == 0) { | |
return 0; | |
} | |
cur_ipt_do_table_args.delete(&pid); | |
struct route_evt_t evt = { | |
.flags = ROUTE_EVT_IPTABLE, | |
.pid = pid, | |
}; | |
struct sk_buff *skb = args->skb; | |
do_trace_skb(&evt, ctx, skb); | |
const struct nf_hook_state *state = args->state; | |
bpf_probe_read(&evt.hook, sizeof(state->hook), GET_ADDRESS(state, hook)); | |
struct xt_table *table = args->table; | |
bpf_probe_read(&evt.tablename, sizeof(table->name), GET_ADDRESS(table, name)); | |
int ret = PT_REGS_RC(ctx); | |
evt.verdict = ret; | |
route_evt.perf_submit(ctx, &evt, sizeof(evt)); | |
return 0; | |
} | |
/* | |
* Kernel probes for iptables | |
*/ | |
int kprobe__ipt_do_table(struct pt_regs *ctx, struct sk_buff *skb, const struct nf_hook_state *state, struct xt_table *table) | |
{ | |
return parse_ip_table_input(ctx, skb, state, table); | |
}; | |
int kretprobe__ipt_do_table(struct pt_regs *ctx) | |
{ | |
return parse_ip_table_output(ctx); | |
} | |
/* | |
* FIB table parsers | |
*/ | |
static inline int parse_fib_table_input(struct pt_regs *ctx, struct sk_buff *skb, u32 dst, u32 src, | |
u8 tos, struct net_device *dev, struct fib_result *res) { | |
u32 pid = bpf_get_current_pid_tgid(); | |
struct ip_route_table_args args = { | |
.skb = skb, | |
.src = src, | |
.dst = dst, | |
.dev = dev, | |
.res = res, | |
}; | |
cur_ip_route_table_args.update(&pid, &args); | |
return 0; | |
} | |
static inline int parse_fib_table_output(struct pt_regs * ctx) | |
{ | |
u32 pid = bpf_get_current_pid_tgid(); | |
struct ip_route_table_args *args; | |
args = cur_ip_route_table_args.lookup(&pid); | |
if (args == 0) { | |
return 0; | |
} | |
cur_ip_route_table_args.delete(&pid); | |
struct route_evt_t evt = { | |
.flags = ROUTE_EVT_RTTABLE, | |
.pid = pid, | |
}; | |
struct sk_buff *skb = args->skb; | |
do_trace_skb(&evt, ctx, skb); | |
struct fib_result *res = args->res; | |
bpf_probe_read(&evt.fib_res_addr, sizeof(res->prefix), GET_ADDRESS(res, prefix)); | |
bpf_probe_read(&evt.fib_res_prefixlen, sizeof(res->prefixlen), GET_ADDRESS(res, prefixlen)); | |
bpf_probe_read(&evt.fib_res_type, sizeof(res->type), GET_ADDRESS(res, type)); | |
int ret = PT_REGS_RC(ctx); | |
evt.verdict = ret; | |
route_evt.perf_submit(ctx, &evt, sizeof(evt)); | |
return 0; | |
} | |
/* | |
* Kernel probes for fib tables | |
*/ | |
int kprobe__ip_route_input_rcu(struct pt_regs *ctx, struct sk_buff *skb, u32 dst, u32 src, | |
u8 tos, struct net_device *dev, struct fib_result *res) | |
{ | |
return parse_fib_table_input(ctx, skb, dst, src, tos, dev, res); | |
} | |
int kretprobe__ip_route_input_rcu(struct pt_regs *ctx) | |
{ | |
return parse_fib_table_output(ctx); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment