Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Origin/v0.5.12 release candidate nf #29

Merged
merged 2 commits into from
Mar 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions BUILD.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
```bash
mkdir ~/repos
cd repos
git clone https://github.com/r-caamano/zfw.git
git clone https://github.com/netfoundry/zfw.git
cd zfw/src
make all
sudo make install ARGS=<router|tunnel>
Expand All @@ -40,7 +40,7 @@
```bash
mkdir ~/repos
cd repos
git clone https://github.com/r-caamano/zfw.git
git clone https://github.com/netfoundry/zfw.git
cd zfw/src
make all
sudo make install ARGS=<router|tunnel>
Expand Down
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@
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.12] - 2024-03-14

###

- Added ddos_protect diag mode
- Added icmp unrecheable ttl logging. Inner and outer.
- Fixed BUILD.md incorrect reference to parent repo

# [0.5.11] - 2024-02-27

###
Expand Down
85 changes: 72 additions & 13 deletions src/zfw.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
#define CLIENT_INITIATED_UDP_SESSION 12
#define ICMP_INNER_IP_HEADER_TOO_BIG 13

bool ddos = false;
bool add = false;
bool delete = false;
bool list = false;
Expand Down Expand Up @@ -137,6 +138,7 @@ const char *tun_map_path = "/sys/fs/bpf/tc/globals/tun_map";
const char *if_tun_map_path = "/sys/fs/bpf/tc/globals/ifindex_tun_map";
const char *transp_map_path = "/sys/fs/bpf/tc/globals/zet_transp_map";
const char *rb_map_path = "/sys/fs/bpf/tc/globals/rb_map";
const char *ddos_map_path = "/sys/fs/bpf/tc/globals/ddos_protect_map";
char doc[] = "zfw -- ebpf firewall configuration tool";
const char *if_map_path;
char *diag_interface;
Expand All @@ -147,12 +149,13 @@ char *ssh_interface;
char *prefix_interface;
char *tun_interface;
char *vrrp_interface;
char *ddos_interface;
char *monitor_interface;
char *tc_interface;
char *log_file_name;
char *object_file;
char *direction_string;
const char *argp_program_version = "0.5.11";
const char *argp_program_version = "0.5.12";
struct ring_buffer *ring_buffer;

__u8 if_list[MAX_IF_LIST_ENTRIES];
Expand Down Expand Up @@ -220,6 +223,7 @@ struct diag_ip4
bool tun_mode;
bool vrrp;
bool eapol;
bool ddos_filtering;
};

struct tproxy_port_mapping
Expand Down Expand Up @@ -428,10 +432,10 @@ void disable_ebpf()
disable = true;
tc = true;
interface_tc();
const char *maps[11] = {tproxy_map_path, diag_map_path, if_map_path, count_map_path,
const char *maps[12] = {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};
for (int map_count = 0; map_count < 11; map_count++)
transp_map_path, rb_map_path, ddos_map_path};
for (int map_count = 0; map_count < 12; map_count++)
{

int stat = remove(maps[map_count]);
Expand Down Expand Up @@ -989,6 +993,18 @@ bool set_diag(uint32_t *idx)
}
printf("Set vrrp mode to %d for %s\n", !disable, vrrp_interface);
}
if (ddos)
{
if (!disable)
{
o_diag.ddos_filtering = true;
}
else
{
o_diag.ddos_filtering = false;
}
printf("Set ddos detect to %d for %s\n", !disable, ddos_interface);
}
int ret = syscall(__NR_bpf, BPF_MAP_UPDATE_ELEM, &diag_map, sizeof(diag_map));
if (ret)
{
Expand Down Expand Up @@ -1017,6 +1033,7 @@ bool set_diag(uint32_t *idx)
printf("%-24s:%d\n", "tun mode intercept", o_diag.tun_mode);
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("--------------------------\n\n");
}
return true;
Expand Down Expand Up @@ -1163,8 +1180,9 @@ void interface_diag()
tun_interface = address->ifa_name;
vrrp_interface = address->ifa_name;
eapol_interface = address->ifa_name;
ddos_interface = address->ifa_name;
}
if(!strncmp(address->ifa_name, "ziti", 4) && (tun || per_interface || ssh_disable || echo || vrrp || eapol)){
if(!strncmp(address->ifa_name, "ziti", 4) && (tun || per_interface || ssh_disable || echo || vrrp || eapol || ddos)){
if(per_interface && !strncmp(prefix_interface, "ziti", 4)){
printf("%s:zfw does not allow setting on tun interfaces!\n", address->ifa_name);
}
Expand All @@ -1183,6 +1201,9 @@ void interface_diag()
if(eapol && !strncmp(eapol_interface, "ziti", 4)){
printf("%s:zfw does not allow setting on 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);
}
address = address->ifa_next;
continue;
}
Expand All @@ -1202,6 +1223,14 @@ void interface_diag()
}
}

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

if (eapol)
{
if (!strcmp(eapol_interface, address->ifa_name))
Expand Down Expand Up @@ -1779,7 +1808,10 @@ static int process_events(void *ctx, void *data, size_t len){
}
else if(evt->proto == IPPROTO_ICMP && ifname){
__u16 code = evt->tracking_code;
__u8 inner_ttl = evt->dest[0];
__u8 outer_ttl = evt->source[0];
if(code == 4){
/*evt->sport is use repurposed store next hop mtu*/
sprintf(message, "%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));
if(logging){
Expand All @@ -1790,8 +1822,7 @@ static int process_events(void *ctx, void *data, size_t len){
}else{
char *code_string = NULL;
char *protocol_string = NULL;
/*evt->sport is use repurposed store encapsulated higher layer protocol*/
if(evt->sport == IPPROTO_TCP){
if(evt->dest[1] == IPPROTO_TCP){
protocol_string = "TCP";
}else{
protocol_string = "UDP";
Expand All @@ -1810,8 +1841,8 @@ static int process_events(void *ctx, void *data, size_t len){
}

if(code_string){
sprintf(message, "%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));
sprintf(message, "%s : %s : %s : %s :%s --> REPORTED:%s > in PATH TO:%s:%s:%d OUTER-TTL:%d INNER-TTL:%d\n", ts, ifname,
(evt->direction == INGRESS) ? "INGRESS" : "EGRESS", protocol,saddr, code_string, daddr, protocol_string, ntohs(evt->dport), outer_ttl, inner_ttl);
if(logging){
res = write_log(log_file_name, message);
}else{
Expand Down Expand Up @@ -2441,6 +2472,7 @@ static struct argp_option options[] = {
{"verbose", 'v', "", 0, "Enable verbose tracing on interface", 0},
{"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-filtering", 'a', "", 0, "Manually enable/disable ddos filtering on interface", 0},
{"direction", 'z', "", 0, "Set direction", 0},
{0}};

Expand Down Expand Up @@ -2626,6 +2658,28 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state)
tc_interface = arg;
}
break;
case 'a':
if (!strlen(arg) || (strchr(arg, '-') != NULL))
{
fprintf(stderr, "Interface name or all required as arg to -a, --ddos-filter: %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);
}
ddos = true;
if (!strcmp("all", arg))
{
all_interface = true;
}
else
{
ddos_interface = arg;
}
break;
case 'c':
if (!inet_aton(arg, &dcidr))
{
Expand Down Expand Up @@ -2922,15 +2976,15 @@ int main(int argc, char **argv)
if (logging)
{
if ((tcfilter || echo || ssh_disable || verbose || per_interface
|| add || delete || list || flush || eapol) || (!monitor))
|| add || delete || list || flush || eapol) || ddos || vrrp || (!monitor))
{
usage("W, --write-log can only be used in combination call to -M, --monitor");
}
}

if (ebpf_disable)
{
if (tcfilter || echo || ssh_disable || verbose || per_interface || add || delete || list || flush || monitor || eapol)
if (tcfilter || echo || ssh_disable || verbose || per_interface || add || delete || list || flush || monitor || eapol || vrrp || ddos)
{
usage("Q, --disable-ebpf cannot be used in combination call");
}
Expand All @@ -2957,6 +3011,11 @@ int main(int argc, char **argv)
usage("-T, --set-tun-mode cannot be set as a part of combination call to zfw");
}

if ((ddos && (monitor || tun || echo || ssh_disable || verbose || per_interface || add || delete || list || flush || tcfilter || vrrp || eapol)))
{
usage("-a, --ddsos-filter cannot be set as a part of combination call to zfw");
}

if ((eapol && (monitor || tun || echo || ssh_disable || verbose || per_interface || add || delete || list || flush || tcfilter || vrrp)))
{
usage("-M, --enable-eapol cannot be set as a part of combination call to zfw");
Expand Down Expand Up @@ -3007,7 +3066,7 @@ 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 && !vrrp && !eapol))
if (disable && (!ssh_disable && !echo && !verbose && !per_interface && !tcfilter && !tun && !vrrp && !eapol && !ddos))
{
usage("Missing argument at least one of -e, -v, -x, w, or -E, -P, -R, -T, -X");
}
Expand Down Expand Up @@ -3160,7 +3219,7 @@ int main(int argc, char **argv)
map_list();
}
}
else if (vrrp || verbose || ssh_disable || echo || per_interface || tun || eapol)
else if (vrrp || verbose || ssh_disable || echo || per_interface || tun || eapol || ddos)
{
interface_diag();
exit(0);
Expand Down
40 changes: 36 additions & 4 deletions src/zfw_tc_ingress.c
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ struct diag_ip4 {
bool tun_mode;
bool vrrp;
bool eapol;
bool ddos_filtering;
};

/*Value to tun_map*/
Expand Down Expand Up @@ -236,6 +237,15 @@ struct {
__uint(map_flags, BPF_F_NO_PREALLOC);
} zet_transp_map SEC(".maps");

struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(key_size, sizeof(uint32_t));
__uint(value_size,sizeof(bool));
__uint(max_entries, BPF_MAX_ENTRIES);
__uint(pinning, LIBBPF_PIN_BY_NAME);
__uint(map_flags, BPF_F_NO_PREALLOC);
} ddos_protect_map SEC(".maps");

/*map to track up to 3 key matches per incoming packet search. Map is
then used to search for port mappings. This was required when source filtering was
added to accommodate the additional instructions per ebpf program. The search now spans
Expand Down Expand Up @@ -458,6 +468,13 @@ static inline void clear_match_tracker(struct match_key key){
bpf_map_delete_elem(&matched_map, &key);
}

/*Function to check if ip is in ddos whitelist*/
static inline bool *get_ddos_list(unsigned int key){
bool *match;
match = bpf_map_lookup_elem(&ddos_protect_map, &key);
return match;
}

static inline void send_event(struct bpf_event *new_event){
struct bpf_event *rb_event;
rb_event = bpf_ringbuf_reserve(&rb_map, sizeof(*rb_event), 0);
Expand Down Expand Up @@ -744,6 +761,9 @@ int bpf_sk_splice(struct __sk_buff *skb){
return TC_ACT_SHOT;
}
if((inner_iph->protocol == IPPROTO_TCP) || ((inner_iph->protocol == IPPROTO_UDP))){
event.source[0] = iph->ttl;
event.dest[0] = inner_iph->ttl;
event.dest[1] = inner_iph->protocol;
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;
Expand All @@ -760,8 +780,6 @@ int bpf_sk_splice(struct __sk_buff *skb){
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);
Expand Down Expand Up @@ -1405,7 +1423,14 @@ int bpf_sk_splice5(struct __sk_buff *skb){
sockcheck.ipv4.dport = tproxy->port_mapping[port_key].tproxy_port;
if(!local_diag->per_interface){
if(tproxy->port_mapping[port_key].tproxy_port == 0){
return TC_ACT_OK;
if(!local_diag->ddos_filtering){
return TC_ACT_OK;
}
else{
if(get_ddos_list(tuple->ipv4.saddr)){
return TC_ACT_OK;
}
}
}
if(!local_diag->tun_mode){
sk = get_sk(key, skb, sockcheck);
Expand Down Expand Up @@ -1454,7 +1479,14 @@ int bpf_sk_splice5(struct __sk_buff *skb){
for(int x = 0; x < MAX_IF_LIST_ENTRIES; x++){
if(tproxy->port_mapping[port_key].if_list[x] == skb->ifindex){
if(tproxy->port_mapping[port_key].tproxy_port == 0){
return TC_ACT_OK;
if(!local_diag->ddos_filtering){
return TC_ACT_OK;
}
else{
if(get_ddos_list(tuple->ipv4.saddr)){
return TC_ACT_OK;
}
}
}
if(!local_diag->tun_mode){
sk = get_sk(key, skb, sockcheck);
Expand Down
1 change: 1 addition & 0 deletions src/zfw_tc_outbound_track.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ struct diag_ip4 {
bool tun_mode;
bool vrrp;
bool eapol;
bool ddos_filtering;
};

//map to keep status of diagnostic rules
Expand Down
Loading