Skip to content

Instantly share code, notes, and snippets.

@nithu0115
Created March 12, 2021 20:59
Show Gist options
  • Save nithu0115/198d5849fcf5e5dbbf90132b98a02bf4 to your computer and use it in GitHub Desktop.
Save nithu0115/198d5849fcf5e5dbbf90132b98a02bf4 to your computer and use it in GitHub Desktop.
#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