Created
March 12, 2021 17:06
-
-
Save nithu0115/b2ff587922e3a7c193b1fd1ad1099b0f 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> | |
#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