Skip to content

Instantly share code, notes, and snippets.

@nithu0115
Created March 12, 2021 17:06
Show Gist options
  • Save nithu0115/b2ff587922e3a7c193b1fd1ad1099b0f to your computer and use it in GitHub Desktop.
Save nithu0115/b2ff587922e3a7c193b1fd1ad1099b0f 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>
#include <net/route.h>
#define ROUTE_EVT_IF 1
#define ROUTE_EVT_IPTABLE 2
#define ROUTE_EVT_RTTABLE 4
#define ROUTE_EVT_OUT 8
#define ROUTE_EVENT_DROP 16
#define SKB_DST_NOREF 1UL
#define SKB_DST_PTRMASK ~(SKB_DST_NOREF)
/*
* Cache per event data
* interface name, SIP, DIP, flags
*/
#define FUNCNAME_MAX_LEN 64
struct route_evt_t {
u64 flags;
char func_name[FUNCNAME_MAX_LEN];
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;
u8 skb_sk_is_empty;
u8 l4_proto;
u16 tcpflags;
int kernel_stack_id;
};
BPF_PERF_OUTPUT(route_evt);
BPF_STACK_TRACE(stacks, 2048);
static void bpf_strncpy(char *dst, const char *src, int n)
{
int i = 0, j;
#define CPY(n) \
do { \
for (; i < n; i++) { \
if (src[i] == 0) return; \
dst[i] = src[i]; \
} \
} while(0)
for (j = 10; j < 64; j += 10)
CPY(j);
CPY(64);
#undef CPY
}
enum {
__TCP_FLAG_CWR,
__TCP_FLAG_ECE,
__TCP_FLAG_URG,
__TCP_FLAG_ACK,
__TCP_FLAG_PSH,
__TCP_FLAG_RST,
__TCP_FLAG_SYN,
__TCP_FLAG_FIN
};
#define TCP_FLAGS_INIT(new_flags, orig_flags, flag) \
do { \
if (orig_flags & flag) { \
new_flags |= (1U<<__##flag); \
} \
} while (0)
#define init_tcpflags_bits(new_flags, orig_flags) \
({ \
new_flags = 0; \
TCP_FLAGS_INIT(new_flags, orig_flags, TCP_FLAG_CWR); \
TCP_FLAGS_INIT(new_flags, orig_flags, TCP_FLAG_ECE); \
TCP_FLAGS_INIT(new_flags, orig_flags, TCP_FLAG_URG); \
TCP_FLAGS_INIT(new_flags, orig_flags, TCP_FLAG_ACK); \
TCP_FLAGS_INIT(new_flags, orig_flags, TCP_FLAG_PSH); \
TCP_FLAGS_INIT(new_flags, orig_flags, TCP_FLAG_RST); \
TCP_FLAGS_INIT(new_flags, orig_flags, TCP_FLAG_SYN); \
TCP_FLAGS_INIT(new_flags, orig_flags, TCP_FLAG_FIN); \
})
#define MAC_HEADER_SIZE 14;
#define GET_ADDRESS(buffer, member) (void*) (((char*)buffer) + offsetof(typeof(*buffer), member))
int kprobe__ip_forward(struct pt_regs *ctx, struct sk_buff *skb)
{
struct route_evt_t evt = {};
evt.flags = ROUTE_EVENT_DROP;
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 l4_offset_from_ip_header;
union tcp_word_hdr tcphdr;
struct udphdr udphdr;
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);
l4_offset_from_ip_header = iphdr.ihl * 4;
evt.l4_proto = 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(&evt.l4_proto, 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;
}
char *l4_header_address;
l4_header_address = ip_header_address + l4_offset_from_ip_header;
switch(evt.l4_proto) {
case IPPROTO_TCP:
bpf_probe_read(&tcphdr, sizeof(tcphdr), l4_header_address);
init_tcpflags_bits(evt.tcpflags, tcp_flag_word(&tcphdr));
break;
case IPPROTO_UDP:
bpf_probe_read(&udphdr, sizeof(udphdr), l4_header_address);
break;
}
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
struct sock * sk;
evt.skb_sk_is_empty = 0;
bpf_probe_read(&sk, sizeof(skb->sk), GET_ADDRESS(skb, sk));
if(sk == NULL) {
evt.skb_sk_is_empty = 1;
}
bpf_strncpy(evt.func_name, __func__+8, FUNCNAME_MAX_LEN);
evt.kernel_stack_id = stacks.get_stackid(ctx, 0);
route_evt.perf_submit(ctx, &evt, sizeof(evt));
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment