Skip to content

Commit

Permalink
tracee.bpf.c: adjust networking code for maintainability
Browse files Browse the repository at this point in the history
  • Loading branch information
rafaeldtinoco committed May 9, 2022
1 parent 04e94a3 commit afc4094
Showing 1 changed file with 71 additions and 68 deletions.
139 changes: 71 additions & 68 deletions pkg/ebpf/c/tracee.bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -5051,32 +5051,42 @@ static __always_inline bool skb_revalidate_data(struct __sk_buff *skb, uint8_t *
return true;
}

// set protocol appropriate event_id of net_packet_t
void set_net_event_id(net_packet_t *pkt){
const int dns_port = 53;
if (pkt->protocol == IPPROTO_UDP && pkt->dst_port == dns_port){
pkt->event_id = DNS_REQUEST;
}
if (pkt->protocol == IPPROTO_UDP && pkt->src_port == dns_port){
pkt->event_id = DNS_RESPONSE;
// decide network event_id based on created net_packet_t
static __always_inline void set_net_event_id(net_packet_t *pkt) {
enum ports {
DNS = 53,
};

switch (pkt->protocol) {
case IPPROTO_UDP:
if (pkt->dst_port == DNS)
pkt->event_id = DNS_REQUEST;
if (pkt->src_port == DNS)
pkt->event_id = DNS_RESPONSE;
break;
default:
pkt->event_id = NET_PACKET;
}
}

// decide if payload of packet should be submitted, for traced events
bool should_submit_payload(net_packet_t *pkt){
if (pkt->event_id == DNS_REQUEST || pkt->event_id == DNS_RESPONSE)
// some network events might need payload (even without capture)
static __always_inline bool should_submit_payload(net_packet_t *pkt) {
switch (pkt->event_id) {
case DNS_REQUEST:
case DNS_RESPONSE:
return true;
return false;
default:
return false;
}
}

static __always_inline int tc_probe(struct __sk_buff *skb, bool ingress) {
// Note: if we are attaching to docker0 bridge, the ingress bool argument is actually egress
uint8_t *head = (uint8_t *)(long)skb->data;
uint8_t *tail = (uint8_t *)(long)skb->data_end;

if (head + sizeof(struct ethhdr) > tail) {
if (head + sizeof(struct ethhdr) > tail)
return TC_ACT_UNSPEC;
}

struct ethhdr *eth = (void *)head;
net_packet_t pkt = {0};
Expand All @@ -5091,86 +5101,74 @@ static __always_inline int tc_probe(struct __sk_buff *skb, bool ingress) {
switch (bpf_ntohs(eth->h_proto)) {
case ETH_P_IP:
l4_hdr_off = sizeof(struct ethhdr) + sizeof(struct iphdr);

if (!skb_revalidate_data(skb, &head, &tail, l4_hdr_off)) {
if (!skb_revalidate_data(skb, &head, &tail, l4_hdr_off))
return TC_ACT_UNSPEC;
}

// create a IPv4-Mapped IPv6 Address
struct iphdr *ip = (void *)head + sizeof(struct ethhdr);

// Create a IPv4-Mapped IPv6 Address
pkt.src_addr.s6_addr32[3] = ip->saddr;
pkt.dst_addr.s6_addr32[3] = ip->daddr;

pkt.src_addr.s6_addr16[5] = 0xffff;
pkt.dst_addr.s6_addr16[5] = 0xffff;

pkt.protocol = ip->protocol;

break;

case ETH_P_IPV6:
l4_hdr_off = sizeof(struct ethhdr) + sizeof(struct ipv6hdr);

if (!skb_revalidate_data(skb, &head, &tail, l4_hdr_off)) {
if (!skb_revalidate_data(skb, &head, &tail, l4_hdr_off))
return TC_ACT_UNSPEC;
}

struct ipv6hdr *ip6 = (void *)head + sizeof(struct ethhdr);

pkt.src_addr = ip6->saddr;
pkt.dst_addr = ip6->daddr;

pkt.protocol = ip6->nexthdr;

break;

default:
return TC_ACT_UNSPEC;
}

if (pkt.protocol == IPPROTO_TCP) {
if (!skb_revalidate_data(skb, &head, &tail, l4_hdr_off + sizeof(struct tcphdr))) {
switch (pkt.protocol) {
case IPPROTO_TCP:
if (!skb_revalidate_data(skb, &head, &tail, l4_hdr_off + sizeof(struct tcphdr)))
return TC_ACT_UNSPEC;
}

struct tcphdr *tcp = (void *)head + l4_hdr_off;

pkt.src_port = tcp->source;
pkt.dst_port = tcp->dest;
} else if (pkt.protocol == IPPROTO_UDP) {
if (!skb_revalidate_data(skb, &head, &tail, l4_hdr_off + sizeof(struct udphdr))) {
break;

case IPPROTO_UDP:
if (!skb_revalidate_data(skb, &head, &tail, l4_hdr_off + sizeof(struct udphdr)))
return TC_ACT_UNSPEC;
}

struct udphdr *udp = (void *)head + l4_hdr_off;

pkt.src_port = udp->source;
pkt.dst_port = udp->dest;
} else if (pkt.protocol == IPPROTO_ICMP) {
if (!skb_revalidate_data(skb, &head, &tail, l4_hdr_off + sizeof(struct icmphdr))) {
break;

case IPPROTO_ICMP:
if (!skb_revalidate_data(skb, &head, &tail, l4_hdr_off + sizeof(struct icmphdr)))
return TC_ACT_UNSPEC;
}

struct icmphdr *icmph = (void *)head + l4_hdr_off;
u16 icmp_id = icmph->un.echo.id;
pkt.src_port = icmp_id; // icmp_id so connect_id can be found
pkt.dst_port = icmp_id; // icmp_id so connect_id can be found
break;

// set the ports to icmp_id so that the connect_id could be found
pkt.src_port = icmp_id;
pkt.dst_port = icmp_id;
} else if (pkt.protocol == IPPROTO_ICMPV6) {
if (!skb_revalidate_data(skb, &head, &tail, l4_hdr_off + sizeof(struct icmp6hdr))) {
case IPPROTO_ICMPV6:
if (!skb_revalidate_data(skb, &head, &tail, l4_hdr_off + sizeof(struct icmp6hdr)))
return TC_ACT_UNSPEC;
}

struct icmp6hdr *icmph = (void *)head + l4_hdr_off;
u16 icmp_id = icmph->icmp6_dataun.u_echo.identifier;
struct icmp6hdr *icmp6h = (void *)head + l4_hdr_off;
u16 icmp6_id = icmp6h->icmp6_dataun.u_echo.identifier;
pkt.src_port = icmp6_id; // icmp6_id so connect_id can be found
pkt.dst_port = icmp6_id; // icmp6_id so connect_id can be found
break;

// set the ports to icmp_id so that the connect_id could be found
pkt.src_port = icmp_id;
pkt.dst_port = icmp_id;
}
else {
//todo: support other transport protocols?
return TC_ACT_UNSPEC;
default:
return TC_ACT_UNSPEC; // TODO: support more protocols
}

connect_id.protocol = pkt.protocol;
Expand Down Expand Up @@ -5208,31 +5206,36 @@ static __always_inline int tc_probe(struct __sk_buff *skb, bool ingress) {
pkt.host_tid = net_ctx->host_tid;
__builtin_memcpy(pkt.comm, net_ctx->comm, TASK_COMM_LEN);

// The tc perf_event_output handler will use the upper 32 bits of the flags
// argument as a number of bytes to include of the packet payload in the
// event data. If the size is too big, the call to bpf_perf_event_output
// will fail and return -EFAULT.
//
// See bpf_skb_event_output in net/core/filter.c.
u64 flags = BPF_F_CURRENT_CPU;

// If net_packet event wasn't chosen, only send the minimal required data to save the
// packet. This will be the timestamp (u64), net event_id (u32),
// host_tid (u32), comm (16 bytes), packet len (u32), and ifindex (u32)
// if net_packet event not chosen, send minimal data only:
// timestamp (u64) 8 bytes
// net event_id (u32) 4 bytes
// host_id (u32) 4 bytes
// comm (char[]) 16 bytes
// packet len (u32) 4 bytes
// ifindex (u32) 4 bytes
size_t pkt_size = PACKET_MIN_SIZE;

int iface_conf = get_iface_config(skb->ifindex);
if (iface_conf & TRACE_IFACE){
if (iface_conf & TRACE_IFACE) {
pkt_size = sizeof(pkt);
pkt.src_port = __bpf_ntohs(pkt.src_port);
pkt.dst_port = __bpf_ntohs(pkt.dst_port);
set_net_event_id(&pkt);
}

if (iface_conf & CAPTURE_IFACE || should_submit_payload(&pkt)){
// The tc perf_event_output handler will use the upper 32 bits of the flags
// argument as a number of bytes to include of the packet payload in the
// event data. If the size is too big, the call to bpf_perf_event_output
// will fail and return -EFAULT.
//
// See bpf_skb_event_output in net/core/filter.c.
u64 flags = BPF_F_CURRENT_CPU;

if (iface_conf & CAPTURE_IFACE || should_submit_payload(&pkt))
flags |= (u64)skb->len << 32;
}

bpf_perf_event_output(skb, &net_events, flags, &pkt, pkt_size);

return TC_ACT_UNSPEC;
}

Expand Down

0 comments on commit afc4094

Please sign in to comment.