From bb2404f029ef1594ac8c5767e3aa1ba796b3112d Mon Sep 17 00:00:00 2001 From: r-caamano Date: Tue, 11 Jul 2023 01:46:00 +0000 Subject: [PATCH] added vrrp passthrough support --- CHANGELOG.md | 6 +++ README.md | 49 +++++++++++++------ src/zfw.c | 98 ++++++++++++++++++++++++++++++------- src/zfw_tc_ingress.c | 16 ++++-- src/zfw_tc_outbound_track.c | 1 + 5 files changed, 134 insertions(+), 36 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 276e5c7..a9d4841 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,12 @@ 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.4.1] - 2023-06-30 + +### + +- Added support for inbound vrrp on a per port basis. + # [0.4.0] - 2023-06-29 ### diff --git a/README.md b/README.md index 8ff2fa7..2b016f0 100644 --- a/README.md +++ b/README.md @@ -174,7 +174,7 @@ expected output: The firewall can support subtending devices for two interface scenarios i.e. external and trusted. -external inet <----> (ens33)[ebpf-router](ens37) <----> trusted clients +external inet <----> (ens33)[ebpf-router](ens37) <----> trusted client(s) with zfw_tc_ingress.o applied ingress on ens33 and zfw_tc_oubound_track.o applied egress on ens33 the router will statefully track outbound udp and tcp connections on ens33 and allow the associated inbound traffic. While @@ -286,10 +286,28 @@ fall through to rule check instead where a more specific rule could be applied. interface setting and can be set for all interfaces except loopback. This would need to be put in /opt/openziti/bin/user/user_rules.sh to survive reboot. +- Disable ``` -sudo zfw -x ens33 +sudo zfw -x ``` +- Enable +``` +sudo zfw -x -d +``` + +### vrrp passthrough +- Enable +``` +sudo zfw --vrrp-enable +``` + +- Disable +``` +sudo zfw --vrrp-enable -d +``` + + ### Inserting / Deleting rules The -t, --tproxy-port is has a dual purpose one it to signify the tproxy port used by openziti routers in tproxy mode and the other is to identify either local passthrough with value of 0 and the other is tunnel redirect mode with value of 65535. @@ -371,7 +389,7 @@ target proto origin destination mapping: PASSTHRU udp 0.0.0.0/0 192.168.100.100/32 dpts=50000:60000 PASSTHRU to 192.168.100.100/32 [] ``` -Example: List rules in firewall for a given prefix +- Example: List rules in firewall for a given prefix Usage: zfw -L -c -m -p ``` sudo zfw -L -c 192.168.100.100 -m 32 @@ -382,7 +400,7 @@ target proto origin destination mapping: PASSTHRU udp 0.0.0.0/0 192.168.100.100/32 dpts=50000:60000 PASSTHRU to 192.168.100.100/32 [] PASSTHRU tcp 0.0.0.0/0 192.168.100.100/32 dpts=60000:65535 PASSTHRU to 192.168.100.100/32 [] ``` -Example: List all interface settings +- Example: List all interface settings ``` sudo zfw -L -E @@ -394,34 +412,37 @@ icmp echo :1 verbose :0 ssh disable :0 per interface :0 -tc ingress filter :1 +tc ingress filter :0 tc egress filter :0 tun mode intercept :0 +vrrp enable :0 -------------------------- -ens33: 3 +ens33: 2 -------------------------- icmp echo :0 -verbose :1 -ssh disable :1 -per interface :1 +verbose :0 +ssh disable :0 +per interface :0 tc ingress filter :1 tc egress filter :1 -tun mode intercept :0 +tun mode intercept :1 +vrrp enable :1 -------------------------- -ens37: 4 +ens37: 3 -------------------------- icmp echo :0 verbose :0 ssh disable :0 per interface :0 -tc ingress filter :1 +tc ingress filter :0 tc egress filter :0 tun mode intercept :0 +vrrp enable :0 -------------------------- -tun0: 9 +tun0: 18 -------------------------- verbose :0 cidr :100.64.0.0 @@ -429,7 +450,7 @@ mask :10 -------------------------- ``` -Example Detaching bpf from interface: +- Example Detaching bpf from interface: ``` sudo zfw --set-tc-filter --direction --disable diff --git a/src/zfw.c b/src/zfw.c index 752cb2d..7a49c87 100644 --- a/src/zfw.c +++ b/src/zfw.c @@ -62,6 +62,7 @@ static bool passthru = false; static bool intercept = false; static bool echo = false; static bool verbose = false; +static bool vrrp = false; static bool per_interface = false; static bool interface = false; static bool disable = false; @@ -108,10 +109,11 @@ static char *verbose_interface; static char *ssh_interface; static char *prefix_interface; static char *tun_interface; +static char *vrrp_interface; static char *tc_interface; static char *object_file; static char *direction_string; -const char *argp_program_version = "0.4.0"; +const char *argp_program_version = "0.4.1"; static __u8 if_list[MAX_IF_LIST_ENTRIES]; int ifcount = 0; @@ -149,6 +151,7 @@ struct diag_ip4 bool tc_ingress; bool tc_egress; bool tun_mode; + bool vrrp; }; struct tproxy_port_mapping @@ -726,6 +729,7 @@ void usage(char *message) fprintf(stderr, " zfw -X -O -z direction\n"); fprintf(stderr, " zfw -X -O -z direction -d\n"); fprintf(stderr, " zfw -Q\n"); + fprintf(stderr, " zfw --vrrp-enable \n"); fprintf(stderr, " zfw -V\n"); fprintf(stderr, " zfw --help\n"); exit(1); @@ -916,6 +920,18 @@ bool set_diag(uint32_t *idx) } printf("Set tun mode to %d for %s\n", !disable, tun_interface); } + if (vrrp) + { + if (!disable) + { + o_diag.vrrp = true; + } + else + { + o_diag.vrrp = false; + } + printf("Set vrrp mode to %d for %s\n", !disable, vrrp_interface); + } int ret = syscall(__NR_bpf, BPF_MAP_UPDATE_ELEM, &diag_map, sizeof(diag_map)); if (ret) { @@ -942,6 +958,7 @@ bool set_diag(uint32_t *idx) printf("%-24s:%d\n", "tc ingress filter", o_diag.tc_ingress); printf("%-24s:%d\n", "tc egress filter", o_diag.tc_egress); printf("%-24s:%d\n", "tun mode intercept", o_diag.tun_mode); + printf("%-24s:%d\n", "vrrp enable", o_diag.vrrp); printf("--------------------------\n\n"); } } @@ -1097,8 +1114,9 @@ void interface_diag() ssh_interface = address->ifa_name; diag_interface = address->ifa_name; tun_interface = address->ifa_name; + vrrp_interface = address->ifa_name; } - if(!strncmp(address->ifa_name, "tun", 3) && (tun || per_interface || ssh_disable || echo)){ + if(!strncmp(address->ifa_name, "tun", 3) && (tun || per_interface || ssh_disable || echo || vrrp)){ if(per_interface && !strncmp(prefix_interface, "tun", 3)){ printf("%s:zfw does not allow setting on tun interfaces!\n", address->ifa_name); } @@ -1111,10 +1129,13 @@ void interface_diag() if(echo && !strncmp(echo_interface, "tun", 3)){ printf("%s:zfw does not allow setting on tun interfaces!\n", address->ifa_name); } + if(vrrp && !strncmp(vrrp_interface, "tun", 3)){ + printf("%s:zfw does not allow setting on tun interfaces!\n", address->ifa_name); + } address = address->ifa_next; continue; } - if(!strncmp(address->ifa_name, "ziti", 4) && (tun || per_interface || ssh_disable || echo)){ + if(!strncmp(address->ifa_name, "ziti", 4) && (tun || per_interface || ssh_disable || echo || vrrp)){ if(per_interface && !strncmp(prefix_interface, "ziti", 4)){ printf("%s:zfw does not allow setting on tun interfaces!\n", address->ifa_name); } @@ -1127,10 +1148,13 @@ void interface_diag() if(echo && !strncmp(echo_interface, "ziti", 4)){ printf("%s:zfw does not allow setting on tun interfaces!\n", address->ifa_name); } + if(vrrp && !strncmp(vrrp_interface, "ziti", 4)){ + printf("%s:zfw does not allow setting on tun interfaces!\n", address->ifa_name); + } address = address->ifa_next; continue; } - if (echo && strncmp(address->ifa_name,"tun", 3) && strncmp(address->ifa_name,"ziti", 4)) + if (echo) //&& strncmp(address->ifa_name,"tun", 3) && strncmp(address->ifa_name,"ziti", 4)) { if (!strcmp(echo_interface, address->ifa_name)) { @@ -1138,6 +1162,14 @@ void interface_diag() } } + if (vrrp) + { + if (!strcmp(vrrp_interface, address->ifa_name)) + { + set_diag(&idx); + } + } + if (verbose) { if(!strncmp(address->ifa_name, "tun", 3) && !strncmp(verbose_interface,"tun", 3)){ @@ -1911,14 +1943,15 @@ static struct argp_option options[] = { {"delete", 'D', NULL, 0, "Delete map rule", 0}, {"list", 'L', NULL, 0, "List map rules", 0}, {"flush", 'F', NULL, 0, "Flush all map rules", 0}, - {"set-tun-mode", 'T', "", 0, "set tun mode on interface", 0}, - {"disable-ebpf", 'Q', NULL, 0, "delete tc from all interface and remove all maps", 0}, - {"per-interface-rules", 'P', "", 0, "set interface to per interface rule aware", 0}, - {"disable-ssh", 'x', "", 0, "disable inbound ssh to interface (default enabled)", 0}, + {"set-tun-mode", 'T', "", 0, "Set tun mode on interface", 0}, + {"disable-ebpf", 'Q', NULL, 0, "Delete tc from all interface and remove all maps", 0}, + {"per-interface-rules", 'P', "", 0, "Set interface to per interface rule aware", 0}, + {"disable-ssh", 'x', "", 0, "Disable inbound ssh to interface (default enabled)", 0}, {"dcidr-block", 'c', "", 0, "Set dest ip prefix i.e. 192.168.1.0 ", 0}, - {"icmp-echo", 'e', "", 0, "enable inbound icmp echo to interface", 0}, - {"verbose", 'v', "", 0, "enable verbose tracing on interface", 0}, - {"disable", 'd', NULL, 0, "disable associated diag operation i.e. -e eth0 -d to disable inbound echo on eth0", 0}, + {"icmp-echo", 'e', "", 0, "Enable inbound icmp echo to interface", 0}, + {"verbose", 'v', "", 0, "Enable verbose tracing on interface", 0}, + {"vrrp-enable", 'R', "", 0, "Enable vrrp passthrough on interface", 0}, + {"disable", 'd', NULL, 0, "Disable associated diag operation i.e. -e eth0 -d to disable inbound echo on eth0", 0}, {"ocidr-block", 'o', "", 0, "Set origin ip prefix i.e. 192.168.1.0 ", 0}, {"dprefix-len", 'm', "", 0, "Set dest prefix length (1-32) ", 0}, {"oprefix-len", 'n', "", 0, "Set origin prefix length (1-32) ", 0}, @@ -1927,13 +1960,13 @@ static struct argp_option options[] = { {"tproxy-port", 't', "", 0, "Set high-port value (0-65535)> ", 0}, {"protocol", 'p', "", 0, "Set protocol (tcp or udp) ", 0}, {"route", 'r', NULL, 0, "Add or Delete static ip/prefix for intercept dest to lo interface ", 0}, - {"intercepts", 'i', NULL, 0, "list intercept rules ", 0}, - {"passthrough", 'f', NULL, 0, "list passthrough rules ", 0}, + {"intercepts", 'i', NULL, 0, "List intercept rules ", 0}, + {"passthrough", 'f', NULL, 0, "List passthrough rules ", 0}, {"interface", 'N', "", 0, "Interface ", 0}, {"list-diag", 'E', NULL, 0, "", 0}, - {"set-tc-filter", 'X', "", 0, "add/remove TC filter to/from interface", 0}, - {"object-file", 'O', "", 0, "set object file", 0}, - {"direction", 'z', "", 0, "set direction", 0}, + {"set-tc-filter", 'X', "", 0, "Add/remove TC filter to/from interface", 0}, + {"object-file", 'O', "", 0, "Set object file", 0}, + {"direction", 'z', "", 0, "Set direction", 0}, {0}}; static error_t parse_opt(int key, char *arg, struct argp_state *state) @@ -2020,6 +2053,28 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) case 'Q': ebpf_disable = true; break; + case 'R': + if (!strlen(arg) || (strchr(arg, '-') != NULL)) + { + fprintf(stderr, "Interface name or all required as arg to -R, --vrrp-enable: %s\n", arg); + fprintf(stderr, "%s --help for more info\n", program_name); + exit(1); + } + get_index(arg, &idx); + if(strcmp("all", arg) && idx == 0){ + printf("Interface not found: %s\n", arg); + exit(1); + } + vrrp = true; + if (!strcmp("all", arg)) + { + all_interface = true; + } + else + { + vrrp_interface = arg; + } + break; case 'T': if (!strlen(arg) || (strchr(arg, '-') != NULL)) { @@ -2316,6 +2371,11 @@ int main(int argc, char **argv) usage("-T, --set-tun-mode cannot be set as a part of combination call to zfw"); } + if (( vrrp && (tun || echo || ssh_disable || verbose || per_interface || add || delete || list || flush || tcfilter))) + { + usage("-R, --vrrp-enable cannot be set as a part of combination call to zfw"); + } + if ((tcfilter && (echo || ssh_disable || verbose || per_interface || add || delete || list || flush))) { usage("-X, --set-tc-filter cannot be set as a part of combination call to zfw"); @@ -2351,9 +2411,9 @@ int main(int argc, char **argv) usage("Missing argument -r, --route requires -I --insert, -D --delete or -F --flush"); } - if (disable && (!ssh_disable && !echo && !verbose && !per_interface && !tcfilter && !tun)) + if (disable && (!ssh_disable && !echo && !verbose && !per_interface && !tcfilter && !tun && !vrrp)) { - usage("Missing argument at least one of -e, -v, -x, or -E, -P, -T, -X"); + usage("Missing argument at least one of -e, -v, -x, or -E, -P, -R, -T, -X"); } if (direction && !tcfilter) @@ -2504,7 +2564,7 @@ int main(int argc, char **argv) map_list(); } } - else if (verbose || ssh_disable || echo || per_interface || tun) + else if (vrrp || verbose || ssh_disable || echo || per_interface || tun) { interface_diag(); exit(0); diff --git a/src/zfw_tc_ingress.c b/src/zfw_tc_ingress.c index 1b19496..309902e 100644 --- a/src/zfw_tc_ingress.c +++ b/src/zfw_tc_ingress.c @@ -153,6 +153,7 @@ struct diag_ip4 { bool tc_ingress; bool tc_egress; bool tun_mode; + bool vrrp; }; /*Value to tun_map*/ @@ -408,7 +409,7 @@ static inline void clear_match_tracker(__u32 key){ * from the combined IP SA|DA and the TCP/UDP SP|DP. */ static struct bpf_sock_tuple *get_tuple(struct __sk_buff *skb, __u64 nh_off, - __u16 eth_proto, bool *ipv4, bool *ipv6, bool *udp, bool *tcp, bool *arp, bool *icmp, struct diag_ip4 *local_diag){ + __u16 eth_proto, bool *ipv4, bool *ipv6, bool *udp, bool *tcp, bool *arp, bool *icmp, bool *vrrp, struct diag_ip4 *local_diag){ struct bpf_sock_tuple *result; __u8 proto = 0; int ret; @@ -523,6 +524,10 @@ static struct bpf_sock_tuple *get_tuple(struct __sk_buff *skb, __u64 nh_off, *icmp = true; return NULL; } + if(proto == 112){ + *vrrp = true; + return NULL; + } /* check if ip protocol is not UDP or TCP. Return NULL if true */ if ((proto != IPPROTO_UDP) && (proto != IPPROTO_TCP)) { return NULL; @@ -568,6 +573,7 @@ int bpf_sk_splice(struct __sk_buff *skb){ bool tcp=false; bool arp=false; bool icmp=false; + bool vrrp=false; int ret; /*look up attached interface inbound diag status*/ @@ -590,7 +596,7 @@ int bpf_sk_splice(struct __sk_buff *skb){ } /* check if incoming packet is a UDP or TCP tuple */ - tuple = get_tuple(skb, sizeof(*eth), eth->h_proto, &ipv4,&ipv6, &udp, &tcp, &arp, &icmp, local_diag); + tuple = get_tuple(skb, sizeof(*eth), eth->h_proto, &ipv4,&ipv6, &udp, &tcp, &arp, &icmp, &vrrp, local_diag); /*look up attached interface IP address*/ struct ifindex_ip4 *local_ip4 = get_local_ip4(skb->ingress_ifindex); @@ -626,7 +632,11 @@ int bpf_sk_splice(struct __sk_buff *skb){ else{ return TC_ACT_SHOT; } - }else{ + }else if(vrrp && local_diag && local_diag->vrrp) + { + return TC_ACT_OK; + } + else{ return TC_ACT_SHOT; } } diff --git a/src/zfw_tc_outbound_track.c b/src/zfw_tc_outbound_track.c index 6a7c103..9749a6e 100644 --- a/src/zfw_tc_outbound_track.c +++ b/src/zfw_tc_outbound_track.c @@ -69,6 +69,7 @@ struct diag_ip4 { bool tc_ingress; bool tc_egress; bool tun_mode; + bool vrrp; }; //map to keep status of diagnostic rules