Skip to content

Commit

Permalink
Added logic to disable IPv6 by default except for inbound ipv6 router…
Browse files Browse the repository at this point in the history
… advertisments so that the ipv6 auto-configuration(SLAAC) can occur before zfw enumerates ipv6 interfaces to ensure the ipv6 interface address is included in the ifindex_ip6_map.
  • Loading branch information
r-caamano committed Jun 22, 2024
1 parent 24a6540 commit 6e52519
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 37 deletions.
5 changes: 3 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ All notable changes to this project will be documented in this file. The format

###

- Initial support for IPv6. Added basic neighbor discovery, inbound ipv6 echo (disabled by default)/ echo reply, Inbound ssh, Outbound
stateful tracking.
- Initial support for IPv6. Added basic neighbor discovery, inbound ipv6 echo (disabled by default)/ echo reply, Inbound ssh, Outbound
stateful tracking. IPv6 is disabled by default except for inbound ipv6 router advertisments so that the ipv6 auto-configuration(SLAAC) can occur before zfw enumerates ipv6 interfaces
to ensure the ipv6 interface address is included in the ifindex_ip6_map.'
- Removed unused tuple_key struct from zfw_xdp_tun_ingress.c

# [0.7.8] - 2024-06-13
Expand Down
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,17 @@ the zfw_outbound_track.o is activated in the egress direction. It can also be us
edge-routers.

## New in release 0.8.0 - Initial support for ipv6

- *Enabled via sudo zfw -6 <ifname | all>
Note: Router discovery is always enabled even if ipv6 is disabled in order to ensure the ifindex_ip6_map gets populated.
- Supports ipv6 neighbor discovery (redirects not supported)
- Supports inbound ipv6 echo (disabled by default)/ echo reply
- Supports inbound ssh (Can be disabled via zfw -x <ifname>)
- *Supports inbound ipv6 echo (disabled by default can be enabled via zfw -e)/ echo reply
- *Supports inbound ssh (Can be disabled via zfw -x <ifname | all>) (Care should be taken as this affects IPv4 as well)
- Supports outbound stateful host connections (Inbound only if outbound initiated)
- Supports outbound passthrough tracking. Sessions initiated from non-ebpf enabled interfaces out through interface(s) defined as ExternalInterface or with
"OutboundPassThroughTrack": true in /opt/openziti/etc/ebpf_config.json or manually applied with sudo zfw -X <ifname> -O /opt/openziti/zfw_outbound_track.o
-z egress with allow stateful udp and tcp session traffic back in.
- Monitor connection state via -M, --monitor <ifname> when -v verbose <ifname> enabled
*These setting need to be in /opt/openziti/bin/user_rules.sh to be persistent across reboots

## Build

Expand Down
102 changes: 89 additions & 13 deletions src/zfw.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ bool ddos_saddr_list = false;
bool ddport =false;
bool ddos_dport_list = false;
bool service = false;
bool v6 = false;
char *service_string;
char *ddos_saddr;
char *ddos_dport;
Expand Down Expand Up @@ -182,6 +183,7 @@ char *tun_interface;
char *vrrp_interface;
char *ddos_interface;
char *monitor_interface;
char *ipv6_interface;
char *tc_interface;
char *log_file_name;
char *object_file;
Expand Down Expand Up @@ -310,6 +312,7 @@ struct diag_ip4
bool vrrp;
bool eapol;
bool ddos_filtering;
bool ipv6_enable;
};

struct tproxy_tuple
Expand Down Expand Up @@ -1171,6 +1174,25 @@ bool set_diag(uint32_t *idx)
printf("icmp echo is always set to 1 for lo\n");
}
}
if (v6)
{
if (!disable || *idx == 1)
{
o_diag.ipv6_enable = true;
}
else
{
o_diag.ipv6_enable = false;
}
if (*idx != 1)
{
printf("Set ipv6_enable to %d for %s\n", !disable, ipv6_interface);
}
else
{
printf("ipv6_enable is always set to 1 for lo\n");
}
}
if (verbose)
{
if (!disable)
Expand Down Expand Up @@ -1315,6 +1337,14 @@ bool set_diag(uint32_t *idx)
printf("%-24s:%d\n", "vrrp enable", o_diag.vrrp);
printf("%-24s:%d\n", "eapol enable", o_diag.eapol);
printf("%-24s:%d\n", "ddos filtering", o_diag.ddos_filtering);
if (*idx != 1)
{
printf("%-24s:%d\n", "ipv6 enable", o_diag.ipv6_enable);
}
else
{
printf("%-24s:%d\n", "ipv6 enable", 1);
}
printf("--------------------------\n\n");
}
return true;
Expand Down Expand Up @@ -1470,36 +1500,41 @@ void interface_diag()
vrrp_interface = address->ifa_name;
eapol_interface = address->ifa_name;
ddos_interface = address->ifa_name;
ipv6_interface = address->ifa_name;
}
if (!strncmp(address->ifa_name, "ziti", 4) && (tun || per_interface || ssh_disable || echo || vrrp || eapol || ddos))
if (!strncmp(address->ifa_name, "ziti", 4) && (tun || per_interface || ssh_disable || echo || vrrp || eapol || ddos || v6))
{
if (per_interface && !strncmp(prefix_interface, "ziti", 4))
{
printf("%s:zfw does not allow setting on tun interfaces!\n", address->ifa_name);
printf("%s:zfw does not allow setting on ziti tun interfaces!\n", address->ifa_name);
}
if (tun && !strncmp(tun_interface, "ziti", 4))
{
printf("%s:zfw does not allow setting on tun interfaces!\n", address->ifa_name);
printf("%s:zfw does not allow setting on ziti tun interfaces!\n", address->ifa_name);
}
if (ssh_disable && !strncmp(ssh_interface, "ziti", 4))
{
printf("%s:zfw does not allow setting on tun interfaces!\n", address->ifa_name);
printf("%s:zfw does not allow setting on ziti tun interfaces!\n", address->ifa_name);
}
if (echo && !strncmp(echo_interface, "ziti", 4))
{
printf("%s:zfw does not allow setting on tun interfaces!\n", address->ifa_name);
printf("%s:zfw does not allow setting on ziti 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);
printf("%s:zfw does not allow setting on ziti tun interfaces!\n", address->ifa_name);
}
if (eapol && !strncmp(eapol_interface, "ziti", 4))
{
printf("%s:zfw does not allow setting on tun interfaces!\n", address->ifa_name);
printf("%s:zfw does not allow setting on ziti tun interfaces!\n", address->ifa_name);
}
if (ddos && !strncmp(ddos_interface, "ziti", 4))
{
printf("%s:zfw does not allow setting on tun interfaces!\n", address->ifa_name);
printf("%s:zfw does not allow setting on ziti tun interfaces!\n", address->ifa_name);
}
if (v6 && !strncmp(ipv6_interface, "ziti", 4))
{
printf("%s:zfw does not allow setting on ziti tun interfaces!\n", address->ifa_name);
}
address = address->ifa_next;
continue;
Expand Down Expand Up @@ -1584,6 +1619,14 @@ void interface_diag()
}
}

if (v6)
{
if (!strcmp(ipv6_interface, address->ifa_name))
{
set_diag(&idx);
}
}

if (access(diag_map_path, F_OK) != 0)
{
ebpf_usage();
Expand Down Expand Up @@ -3776,6 +3819,8 @@ static struct argp_option options[] = {
{"write-log", 'W', "", 0, "Write to monitor output to /var/log/<log file name> <optional for monitor>", 0},
{"set-tc-filter", 'X', "", 0, "Add/remove TC filter to/from interface", 0},
{"list-ddos-saddr", 'Y', NULL, 0, "List source IP Addresses currently in DDOS IP whitelist", 0},
{"ddos-filtering", 'a', "", 0, "Manually enable/disable ddos filtering on interface", 0},
{"ipv6-enable", '6', "", 0, "Enable/disable IPv6 packet processing on interface", 0},
{"dcidr-block", 'c', "", 0, "Set dest ip prefix i.e. 192.168.1.0 <mandatory for insert/delete/list>", 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},
Expand All @@ -3795,7 +3840,6 @@ static struct argp_option options[] = {
{"enable-eapol", 'w', "", 0, "enable 802.1X eapol packets inbound on interface", 0},
{"disable-ssh", 'x', "", 0, "Disable inbound ssh to interface (default enabled)", 0},
{"ddos-saddr-add", 'y', "", 0, "Add source IP Address to DDOS IP whitelist i.e. 192.168.1.1", 0},
{"ddos-filtering", 'a', "", 0, "Manually enable/disable ddos filtering on interface", 0},
{"direction", 'z', "", 0, "Set direction", 0},
{0}};

Expand Down Expand Up @@ -4018,6 +4062,29 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state)
ddos_interface = arg;
}
break;
case '6':
if (!strlen(arg) || (strchr(arg, '-') != NULL))
{
fprintf(stderr, "Interface name or all required as arg to -6, --ipv6-enable: %s\n", arg);
fprintf(stderr, "%s --help for more info\n", program_name);
exit(1);
}
idx = if_nametoindex(arg);
if (strcmp("all", arg) && idx == 0)
{
printf("Interface not found: %s\n", arg);
exit(1);
}
v6 = true;
if (!strcmp("all", arg))
{
all_interface = true;
}
else
{
ipv6_interface = arg;
}
break;
case 'c':
if (!inet_aton(arg, &dcidr))
{
Expand Down Expand Up @@ -4471,6 +4538,15 @@ int main(int argc, char **argv)
usage("-X, --set-tc-filter requires -z, --direction for add operation");
}

if (v6)
{
if ((dsip ||tcfilter || echo || ssh_disable || verbose || per_interface || add || delete || list || flush
|| eapol) || ddos || vrrp || monitor || logging|| ddport)
{
usage("-6, --ipv6-enable can not be used in combination call");
}
}

if (ddport)
{
if ((dsip ||tcfilter || echo || ssh_disable || verbose || per_interface || add || delete || list || flush
Expand All @@ -4491,7 +4567,7 @@ int main(int argc, char **argv)

if (logging)
{
if ((tcfilter || echo || ssh_disable || verbose || per_interface || add || delete || list || flush || eapol) || ddos || vrrp || (!monitor))
if (tcfilter || echo || ssh_disable || verbose || per_interface || add || delete || list || flush || eapol || ddos || vrrp || (!monitor))
{
usage("W, --write-log can only be used in combination call to -M, --monitor");
}
Expand Down Expand Up @@ -4593,9 +4669,9 @@ int main(int argc, char **argv)
}

if (disable && (!ssh_disable && !echo && !verbose && !per_interface && !tcfilter && !tun && !vrrp && !eapol && !ddos
&& !dsip && !ddport))
&& !dsip && !ddport && !v6))
{
usage("Missing argument at least one of -e, -u, -v, -w, -x, -y, or -E, -P, -R, -T, -X");
usage("Missing argument at least one of -6,-e, -u, -v, -w, -x, -y, or -E, -P, -R, -T, -X");
}

if (direction && !tcfilter)
Expand Down Expand Up @@ -4764,7 +4840,7 @@ int main(int argc, char **argv)
map_list();
}
}
else if (vrrp || verbose || ssh_disable || echo || per_interface || tun || eapol || ddos)
else if (vrrp || verbose || ssh_disable || echo || per_interface || tun || eapol || ddos || v6)
{
interface_diag();
}
Expand Down
39 changes: 21 additions & 18 deletions src/zfw_tc_ingress.c
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ struct diag_ip4 {
bool vrrp;
bool eapol;
bool ddos_filtering;
bool ipv6_enable;
};

/*Value to tun_map*/
Expand Down Expand Up @@ -1020,7 +1021,7 @@ int bpf_sk_splice(struct __sk_buff *skb){
else{
return TC_ACT_SHOT;
}
}else{
}else if(ipv6){
struct ipv6hdr *ip6h = (struct ipv6hdr *)(skb->data + sizeof(*eth));
if ((unsigned long)(ip6h + 1) > (unsigned long)skb->data_end){
return TC_ACT_SHOT;
Expand All @@ -1031,26 +1032,28 @@ int bpf_sk_splice(struct __sk_buff *skb){
send_event(&event);
return TC_ACT_SHOT;
}
if((icmp6h->icmp6_type == 128) && (icmp6h->icmp6_code == 0)){
if(local_diag && local_diag->echo){
if(local_diag->ipv6_enable){
if((icmp6h->icmp6_type == 128) && (icmp6h->icmp6_code == 0)){ //echo
if(local_diag && local_diag->echo){
return TC_ACT_OK;
}
else{
return TC_ACT_SHOT;
}
}else if((icmp6h->icmp6_type == 129) && (icmp6h->icmp6_code == 0)){ //echo-reply
return TC_ACT_OK;
}else if((icmp6h->icmp6_type == 133) && (icmp6h->icmp6_code == 0)){ //router solicitation
return TC_ACT_OK;
}else if((icmp6h->icmp6_type == 135) && (icmp6h->icmp6_code == 0)){ //neighbor solicitation
return TC_ACT_OK;
}else if((icmp6h->icmp6_type == 136) && (icmp6h->icmp6_code == 0)){ //neighbor advertisement
return TC_ACT_OK;
}
else{
return TC_ACT_SHOT;
}
}else if((icmp6h->icmp6_type == 129) && (icmp6h->icmp6_code == 0)){
return TC_ACT_OK;
}else if((icmp6h->icmp6_type == 133) && (icmp6h->icmp6_code == 0)){
return TC_ACT_OK;
}else if((icmp6h->icmp6_type == 134) && (icmp6h->icmp6_code == 0)){
return TC_ACT_OK;
}else if((icmp6h->icmp6_type == 135) && (icmp6h->icmp6_code == 0)){
return TC_ACT_OK;
}else if((icmp6h->icmp6_type == 136) && (icmp6h->icmp6_code == 0)){
}
if((icmp6h->icmp6_type == 134) && (icmp6h->icmp6_code == 0)){ //router advertisement
return TC_ACT_OK;
}else{
return TC_ACT_SHOT;
}
return TC_ACT_SHOT;
}
}else if(vrrp && local_diag && local_diag->vrrp)
{
Expand Down Expand Up @@ -1311,7 +1314,7 @@ int bpf_sk_splice(struct __sk_buff *skb){
struct match_key mkey = {tuple->ipv4.saddr, tuple->ipv4.daddr, tuple->ipv4.sport, tuple->ipv4.dport, skb->ifindex, event.proto};
clear_match_tracker(mkey);
return TC_ACT_PIPE;
}else if(ipv6)
}else if(ipv6 && local_diag->ipv6_enable)
{
tuple_len = sizeof(tuple->ipv6);
if ((unsigned long)tuple + tuple_len > (unsigned long)skb->data_end){
Expand Down
3 changes: 2 additions & 1 deletion src/zfw_tc_outbound_track.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ struct diag_ip4 {
bool vrrp;
bool eapol;
bool ddos_filtering;
bool ipv6_enable;
};

/*value to ifindex_tun_map*/
Expand Down Expand Up @@ -543,7 +544,7 @@ int bpf_sk_splice(struct __sk_buff *skb){
}
}
}
}else if(ipv6){
}else if(ipv6 && local_diag->ipv6_enable){
/* determine length of tuple */
tuple_len = sizeof(tuple->ipv6);
if ((unsigned long)tuple + tuple_len > (unsigned long)skb->data_end){
Expand Down

0 comments on commit 6e52519

Please sign in to comment.