Skip to content

Commit

Permalink
Merge pull request #66 from netfoundry/v0.8.10-release-candidate
Browse files Browse the repository at this point in the history
V0.8.10 release candidate
  • Loading branch information
r-caamano committed Aug 2, 2024
2 parents 4ef220a + b379051 commit 52951f0
Show file tree
Hide file tree
Showing 7 changed files with 502 additions and 22 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.8.10] - 2024-07-29

- Updated start_ebpf_controller.py to only clear ingress filters on restart and also removed ```-r, --route``` from the flush.
- Added native masquerade for IPv4/IPv6 passthrough connections.

###
# [0.8.9] - 2024-07-28

Expand Down
13 changes: 10 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,19 @@
---
This firewall application utilizes both tc-ebpf and xdp to provide stateful firewalling
for an [OpenZiti](https://docs.openziti.io/) ziti-edge-tunnel installation and is meant as a replacement for packet
filtering. It can be used in conjunction with ufw's masquerade feature on a WAN facing interface if
the zfw_outbound_track.o is activated in the egress direction. It can also be used in conjunction with OpenZiti
edge-routers.
filtering. It can also be used in conjunction with OpenZiti edge-routers or as a standalone fw. It now has built in
EBPF based masquerade capability for both IPv4/IPv6.

## New features in 0.8.x -

### Native EBPF based IPv4 and IPv6 Masquerade support

zfw can now provide native IPv4/IPv6 masquerade operation for outbound pass through connections which can be enabled via:

```sudo zfw -k, --masquerade <ifname>```

This function requires that both ingress and egress TC filters are enabled on outbound interface.

### Explicit Deny Rules
This feature adds the ability to enter explicit deny rules by appending ```-d, --disable to the -I, --insert rule`` to both ingress and egress rules. Rule precedence is based on longest match prefix. If the prefix is the same then the precedence follows the order entry of the rules, which when listed will go from top to bottom for ports with in the same prefix e.g.

Expand Down
2 changes: 1 addition & 1 deletion files/scripts/start_ebpf_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,7 @@ def set_local_rules(ip):
os.system("/opt/openziti/bin/user/user_rules.sh")
else:
print("ebpf already running!");
os.system("/usr/sbin/zfw -F -r")
os.system("/usr/sbin/zfw -F -z ingress")
print("Flushed Table")
for i in internal_list:
if(not tc_status(i, "ingress")):
Expand Down
104 changes: 91 additions & 13 deletions src/zfw.c
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ bool prot = false;
bool route = false;
bool passthru = false;
bool intercept = false;
bool masquerade = false;
bool echo = false;
bool eapol = false;
bool verbose = false;
Expand Down Expand Up @@ -213,7 +214,7 @@ const char *egress_map_path = "/sys/fs/bpf/tc/globals/zt_egress_map";
const char *egress6_map_path = "/sys/fs/bpf/tc/globals/zt_egress6_map";
const char *egress_count_map_path = "/sys/fs/bpf/tc/globals/egress_count_map";
const char *egress_count6_map_path = "/sys/fs/bpf/tc/globals/egress6_count_map";

const char *masquerade_map_path = "/sys/fs/bpf/tc/globals/masquerade_map";
char doc[] = "zfw -- ebpf firewall configuration tool";
const char *if_map_path;
char *diag_interface;
Expand All @@ -232,9 +233,10 @@ char *tc_interface;
char *log_file_name;
char *object_file;
char *direction_string;
char *masq_interface;
char check_alt[IF_NAMESIZE];

const char *argp_program_version = "0.8.9";
const char *argp_program_version = "0.8.10";
struct ring_buffer *ring_buffer;

__u32 if_list[MAX_IF_LIST_ENTRIES];
Expand Down Expand Up @@ -367,8 +369,8 @@ struct bpf_event
unsigned char dest[6];
};

struct diag_ip4
{
/*value to diag_map*/
struct diag_ip4 {
bool echo;
bool verbose;
bool per_interface;
Expand All @@ -381,6 +383,7 @@ struct diag_ip4
bool ddos_filtering;
bool ipv6_enable;
bool outbound_filter;
bool masquerade;
};

struct tproxy_tuple
Expand Down Expand Up @@ -648,14 +651,14 @@ void disable_ebpf()
disable = true;
tc = true;
interface_tc();
const char *maps[33] = {tproxy_map_path, diag_map_path, if_map_path, count_map_path,
const char *maps[34] = {tproxy_map_path, diag_map_path, if_map_path, count_map_path,
udp_map_path, matched_map_path, tcp_map_path, tun_map_path, if_tun_map_path,
transp_map_path, rb_map_path, ddos_saddr_map_path, ddos_dport_map_path, syn_count_map_path,
tp_ext_map_path, if_list_ext_map_path, range_map_path, wildcard_port_map_path, tproxy6_map_path,
if6_map_path, count6_map_path, matched6_map_path, egress_range_map_path, egress_if_list_ext_map_path,
egress_ext_map_path, egress_map_path, egress6_map_path, egress_count_map_path, egress_count6_map_path,
egress_matched6_map_path, egress_matched_map_path, udp_ingress_map_path, tcp_ingress_map_path};
for (int map_count = 0; map_count < 33; map_count++)
egress_matched6_map_path, egress_matched_map_path, udp_ingress_map_path, tcp_ingress_map_path, masquerade_map_path};
for (int map_count = 0; map_count < 34; map_count++)
{

int stat = remove(maps[map_count]);
Expand Down Expand Up @@ -1680,14 +1683,39 @@ bool set_diag(uint32_t *idx)
printf("Set disable_ssh is always set to 0 for lo\n");
}
}
if (masquerade)
{
if (!disable && *idx != 1)
{
if(!check_filter(*idx,"egress")){
o_diag.masquerade = true;
}else{
printf("masquerade not set, no egress filter exists for %s\n", masq_interface);
printf("set first with: sudo zfw -X %s -O /opt/openziti/bin/zfw_tc_outbound_track.o -z egress\n", masq_interface);
close_maps(1);
}
}
else
{
o_diag.masquerade = false;
}
if (*idx != 1)
{
printf("Set masquerade to %d for %s\n", !disable, masq_interface);
}
else
{
printf("Masquerade is always set to 0 for lo\n");
}
}
if (outbound)
{
if (!disable && *idx != 1)
{
if(!check_filter(*idx,"egress")){
o_diag.outbound_filter = true;
}else{
printf("outbound filter not set no egress filter exists for %s\n", outbound_interface);
printf("outbound filter not set, no egress filter exists for %s\n", outbound_interface);
printf("set first with: sudo zfw -X %s -O /opt/openziti/bin/zfw_tc_outbound_track.o -z egress\n", outbound_interface);
close_maps(1);
}
Expand Down Expand Up @@ -1795,6 +1823,7 @@ 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);
printf("%-24s:%d\n", "masquerade", o_diag.masquerade);
if (*idx != 1)
{
printf("%-24s:%d\n", "ipv6 enable", o_diag.ipv6_enable);
Expand Down Expand Up @@ -1897,7 +1926,9 @@ void interface_tc()
set_tc_filter("del");
if(egress){
outbound = true;
masquerade = true;
outbound_interface = tc_interface;
masq_interface = tc_interface;
}
if (diag_fd == -1)
{
Expand Down Expand Up @@ -1968,8 +1999,9 @@ void interface_diag()
ddos_interface = address->ifa_name;
ipv6_interface = address->ifa_name;
outbound_interface = address->ifa_name;
masq_interface = address->ifa_name;
}
if (!strncmp(address->ifa_name, "ziti", 4) && (tun || per_interface || ssh_disable || echo || vrrp || eapol || ddos || v6 || outbound))
if (!strncmp(address->ifa_name, "ziti", 4) && (tun || per_interface || ssh_disable || echo || vrrp || eapol || ddos || v6 || outbound || masquerade))
{
if (per_interface && !strncmp(prefix_interface, "ziti", 4))
{
Expand Down Expand Up @@ -1999,6 +2031,10 @@ void interface_diag()
{
printf("%s:zfw does not allow setting on ziti tun interfaces!\n", address->ifa_name);
}
if (masquerade && !strncmp(masq_interface, "ziti", 4))
{
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);
Expand All @@ -2017,7 +2053,13 @@ void interface_diag()
set_diag(&idx);
}
}

if (masquerade)
{
if (!strcmp(masq_interface, address->ifa_name))
{
set_diag(&idx);
}
}
if (outbound)
{
if (!strcmp(outbound_interface, address->ifa_name))
Expand Down Expand Up @@ -5473,6 +5515,7 @@ static struct argp_option options[] = {
{"passthrough", 'f', NULL, 0, "List passthrough rules <optional list>", 0},
{"high-port", 'h', "", 0, "Set high-port value (1-65535)> <mandatory for insert>", 0},
{"intercepts", 'i', NULL, 0, "List intercept rules <optional for list>", 0},
{"masquerade", 'k', "", 0, "enable outbound masquerade", 0},
{"low-port", 'l', "", 0, "Set low-port value (1-65535)> <mandatory insert/delete>", 0},
{"dprefix-len", 'm', "", 0, "Set dest prefix length (1-32) <mandatory for insert/delete/list >", 0},
{"oprefix-len", 'n', "", 0, "Set origin prefix length (1-32) <mandatory for insert/delete/list >", 0},
Expand Down Expand Up @@ -5844,6 +5887,33 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state)
case 'i':
intercept = true;
break;
case 'k':
if (!strlen(arg) || (strchr(arg, '-') != NULL))
{
fprintf(stderr, "Interface name or all required as arg to -k, --masquerade: %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);
}
masquerade = true;
if (!strcmp("all", arg))
{
all_interface = true;
}
else
{
if(if_indextoname(idx, check_alt)){
masq_interface = check_alt;
}else{
masq_interface = arg;
}
}
break;
case 'l':
low_port = port2s(arg);
lpt = true;
Expand Down Expand Up @@ -6346,6 +6416,14 @@ int main(int argc, char **argv)
usage("-X, --set-tc-filter requires -z, --direction for add operation");
}

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

if (v6)
{
if ((dsip || tcfilter || echo || ssh_disable || verbose || per_interface || add || delete || flush || eapol) || ddos || vrrp || monitor || logging || ddport)
Expand Down Expand Up @@ -6477,9 +6555,9 @@ int main(int argc, char **argv)
}

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

if (direction && (!tcfilter && !list && !flush && !delete && !add))
Expand Down Expand Up @@ -6745,7 +6823,7 @@ int main(int argc, char **argv)
}
}
}
else if (vrrp || verbose || ssh_disable || echo || per_interface || tun || eapol || ddos || v6 || outbound)
else if (vrrp || verbose || ssh_disable || echo || per_interface || tun || eapol || ddos || v6 || outbound || masquerade)
{
interface_diag();
}
Expand Down
2 changes: 1 addition & 1 deletion src/zfw_monitor.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ char check_alt[IF_NAMESIZE];
char doc[] = "zfw_monitor -- ebpf firewall monitor tool";
const char *rb_map_path = "/sys/fs/bpf/tc/globals/rb_map";
const char *tproxy_map_path = "/sys/fs/bpf/tc/globals/zt_tproxy_map";
const char *argp_program_version = "0.8.8";
const char *argp_program_version = "0.8.10";
union bpf_attr rb_map;
int rb_fd = -1;

Expand Down
Loading

0 comments on commit 52951f0

Please sign in to comment.