From e37ee068f53d40a37405bc26d1ef7df5e8f95614 Mon Sep 17 00:00:00 2001 From: r-caamano Date: Mon, 25 Dec 2023 06:14:40 +0000 Subject: [PATCH 1/2] added support for stateful icmp unreachable filtering and some minor code fixes for monitoring --- CHANGELOG.md | 10 +++++++ src/zfw.c | 45 ++++++++++++++++++++++++++++-- src/zfw_tc_ingress.c | 66 +++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 117 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 341f462..272772b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,16 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). --- +# [0.5.4] - 2023-12-24 + +### + +-- Added support for stateful stateful icmp unreachable inbound support in order to support + pmtud and unreachable metric collection. +-- Fixed added ring_buffer__free() to INThandler in zfw.c to properly de-allocate memory + allocated by ring_buffer__new in main() if -M argument was supplied and SIGINT or SIGTERM + is received. + # [0.5.3] - 2023-12-19 ### diff --git a/src/zfw.c b/src/zfw.c index 3688e0d..bb4ba7a 100644 --- a/src/zfw.c +++ b/src/zfw.c @@ -149,7 +149,7 @@ char *monitor_interface; char *tc_interface; char *object_file; char *direction_string; -const char *argp_program_version = "0.5.3"; +const char *argp_program_version = "0.5.4"; struct ring_buffer *ring_buffer; __u8 if_list[MAX_IF_LIST_ENTRIES]; @@ -246,6 +246,9 @@ struct tproxy_key void INThandler(int sig){ signal(sig, SIG_IGN); + if(ring_buffer){ + ring_buffer__free(ring_buffer); + } close_maps(1); } @@ -1624,6 +1627,9 @@ static int process_events(void *ctx, void *data, size_t len){ char * protocol; if(evt->proto == IPPROTO_TCP){ protocol = "TCP"; + } + else if(evt->proto == IPPROTO_ICMP){ + protocol = "ICMP"; }else{ protocol = "UDP"; } @@ -1641,7 +1647,7 @@ static int process_events(void *ctx, void *data, size_t len){ ts, ifname, (evt->direction == INGRESS) ? "INGRESS" : "EGRESS", protocol,saddr, ntohs(evt->sport), daddr, ntohs(evt->dport), ntohs(evt->tport)); } - else if(evt->tracking_code && ifname){ + else if(((evt->proto == IPPROTO_TCP) | (evt->proto == IPPROTO_UDP)) && evt->tracking_code && ifname){ char *state = NULL; __u16 code = evt->tracking_code; @@ -1686,6 +1692,39 @@ static int process_events(void *ctx, void *data, size_t len){ (evt->direction == INGRESS) ? "INGRESS" : "EGRESS", protocol,saddr, ntohs(evt->sport), daddr, ntohs(evt->dport), state); } } + else if(evt->proto == IPPROTO_ICMP && ifname){ + __u16 code = evt->tracking_code; + if(code == 4){ + printf("%s : %s : %s : %s :%s --> reported next hop mtu:%d > FRAGMENTATION NEEDED IN PATH TO:%s:%d\n", ts, ifname, + (evt->direction == INGRESS) ? "INGRESS" : "EGRESS", protocol,saddr, ntohs(evt->sport), daddr, ntohs(evt->dport)); + }else{ + char *code_string = NULL; + char *protocol_string = NULL; + /*evt->sport is use repurposed store encapsulated higher layer protocol*/ + if(evt->sport == IPPROTO_TCP){ + protocol_string = "TCP"; + }else{ + protocol_string = "UDP"; + } + if(code == 0){ + code_string = "NET UNREACHABLE"; + } + else if(code == 1){ + code_string = "HOST UNREACHABLE"; + } + else if(code == 2){ + code_string = "PROTOCOL UNREACHABLE"; + } + else if(code == 3){ + code_string = "PORT UNREACHABLE"; + } + + if(code_string){ + printf("%s : %s : %s : %s :%s --> REPORTED:%s > in PATH TO:%s:%s:%d\n", ts, ifname, + (evt->direction == INGRESS) ? "INGRESS" : "EGRESS", protocol,saddr, code_string, daddr, protocol_string, ntohs(evt->dport)); + } + } + } else if(ifname){ printf("%s : %s : %s : %s :%s:%d > %s:%d\n", ts, ifname, (evt->direction == INGRESS) ? "INGRESS" : "EGRESS", protocol,saddr, ntohs(evt->sport), daddr, ntohs(evt->dport)); @@ -3010,7 +3049,7 @@ int main(int argc, char **argv) ring_buffer = ring_buffer__new(rb_fd, process_events, NULL, NULL); while(true){ ring_buffer__poll(ring_buffer, 1000); - } + } } else { diff --git a/src/zfw_tc_ingress.c b/src/zfw_tc_ingress.c index 1c32190..29205c3 100644 --- a/src/zfw_tc_ingress.c +++ b/src/zfw_tc_ingress.c @@ -725,6 +725,70 @@ int bpf_sk_splice(struct __sk_buff *skb){ else if((icmph->type == 0) && (icmph->code == 0)){ return TC_ACT_OK; } + else if(icmph->type == 3){ + struct iphdr *inner_iph = (struct iphdr *)((unsigned long)icmph + sizeof(*icmph)); + if ((unsigned long)(inner_iph + 1) > (unsigned long)skb->data_end){ + if(local_diag->verbose){ + event.error_code = IP_HEADER_TOO_BIG; + send_event(&event); + } + return TC_ACT_SHOT; + } + if((inner_iph->protocol == IPPROTO_TCP) || ((inner_iph->protocol == IPPROTO_UDP))){ + struct bpf_sock_tuple *o_session = (struct bpf_sock_tuple *)(void*)(long)&inner_iph->saddr; + if ((unsigned long)(o_session + 1) > (unsigned long)skb->data_end){ + event.error_code = IP_TUPLE_TOO_BIG; + send_event(&event); + return TC_ACT_SHOT; + } + if(inner_iph->protocol == IPPROTO_TCP){ + sk = bpf_skc_lookup_tcp(skb, o_session, sizeof(o_session->ipv4),BPF_F_CURRENT_NETNS, 0); + if(sk){ + if (sk->state == BPF_TCP_LISTEN){ + event.proto = IPPROTO_ICMP; + event.saddr = iph->saddr; + event.daddr = o_session->ipv4.daddr; + event.tracking_code = icmph->code; + if(icmph->code == 4){ + event.sport = icmph->un.frag.mtu; + }else{ + event.sport = inner_iph->protocol; + } + event.dport = o_session->ipv4.dport; + send_event(&event); + bpf_sk_release(sk); + return TC_ACT_OK; + } + bpf_sk_release(sk); + } + } + else{ + struct bpf_sock_tuple oudp_session = {0}; + oudp_session.ipv4.daddr = o_session->ipv4.saddr; + oudp_session.ipv4.saddr = o_session->ipv4.daddr; + oudp_session.ipv4.dport = o_session->ipv4.sport; + oudp_session.ipv4.sport = o_session->ipv4.dport; + sk = bpf_sk_lookup_udp(skb, &oudp_session, sizeof(oudp_session.ipv4), BPF_F_CURRENT_NETNS, 0); + if(sk){ + event.proto = IPPROTO_ICMP; + event.saddr = iph->saddr; + event.daddr = o_session->ipv4.daddr; + event.tracking_code = icmph->code; + if(icmph->code == 4){ + event.sport = icmph->un.frag.mtu; + }else{ + event.sport = inner_iph->protocol; + } + event.dport = o_session->ipv4.dport; + send_event(&event); + bpf_sk_release(sk); + return TC_ACT_OK; + } + } + + } + return TC_ACT_SHOT; + } else{ return TC_ACT_SHOT; } @@ -734,7 +798,7 @@ int bpf_sk_splice(struct __sk_buff *skb){ } else{ return TC_ACT_SHOT; - } + } } /* determine length of tuple */ From f7e208b1cda0f3d3f809aec66236ebd22fbf1e00 Mon Sep 17 00:00:00 2001 From: r-caamano Date: Tue, 26 Dec 2023 02:26:53 +0000 Subject: [PATCH 2/2] changed -M output for ICMP Unreachable to require verbose mode and reduced local ssh log verbosity --- src/zfw_tc_ingress.c | 46 ++++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/src/zfw_tc_ingress.c b/src/zfw_tc_ingress.c index 29205c3..a4f883a 100644 --- a/src/zfw_tc_ingress.c +++ b/src/zfw_tc_ingress.c @@ -745,17 +745,19 @@ int bpf_sk_splice(struct __sk_buff *skb){ sk = bpf_skc_lookup_tcp(skb, o_session, sizeof(o_session->ipv4),BPF_F_CURRENT_NETNS, 0); if(sk){ if (sk->state == BPF_TCP_LISTEN){ - event.proto = IPPROTO_ICMP; - event.saddr = iph->saddr; - event.daddr = o_session->ipv4.daddr; - event.tracking_code = icmph->code; - if(icmph->code == 4){ - event.sport = icmph->un.frag.mtu; - }else{ - event.sport = inner_iph->protocol; + if(local_diag->verbose){ + event.proto = IPPROTO_ICMP; + event.saddr = iph->saddr; + event.daddr = o_session->ipv4.daddr; + event.tracking_code = icmph->code; + if(icmph->code == 4){ + event.sport = icmph->un.frag.mtu; + }else{ + event.sport = inner_iph->protocol; + } + event.dport = o_session->ipv4.dport; + send_event(&event); } - event.dport = o_session->ipv4.dport; - send_event(&event); bpf_sk_release(sk); return TC_ACT_OK; } @@ -770,17 +772,19 @@ int bpf_sk_splice(struct __sk_buff *skb){ oudp_session.ipv4.sport = o_session->ipv4.dport; sk = bpf_sk_lookup_udp(skb, &oudp_session, sizeof(oudp_session.ipv4), BPF_F_CURRENT_NETNS, 0); if(sk){ - event.proto = IPPROTO_ICMP; - event.saddr = iph->saddr; - event.daddr = o_session->ipv4.daddr; - event.tracking_code = icmph->code; - if(icmph->code == 4){ - event.sport = icmph->un.frag.mtu; - }else{ - event.sport = inner_iph->protocol; + if(local_diag->verbose){ + event.proto = IPPROTO_ICMP; + event.saddr = iph->saddr; + event.daddr = o_session->ipv4.daddr; + event.tracking_code = icmph->code; + if(icmph->code == 4){ + event.sport = icmph->un.frag.mtu; + }else{ + event.sport = inner_iph->protocol; + } + event.dport = o_session->ipv4.dport; + send_event(&event); } - event.dport = o_session->ipv4.dport; - send_event(&event); bpf_sk_release(sk); return TC_ACT_OK; } @@ -830,7 +834,7 @@ int bpf_sk_splice(struct __sk_buff *skb){ } for(int x = 0; x < addresses; x++){ if((tuple->ipv4.daddr == local_ip4->ipaddr[x]) && !local_diag->ssh_disable){ - if(local_diag->verbose){ + if(local_diag->verbose && ((event.tstamp % 2) == 0)){ event.proto = IPPROTO_TCP; send_event(&event); }