diff --git a/CHANGELOG.md b/CHANGELOG.md index e7cf5d1..ad5b35b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,25 @@ 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.3] - 2024-07-04 + +### + +- Added ability to apply outbound IPv4 and IPv6 filters to an interface. The default is set to no + filtering but outbound tracking of passthrough client traffic when afw_tc_outbound_track.o is applied. + Outbound filtering is enabled by ```sudo zfw -b, --outbound_filter ``` + +- Fixed issue where if ingress filtering enabled on loopback + interface IPv6 was not enabled by default + +- Fixed an issue where udp inbound initiated connections were disconnected for some ipv4 sockets + when passing through to the local OS. + +- Hardened zfw_tunnel_wrapper.c around the currently incorrect ipv6 event channel IP info. + Also fixed invalid strlen() calc. + +- Fixed issue where alt interface names could not be used. + # [0.8.2] - 2024-07-01 ### diff --git a/README.md b/README.md index fd90780..8705914 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,76 @@ filtering. It can be used in conjunction with ufw's masquerade feature on a Wan the zfw_outbound_track.o is activated in the egress direction. It can also be used in conjunction with OpenZiti edge-routers. -## New features - Initial support for ipv6 +## New features - + +### Outbound filtering +- This new feature is currently meant ot be used in stand alone FW mode (No OpenZiti). + See note in section ```User space manual configuration``` which briefly describes installing + zfw without OpenZiti. + + The feature allows for both IPv4 and IPv6 ingress/egress filters on a single external interface. i.e. + This mode maintains state for outbound traffic associated with traffic allowed by ingress filters so + there is no need to statically configure high port ranges for return traffic. The assumption is + if you enable inbound ports you want to allow the stateful reply packets for udp and tcp. + +``` +i.e. set /opt/openziti/etc/ebpf_config.json as below changing interface name only + + {"InternalInterfaces":[], "ExternalInterfaces":[{"Name":"ens33", "PerInterfaceRules": false}]} + + or equivalent InternalInterfaces config: + + {"InternalInterfaces":[{"Name":"ens33", "OutboundPassThroughTrack": true}], + "ExternalInterfaces":[]} +``` +Then in executable script file ```/opt/openziti/bin/user/user_rules.sh``` +``` +#!/bin/bash + +# enable outbound filtering (Can be set before or after egress rule entry) +# If set before DNS rules some systems command response might be slow till +# a DNS egress rule is entered + +sudo /opt/openziti/bin/zfw --outbound-filter ens33 + +#example outbound rules set by adding -z, --direction egress +#ipv4 +sudo /opt/openziti/bin/zfw -I -c 0.0.0.0 -m 0 -l 53 -h 53 -t 0 -p udp --direction egress +sudo /opt/openziti/bin/zfw -I -c 172.16.240.139 -m 32 -l 5201 -h 5201 -t 0 -p tcp -z egress +sudo /opt/openziti/bin/zfw -I -c 172.16.240.139 -m 32 -l 5201 -h 5201 -t 0 -p udp --direction egress + +#ipv6 +sudo /opt/openziti/bin/zfw -6 ens33 #enables ipv6 +sudo /opt/openziti/bin/zfw -I -c 2001:db8::2 -m 32 -l 5201 -h 5201 -t 0 -p tcp -z egress +sudo /opt/openziti/bin/zfw -I -c 2001:db8::2 -m 32 -l 5201 -h 5201 -t 0 -p udp --direction egress + +#inbound rules +sudo /opt/openziti/bin/zfw -I -c 172.16.240.0 -m 24 -l 22 -h 22 -t 0 -p tcp +``` + +- To view ipv4 egress rules: ```sudo zfw -L -z egress``` + +``` +EGRESS FILTERS: +service id proto origin destination mapping: interface list +---------------------- ----- ----------------- ------------------ ------------------------------------------------------- ----------------- +0000000000000000000000 udp 0.0.0.0/0 172.16.240.139/32 dpts=5201:5201 PASSTHRU to 172.16.240.139/32 [] +0000000000000000000000 tcp 0.0.0.0/0 172.16.240.139/32 dpts=5201:5201 PASSTHRU to 172.16.240.139/32 [] + +``` + +- To view ipv6 egress rules: ```sudo zfw -L -6 all -z egress``` + +``` +EGRESS FILTERS: +service id proto origin destination mapping: interface list +---------------------- ----- ------------------------------------------ ------------------------------------------ ------------------------- -------------- +0000000000000000000000|tcp |::/0 |2001:db8::2/32 | dpts=5201:5201 PASSTHRU | [] +0000000000000000000000|udp |::/0 |2001:db8::2/32 | dpts=5201:5201 PASSTHRU | [] + +``` + +### Initial support for ipv6 - *Enabled via ```sudo zfw -6 ``` Note: Router discovery / DHCPv6 are always enabled even if ipv6 is disabled in order to ensure the ifindex_ip6_map gets populated. - Supports ipv6 neighbor discovery (redirects not supported) @@ -348,8 +417,14 @@ with listening ports in the config.yml. ### ssh default operation By default ssh is enabled to pass through to the ip address of the attached interface from any source. If secondary addresses exist on the interface this will only work for the first 10. After that you would need -to add manual entries via ```zfw -I```. +to add manual entries via ```zfw -I```. +NOTE: **For environments where the IP will change it is highly recommended that a manual ssh rule is entered in /opt/openziti/bin/user_rules.sh with an entry for the entire subnet. e.g if subnet is 192.168.1.0/24 or you will lose ssh access to the system till system restart** +``` +#!/bin/bash +sudo /opt/openziti/bin/zfw -I -c 192.168.1.0 -m 24 -l 22 -h 22 -t 0 -p tcp +``` + The following command will disable default ssh action to pass to the IP addresses of the local interface and will fall through to rule check instead where a more specific rule could be applied. This is a per interface setting and can be set for all interfaces except loopback. This would need to be put in diff --git a/src/install.sh b/src/install.sh index b07f5d5..a8164f7 100755 --- a/src/install.sh +++ b/src/install.sh @@ -7,7 +7,7 @@ if [ $# -lt 1 ]; then fi if [ $1 == "router" ] then - if [ ! -d "/opt/openziti/bin" ] + if [ ! -d "/opt/openziti/bin/user" ] then mkdir -p /opt/openziti/bin/user fi diff --git a/src/zfw.c b/src/zfw.c index 1b97a1e..0b12366 100644 --- a/src/zfw.c +++ b/src/zfw.c @@ -75,6 +75,18 @@ #define CLIENT_FINAL_ACK_RCVD 11 #define CLIENT_INITIATED_UDP_SESSION 12 #define ICMP_INNER_IP_HEADER_TOO_BIG 13 +#define INGRESS_INITIATED_UDP_SESSION 14 +#define INGRESS_UDP_MATCHED_EXPIRED_STATE 15 +#define INGRESS_UDP_MATCHED_ACTIVE_STATE 16 +#define INGRESS_CLIENT_SYN_RCVD 17 +#define INGRESS_CLIENT_FIN_RCVD 18 +#define INGRESS_CLIENT_RST_RCVD 19 +#define INGRESS_TCP_CONNECTION_ESTABLISHED 20 +#define INGRESS_CLIENT_FINAL_ACK_RCVD 21 +#define INGRESS_SERVER_SYN_ACK_RCVD 22 +#define INGRESS_SERVER_FIN_RCVD 23 +#define INGRESS_SERVER_RST_RCVD 24 +#define INGRESS_SERVER_FINAL_ACK_RCVD 25 #define IP6_HEADER_TOO_BIG 30 #define IPV6_TUPLE_TOO_BIG 31 @@ -101,8 +113,10 @@ bool eapol = false; bool verbose = false; bool vrrp = false; bool per_interface = false; +bool outbound = false; bool interface = false; bool disable = false; +bool egress = false; bool all_interface = false; bool ssh_disable = false; bool tc = false; @@ -153,10 +167,16 @@ union bpf_attr rb_map; int rb_fd = -1; union bpf_attr tp_ext_map; int tp_ext_fd = -1; +union bpf_attr egress_ext_map; +int egress_ext_fd = -1; union bpf_attr if_list_ext_map; int if_list_ext_fd = -1; +union bpf_attr egress_if_list_ext_map; +int egress_if_list_ext_fd = -1; union bpf_attr range_map; int range_fd = -1; +union bpf_attr egress_range_map; +int egress_range_fd = -1; const char *tproxy_map_path = "/sys/fs/bpf/tc/globals/zt_tproxy_map"; const char *tproxy6_map_path = "/sys/fs/bpf/tc/globals/zt_tproxy6_map"; @@ -167,8 +187,12 @@ const char *if_map_path = "/sys/fs/bpf/tc/globals/ifindex_ip_map"; const char *if6_map_path = "/sys/fs/bpf/tc/globals/ifindex_ip6_map"; const char *matched6_map_path ="/sys/fs/bpf/tc/globals/matched6_map"; const char *matched_map_path = "/sys/fs/bpf/tc//globals/matched_map"; +const char *egress_matched6_map_path ="/sys/fs/bpf/tc/globals/egress_matched6_map"; +const char *egress_matched_map_path = "/sys/fs/bpf/tc//globals/egress_matched_map"; const char *tcp_map_path = "/sys/fs/bpf/tc/globals/tcp_map"; +const char *tcp_ingress_map_path = "/sys/fs/bpf/tc/globals/tcp_ingress_map"; const char *udp_map_path = "/sys/fs/bpf/tc/globals/udp_map"; +const char *udp_ingress_map_path = "/sys/fs/bpf/tc/globals/udp_ingress_map"; 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"; @@ -180,6 +204,14 @@ const char *tp_ext_map_path = "/sys/fs/bpf/tc/globals/tproxy_extension_map"; const char *if_list_ext_map_path = "/sys/fs/bpf/tc/globals/if_list_extension_map"; const char *wildcard_port_map_path = "/sys/fs/bpf/tc/globals/wildcard_port_map"; const char *range_map_path = "/sys/fs/bpf/tc/globals/range_map"; +const char *egress_range_map_path = "/sys/fs/bpf/tc/globals/egress_range_map"; +const char *egress_if_list_ext_map_path = "/sys/fs/bpf/tc/globals/egress_if_list_extension_map"; +const char *egress_ext_map_path = "/sys/fs/bpf/tc/globals/egress_extension_map"; +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"; + char doc[] = "zfw -- ebpf firewall configuration tool"; const char *if_map_path; char *diag_interface; @@ -191,14 +223,16 @@ char *prefix_interface; char *tun_interface; char *vrrp_interface; char *ddos_interface; +char *outbound_interface; char *monitor_interface; char *ipv6_interface; char *tc_interface; char *log_file_name; char *object_file; char *direction_string; +char check_alt[IF_NAMESIZE]; -const char *argp_program_version = "0.8.2"; +const char *argp_program_version = "0.8.3"; struct ring_buffer *ring_buffer; __u32 if_list[MAX_IF_LIST_ENTRIES]; @@ -252,10 +286,13 @@ void open_if_map(); void open_if6_map(); void open_rb_map(); void open_tun_map(); +void open_egress_range_map(); void open_ddos_saddr_map(); void open_ddos_dport_map(); void open_tproxy_ext_map(); +void open_egress_ext_map(); void open_if_list_ext_map(); +void open_egress_if_list_ext_map(); void map_insert6(); void map_delete6(); void map_insert(); @@ -341,6 +378,7 @@ struct diag_ip4 bool eapol; bool ddos_filtering; bool ipv6_enable; + bool outbound_filter; }; struct tproxy_tuple @@ -497,7 +535,7 @@ void set_tc_filter(char *action) if (!strcmp(action, "add")) { set_tc(action); - for (int x = 0; x < 6; x++) + for (int x = 0; x < 7; x++) { char prio[10]; sprintf(prio, "%d", x + 1); @@ -505,14 +543,9 @@ void set_tc_filter(char *action) if (x == 0) { sprintf(section, "action"); - ; } else { - if (!strcmp(direction_string, "egress")) - { - break; - } sprintf(section, "action/%d", x); } char *const parmList[] = {"/usr/sbin/tc", "filter", action, "dev", tc_interface, direction_string, "prio", prio, "bpf", @@ -565,11 +598,14 @@ void disable_ebpf() disable = true; tc = true; interface_tc(); - const char *maps[22] = {tproxy_map_path, diag_map_path, if_map_path, count_map_path, + const char *maps[33] = {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}; - for (int map_count = 0; map_count < 22; map_count++) + 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++) { int stat = remove(maps[map_count]); @@ -724,14 +760,26 @@ void print_rule6(struct tproxy6_key *key, struct tproxy_tuple *tuple, int *rule_ { open_tproxy_ext_map(); } + if (egress_ext_fd == -1) + { + open_egress_ext_map(); + } if (if_list_ext_fd == -1) { open_if_list_ext_map(); } + if (egress_if_list_ext_fd == -1) + { + open_egress_if_list_ext_map(); + } if (range_fd == -1) { open_range_map(); } + if (egress_range_fd == -1) + { + open_egress_range_map(); + } uint32_t tun_key = 0; struct ifindex_tun o_tunif; tun_map.map_fd = tun_fd; @@ -762,21 +810,39 @@ void print_rule6(struct tproxy6_key *key, struct tproxy_tuple *tuple, int *rule_ { proto = "unknown"; } + union bpf_attr *if_list_map = NULL; + union bpf_attr *ext_map = NULL; + union bpf_attr *port_range_map = NULL; + if(!egress){ + ext_map = &tp_ext_map; + ext_map->map_fd = tp_ext_fd; + if_list_map = &if_list_ext_map; + if_list_map->map_fd = if_list_ext_fd; + port_range_map = &range_map; + port_range_map->map_fd = range_fd; + }else{ + ext_map = &egress_ext_map; + ext_map->map_fd = egress_ext_fd; + if_list_map = &egress_if_list_ext_map; + if_list_map->map_fd = egress_if_list_ext_fd; + port_range_map = &egress_range_map; + port_range_map->map_fd = egress_range_fd; + } struct tproxy_extension_key ext_key = {0}; - tp_ext_map.key = (uint64_t)&ext_key; + ext_map->key = (uint64_t)&ext_key; struct tproxy_extension_mapping ext_value; - tp_ext_map.value = (uint64_t)&ext_value; - tp_ext_map.map_fd = tp_ext_fd; - tp_ext_map.flags = BPF_ANY; + ext_map->value = (uint64_t)&ext_value; + + ext_map->flags = BPF_ANY; ext_key.protocol = key->protocol; ext_key.pad = 0; struct port_extension_key port_ext_key = {0}; - if_list_ext_map.key = (uint64_t)&port_ext_key; + if_list_map->key = (uint64_t)&port_ext_key; struct if_list_extension_mapping if_ext_value; - if_list_ext_map.value = (uint64_t)&if_ext_value; - if_list_ext_map.map_fd = if_list_ext_fd; - if_list_ext_map.flags = BPF_ANY; + if_list_map->value = (uint64_t)&if_ext_value; + if_list_map->flags = BPF_ANY; + memcpy(port_ext_key.__in46_u_dst.ip6, key->dst_ip, sizeof(key->dst_ip)); memcpy(port_ext_key.__in46_u_src.ip6, key->src_ip, sizeof(key->src_ip)); port_ext_key.dprefix_len = key->dprefix_len; @@ -797,37 +863,37 @@ void print_rule6(struct tproxy6_key *key, struct tproxy_tuple *tuple, int *rule_ sprintf(scidr_block, "%s/%d", saddr6, key->sprefix_len); char dpts[17]; int x = 0; - range_map.key = (uint64_t)&port_ext_key; + + port_range_map->key = (uint64_t)&port_ext_key; struct range_mapping range_value; - range_map.value = (uint64_t)&range_value; - range_map.map_fd = range_fd; - range_map.flags = BPF_ANY; + port_range_map->value = (uint64_t)&range_value; + port_range_map->flags = BPF_ANY; for (; x < tuple->index_len; x++) { __u16 port_key = tuple->index_table[x]; port_ext_key.low_port = port_key; - int range_lookup = syscall(__NR_bpf, BPF_MAP_LOOKUP_ELEM, &range_map, sizeof(range_map)); + int range_lookup = syscall(__NR_bpf, BPF_MAP_LOOKUP_ELEM, port_range_map, sizeof(*port_range_map)); ext_key.tproxy_port = range_value.tproxy_port; - int tp_ext_lookup = syscall(__NR_bpf, BPF_MAP_LOOKUP_ELEM, &tp_ext_map, sizeof(tp_ext_map)); + int ext_lookup = syscall(__NR_bpf, BPF_MAP_LOOKUP_ELEM, ext_map, sizeof(*ext_map)); if (!range_lookup) { sprintf(dpts, "dpts=%d:%d", ntohs(port_key), ntohs(range_value.high_port)); - int if_ext_lookup = syscall(__NR_bpf, BPF_MAP_LOOKUP_ELEM, &if_list_ext_map, sizeof(if_list_ext_map)); + int if_ext_lookup = syscall(__NR_bpf, BPF_MAP_LOOKUP_ELEM, if_list_map, sizeof(*if_list_map)); if (intercept && !passthru) { bool entry_exists = false; if (tun_mode && (ntohs(range_value.tproxy_port) > 0)) { - printf("%-22s|%-5s|%-42s|%-42s | %-17sTU:%-5s | ", tp_ext_lookup ? "" : ext_value.service_id, proto, scidr_block, dcidr_block, + printf("%-22s|%-5s|%-42s|%-42s | %-17sTU:%-5s | ", ext_lookup ? "" : ext_value.service_id, proto, scidr_block, dcidr_block, dpts, o_tunif.ifname); entry_exists = true; *rule_count += 1; } else if (ntohs(range_value.tproxy_port) > 0) { - printf("%-22s|%-5s|%-42s|%-42s | %-17sTP:%-5d | ", tp_ext_lookup ? "" : ext_value.service_id, proto, scidr_block, dcidr_block, + printf("%-22s|%-5s|%-42s|%-42s | %-17sTP:%-5d | ", ext_lookup ? "" : ext_value.service_id, proto, scidr_block, dcidr_block, dpts, ntohs(range_value.tproxy_port)); entry_exists = true; *rule_count += 1; @@ -866,7 +932,7 @@ void print_rule6(struct tproxy6_key *key, struct tproxy_tuple *tuple, int *rule_ { if (ntohs(range_value.tproxy_port) == 0) { - printf("%-22s|%-5s|%-42s|%-42s | %-17s%-5s | ", tp_ext_lookup ? "" : ext_value.service_id, proto, scidr_block, dcidr_block, + printf("%-22s|%-5s|%-42s|%-42s | %-17s%-5s | ", ext_lookup ? "" : ext_value.service_id, proto, scidr_block, dcidr_block, dpts, "PASSTHRU"); char interfaces[IF_NAMESIZE * MAX_IF_LIST_ENTRIES + 8] = ""; if (!if_ext_lookup) @@ -902,17 +968,17 @@ void print_rule6(struct tproxy6_key *key, struct tproxy_tuple *tuple, int *rule_ { if (tun_mode && (ntohs(range_value.tproxy_port) > 0)) { - printf("%-22s|%-5s|%-42s|%-42s | %-17sTU:%-5s | ", tp_ext_lookup ? "" : ext_value.service_id, proto, scidr_block, dcidr_block, + printf("%-22s|%-5s|%-42s|%-42s | %-17sTU:%-5s | ", ext_lookup ? "" : ext_value.service_id, proto, scidr_block, dcidr_block, dpts, o_tunif.ifname); } else if (ntohs(range_value.tproxy_port) > 0) { - printf("%-22s|%-5s|%-42s|%-42s | %-17sTP:%-5d | ", tp_ext_lookup ? "" : ext_value.service_id, proto, scidr_block, dcidr_block, + printf("%-22s|%-5s|%-42s|%-42s | %-17sTP:%-5d | ", ext_lookup ? "" : ext_value.service_id, proto, scidr_block, dcidr_block, dpts, ntohs(range_value.tproxy_port)); } else { - printf("%-22s|%-5s|%-42s|%-42s | %-17s%-5s | ", tp_ext_lookup ? "" : ext_value.service_id, proto, scidr_block, dcidr_block, + printf("%-22s|%-5s|%-42s|%-42s | %-17s%-5s | ", ext_lookup ? "" : ext_value.service_id, proto, scidr_block, dcidr_block, dpts, "PASSTHRU"); } char interfaces[IF_NAMESIZE * MAX_IF_LIST_ENTRIES + 8] = ""; @@ -962,14 +1028,27 @@ void print_rule(struct tproxy_key *key, struct tproxy_tuple *tuple, int *rule_co { open_tproxy_ext_map(); } + if (egress_ext_fd == -1) + { + open_egress_ext_map(); + } if (if_list_ext_fd == -1) { open_if_list_ext_map(); } + if (egress_if_list_ext_fd == -1) + { + open_egress_if_list_ext_map(); + } if (range_fd == -1) { open_range_map(); } + if (egress_range_fd == -1) + { + open_egress_range_map(); + } + uint32_t tun_key = 0; struct ifindex_tun o_tunif; tun_map.map_fd = tun_fd; @@ -1008,60 +1087,77 @@ void print_rule(struct tproxy_key *key, struct tproxy_tuple *tuple, int *rule_co sprintf(scidr_block, "%s/%d", sprefix, key->sprefix_len); char *dpts = malloc(17); int x = 0; - + + union bpf_attr *if_list_map = NULL; + union bpf_attr *ext_map = NULL; + union bpf_attr *port_range_map = NULL; + if(!egress){ + ext_map = &tp_ext_map; + ext_map->map_fd = tp_ext_fd; + if_list_map = &if_list_ext_map; + if_list_map->map_fd = if_list_ext_fd; + port_range_map = &range_map; + port_range_map->map_fd = range_fd; + }else{ + ext_map = &egress_ext_map; + ext_map->map_fd = egress_ext_fd; + if_list_map = &egress_if_list_ext_map; + if_list_map->map_fd = egress_if_list_ext_fd; + port_range_map = &egress_range_map; + port_range_map->map_fd = egress_range_fd; + } struct tproxy_extension_key ext_key = {0}; - tp_ext_map.key = (uint64_t)&ext_key; + ext_map->key = (uint64_t)&ext_key; struct tproxy_extension_mapping ext_value; - tp_ext_map.value = (uint64_t)&ext_value; - tp_ext_map.map_fd = tp_ext_fd; - tp_ext_map.flags = BPF_ANY; + ext_map->value = (uint64_t)&ext_value; + ext_map->flags = BPF_ANY; ext_key.protocol = key->protocol; ext_key.pad = 0; + struct port_extension_key port_ext_key = {0}; - if_list_ext_map.key = (uint64_t)&port_ext_key; + if_list_map->key = (uint64_t)&port_ext_key; struct if_list_extension_mapping if_ext_value; - if_list_ext_map.value = (uint64_t)&if_ext_value; - if_list_ext_map.map_fd = if_list_ext_fd; - if_list_ext_map.flags = BPF_ANY; + if_list_map->value = (uint64_t)&if_ext_value; + if_list_map->flags = BPF_ANY; + port_ext_key.__in46_u_dst.ip = key->dst_ip; port_ext_key.__in46_u_src.ip = key->src_ip; port_ext_key.dprefix_len = key->dprefix_len; port_ext_key.sprefix_len = key->sprefix_len; port_ext_key.protocol = key->protocol; port_ext_key.pad = 0; + port_range_map->key = (uint64_t)&port_ext_key; - range_map.key = (uint64_t)&port_ext_key; struct range_mapping range_value; - range_map.value = (uint64_t)&range_value; - range_map.map_fd = range_fd; - range_map.flags = BPF_ANY; + port_range_map->value = (uint64_t)&range_value; + port_range_map->flags = BPF_ANY; for (; x < tuple->index_len; x++) { __u16 port_key = tuple->index_table[x]; port_ext_key.low_port = port_key; - int range_lookup = syscall(__NR_bpf, BPF_MAP_LOOKUP_ELEM, &range_map, sizeof(range_map)); + int range_lookup = syscall(__NR_bpf, BPF_MAP_LOOKUP_ELEM, port_range_map, sizeof(*port_range_map)); ext_key.tproxy_port = range_value.tproxy_port; - int tp_ext_lookup = syscall(__NR_bpf, BPF_MAP_LOOKUP_ELEM, &tp_ext_map, sizeof(tp_ext_map)); + int ext_lookup = syscall(__NR_bpf, BPF_MAP_LOOKUP_ELEM, ext_map, sizeof(*ext_map)); if (!range_lookup) { sprintf(dpts, "dpts=%d:%d", ntohs(port_key), ntohs(range_value.high_port)); - int if_ext_lookup = syscall(__NR_bpf, BPF_MAP_LOOKUP_ELEM, &if_list_ext_map, sizeof(if_list_ext_map)); + int if_ext_lookup = syscall(__NR_bpf, BPF_MAP_LOOKUP_ELEM, if_list_map, sizeof(*if_list_map)); if (intercept && !passthru) { bool entry_exists = false; if (tun_mode && (ntohs(range_value.tproxy_port) > 0)) { - printf("%-22s\t%-3s\t%-20s\t%-32s%-17s\tTUNMODE redirect:%-15s", tp_ext_lookup ? "?" : ext_value.service_id, proto, scidr_block, dcidr_block, + printf("%-22s\t%-3s\t%-20s\t%-32s%-17s\tTUNMODE redirect:%-15s", ext_lookup ? "?" : ext_value.service_id, proto, scidr_block, dcidr_block, dpts, o_tunif.ifname); entry_exists = true; *rule_count += 1; } else if (ntohs(range_value.tproxy_port) > 0) { - printf("%-22s\t%-3s\t%-20s\t%-32s%-17s\tTPROXY redirect 127.0.0.1:%-6d", tp_ext_lookup ? "?" : ext_value.service_id, proto, scidr_block, dcidr_block, + printf("%-22s\t%-3s\t%-20s\t%-32s%-17s\tTPROXY redirect 127.0.0.1:%-6d", ext_lookup ? "?" : ext_value.service_id, proto, scidr_block, dcidr_block, dpts, ntohs(range_value.tproxy_port)); entry_exists = true; *rule_count += 1; @@ -1098,7 +1194,7 @@ void print_rule(struct tproxy_key *key, struct tproxy_tuple *tuple, int *rule_co { if (ntohs(range_value.tproxy_port) == 0) { - printf("%-22s\t%-3s\t%-20s\t%-32s%-17s\t%s to %-20s", tp_ext_lookup ? "?" : ext_value.service_id, proto, scidr_block, dcidr_block, + printf("%-22s\t%-3s\t%-20s\t%-32s%-17s\t%s to %-20s", ext_lookup ? "?" : ext_value.service_id, proto, scidr_block, dcidr_block, dpts, "PASSTHRU", dcidr_block); char interfaces[IF_NAMESIZE * MAX_IF_LIST_ENTRIES + 8] = ""; if (!if_ext_lookup) @@ -1134,17 +1230,17 @@ void print_rule(struct tproxy_key *key, struct tproxy_tuple *tuple, int *rule_co { if (tun_mode && (ntohs(range_value.tproxy_port) > 0)) { - printf("%-22s\t%-3s\t%-20s\t%-32s%-17s\tTUNMODE redirect:%-15s", tp_ext_lookup ? "?" : ext_value.service_id, proto, scidr_block, dcidr_block, + printf("%-22s\t%-3s\t%-20s\t%-32s%-17s\tTUNMODE redirect:%-15s", ext_lookup ? "?" : ext_value.service_id, proto, scidr_block, dcidr_block, dpts, o_tunif.ifname); } else if (ntohs(range_value.tproxy_port) > 0) { - printf("%-22s\t%-3s\t%-20s\t%-32s%-17s\tTPROXY redirect 127.0.0.1:%-6d", tp_ext_lookup ? "?" : ext_value.service_id, proto, scidr_block, dcidr_block, + printf("%-22s\t%-3s\t%-20s\t%-32s%-17s\tTPROXY redirect 127.0.0.1:%-6d", ext_lookup ? "?" : ext_value.service_id, proto, scidr_block, dcidr_block, dpts, ntohs(range_value.tproxy_port)); } else { - printf("%-22s\t%-3s\t%-20s\t%-32s%-17s\t%s to %-20s", tp_ext_lookup ? "" : ext_value.service_id, proto, scidr_block, dcidr_block, + printf("%-22s\t%-3s\t%-20s\t%-32s%-17s\t%s to %-20s", ext_lookup ? "" : ext_value.service_id, proto, scidr_block, dcidr_block, dpts, "PASSTHRU", dcidr_block); } char interfaces[IF_NAMESIZE * MAX_IF_LIST_ENTRIES + 8] = ""; @@ -1459,6 +1555,7 @@ bool set_diag(uint32_t *idx) printf("icmp echo is always set to 1 for lo\n"); } } + if (v6) { if (!disable || *idx == 1) @@ -1533,6 +1630,25 @@ bool set_diag(uint32_t *idx) printf("Set disable_ssh is always set to 0 for lo\n"); } } + if (outbound) + { + if (!disable && *idx != 1) + { + o_diag.outbound_filter = true; + } + else + { + o_diag.outbound_filter = false; + } + if (*idx != 1) + { + printf("Set outbound_filter to %d for %s\n", !disable, outbound_interface); + } + else + { + printf("Set outbound_filter is always set to 0 for lo\n"); + } + } if (tcfilter && !strcmp("ingress", direction_string)) { if (!disable) @@ -1615,6 +1731,7 @@ bool set_diag(uint32_t *idx) } printf("%-24s:%d\n", "verbose", o_diag.verbose); printf("%-24s:%d\n", "ssh disable", o_diag.ssh_disable); + printf("%-24s:%d\n", "outbound_filter", o_diag.outbound_filter); printf("%-24s:%d\n", "per interface", o_diag.per_interface); printf("%-24s:%d\n", "tc ingress filter", o_diag.tc_ingress); printf("%-24s:%d\n", "tc egress filter", o_diag.tc_egress); @@ -1786,8 +1903,9 @@ void interface_diag() eapol_interface = address->ifa_name; ddos_interface = address->ifa_name; ipv6_interface = address->ifa_name; + outbound_interface = address->ifa_name; } - if (!strncmp(address->ifa_name, "ziti", 4) && (tun || per_interface || ssh_disable || echo || vrrp || eapol || ddos || v6)) + if (!strncmp(address->ifa_name, "ziti", 4) && (tun || per_interface || ssh_disable || echo || vrrp || eapol || ddos || v6 || outbound)) { if (per_interface && !strncmp(prefix_interface, "ziti", 4)) { @@ -1821,6 +1939,10 @@ void interface_diag() { printf("%s:zfw does not allow setting on ziti tun interfaces!\n", address->ifa_name); } + if (outbound && !strncmp(outbound_interface, "ziti", 4)) + { + printf("%s:zfw does not allow setting on ziti tun interfaces!\n", address->ifa_name); + } address = address->ifa_next; continue; } @@ -1832,6 +1954,14 @@ void interface_diag() } } + if (outbound) + { + if (!strcmp(outbound_interface, address->ifa_name)) + { + set_diag(&idx); + } + } + if (vrrp) { if (!strcmp(vrrp_interface, address->ifa_name)) @@ -2819,6 +2949,48 @@ static int process_events(void *ctx, void *data, size_t len) { state = "CLIENT_INITIATED_UDP_SESSION"; } + else if (code == INGRESS_INITIATED_UDP_SESSION) + { + state = "INGRESS_INITIATED_UDP_SESSION"; + } + else if (code == INGRESS_UDP_MATCHED_EXPIRED_STATE) + { + state = "INGRESS_UDP_MATCHED_EXPIRED_STATE"; + } + else if (code == INGRESS_UDP_MATCHED_ACTIVE_STATE) + { + state = "INGRESS_UDP_MATCHED_ACTIVE_STATE"; + } + else if (code == INGRESS_CLIENT_SYN_RCVD) + { + state = "INGRESS_CLIENT_SYN_RCVD"; + }else if (code == INGRESS_CLIENT_FIN_RCVD) + { + state = "INGRESS_CLIENT_FIN_RCVD"; + }else if (code == INGRESS_CLIENT_RST_RCVD) + { + state = "INGRESS_CLIENT_RST_RCVD"; + }else if (code == INGRESS_SERVER_RST_RCVD) + { + state = "INGRESS_SERVER_RST_RCVD"; + }else if (code == INGRESS_TCP_CONNECTION_ESTABLISHED) + { + state = "INGRESS_TCP_CONNECTION_ESTABLISHED"; + }else if (code == INGRESS_CLIENT_FINAL_ACK_RCVD) + { + state = "INGRESS_CLIENT_FINAL_ACK_RCVD"; + }else if (code == INGRESS_SERVER_SYN_ACK_RCVD) + { + state = "INGRESS_SERVER_SYN_ACK_RCVD"; + }else if (code == INGRESS_SERVER_FIN_RCVD) + { + state = "INGRESS_SERVER_FIN_RCVD"; + } + else if (code == INGRESS_SERVER_FINAL_ACK_RCVD) + { + state = "INGRESS_SERVER_FINAL_ACK_RCVD"; + } + if (state) { sprintf(message, "%s : %s : %s : %s :%s:%d > %s:%d outbound_tracking ---> %s\n", ts, ifname, @@ -3085,6 +3257,49 @@ static int process_events(void *ctx, void *data, size_t len) { state = "CLIENT_INITIATED_UDP_SESSION"; } + else if (code == INGRESS_INITIATED_UDP_SESSION) + { + state = "INGRESS_INITIATED_UDP_SESSION"; + } + else if (code == INGRESS_UDP_MATCHED_EXPIRED_STATE) + { + state = "INGRESS_UDP_MATCHED_EXPIRED_STATE"; + } + else if (code == INGRESS_UDP_MATCHED_ACTIVE_STATE) + { + state = "INGRESS_UDP_MATCHED_ACTIVE_STATE"; + } + else if (code == INGRESS_CLIENT_SYN_RCVD) + { + state = "INGRESS_CLIENT_SYN_RCVD"; + }else if (code == INGRESS_CLIENT_FIN_RCVD) + { + state = "INGRESS_CLIENT_FIN_RCVD"; + }else if (code == INGRESS_CLIENT_RST_RCVD) + { + state = "INGRESS_CLIENT_RST_RCVD"; + }else if (code == INGRESS_SERVER_RST_RCVD) + { + state = "INGRESS_SERVER_RST_RCVD"; + }else if (code == INGRESS_TCP_CONNECTION_ESTABLISHED) + { + state = "INGRESS_TCP_CONNECTION_ESTABLISHED"; + }else if (code == INGRESS_CLIENT_FINAL_ACK_RCVD) + { + state = "INGRESS_CLIENT_FINAL_ACK_RCVD"; + }else if (code == INGRESS_SERVER_SYN_ACK_RCVD) + { + state = "INGRESS_SERVER_SYN_ACK_RCVD"; + }else if (code == INGRESS_SERVER_FIN_RCVD) + { + state = "INGRESS_SERVER_FIN_RCVD"; + } + else if (code == INGRESS_SERVER_FINAL_ACK_RCVD) + { + state = "INGRESS_SERVER_FINAL_ACK_RCVD"; + } + + if (state) { sprintf(message, "%s : %s : %s : %s :%s:%d > %s:%d outbound_tracking ---> %s\n", ts, ifname, @@ -3133,10 +3348,21 @@ static int process_events(void *ctx, void *data, size_t len) void set_tp_ext_data(struct tproxy_extension_key key) { - if (tp_ext_fd == -1) + union bpf_attr map; + memset(&map, 0, sizeof(map)); + if(!egress){ + map.pathname = (uint64_t)tp_ext_map_path; + }else{ + map.pathname = (uint64_t)egress_ext_map_path; + } + map.bpf_fd = 0; + int fd = syscall(__NR_bpf, BPF_OBJ_GET, &map, sizeof(map)); + if (fd == -1) { - open_tproxy_ext_map(); + printf("BPF_OBJ_GET: %s\n", strerror(errno)); + close_maps(1); } + map.map_fd = fd; struct tproxy_extension_mapping ext_value = {0}; char *sid = "0000000000000000000000"; if (service) @@ -3147,23 +3373,34 @@ void set_tp_ext_data(struct tproxy_extension_key key) { memcpy(ext_value.service_id, sid, strlen(sid) + 1); } - tp_ext_map.key = (uint64_t)&key; - tp_ext_map.value = (uint64_t)&ext_value; - tp_ext_map.map_fd = tp_ext_fd; - tp_ext_map.flags = BPF_ANY; - int result = syscall(__NR_bpf, BPF_MAP_UPDATE_ELEM, &tp_ext_map, sizeof(tp_ext_map)); + map.key = (uint64_t)&key; + map.value = (uint64_t)&ext_value; + map.flags = BPF_ANY; + int result = syscall(__NR_bpf, BPF_MAP_UPDATE_ELEM, &map, sizeof(map)); if (result) { printf("MAP_UPDATE_ELEM_DATA: %s \n", strerror(errno)); } + close(fd); } void set_if_list_ext_data(struct port_extension_key key) { - if (if_list_ext_fd == -1) + union bpf_attr map; + memset(&map, 0, sizeof(map)); + if(!egress){ + map.pathname = (uint64_t)if_list_ext_map_path; + }else{ + map.pathname = (uint64_t)egress_if_list_ext_map_path; + } + map.bpf_fd = 0; + int fd = syscall(__NR_bpf, BPF_OBJ_GET, &map, sizeof(map)); + if (fd == -1) { - open_if_list_ext_map(); + printf("BPF_OBJ_GET: %s\n", strerror(errno)); + close_maps(1); } + map.map_fd = fd; struct if_list_extension_mapping ext_value = {0}; if (interface) { @@ -3172,36 +3409,46 @@ void set_if_list_ext_data(struct port_extension_key key) ext_value.if_list[x] = if_list[x]; } } - if_list_ext_map.key = (uint64_t)&key; - if_list_ext_map.value = (uint64_t)&ext_value; - if_list_ext_map.map_fd = if_list_ext_fd; - if_list_ext_map.flags = BPF_ANY; - int result = syscall(__NR_bpf, BPF_MAP_UPDATE_ELEM, &if_list_ext_map, sizeof(if_list_ext_map)); + map.key = (uint64_t)&key; + map.value = (uint64_t)&ext_value; + map.flags = BPF_ANY; + int result = syscall(__NR_bpf, BPF_MAP_UPDATE_ELEM, &map, sizeof(map)); if (result) { printf("MAP_UPDATE_ELEM_DATA: %s \n", strerror(errno)); } + close(fd); } void set_range(struct port_extension_key key) { - if (range_fd == -1) + union bpf_attr map; + memset(&map, 0, sizeof(map)); + if(!egress){ + map.pathname = (uint64_t)range_map_path; + }else{ + map.pathname = (uint64_t)egress_range_map_path; + } + map.bpf_fd = 0; + int fd = syscall(__NR_bpf, BPF_OBJ_GET, &map, sizeof(map)); + if (fd == -1) { - open_range_map(); + printf("BPF_OBJ_GET: %s\n", strerror(errno)); + close_maps(1); } - printf("Setting range\n"); - range_map.key = (uint64_t)&key; + map.map_fd = fd; + map.key = (uint64_t)&key; struct range_mapping range_ports = { htons(high_port), htons(tproxy_port)}; - range_map.value = (uint64_t)&range_ports; - range_map.map_fd = range_fd; - range_map.flags = BPF_ANY; - int result = syscall(__NR_bpf, BPF_MAP_UPDATE_ELEM, &range_map, sizeof(range_map)); + map.value = (uint64_t)&range_ports; + map.flags = BPF_ANY; + int result = syscall(__NR_bpf, BPF_MAP_UPDATE_ELEM, &map, sizeof(map)); if (result) { printf("MAP_UPDATE_ELEM_DATA: %s \n", strerror(errno)); } + close(fd); } void map_insert6() @@ -3231,7 +3478,11 @@ void map_insert6() struct tproxy_tuple *orule = (struct tproxy_tuple *)malloc(sizeof(struct tproxy_tuple)); memset(orule, 0, sizeof(struct tproxy_tuple)); /* set path name with location of map in filesystem */ - map.pathname = (uint64_t)tproxy6_map_path; + if(!egress){ + map.pathname = (uint64_t)tproxy6_map_path; + }else{ + map.pathname = (uint64_t)egress6_map_path; + } map.bpf_fd = 0; map.file_flags = 0; /* make system call to get fd for map */ @@ -3287,7 +3538,11 @@ void map_insert6() union bpf_attr count_map; memset(&count_map, 0, sizeof(count_map)); /* set path name with location of map in filesystem */ - count_map.pathname = (uint64_t)count6_map_path; + if(!egress){ + count_map.pathname = (uint64_t)count6_map_path; + }else{ + count_map.pathname = (uint64_t)egress_count6_map_path; + } count_map.bpf_fd = 0; count_map.file_flags = 0; /* make system call to get fd for map */ @@ -3370,7 +3625,7 @@ void map_insert() close_maps(1); } bool route_insert = false; - if (route) + if (route && !egress) { route_insert = interface_map(); } @@ -3389,7 +3644,11 @@ void map_insert() struct tproxy_tuple *orule = (struct tproxy_tuple *)malloc(sizeof(struct tproxy_tuple)); memset(orule, 0, sizeof(struct tproxy_tuple)); /* set path name with location of map in filesystem */ - map.pathname = (uint64_t)tproxy_map_path; + if(!egress){ + map.pathname = (uint64_t)tproxy_map_path; + }else{ + map.pathname = (uint64_t)egress_map_path; + } map.bpf_fd = 0; map.file_flags = 0; /* make system call to get fd for map */ @@ -3445,7 +3704,11 @@ void map_insert() union bpf_attr count_map; memset(&count_map, 0, sizeof(count_map)); /* set path name with location of map in filesystem */ - count_map.pathname = (uint64_t)count_map_path; + if(!egress){ + count_map.pathname = (uint64_t)count_map_path; + }else{ + count_map.pathname = (uint64_t)egress_count_map_path; + } count_map.bpf_fd = 0; count_map.file_flags = 0; /* make system call to get fd for map */ @@ -3550,7 +3813,11 @@ void if_list_ext_delete_key(struct port_extension_key key) { union bpf_attr map; memset(&map, 0, sizeof(map)); - map.pathname = (uint64_t)if_list_ext_map_path; + if(!egress){ + map.pathname = (uint64_t)if_list_ext_map_path; + }else{ + map.pathname = (uint64_t)egress_if_list_ext_map_path; + } map.bpf_fd = 0; int fd = syscall(__NR_bpf, BPF_OBJ_GET, &map, sizeof(map)); if (fd == -1) @@ -3573,7 +3840,11 @@ void range_delete_key(struct port_extension_key key) { union bpf_attr map; memset(&map, 0, sizeof(map)); - map.pathname = (uint64_t)range_map_path; + if(!egress){ + map.pathname = (uint64_t)range_map_path; + }else{ + map.pathname = (uint64_t)egress_range_map_path; + } map.bpf_fd = 0; int fd = syscall(__NR_bpf, BPF_OBJ_GET, &map, sizeof(map)); if (fd == -1) @@ -3628,7 +3899,11 @@ void tp_ext_delete_key(struct tproxy_extension_key key) { union bpf_attr map; memset(&map, 0, sizeof(map)); - map.pathname = (uint64_t)tp_ext_map_path; + if(!egress){ + map.pathname = (uint64_t)tp_ext_map_path; + }else{ + map.pathname = (uint64_t)egress_ext_map_path; + } map.bpf_fd = 0; int fd = syscall(__NR_bpf, BPF_OBJ_GET, &map, sizeof(map)); if (fd == -1) @@ -3678,7 +3953,11 @@ void map_delete6_key(struct tproxy6_key key) { union bpf_attr map; memset(&map, 0, sizeof(map)); - map.pathname = (uint64_t)tproxy6_map_path; + if(!egress){ + map.pathname = (uint64_t)tproxy6_map_path; + }else{ + map.pathname = (uint64_t)egress6_map_path; + } map.bpf_fd = 0; int fd = syscall(__NR_bpf, BPF_OBJ_GET, &map, sizeof(map)); if (fd == -1) @@ -3704,13 +3983,17 @@ void map_delete_key(struct tproxy_key key) dplen = key.dprefix_len; free(prefix); bool route_delete = false; - if (route) + if (route && !egress) { route_delete = interface_map(); } union bpf_attr map; memset(&map, 0, sizeof(map)); - map.pathname = (uint64_t)tproxy_map_path; + if(!egress){ + map.pathname = (uint64_t)tproxy_map_path; + }else{ + map.pathname = (uint64_t)egress_map_path; + } map.bpf_fd = 0; int fd = syscall(__NR_bpf, BPF_OBJ_GET, &map, sizeof(map)); if (fd == -1) @@ -3738,11 +4021,6 @@ void map_delete_key(struct tproxy_key key) void map_delete6() { - bool route_delete = false; - if (route) - { - route_delete = interface_map(); - } union bpf_attr map; memset(&map, 0, sizeof(map)); struct tproxy6_key *key = (struct tproxy6_key *)malloc(sizeof(struct tproxy6_key)); @@ -3755,7 +4033,11 @@ void map_delete6() key->pad = 0; struct tproxy_tuple *orule = (struct tproxy_tuple *)malloc(sizeof(struct tproxy_tuple)); memset(orule, 0, sizeof(struct tproxy_tuple)); - map.pathname = (uint64_t)tproxy6_map_path; + if(!egress){ + map.pathname = (uint64_t)tproxy6_map_path; + }else{ + map.pathname = (uint64_t)egress6_map_path; + } map.bpf_fd = 0; map.file_flags = 0; struct port_extension_key port_ext_key = {0}; @@ -3807,7 +4089,11 @@ void map_delete6() if (orule->index_len == 0) { memset(&map, 0, sizeof(map)); - map.pathname = (uint64_t)tproxy6_map_path; + if(!egress){ + map.pathname = (uint64_t)tproxy6_map_path; + }else{ + map.pathname = (uint64_t)egress6_map_path; + } map.bpf_fd = 0; int end_fd = syscall(__NR_bpf, BPF_OBJ_GET, &map, sizeof(map)); if (end_fd == -1) @@ -3835,7 +4121,11 @@ void map_delete6() union bpf_attr count_map; memset(&count_map, 0, sizeof(count_map)); /* set path name with location of map in filesystem */ - count_map.pathname = (uint64_t)count6_map_path; + if(!egress){ + count_map.pathname = (uint64_t)count6_map_path; + }else{ + count_map.pathname = (uint64_t)egress_count6_map_path; + } count_map.bpf_fd = 0; count_map.file_flags = 0; /* make system call to get fd for map */ @@ -3867,10 +4157,6 @@ void map_delete6() } close(count_fd); printf("Last Element: Hash Entry Deleted\n"); - if (route_delete) - { - unbind_prefix(&dcidr, dplen); - } close(end_fd); close(fd); free(orule); @@ -3903,7 +4189,7 @@ void map_delete6() void map_delete() { bool route_delete = false; - if (route) + if (route && !egress) { route_delete = interface_map(); } @@ -3919,7 +4205,12 @@ void map_delete() key->pad = 0; struct tproxy_tuple *orule = (struct tproxy_tuple *)malloc(sizeof(struct tproxy_tuple)); memset(orule, 0, sizeof(struct tproxy_tuple)); - map.pathname = (uint64_t)tproxy_map_path; + if(!egress){ + map.pathname = (uint64_t)tproxy_map_path; + } + else{ + map.pathname = (uint64_t)egress_map_path; + } map.bpf_fd = 0; map.file_flags = 0; struct port_extension_key port_ext_key = {0}; @@ -3971,7 +4262,11 @@ void map_delete() if (orule->index_len == 0) { memset(&map, 0, sizeof(map)); - map.pathname = (uint64_t)tproxy_map_path; + if(!egress){ + map.pathname = (uint64_t)tproxy_map_path; + }else{ + map.pathname = (uint64_t)egress_map_path; + } map.bpf_fd = 0; int end_fd = syscall(__NR_bpf, BPF_OBJ_GET, &map, sizeof(map)); if (end_fd == -1) @@ -3999,7 +4294,11 @@ void map_delete() union bpf_attr count_map; memset(&count_map, 0, sizeof(count_map)); /* set path name with location of map in filesystem */ - count_map.pathname = (uint64_t)count_map_path; + if(!egress){ + count_map.pathname = (uint64_t)count_map_path; + }else{ + count_map.pathname = (uint64_t)egress_count_map_path; + } count_map.bpf_fd = 0; count_map.file_flags = 0; /* make system call to get fd for map */ @@ -4235,7 +4534,11 @@ int flush6() struct tproxy_tuple orule; // Open BPF zt_tproxy_map map memset(&map, 0, sizeof(map)); - map.pathname = (uint64_t)tproxy6_map_path; + if(!egress){ + map.pathname = (uint64_t)tproxy6_map_path; + }else{ + map.pathname = (uint64_t)egress6_map_path; + } map.bpf_fd = 0; map.file_flags = 0; int fd = syscall(__NR_bpf, BPF_OBJ_GET, &map, sizeof(map)); @@ -4263,7 +4566,11 @@ int flush6() union bpf_attr count_map; memset(&count_map, 0, sizeof(count_map)); /* set path name with location of map in filesystem */ - count_map.pathname = (uint64_t)count6_map_path; + if(!egress){ + count_map.pathname = (uint64_t)count6_map_path; + }else{ + count_map.pathname = (uint64_t)egress_count6_map_path; + } count_map.bpf_fd = 0; count_map.file_flags = 0; /* make system call to get fd for map */ @@ -4302,7 +4609,11 @@ int flush4() struct tproxy_tuple orule; // Open BPF zt_tproxy_map map memset(&map, 0, sizeof(map)); - map.pathname = (uint64_t)tproxy_map_path; + if(!egress){ + map.pathname = (uint64_t)tproxy_map_path; + }else{ + map.pathname = (uint64_t)egress_map_path; + } map.bpf_fd = 0; map.file_flags = 0; int fd = syscall(__NR_bpf, BPF_OBJ_GET, &map, sizeof(map)); @@ -4330,7 +4641,11 @@ int flush4() union bpf_attr count_map; memset(&count_map, 0, sizeof(count_map)); /* set path name with location of map in filesystem */ - count_map.pathname = (uint64_t)count_map_path; + if(!egress){ + count_map.pathname = (uint64_t)count_map_path; + }else{ + count_map.pathname = (uint64_t)egress_count_map_path; + } count_map.bpf_fd = 0; count_map.file_flags = 0; /* make system call to get fd for map */ @@ -4654,7 +4969,11 @@ int get_key_count6() union bpf_attr count_map; memset(&count_map, 0, sizeof(count_map)); /* set path name with location of map in filesystem */ - count_map.pathname = (uint64_t)count6_map_path; + if(!egress){ + count_map.pathname = (uint64_t)count6_map_path; + }else{ + count_map.pathname = (uint64_t)egress_count6_map_path; + } count_map.bpf_fd = 0; count_map.file_flags = 0; /* make system call to get fd for map */ @@ -4683,7 +5002,11 @@ int get_key_count() union bpf_attr count_map; memset(&count_map, 0, sizeof(count_map)); /* set path name with location of map in filesystem */ - count_map.pathname = (uint64_t)count_map_path; + if(!egress){ + count_map.pathname = (uint64_t)count_map_path; + }else{ + count_map.pathname = (uint64_t)egress_count_map_path; + } count_map.bpf_fd = 0; count_map.file_flags = 0; /* make system call to get fd for map */ @@ -4715,7 +5038,11 @@ void map_list_all6() struct tproxy6_key current_key; struct tproxy_tuple orule; memset(&map, 0, sizeof(map)); - map.pathname = (uint64_t)tproxy6_map_path; + if(!egress){ + map.pathname = (uint64_t)tproxy6_map_path; + }else{ + map.pathname = (uint64_t)egress6_map_path; + } map.bpf_fd = 0; map.file_flags = 0; int fd = syscall(__NR_bpf, BPF_OBJ_GET, &map, sizeof(map)); @@ -4729,6 +5056,11 @@ void map_list_all6() map.value = (uint64_t)&orule; int lookup = 0; int ret = 0; + if(!egress){ + printf("INGRESS FILTERS:\n"); + }else{ + printf("EGRESS FILTERS:\n"); + } printf("%-23s%-6s%-43s%-45s%-28s%s\n", "service id", "proto", "origin", "destination", "mapping:", "interface list"); printf("---------------------- ----- ------------------------------------------ ------------------------------------------ ------------------------- --------------\n"); int rule_count = 0; @@ -4765,7 +5097,11 @@ void map_list_all() struct tproxy_key current_key; struct tproxy_tuple orule; memset(&map, 0, sizeof(map)); - map.pathname = (uint64_t)tproxy_map_path; + if(!egress){ + map.pathname = (uint64_t)tproxy_map_path; + }else{ + map.pathname = (uint64_t)egress_map_path; + } map.bpf_fd = 0; map.file_flags = 0; int fd = syscall(__NR_bpf, BPF_OBJ_GET, &map, sizeof(map)); @@ -4779,6 +5115,11 @@ void map_list_all() map.value = (uint64_t)&orule; int lookup = 0; int ret = 0; + if(!egress){ + printf("INGRESS FILTERS:\n"); + }else{ + printf("EGRESS FILTERS:\n"); + } printf("%-22s\t%-3s\t%-20s\t%-32s%-24s\t\t\t\t%-31s\n", "service id", "proto", "origin", "destination", "mapping:", "interface list"); printf("----------------------\t-----\t-----------------\t------------------\t\t-------------------------------------------------------\t-----------------\n"); int rule_count = 0; @@ -4826,6 +5167,7 @@ static struct argp_option options[] = { {"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}, + {"outbound-filtering", 'b', "", 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 ", 0}, {"disable", 'd', NULL, 0, "Disable associated diag operation i.e. -e eth0 -d to disable inbound echo on eth0", 0}, @@ -4891,7 +5233,11 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) } else { - monitor_interface = arg; + if(if_indextoname(idx, check_alt)){ + monitor_interface = check_alt; + }else{ + monitor_interface = arg; + } } break; case 'N': @@ -4956,7 +5302,11 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) } else { - prefix_interface = arg; + if(if_indextoname(idx, check_alt)){ + prefix_interface = check_alt; + }else{ + prefix_interface = arg; + } } break; case 'Q': @@ -4982,7 +5332,11 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) } else { - vrrp_interface = arg; + if(if_indextoname(idx, check_alt)){ + vrrp_interface = check_alt; + }else{ + vrrp_interface = arg; + } } break; case 'T': @@ -5005,7 +5359,11 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) } else { - tun_interface = arg; + if(if_indextoname(idx, check_alt)){ + tun_interface = check_alt; + }else{ + tun_interface = arg; + } } break; case 'U': @@ -5041,7 +5399,11 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) } else { - tc_interface = arg; + if(if_indextoname(idx, check_alt)){ + tc_interface = check_alt; + }else{ + tc_interface = arg; + } } break; case 'Y': @@ -5067,7 +5429,38 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) } else { - ddos_interface = arg; + if(if_indextoname(idx, check_alt)){ + ddos_interface = check_alt; + }else{ + ddos_interface = arg; + } + } + break; + case 'b': + if (!strlen(arg) || (strchr(arg, '-') != NULL)) + { + fprintf(stderr, "Interface name or all required as arg to -b, --outbound-filtering: %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); + } + outbound = true; + if (!strcmp("all", arg)) + { + all_interface = true; + } + else + { + if(if_indextoname(idx, check_alt)){ + outbound_interface = check_alt; + }else{ + outbound_interface = arg; + } } break; case '6': @@ -5090,7 +5483,11 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) } else { - ipv6_interface = arg; + if(if_indextoname(idx, check_alt)){ + ipv6_interface = check_alt; + }else{ + ipv6_interface = arg; + } } break; case 'c': @@ -5129,7 +5526,11 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) } else { - echo_interface = arg; + if(if_indextoname(idx, check_alt)){ + echo_interface = check_alt; + }else{ + echo_interface = arg; + } } break; case 'd': @@ -5237,7 +5638,11 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) } else { - verbose_interface = arg; + if(if_indextoname(idx, check_alt)){ + verbose_interface = check_alt; + }else{ + verbose_interface = arg; + } } break; case 'w': @@ -5260,7 +5665,11 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) } else { - eapol_interface = arg; + if(if_indextoname(idx, check_alt)){ + eapol_interface = check_alt; + }else{ + eapol_interface = arg; + } } break; case 'x': @@ -5283,7 +5692,11 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) } else { - ssh_interface = arg; + if(if_indextoname(idx, check_alt)){ + ssh_interface = check_alt; + }else{ + ssh_interface = arg; + } } break; case 'y': @@ -5305,6 +5718,9 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) } direction = true; direction_string = arg; + if(!strcmp("egress", arg)){ + egress = true; + } break; default: return ARGP_ERR_UNKNOWN; @@ -5356,6 +5772,18 @@ void close_maps(int code) { close(range_fd); } + if (egress_range_fd != -1) + { + close(egress_range_fd); + } + if (egress_if_list_ext_fd != -1) + { + close(egress_if_list_ext_fd); + } + if (egress_ext_fd != -1) + { + close(egress_ext_fd); + } exit(code); } @@ -5422,6 +5850,20 @@ void open_range_map() } } +void open_egress_range_map() +{ + memset(&egress_range_map, 0, sizeof(egress_range_map)); + egress_range_map.pathname = (uint64_t)egress_range_map_path; + egress_range_map.bpf_fd = 0; + egress_range_map.file_flags = 0; + /* make system call to get fd for map */ + egress_range_fd = syscall(__NR_bpf, BPF_OBJ_GET, &egress_range_map, sizeof(egress_range_map)); + if (egress_range_fd == -1) + { + ebpf_usage(); + } +} + void open_ddos_dport_map() { memset(&ddos_dport_map, 0, sizeof(ddos_dport_map)); @@ -5451,6 +5893,21 @@ void open_tproxy_ext_map() } } +void open_egress_ext_map() +{ + memset(&egress_ext_map, 0, sizeof(egress_ext_map)); + /* set path name with location of map in filesystem */ + egress_ext_map.pathname = (uint64_t)egress_ext_map_path; + egress_ext_map.bpf_fd = 0; + egress_ext_map.file_flags = 0; + /* make system call to get fd for map */ + egress_ext_fd = syscall(__NR_bpf, BPF_OBJ_GET, &egress_ext_map, sizeof(egress_ext_map)); + if (egress_ext_fd == -1) + { + ebpf_usage(); + } +} + void open_if_list_ext_map() { memset(&if_list_ext_map, 0, sizeof(if_list_ext_map)); @@ -5466,6 +5923,21 @@ void open_if_list_ext_map() } } +void open_egress_if_list_ext_map() +{ + memset(&egress_if_list_ext_map, 0, sizeof(egress_if_list_ext_map)); + /* set path name with location of map in filesystem */ + egress_if_list_ext_map.pathname = (uint64_t)egress_if_list_ext_map_path; + egress_if_list_ext_map.bpf_fd = 0; + egress_if_list_ext_map.file_flags = 0; + /* make system call to get fd for map */ + egress_if_list_ext_fd = syscall(__NR_bpf, BPF_OBJ_GET, &egress_if_list_ext_map, sizeof(egress_if_list_ext_map)); + if (egress_if_list_ext_fd == -1) + { + ebpf_usage(); + } +} + void open_diag_map() { /*path to pinned ifindex_ip_map*/ @@ -5542,6 +6014,13 @@ void open_tun_map() } } +void egress_usage(){ + printf("No egress maps exist or not running as sudo!\n"); + printf("Ensure at least one interface has an egress filter enabled!\n"); + printf("e.g. sudo zfw -X ens33 -O /opt/openziti/bin/zfw_tc_outbound_track.o -z egress\n"); + close_maps(1); +} + int main(int argc, char **argv) { signal(SIGINT, INThandler); @@ -5553,6 +6032,10 @@ int main(int argc, char **argv) usage("-s, --service-id requires -I, --insert or -D, --delete"); } + if(list && flush){ + usage("-L, --list and -F, --flush not be used in combination call"); + } + if (tcfilter && !object && !disable) { usage("-X, --set-tc-filter requires -O, --object-file for add operation"); @@ -5693,14 +6176,15 @@ 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 && !ddos && !dsip && !ddport && !v6)) + if (disable && (!ssh_disable && !echo && !verbose && !per_interface && !tcfilter && !tun && !vrrp + && !eapol && !ddos && !dsip && !ddport && !v6 && !outbound)) { - usage("Missing argument at least one of -6,-e, -u, -v, -w, -x, -y, or -E, -P, -R, -T, -X"); + usage("Missing argument at least one of -a,-b,-6,-e, -u, -v, -w, -x, -y, or -E, -P, -R, -T, -X"); } - if (direction && !tcfilter) + if (direction && (!tcfilter && !list && !flush && !delete && !add)) { - usage("missing argument -z, --direction requires -X, --set-tc-filter"); + usage("missing argument -z, --direction requires -X, --set-tc-filter or -D, --delete or --I, --insert or -L, --list or -F, --flush"); } if (object && !tcfilter) @@ -5710,6 +6194,9 @@ int main(int argc, char **argv) if (add) { + if(egress && ((access(egress6_map_path, F_OK) != 0) || (access(egress_map_path, F_OK) != 0))){ + egress_usage(); + } if ((access(tproxy_map_path, F_OK) != 0) || (access(tproxy6_map_path, F_OK) != 0)) { ebpf_usage(); @@ -5776,16 +6263,25 @@ int main(int argc, char **argv) } if (cd6) { + if(egress && (tproxy_port != 0)){ + usage("-t, tproxy-port 0 is currently the only supported value in egress filters"); + } map_insert6(); } else { + if(egress && (tproxy_port != 0)){ + usage("-t, tproxy-port 0 is currently the only supported value in egress filters"); + } map_insert(); } } } else if (delete) { + if(egress && ((access(egress6_map_path, F_OK) != 0) || (access(egress_map_path, F_OK) != 0))){ + egress_usage(); + } if (access(tproxy_map_path, F_OK) != 0) { ebpf_usage(); @@ -5854,6 +6350,9 @@ int main(int argc, char **argv) } else if (flush) { + if(egress && ((access(egress6_map_path, F_OK) != 0) || (access(egress_map_path, F_OK) != 0))){ + egress_usage(); + } if (access(tproxy_map_path, F_OK) != 0) { ebpf_usage(); @@ -5862,6 +6361,9 @@ int main(int argc, char **argv) } else if (list) { + if(egress && ((access(egress6_map_path, F_OK) != 0) || (access(egress_map_path, F_OK) != 0))){ + egress_usage(); + } if ((access(tproxy_map_path, F_OK) != 0) || (access(tproxy6_map_path, F_OK) != 0) || (access(diag_map_path, F_OK) != 0)) { ebpf_usage(); @@ -5927,7 +6429,7 @@ int main(int argc, char **argv) map_list(); } } - else if (vrrp || verbose || ssh_disable || echo || per_interface || tun || eapol || ddos || v6) + else if (vrrp || verbose || ssh_disable || echo || per_interface || tun || eapol || ddos || v6 || outbound) { interface_diag(); } diff --git a/src/zfw_tc_ingress.c b/src/zfw_tc_ingress.c index ccd6a1a..b2d1481 100644 --- a/src/zfw_tc_ingress.c +++ b/src/zfw_tc_ingress.c @@ -32,42 +32,49 @@ #include #ifndef BPF_MAX_ENTRIES -#define BPF_MAX_ENTRIES 100 //MAX # PREFIXES +#define BPF_MAX_ENTRIES 100 //MAX # PREFIXES #endif #define BPF_MAX_RANGES 250000 -#define MAX_INDEX_ENTRIES 100 //MAX port ranges per prefix need to match in user space apps -#define MAX_TABLE_SIZE 65536 //needs to match in userspace -#define GENEVE_UDP_PORT 6081 -#define GENEVE_VER 0 -#define AWS_GNV_HDR_OPT_LEN 32 // Bytes -#define AWS_GNV_HDR_LEN 40 // Bytes -#define MATCHED_KEY_DEPTH 3 -#define MATCHED_INT_DEPTH 50 -#define MAX_IF_LIST_ENTRIES 3 -#define MAX_IF_ENTRIES 256 -#define SERVICE_ID_BYTES 32 -#define MAX_TRANSP_ROUTES 256 -#define BPF_MAX_SESSIONS 10000 -#define MAX_ADDRESSES 10 -#define IP_HEADER_TOO_BIG 1 -#define NO_IP_OPTIONS_ALLOWED 2 -#define UDP_HEADER_TOO_BIG 3 -#define GENEVE_HEADER_TOO_BIG 4 +#define MAX_INDEX_ENTRIES 100 //MAX port ranges per prefix need to match in user space apps +#define MAX_TABLE_SIZE 65536 //needs to match in userspace +#define GENEVE_UDP_PORT 6081 +#define GENEVE_VER 0 +#define AWS_GNV_HDR_OPT_LEN 32 // Bytes +#define AWS_GNV_HDR_LEN 40 // Bytes +#define MATCHED_KEY_DEPTH 3 +#define MATCHED_INT_DEPTH 50 +#define MAX_IF_LIST_ENTRIES 3 +#define MAX_IF_ENTRIES 256 +#define SERVICE_ID_BYTES 32 +#define MAX_TRANSP_ROUTES 256 +#define BPF_MAX_SESSIONS 65535 +#define BPF_MAX_TUN_SESSIONS 10000 +#define MAX_ADDRESSES 10 +#define IP_HEADER_TOO_BIG 1 +#define NO_IP_OPTIONS_ALLOWED 2 +#define UDP_HEADER_TOO_BIG 3 +#define GENEVE_HEADER_TOO_BIG 4 #define GENEVE_HEADER_LENGTH_VERSION_ERROR 5 -#define SKB_ADJUST_ERROR 6 -#define ICMP_HEADER_TOO_BIG 7 -#define IP_TUPLE_TOO_BIG 8 -#define IF_LIST_MATCH_ERROR 9 -#define INGRESS 0 -#define SERVER_SYN_ACK_RCVD 1 -#define SERVER_FIN_RCVD 2 -#define SERVER_RST_RCVD 3 -#define SERVER_FINAL_ACK_RCVD 4 -#define UDP_MATCHED_EXPIRED_STATE 5 -#define UDP_MATCHED_ACTIVE_STATE 6 -#define ICMP_INNER_IP_HEADER_TOO_BIG 13 -#define IP6_HEADER_TOO_BIG 30 -#define IPV6_TUPLE_TOO_BIG 31 +#define SKB_ADJUST_ERROR 6 +#define ICMP_HEADER_TOO_BIG 7 +#define IP_TUPLE_TOO_BIG 8 +#define IF_LIST_MATCH_ERROR 9 +#define INGRESS 0 +#define SERVER_SYN_ACK_RCVD 1 +#define SERVER_FIN_RCVD 2 +#define SERVER_RST_RCVD 3 +#define SERVER_FINAL_ACK_RCVD 4 +#define UDP_MATCHED_EXPIRED_STATE 5 +#define UDP_MATCHED_ACTIVE_STATE 6 +#define ICMP_INNER_IP_HEADER_TOO_BIG 13 +#define INGRESS_INITIATED_UDP_SESSION 14 +#define INGRESS_CLIENT_SYN_RCVD 17 +#define INGRESS_CLIENT_FIN_RCVD 18 +#define INGRESS_CLIENT_RST_RCVD 19 +#define INGRESS_TCP_CONNECTION_ESTABLISHED 20 +#define INGRESS_CLIENT_FINAL_ACK_RCVD 21 +#define IP6_HEADER_TOO_BIG 30 +#define IPV6_TUPLE_TOO_BIG 31 #ifndef memcpy #define memcpy(dest, src, n) __builtin_memcpy((dest), (src), (n)) #endif @@ -272,6 +279,7 @@ struct diag_ip4 { bool eapol; bool ddos_filtering; bool ipv6_enable; + bool outbound_filter; }; /*Value to tun_map*/ @@ -332,7 +340,7 @@ struct { __uint(pinning, LIBBPF_PIN_BY_NAME); } ddos_dport_map SEC(".maps"); -/*map to track up to 3 key matches per incoming packet search. Map is +/*map to track up to 3 key matches per incoming IPv4 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 5 ebpf programs */ @@ -503,6 +511,16 @@ struct { __uint(pinning, LIBBPF_PIN_BY_NAME); } tcp_map SEC(".maps"); +/*Hashmap to track ingress passthrough TCP connections i.e. to LAN or host +VMs/Containers*/ +struct { + __uint(type, BPF_MAP_TYPE_LRU_HASH); + __uint(key_size, sizeof(struct tuple_key)); + __uint(value_size,sizeof(struct tcp_state)); + __uint(max_entries, BPF_MAX_SESSIONS); + __uint(pinning, LIBBPF_PIN_BY_NAME); +} tcp_ingress_map SEC(".maps"); + struct { __uint(type, BPF_MAP_TYPE_LRU_HASH); __uint(key_size, sizeof(struct tuple_key)); @@ -511,12 +529,21 @@ struct { __uint(pinning, LIBBPF_PIN_BY_NAME); } udp_map SEC(".maps"); +/*tracks inbound allowed sessions*/ +struct { + __uint(type, BPF_MAP_TYPE_LRU_HASH); + __uint(key_size, sizeof(struct tuple_key)); + __uint(value_size,sizeof(struct udp_state)); + __uint(max_entries, BPF_MAX_SESSIONS); + __uint(pinning, LIBBPF_PIN_BY_NAME); +} udp_ingress_map SEC(".maps"); + /*Hashmap to track tun interface inbound passthrough connections*/ struct { __uint(type, BPF_MAP_TYPE_LRU_HASH); __uint(key_size, sizeof(struct tun_key)); __uint(value_size,sizeof(struct tun_state)); - __uint(max_entries, BPF_MAX_SESSIONS); + __uint(max_entries, BPF_MAX_TUN_SESSIONS); __uint(pinning, LIBBPF_PIN_BY_NAME); } tun_map SEC(".maps"); @@ -584,6 +611,23 @@ static inline struct tcp_state *get_tcp(struct tuple_key key){ return ts; } +/*Insert entry into ingress tcp state table*/ +static inline void insert_ingress_tcp(struct tcp_state tstate, struct tuple_key key){ + bpf_map_update_elem(&tcp_ingress_map, &key, &tstate,0); +} + +/*Remove entry into ingress tcp state table*/ +static inline void del_ingress_tcp(struct tuple_key key){ + bpf_map_delete_elem(&tcp_ingress_map, &key); +} + +/*get entry from ingress tcp state table*/ +static inline struct tcp_state *get_ingress_tcp(struct tuple_key key){ + struct tcp_state *ts; + ts = bpf_map_lookup_elem(&tcp_ingress_map, &key); + return ts; +} + static inline void del_udp(struct tuple_key key){ bpf_map_delete_elem(&udp_map, &key); } @@ -594,6 +638,17 @@ static inline struct udp_state *get_udp(struct tuple_key key){ return us; } +static inline struct udp_state *get_udp_ingress(struct tuple_key key){ + struct udp_state *us; + us = bpf_map_lookup_elem(&udp_ingress_map, &key); + return us; +} + +/*Insert entry into udp state table*/ +static inline void insert_udp_ingress(struct udp_state ustate, struct tuple_key key){ + bpf_map_update_elem(&udp_ingress_map, &key, &ustate,0); +} + /*Insert entry into tun state table*/ static inline void insert_tun(struct tun_state tustate, struct tun_key key){ bpf_map_update_elem(&tun_map, &key, &tustate,0); @@ -777,18 +832,12 @@ static inline void send_event(struct bpf_event *new_event){ * 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, bool *vrrp, + __u16 eth_proto, bool *ipv4, bool *ipv6, bool *udp, bool *tcp, bool *icmp, bool *vrrp, struct bpf_event *event, struct diag_ip4 *local_diag){ struct bpf_sock_tuple *result = NULL; __u8 proto = 0; - /* check if ARP */ - if (eth_proto == bpf_htons(ETH_P_ARP)) { - *arp = true; - return NULL; - } - /* check IP */ struct iphdr *iph = NULL; struct ipv6hdr *ip6h = NULL; @@ -980,7 +1029,6 @@ int bpf_sk_splice(struct __sk_buff *skb){ bool ipv6 = false; bool udp=false; bool tcp=false; - bool arp=false; bool icmp=false; bool vrrp=false; int ret; @@ -1023,29 +1071,31 @@ int bpf_sk_splice(struct __sk_buff *skb){ return TC_ACT_SHOT; } + /*check if ARP and pass if true*/ + if((bpf_ntohs(eth->h_proto) == ETH_P_ARP)){ + return TC_ACT_OK; + } + /*check if 802.1X and passthrough is enabled*/ if((bpf_ntohs(eth->h_proto) == 0x888e) && local_diag->eapol){ return TC_ACT_OK; } /* 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, &vrrp, &event, local_diag); + tuple = get_tuple(skb, sizeof(*eth), eth->h_proto, &ipv4,&ipv6, &udp, &tcp, &icmp, &vrrp, &event, local_diag); //get ipv4 interface addr mappings struct ifindex_ip4 *local_ip4 = get_local_ip4(skb->ifindex); //get ipv6 interface addr mappings struct ifindex_ip6 *local_ip6 = get_local_ip6(skb->ifindex); - + /* if not tuple forward ARP and drop all other traffic */ if (!tuple){ if(skb->ifindex == 1){ return TC_ACT_OK; } - else if(arp){ - return TC_ACT_OK; - } else if(icmp){ if(ipv4){ struct iphdr *iph = (struct iphdr *)(skb->data + sizeof(*eth)); @@ -1408,13 +1458,13 @@ int bpf_sk_splice(struct __sk_buff *skb){ * check if there is a dest ip associated with the local socket. if yes jump to assign if not * disregard and release the sk and continue on to check for tproxy mapping. */ - if(sk->dst_ip4){ + if(sk->dst_ip4){ if(local_diag->verbose){ send_event(&event); } goto assign; - } - bpf_sk_release(sk); + } + bpf_sk_release(sk); /*reply to outbound passthrough check*/ }else{ udp_state_key.__in46_u_dst.ip = tuple->ipv4.saddr; @@ -1449,7 +1499,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 && local_diag->ipv6_enable) + }else if(ipv6 && (local_diag->ipv6_enable || skb->ifindex == 1)) { tuple_len = sizeof(tuple->ipv6); if ((unsigned long)tuple + tuple_len > (unsigned long)skb->data_end){ @@ -1593,19 +1643,21 @@ int bpf_sk_splice(struct __sk_buff *skb){ * defined for the flow*/ event.proto = IPPROTO_UDP; sk = bpf_sk_lookup_udp(skb, tuple, tuple_len, BPF_F_CURRENT_NETNS, 0); - if(sk){ - /* + if(sk) + { + + /* * check if there is a dest ip associated with the local socket. if yes jump to assign if not * disregard and release the sk and continue on to check for tproxy mapping. */ - if(sk->dst_ip4){ + if(sk->dst_ip6[0]){ if(local_diag->verbose){ send_event(&event); } goto assign; - } - bpf_sk_release(sk); - /*reply to outbound passthrough check*/ + } + bpf_sk_release(sk); + /*reply to outbound passthrough check*/ }else{ memcpy(udp_state_key.__in46_u_dst.ip6,tuple->ipv6.saddr, sizeof(tuple->ipv6.saddr)); memcpy(udp_state_key.__in46_u_src.ip6,tuple->ipv6.daddr, sizeof(tuple->ipv6.daddr)); @@ -1659,11 +1711,11 @@ int bpf_sk_splice(struct __sk_buff *skb){ //if succeeded forward to the stack return TC_ACT_OK; } - /*else drop packet if not running on loopback*/ + /*else forward packet to next filter for processing if not running on loopback*/ if(skb->ifindex == 1){ return TC_ACT_OK; }else{ - return TC_ACT_SHOT; + return TC_ACT_PIPE; } } @@ -2154,7 +2206,7 @@ int bpf_sk_splice5(struct __sk_buff *skb){ struct match_key mkey = {tuple->ipv4.saddr, tuple->ipv4.daddr, tuple->ipv4.sport, tuple->ipv4.dport, skb->ifindex, protocol}; __u16 match_count = get_matched_count(mkey); if (match_count > MATCHED_KEY_DEPTH){ - match_count = MATCHED_KEY_DEPTH; + match_count = MATCHED_KEY_DEPTH; } for(__u16 count =0; count < match_count; count++) { @@ -2197,6 +2249,9 @@ int bpf_sk_splice5(struct __sk_buff *skb){ if(local_diag->verbose){ send_event(&event); } + if(local_diag->outbound_filter){ + return TC_ACT_PIPE; + } return TC_ACT_OK; } if(!local_diag->tun_mode){ @@ -2246,10 +2301,14 @@ int bpf_sk_splice5(struct __sk_buff *skb){ if(ext_mapping){ for(int x = 0; x < MAX_IF_LIST_ENTRIES; x++){ if(ext_mapping->if_list[x] == skb->ifindex){ - if(range->tproxy_port == 0){ + if(range->tproxy_port == 0) + { if(local_diag->verbose){ send_event(&event); } + if(local_diag->outbound_filter){ + return TC_ACT_PIPE; + } return TC_ACT_OK; } if(!local_diag->tun_mode){ @@ -2382,6 +2441,9 @@ int bpf_sk_splice5(struct __sk_buff *skb){ if(local_diag->verbose){ send_event(&event); } + if(local_diag->outbound_filter){ + return TC_ACT_PIPE; + } return TC_ACT_OK; } if(!local_diag->tun_mode){ @@ -2390,7 +2452,6 @@ int bpf_sk_splice5(struct __sk_buff *skb){ return TC_ACT_SHOT; } if(!(key->protocol == IPPROTO_UDP) || local_diag->verbose){ - bpf_printk("sent event"); send_event(&event); } goto assign; @@ -2435,6 +2496,9 @@ int bpf_sk_splice5(struct __sk_buff *skb){ if(range->tproxy_port == 0){ if(local_diag->verbose){ send_event(&event); + } + if(local_diag->outbound_filter){ + return TC_ACT_PIPE; } return TC_ACT_OK; } @@ -2520,4 +2584,325 @@ int bpf_sk_splice5(struct __sk_buff *skb){ } } +SEC("action/6") +int bpf_sk_splice6(struct __sk_buff *skb){ + struct bpf_sock_tuple *tuple; + int tuple_len; + struct tuple_key udp_state_key ={0}; + struct tuple_key tcp_state_key ={0}; + + /*look up attached interface inbound diag status*/ + struct diag_ip4 *local_diag = get_diag_ip4(skb->ifindex); + if(!local_diag){ + if(skb->ifindex == 1){ + return TC_ACT_OK; + }else{ + return TC_ACT_SHOT; + } + } + + /* find ethernet header from skb->data pointer */ + struct ethhdr *eth = (struct ethhdr *)(unsigned long)(skb->data); + if ((unsigned long)(eth + 1) > (unsigned long)skb->data_end){ + return TC_ACT_SHOT; + } + + unsigned long long tstamp = bpf_ktime_get_ns(); + struct bpf_event event = { + 0, + tstamp, + skb->ifindex, + 0, + {0}, + {0}, + 0, + 0, + 0, + 0, + INGRESS, + 0, + 0, + {}, + {} + }; + + if(eth->h_proto == bpf_htons(ETH_P_IP)){ + /* check if incomming packet is a UDP or TCP tuple */ + struct iphdr *iph = (struct iphdr *)(skb->data + sizeof(*eth)); + if ((unsigned long)(iph + 1) > (unsigned long)skb->data_end){ + return TC_ACT_SHOT; + } + event.proto = iph->protocol; + tuple = (struct bpf_sock_tuple *)(void*)(long)&iph->saddr; + if(!tuple){ + return TC_ACT_SHOT; + } + /* determine length of tuple */ + tuple_len = sizeof(tuple->ipv4); + if ((unsigned long)tuple + tuple_len > (unsigned long)skb->data_end){ + return TC_ACT_SHOT; + } + event.version = iph->version; + uint32_t daddr[4] = {tuple->ipv4.daddr,0,0,0}; + uint32_t saddr[4] = {tuple->ipv4.saddr,0,0,0}; + memcpy(event.daddr, daddr, sizeof(event.daddr)); + memcpy(event.saddr, saddr, sizeof(event.saddr)); + event.dport = tuple->ipv4.dport; + event.sport = tuple->ipv4.sport; + if(event.proto == IPPROTO_UDP){ + udp_state_key.__in46_u_src.ip = tuple->ipv4.saddr; + udp_state_key.__in46_u_dst.ip = tuple->ipv4.daddr; + udp_state_key.sport = tuple->ipv4.sport; + udp_state_key.dport = tuple->ipv4.dport; + struct udp_state *ustate = get_udp_ingress(udp_state_key); + if((!ustate) || (ustate->tstamp > (tstamp + 30000000000))){ + struct udp_state us = { + tstamp + }; + insert_udp_ingress(us, udp_state_key); + if(local_diag->verbose){ + event.tracking_code = INGRESS_INITIATED_UDP_SESSION; + send_event(&event); + } + } + else if(ustate){ + ustate->tstamp = tstamp; + } + return TC_ACT_OK; + } + if(event.proto == IPPROTO_TCP) + { + struct tcphdr *tcph = (struct tcphdr *)((unsigned long)iph + sizeof(*iph)); + if ((unsigned long)(tcph + 1) > (unsigned long)skb->data_end){ + return TC_ACT_SHOT; + } + tcp_state_key.__in46_u_src.ip = tuple->ipv4.saddr; + tcp_state_key.__in46_u_dst.ip = tuple->ipv4.daddr; + tcp_state_key.sport = tuple->ipv4.sport; + tcp_state_key.dport = tuple->ipv4.dport; + unsigned long long tstamp = bpf_ktime_get_ns(); + struct tcp_state *tstate; + if(tcph->syn && !tcph->ack){ + struct tcp_state ts = { + tstamp, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + }; + insert_ingress_tcp(ts, tcp_state_key); + if(local_diag->verbose){ + event.tracking_code = INGRESS_CLIENT_SYN_RCVD; + send_event(&event); + } + } + else if(tcph->fin){ + tstate = get_ingress_tcp(tcp_state_key); + if(tstate){ + tstate->tstamp = tstamp; + tstate->cfin = 1; + tstate->cfseq = tcph->seq; + if(local_diag->verbose){ + event.tracking_code = INGRESS_CLIENT_FIN_RCVD; + send_event(&event); + } + } + } + else if(tcph->rst){ + tstate = get_ingress_tcp(tcp_state_key); + if(tstate){ + del_ingress_tcp(tcp_state_key); + tstate = get_ingress_tcp(tcp_state_key); + if(!tstate){ + if(local_diag->verbose){ + event.tracking_code = INGRESS_CLIENT_RST_RCVD; + send_event(&event); + } + } + } + } + else if(tcph->ack){ + tstate = get_ingress_tcp(tcp_state_key); + if(tstate){ + if(tstate->ack && tstate->syn){ + if(local_diag->verbose){ + event.tracking_code = INGRESS_TCP_CONNECTION_ESTABLISHED; + send_event(&event); + } + tstate->tstamp = tstamp; + tstate->syn = 0; + tstate->est = 1; + } + if((tstate->est) && (tstate->sfin == 1) && (tstate->cfin == 1) && (tstate->sfack) && (bpf_htonl(tcph->ack_seq) == (bpf_htonl(tstate->sfseq) + 1))){ + del_ingress_tcp(tcp_state_key); + tstate = get_ingress_tcp(tcp_state_key); + if(!tstate){ + if(local_diag->verbose){ + event.tracking_code = INGRESS_CLIENT_FINAL_ACK_RCVD; + send_event(&event); + } + } + } + else if((tstate->est) && (tstate->sfin == 1) && (bpf_htonl(tcph->ack_seq) == (bpf_htonl(tstate->sfseq) + 1))){ + tstate->cfack = 1; + tstate->tstamp = tstamp; + } + else{ + tstate->tstamp = tstamp; + } + } + } + return TC_ACT_OK; + } + }else + { + struct ipv6hdr *ip6h = (struct ipv6hdr *)(skb->data + sizeof(*eth)); + // ensure ip header is in packet bounds + if ((unsigned long)(ip6h + 1) > (unsigned long)skb->data_end){ + return TC_ACT_SHOT; + } + tuple = (struct bpf_sock_tuple *)(void*)(long)&ip6h->saddr; + if(!tuple){ + return TC_ACT_SHOT; + } + // determine length of tuple + tuple_len = sizeof(tuple->ipv6); + if ((unsigned long)tuple + tuple_len > (unsigned long)skb->data_end){ + return TC_ACT_SHOT; + } + memcpy(event.daddr, tuple->ipv6.daddr, sizeof(event.daddr)); + memcpy(event.saddr, tuple->ipv6.saddr, sizeof(event.saddr)); + event.dport = tuple->ipv6.dport; + event.sport = tuple->ipv6.sport; + event.version = ip6h->version; + event.proto = ip6h->nexthdr; + tuple = (struct bpf_sock_tuple *)(void*)(long)&ip6h->saddr; + tuple_len = sizeof(tuple->ipv6); + if ((unsigned long)tuple + tuple_len > (unsigned long)skb->data_end){ + return TC_ACT_SHOT; + } + if(event.proto == IPPROTO_UDP){ + memcpy(udp_state_key.__in46_u_src.ip6,tuple->ipv6.saddr, sizeof(tuple->ipv6.saddr)); + memcpy(udp_state_key.__in46_u_dst.ip6,tuple->ipv6.daddr, sizeof(tuple->ipv6.daddr)); + udp_state_key.sport = tuple->ipv6.sport; + udp_state_key.dport = tuple->ipv6.dport; + struct udp_state *ustate = get_udp_ingress(udp_state_key); + if((!ustate) || (ustate->tstamp > (tstamp + 30000000000))){ + struct udp_state us = { + tstamp + }; + insert_udp_ingress(us, udp_state_key); + if(local_diag->verbose){ + event.tracking_code = INGRESS_INITIATED_UDP_SESSION; + send_event(&event); + } + } + else if(ustate){ + ustate->tstamp = tstamp; + } + return TC_ACT_OK; + } + if(event.proto == IPPROTO_TCP){ + struct tcphdr *tcph = (struct tcphdr *)((unsigned long)ip6h + sizeof(*ip6h)); + if ((unsigned long)(tcph + 1) > (unsigned long)skb->data_end){ + return TC_ACT_SHOT; + } + memcpy(tcp_state_key.__in46_u_src.ip6,tuple->ipv6.saddr, sizeof(tuple->ipv6.saddr)); + memcpy(tcp_state_key.__in46_u_dst.ip6,tuple->ipv6.daddr, sizeof(tuple->ipv6.daddr)); + tcp_state_key.sport = tuple->ipv6.sport; + tcp_state_key.dport = tuple->ipv6.dport; + unsigned long long tstamp = bpf_ktime_get_ns(); + struct tcp_state *tstate; + if(tcph->syn && !tcph->ack){ + struct tcp_state ts = { + tstamp, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + }; + insert_ingress_tcp(ts, tcp_state_key); + if(local_diag->verbose){ + event.tracking_code = INGRESS_CLIENT_SYN_RCVD; + send_event(&event); + } + } + else if(tcph->fin){ + tstate = get_ingress_tcp(tcp_state_key); + if(tstate){ + tstate->tstamp = tstamp; + tstate->cfin = 1; + tstate->cfseq = tcph->seq; + if(local_diag->verbose){ + event.tracking_code = INGRESS_CLIENT_FIN_RCVD; + send_event(&event); + } + } + } + else if(tcph->rst){ + tstate = get_ingress_tcp(tcp_state_key); + if(tstate){ + del_ingress_tcp(tcp_state_key); + tstate = get_ingress_tcp(tcp_state_key); + if(!tstate){ + if(local_diag->verbose){ + event.tracking_code = INGRESS_CLIENT_RST_RCVD; + send_event(&event); + } + } + } + } + else if(tcph->ack){ + tstate = get_ingress_tcp(tcp_state_key); + if(tstate){ + if(tstate->ack && tstate->syn){ + if(local_diag->verbose){ + event.tracking_code = INGRESS_TCP_CONNECTION_ESTABLISHED; + send_event(&event); + } + tstate->tstamp = tstamp; + tstate->syn = 0; + tstate->est = 1; + } + if((tstate->est) && (tstate->sfin == 1) && (tstate->cfin == 1) && (tstate->sfack) && (bpf_htonl(tcph->ack_seq) == (bpf_htonl(tstate->sfseq) + 1))){ + del_ingress_tcp(tcp_state_key); + tstate = get_ingress_tcp(tcp_state_key); + if(!tstate){ + if(local_diag->verbose){ + event.tracking_code = INGRESS_CLIENT_FINAL_ACK_RCVD; + send_event(&event); + } + } + } + else if((tstate->est) && (tstate->sfin == 1) && (bpf_htonl(tcph->ack_seq) == (bpf_htonl(tstate->sfseq) + 1))){ + tstate->cfack = 1; + tstate->tstamp = tstamp; + } + else{ + tstate->tstamp = tstamp; + } + } + } + return TC_ACT_OK; + } + } + if(skb->ifindex == 1){ + return TC_ACT_OK; + }else{ + return TC_ACT_SHOT; + } +} + SEC("license") const char __license[] = "Dual BSD/GPL"; diff --git a/src/zfw_tc_outbound_track.c b/src/zfw_tc_outbound_track.c index 4d5f636..9f8770b 100644 --- a/src/zfw_tc_outbound_track.c +++ b/src/zfw_tc_outbound_track.c @@ -31,20 +31,36 @@ #include #include -#define MAX_IF_ENTRIES 256 -#define BPF_MAX_SESSIONS 10000 -#define IP_HEADER_TOO_BIG 1 -#define NO_IP_OPTIONS_ALLOWED 2 -#define IP_TUPLE_TOO_BIG 8 -#define EGRESS 1 -#define CLIENT_SYN_RCVD 7 -#define CLIENT_FIN_RCVD 8 -#define CLIENT_RST_RCVD 9 -#define TCP_CONNECTION_ESTABLISHED 10 -#define CLIENT_FINAL_ACK_RCVD 11 -#define CLIENT_INITIATED_UDP_SESSION 12 -#define IP6_HEADER_TOO_BIG 30 -#define IPV6_TUPLE_TOO_BIG 31 +#ifndef BPF_MAX_ENTRIES +#define BPF_MAX_ENTRIES 100 //MAX # PREFIXES +#endif +#define MAX_INDEX_ENTRIES 100 +#define MAX_ADDRESSES 10 +#define BPF_MAX_RANGES 250000 +#define MAX_IF_LIST_ENTRIES 3 +#define MATCHED_KEY_DEPTH 3 +#define MAX_IF_ENTRIES 256 +#define BPF_MAX_SESSIONS 65535 +#define IP_HEADER_TOO_BIG 1 +#define NO_IP_OPTIONS_ALLOWED 2 +#define IP_TUPLE_TOO_BIG 8 +#define IF_LIST_MATCH_ERROR 9 +#define EGRESS 1 +#define ICMP_HEADER_TOO_BIG 7 +#define CLIENT_SYN_RCVD 7 +#define CLIENT_FIN_RCVD 8 +#define CLIENT_RST_RCVD 9 +#define TCP_CONNECTION_ESTABLISHED 10 +#define CLIENT_FINAL_ACK_RCVD 11 +#define CLIENT_INITIATED_UDP_SESSION 12 +#define INGRESS_UDP_MATCHED_EXPIRED_STATE 15 +#define INGRESS_UDP_MATCHED_ACTIVE_STATE 16 +#define INGRESS_SERVER_SYN_ACK_RCVD 22 +#define INGRESS_SERVER_FIN_RCVD 23 +#define INGRESS_SERVER_RST_RCVD 24 +#define INGRESS_SERVER_FINAL_ACK_RCVD 25 +#define IP6_HEADER_TOO_BIG 30 +#define IPV6_TUPLE_TOO_BIG 31 #define memcpy(dest, src, n) __builtin_memcpy((dest), (src), (n)) @@ -113,6 +129,7 @@ struct diag_ip4 { bool eapol; bool ddos_filtering; bool ipv6_enable; + bool outbound_filter; }; /*value to ifindex_tun_map*/ @@ -125,6 +142,191 @@ struct ifindex_tun { bool verbose; }; +struct tproxy_tuple { + __u16 index_len; /*tracks the number of entries in the index_table*/ + __u16 index_table[MAX_INDEX_ENTRIES];/*Array used as index table to associate + *port ranges and tproxy ports with prefix tuples/protocol + */ +}; + +/*key to zt_tproxy_map*/ +struct tproxy_key { + __u32 dst_ip; + __u32 src_ip; + __u8 dprefix_len; + __u8 sprefix_len; + __u8 protocol; + __u8 pad; +}; + +/*key to zt_tproxy_map6*/ +struct tproxy6_key { + __u32 dst_ip[4]; + __u32 src_ip[4]; + __u8 dprefix_len; + __u8 sprefix_len; + __u8 protocol; + __u8 pad; +}; + +struct range_mapping { + __u16 high_port; + __u16 tproxy_port; +}; + +struct tproxy_extension_key { + __u16 tproxy_port; + __u8 protocol; + __u8 pad; +}; + +struct port_extension_key { + union { + __u32 ip; + __u32 ip6[4]; + }__in46_u_dst; + union { + __u32 ip; + __u32 ip6[4]; + }__in46_u_src; + __u16 low_port; + __u8 dprefix_len; + __u8 sprefix_len; + __u8 protocol; + __u8 pad; +}; + +struct tproxy_extension_mapping { + char service_id[23]; +}; + +struct if_list_extension_mapping { + __u32 if_list[MAX_IF_LIST_ENTRIES]; +}; + +/*value to ifindex_ip_map*/ +struct ifindex_ip4 { + uint32_t ipaddr[MAX_ADDRESSES]; + char ifname[IFNAMSIZ]; + uint8_t count; +}; + +/*value to ifindex_ip6_map*/ +struct ifindex_ip6 { + char ifname[IFNAMSIZ]; + uint32_t ipaddr[MAX_ADDRESSES][4]; + uint8_t count; +}; + +/*Value to egress_matched_map*/ +struct match_tracker { + __u16 count; + struct tproxy_key matched_keys[MATCHED_KEY_DEPTH]; +}; + +/*Key to egress_matched_map*/ +struct match_key { + __u32 saddr; + __u32 daddr; + __u16 sport; + __u16 dport; + __u32 ifindex; + __u32 protocol; +}; + +/*Key to egress_matched6_map*/ +struct match6_key { + __u32 saddr[4]; + __u32 daddr[4]; + __u16 sport; + __u16 dport; + __u32 ifindex; + __u32 protocol; +}; + +/* map to track up to 3 key matches per egressing IPv4 packet search. Map is +then used to search for port mappings.*/ + +struct { + __uint(type, BPF_MAP_TYPE_LRU_HASH); + __uint(key_size, sizeof(struct match_key)); + __uint(value_size, sizeof(struct match_tracker)); + __uint(max_entries, 65535); + __uint(pinning, LIBBPF_PIN_BY_NAME); +} egress_matched_map SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_LRU_HASH); + __uint(key_size, sizeof(struct match6_key)); + __uint(value_size, sizeof(struct tproxy6_key)); + __uint(max_entries, 65535); + __uint(pinning, LIBBPF_PIN_BY_NAME); +} egress_matched6_map SEC(".maps"); + +/*Map for filtering outbound IPv4 traffic*/ +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(key_size, sizeof(struct tproxy_key)); + __uint(value_size,sizeof(struct tproxy_tuple)); + __uint(max_entries, BPF_MAX_ENTRIES); + __uint(pinning, LIBBPF_PIN_BY_NAME); + __uint(map_flags, BPF_F_NO_PREALLOC); +} zt_egress_map SEC(".maps"); + +/*Map for filtering outbound IPv6 traffic*/ +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(key_size, sizeof(struct tproxy6_key)); + __uint(value_size,sizeof(struct tproxy_tuple)); + __uint(max_entries, BPF_MAX_ENTRIES); + __uint(pinning, LIBBPF_PIN_BY_NAME); + __uint(map_flags, BPF_F_NO_PREALLOC); +} zt_egress6_map SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(key_size, sizeof(struct tproxy_extension_key)); + __uint(value_size, sizeof(struct tproxy_extension_mapping)); + __uint(max_entries, BPF_MAX_RANGES); + __uint(pinning, LIBBPF_PIN_BY_NAME); + __uint(map_flags, BPF_F_NO_PREALLOC); +} egress_extension_map SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(key_size, sizeof(struct port_extension_key)); + __uint(value_size, sizeof(struct if_list_extension_mapping)); + __uint(max_entries, BPF_MAX_RANGES); + __uint(pinning, LIBBPF_PIN_BY_NAME); + __uint(map_flags, BPF_F_NO_PREALLOC); +} egress_if_list_extension_map SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(key_size, sizeof(struct port_extension_key)); + __uint(value_size, sizeof(struct range_mapping)); + __uint(max_entries, BPF_MAX_RANGES); + __uint(pinning, LIBBPF_PIN_BY_NAME); + __uint(map_flags, BPF_F_NO_PREALLOC); +} egress_range_map SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __uint(key_size, sizeof(uint32_t)); + __uint(value_size, sizeof(uint32_t)); + __uint(max_entries, 1); + __uint(pinning, LIBBPF_PIN_BY_NAME); +} egress_count_map SEC(".maps"); + +//map to keep track of total entries in zt_tproxy6_map +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __uint(key_size, sizeof(uint32_t)); + __uint(value_size, sizeof(uint32_t)); + __uint(max_entries, 1); + __uint(pinning, LIBBPF_PIN_BY_NAME); +} egress6_count_map SEC(".maps"); + /*tun ifindex map*/ struct { __uint(type, BPF_MAP_TYPE_ARRAY); @@ -153,6 +355,16 @@ struct { __uint(pinning, LIBBPF_PIN_BY_NAME); } tcp_map SEC(".maps"); +/*Hashmap to track ingress passthrough TCP connections i.e. to LAN or host +VMs/Containers*/ +struct { + __uint(type, BPF_MAP_TYPE_LRU_HASH); + __uint(key_size, sizeof(struct tuple_key)); + __uint(value_size,sizeof(struct tcp_state)); + __uint(max_entries, BPF_MAX_SESSIONS); + __uint(pinning, LIBBPF_PIN_BY_NAME); +} tcp_ingress_map SEC(".maps"); + /*Hashmap to track outbound passthrough UDP connections*/ struct { __uint(type, BPF_MAP_TYPE_LRU_HASH); @@ -162,6 +374,15 @@ struct { __uint(pinning, LIBBPF_PIN_BY_NAME); } udp_map SEC(".maps"); +/*tracks inbound allowed sessions*/ +struct { + __uint(type, BPF_MAP_TYPE_LRU_HASH); + __uint(key_size, sizeof(struct tuple_key)); + __uint(value_size,sizeof(struct udp_state)); + __uint(max_entries, BPF_MAX_SESSIONS); + __uint(pinning, LIBBPF_PIN_BY_NAME); +} udp_ingress_map SEC(".maps"); + /*Ringbuf map*/ struct { __uint(type, BPF_MAP_TYPE_RINGBUF); @@ -169,6 +390,38 @@ struct { __uint(pinning, LIBBPF_PIN_BY_NAME); } rb_map SEC(".maps"); +/* File system pinned Array Map key mapping to ifindex with used to allow + * ebpf program to learn the ip address + * of the interface it is attached to by reading the mapping + * provided by user space it can use skb->ifindex __uint(key_size, sizeof(uint32_t));ss_ifindex + * to find its corresponding ip address. Currently used to limit + * ssh to only the attached interface ip +*/ +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(key_size, sizeof(uint32_t)); + __uint(value_size, sizeof(struct ifindex_ip4)); + __uint(max_entries, MAX_IF_ENTRIES); + __uint(pinning, LIBBPF_PIN_BY_NAME); + __uint(map_flags, BPF_F_NO_PREALLOC); +} ifindex_ip_map SEC(".maps"); + +/* File system pinned Array Map key mapping to ifindex with used to allow + * ebpf program to learn the ip address + * of the interface it is attached to by reading the mapping + * provided by user space it can use skb->ifindex __uint(key_size, sizeof(uint32_t));ss_ifindex + * to find its corresponding ip6 address. Currently used to limit + * ssh to only the attached interface ip6 +*/ +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(key_size, sizeof(uint32_t)); + __uint(value_size, sizeof(struct ifindex_ip6)); + __uint(max_entries, MAX_IF_ENTRIES); + __uint(pinning, LIBBPF_PIN_BY_NAME); + __uint(map_flags, BPF_F_NO_PREALLOC); +} ifindex_ip6_map SEC(".maps"); + /*get entry from tun ifindex map*/ static inline struct ifindex_tun *get_tun_index(uint32_t key){ struct ifindex_tun *iftun; @@ -181,150 +434,1497 @@ static inline void insert_tcp(struct tcp_state tstate, struct tuple_key key){ bpf_map_update_elem(&tcp_map, &key, &tstate,0); } -/*Remove entry into tcp state table*/ -static inline void del_tcp(struct tuple_key key){ - bpf_map_delete_elem(&tcp_map, &key); -} +/*Remove entry into tcp state table*/ +static inline void del_tcp(struct tuple_key key){ + bpf_map_delete_elem(&tcp_map, &key); +} + +/*get entry from tcp state table*/ +static inline struct tcp_state *get_tcp(struct tuple_key key){ + struct tcp_state *ts; + ts = bpf_map_lookup_elem(&tcp_map, &key); + return ts; +} + +/*Remove entry into ingress tcp state table*/ +static inline void del_ingress_tcp(struct tuple_key key){ + bpf_map_delete_elem(&tcp_ingress_map, &key); +} + +/*get entry from ingress tcp state table*/ +static inline struct tcp_state *get_ingress_tcp(struct tuple_key key){ + struct tcp_state *ts; + ts = bpf_map_lookup_elem(&tcp_ingress_map, &key); + return ts; +} + +/*Insert entry into udp state table*/ +static inline void insert_udp(struct udp_state ustate, struct tuple_key key){ + bpf_map_update_elem(&udp_map, &key, &ustate,0); +} + +/*get entry from udp state table*/ +static inline struct udp_state *get_udp(struct tuple_key key){ + struct udp_state *us; + us = bpf_map_lookup_elem(&udp_map, &key); + return us; +} + +static inline struct udp_state *get_udp_ingress(struct tuple_key key){ + struct udp_state *us; + us = bpf_map_lookup_elem(&udp_ingress_map, &key); + return us; +} + +static inline void del_udp_ingress(struct tuple_key key){ + bpf_map_delete_elem(&udp_ingress_map, &key); +} + +static inline struct diag_ip4 *get_diag_ip4(__u32 key){ + struct diag_ip4 *if_diag; + if_diag = bpf_map_lookup_elem(&diag_map, &key); + + return if_diag; +} + +/* Function used by ebpf program to access ifindex_ip_map + * in order to lookup the ip associated with its attached interface + * This allows distinguishing between socket to the local system i.e. ssh + * vs socket that need to be forwarded to the tproxy splicing function + * + */ +static inline struct ifindex_ip4 *get_local_ip4(__u32 key){ + struct ifindex_ip4 *ifip4; + ifip4 = bpf_map_lookup_elem(&ifindex_ip_map, &key); + return ifip4; +} + +/* Function used by ebpf program to access ifindex_ip6_map + * in order to lookup the ipv6 addr associated with its attached interface + * This allows distinguishing between socket to the local system i.e. ssh + * vs socket that need to be forwarded to the tproxy splicing function + * + */ +static inline struct ifindex_ip6 *get_local_ip6(__u32 key){ + struct ifindex_ip6 *ifip6; + ifip6 = bpf_map_lookup_elem(&ifindex_ip6_map, &key); + return ifip6; +} + +/*function to update the matched_map locally from ebpf*/ +static inline void insert_matched_key(struct match_tracker matched_keys, struct match_key key){ + bpf_map_update_elem(&egress_matched_map, &key, &matched_keys,0); +} + +/*Function to get stored matched tracker*/ +static inline struct match_tracker *get_matched_keys(struct match_key key){ + struct match_tracker *mt; + mt = bpf_map_lookup_elem(&egress_matched_map, &key); + return mt; +} + +/*Function to get stored matched key count*/ +static inline __u16 get_matched_count(struct match_key key){ + struct match_tracker *mt; + __u16 mc = 0; + mt = bpf_map_lookup_elem(&egress_matched_map,&key); + if(mt){ + mc = mt->count; + } + return mc; +} + +/*Function to clear matched tracker*/ +static inline void clear_match_tracker(struct match_key key){ + bpf_map_delete_elem(&egress_matched_map, &key); +} + +/*function to update the matched_map locally from ebpf*/ +static inline void insert_matched6_key(struct tproxy6_key matched6_key, struct match6_key key){ + bpf_map_update_elem(&egress_matched6_map, &key, &matched6_key,0); +} + +/*Function to get stored matched tracker*/ +static inline struct tproxy6_key *get_matched6_key(struct match6_key key){ + struct tproxy6_key *tp6; + tp6 = bpf_map_lookup_elem(&egress_matched6_map, &key); + return tp6; +} + +/*Function to clear matched tracker*/ +static inline void clear_match6_tracker(struct match6_key key){ + bpf_map_delete_elem(&egress_matched6_map, &key); +} + +/* function for ebpf program to access zt_tproxy_map entries + * based on {prefix,mask,protocol} i.e. {192.168.1.0,24,IPPROTO_TCP} + */ +static inline struct tproxy_tuple *get_egress(struct tproxy_key key){ + struct tproxy_tuple *tu; + tu = bpf_map_lookup_elem(&zt_egress_map, &key); + return tu; +} + +static inline struct tproxy_tuple *get_egress6(struct tproxy6_key key){ + struct tproxy_tuple *tu; + tu = bpf_map_lookup_elem(&zt_egress6_map, &key); + return tu; +} + +static inline struct if_list_extension_mapping *get_if_list_ext_mapping(struct port_extension_key key){ + struct if_list_extension_mapping *ifem; + ifem = bpf_map_lookup_elem(&egress_if_list_extension_map, &key); + return ifem; +} + +static inline struct range_mapping *get_range_ports(struct port_extension_key key){ + struct range_mapping *hp; + hp = bpf_map_lookup_elem(&egress_range_map, &key); + return hp; +} + +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); + if(rb_event){ + rb_event->version = new_event->version; + rb_event->ifindex = new_event->ifindex; + rb_event->tun_ifindex = new_event->tun_ifindex; + rb_event->tstamp = new_event->tstamp; + memcpy(rb_event->daddr, new_event->daddr, sizeof(rb_event->daddr)); + memcpy(rb_event->saddr, new_event->saddr, sizeof(rb_event->saddr)); + rb_event->dport = new_event->dport; + rb_event->sport = new_event->sport; + rb_event->tport = new_event->tport; + rb_event->proto = new_event->proto; + rb_event->direction = new_event->direction; + rb_event->tracking_code = new_event->tracking_code; + rb_event->error_code = new_event->error_code; + bpf_ringbuf_submit(rb_event, 0); + } +} + +/* function to determine if an incoming packet is a udp/tcp IP tuple +* or not. If not returns NULL. If true returns a struct bpf_sock_tuple +* from the combined IP SA|DA and the TCP/UDP SP|DP. +*/ +static struct bpf_sock_tuple *get_tuple(struct __sk_buff *skb, struct bpf_event *event,struct diag_ip4 *local_diag){ + struct bpf_sock_tuple *result = NULL; + __u8 proto = 0; + + struct ethhdr *eth = (struct ethhdr *)(unsigned long)(skb->data); + /* verify its a valid eth header within the packet bounds */ + if ((unsigned long)(eth + 1) > (unsigned long)skb->data_end){ + return NULL; + } + /* check IP */ + struct iphdr *iph = NULL; + struct ipv6hdr *ip6h = NULL; + unsigned short eth_proto = eth->h_proto; + bool ipv4 =false; + bool ipv6 = false; + if(eth_proto == bpf_htons(ETH_P_IP)){ + ipv4 = true; + } + if(eth_proto == bpf_htons(ETH_P_IPV6)){ + ipv6 = true; + } + if (ipv4) + { + event->version = 4; + /* find ip hdr */ + iph = (struct iphdr *)(skb->data + sizeof(struct ethhdr)); + /* ensure ip header is in packet bounds */ + if ((unsigned long)(iph + 1) > (unsigned long)skb->data_end){ + event->error_code = IP_HEADER_TOO_BIG; + send_event(event); + return NULL; + } + /* ip options not allowed */ + if (iph->ihl != 5){ + if(local_diag->verbose){ + event->error_code = NO_IP_OPTIONS_ALLOWED; + send_event(event); + } + return NULL; + } + proto = iph->protocol; + }else if(ipv6){ + event->version = 6; + ip6h = (struct ipv6hdr *)(skb->data + sizeof(struct ethhdr)); + /* ensure ip header is in packet bounds */ + if ((unsigned long)(ip6h + 1) > (unsigned long)skb->data_end){ + event->error_code = IP6_HEADER_TOO_BIG; + send_event(event); + return NULL; + } + proto = ip6h->nexthdr; + }else{ + return NULL; + } + + /* check if ip protocol is not UDP or TCP. Return NULL if true */ + if ((proto != IPPROTO_UDP) && (proto != IPPROTO_TCP)) { + return NULL; + } + /*return bpf_sock_tuple*/ + if(ipv4){ + result = (struct bpf_sock_tuple *)(void*)(long)&iph->saddr; + }else + { + result = (struct bpf_sock_tuple *)(void*)(long)&ip6h->saddr; + } + return result; +} + +static inline void iterate_masks(__u32 *mask, __u32 *exponent){ + if(*mask == 0x00ffffff){ + *exponent=16; + } + if(*mask == 0x0000ffff){ + *exponent=8; + } + if(*mask == 0x000000ff){ + *exponent=0; + } + if((*mask >= 0x80ffffff) && (*exponent >= 24)){ + *mask = *mask - (1 << *exponent); + }else if((*mask >= 0x0080ffff) && (*exponent >= 16)){ + *mask = *mask - (1 << *exponent); + }else if((*mask >= 0x000080ff) && (*exponent >= 8)){ + *mask = *mask - (1 << *exponent); + }else if((*mask >= 0x00000080) && (*exponent >= 0)){ + *mask = *mask - (1 << *exponent); + } +} + +SEC("action") +int bpf_sk_splice(struct __sk_buff *skb){ + struct bpf_sock *sk; + struct bpf_sock_tuple *tuple, reverse_tuple = {0}; + int tuple_len; + bool ipv4 = false; + bool ipv6 = false; + bool tcp = false; + struct tuple_key tcp_state_key = {0}; + struct tuple_key udp_state_key ={0}; + + unsigned long long tstamp = bpf_ktime_get_ns(); + struct bpf_event event = { + 4, + tstamp, + skb->ifindex, + 0, + {0,0,0,0}, + {0,0,0,0}, + 0, + 0, + 0, + 0, + EGRESS, + 0, + 0, + {0}, + {0} + }; + + /*look up attached interface inbound diag status*/ + struct diag_ip4 *local_diag = get_diag_ip4(skb->ifindex); + if(!local_diag){ + return TC_ACT_OK; + } + /*get entry from tun ifindex map*/ + struct ifindex_tun *tun_if = get_tun_index(0); + + /* find ethernet header from skb->data pointer */ + struct ethhdr *eth = (struct ethhdr *)(unsigned long)(skb->data); + /* verify its a valid eth header within the packet bounds */ + if ((unsigned long)(eth + 1) > (unsigned long)skb->data_end){ + return TC_ACT_SHOT; + } + + /*check if ARP and pass if true*/ + if((bpf_ntohs(eth->h_proto) == ETH_P_ARP)){ + return TC_ACT_OK; + } + + /*check if 802.1X and passthrough is enabled*/ + if((bpf_ntohs(eth->h_proto) == 0x888e) && local_diag->eapol){ + return TC_ACT_OK; + } + + if(eth->h_proto == bpf_ntohs(ETH_P_IP)){ + ipv4 = true; + } + + + if(eth->h_proto == bpf_ntohs(ETH_P_IPV6)){ + ipv6 = true; + } + + /* check if incoming packet is a UDP or TCP tuple */ + tuple = get_tuple(skb, &event, local_diag); + + //get ipv4 interface addr mappings + struct ifindex_ip4 *local_ip4 = get_local_ip4(skb->ifindex); + + //get ipv6 interface addr mappings + struct ifindex_ip6 *local_ip6 = get_local_ip6(skb->ifindex); + + /* if not tuple forward */ + if (!tuple){ + if(ipv4){ + struct iphdr *iph = (struct iphdr *)(skb->data + sizeof(*eth)); + if ((unsigned long)(iph + 1) > (unsigned long)skb->data_end){ + return TC_ACT_SHOT; + } + event.proto = iph->protocol; + if(event.proto == IPPROTO_ICMP) + { + struct icmphdr *icmph = (struct icmphdr *)((unsigned long)iph + sizeof(*iph)); + if ((unsigned long)(icmph + 1) > (unsigned long)skb->data_end){ + event.error_code = ICMP_HEADER_TOO_BIG; + send_event(&event); + return TC_ACT_SHOT; + } + if((skb->ifindex != 1) && (icmph->type == 0) && (icmph->code == 0)){ + if(local_diag->echo){ + return TC_ACT_OK; + }else{ + return TC_ACT_SHOT; + } + } + return TC_ACT_OK; + } + if(local_diag->vrrp && (event.proto == 112)){ + return TC_ACT_OK; + } + } + 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; + } + event.proto = ip6h->nexthdr; + if(event.proto == IPPROTO_ICMPV6){ + struct icmp6hdr *icmp6h = (struct icmp6hdr *)((unsigned long)ip6h + sizeof(*ip6h)); + if ((unsigned long)(icmp6h + 1) > (unsigned long)skb->data_end){ + event.error_code = ICMP_HEADER_TOO_BIG; + send_event(&event); + return TC_ACT_SHOT; + } + if(skb->ifindex != 1){ + if((icmp6h->icmp6_type == 129) && (icmp6h->icmp6_code == 0)){ //echo-reply + if(local_diag->ipv6_enable && local_diag->echo){ + return TC_ACT_OK; + } + else{ + return TC_ACT_SHOT; + } + } + } + return TC_ACT_OK; + } + if(local_diag->vrrp && (event.proto == 112)){ + return TC_ACT_OK; + } + } + return TC_ACT_SHOT; + } + + /*Allow IPv6 DHCP*/ + if(ipv6){ + tuple_len = sizeof(tuple->ipv6); + if ((unsigned long)tuple + tuple_len > (unsigned long)skb->data_end){ + if(local_diag->verbose){ + event.error_code = IPV6_TUPLE_TOO_BIG; + send_event(&event); + } + return TC_ACT_SHOT; + } + if((bpf_ntohs(tuple->ipv6.sport) == 546) && (bpf_ntohs(tuple->ipv6.dport) == 547)){ + return TC_ACT_OK; + } + } + + if(ipv4) + { + struct iphdr *iph = (struct iphdr *)(skb->data + sizeof(*eth)); + if ((unsigned long)(iph + 1) > (unsigned long)skb->data_end){ + return TC_ACT_SHOT; + } + __u8 protocol = iph->protocol; + if(protocol == IPPROTO_TCP){ + tcp = true; + } + tuple_len = sizeof(tuple->ipv4); + if ((unsigned long)tuple + tuple_len > (unsigned long)skb->data_end){ + if(local_diag->verbose){ + event.error_code = IP_TUPLE_TOO_BIG; + send_event(&event); + } + return TC_ACT_SHOT; + } + __u32 saddr_array[4] = {tuple->ipv4.saddr,0,0,0}; + __u32 daddr_array[4] = {tuple->ipv4.daddr,0,0,0}; + memcpy(event.saddr,saddr_array, sizeof(saddr_array)); + memcpy(event.daddr,daddr_array, sizeof(daddr_array)); + event.sport = tuple->ipv4.sport; + event.dport = tuple->ipv4.dport; + /*if packet egressing on loopback interface and its source is the ziti0 ip address + *redirect the packet to the ziti0 interface. Added to provide support for L2tpV3 over + *over openziti with ziti-edge-tunnel + */ + if((skb->ifindex == 1) && tun_if && tun_if->resolver){ + uint32_t tun_ip = bpf_ntohl(tun_if->resolver) - 1; + if(tuple->ipv4.saddr == bpf_htonl(tun_ip)){ + return bpf_redirect(tun_if->index, 0); + } + } + if(skb->ifindex == 1){ + return TC_ACT_OK; + } + + if(!local_diag->outbound_filter){ + return TC_ACT_PIPE; + } + + /* allow return traffic from ssh to local interface ip addresses + *if inbound ssh is enabled + */ + if(!local_diag->ssh_disable){ + if(tcp && (bpf_ntohs(tuple->ipv4.sport) == 22)){ + if((!local_ip4 || !local_ip4->count)){ + return TC_ACT_OK; + }else{ + uint8_t addresses = 0; + if(local_ip4->count < MAX_ADDRESSES){ + addresses = local_ip4->count; + }else{ + addresses = MAX_ADDRESSES; + } + for(int x = 0; x < addresses; x++){ + if(tuple->ipv4.saddr == local_ip4->ipaddr[x]){ + if(local_diag->verbose && ((event.tstamp % 2) == 0)){ + event.proto = IPPROTO_TCP; + send_event(&event); + } + return TC_ACT_OK; + } + } + } + } + } + + if(tcp) + { + + + event.proto = IPPROTO_TCP; + struct tcphdr *tcph = (struct tcphdr *)((unsigned long)iph + sizeof(*iph)); + if ((unsigned long)(tcph + 1) > (unsigned long)skb->data_end){ + return TC_ACT_SHOT; + } + reverse_tuple.ipv4.daddr = tuple->ipv4.saddr; + reverse_tuple.ipv4.dport = tuple->ipv4.sport; + reverse_tuple.ipv4.saddr = tuple->ipv4.daddr; + reverse_tuple.ipv4.sport = tuple->ipv4.dport; + sk = bpf_skc_lookup_tcp(skb, &reverse_tuple, sizeof(reverse_tuple.ipv4),BPF_F_CURRENT_NETNS, 0); + if(sk && sk->dst_ip4){ + if ((sk->state != BPF_TCP_LISTEN) && (sk->state != BPF_TCP_SYN_SENT)){ + bpf_sk_release(sk); + if(local_diag->verbose){ + send_event(&event); + } + return TC_ACT_OK; + } + bpf_sk_release(sk); + }else{ + if(sk){ + bpf_sk_release(sk); + } + tcp_state_key.__in46_u_dst.ip = tuple->ipv4.saddr; + tcp_state_key.__in46_u_src.ip = tuple->ipv4.daddr; + tcp_state_key.sport = tuple->ipv4.dport; + tcp_state_key.dport = tuple->ipv4.sport; + unsigned long long tstamp = bpf_ktime_get_ns(); + struct tcp_state *tstate = get_ingress_tcp(tcp_state_key); + /*check tcp state and timeout if greater than 60 minutes without traffic*/ + if(tstate && (tstamp < (tstate->tstamp + 3600000000000))){ + if(tcph->syn && tcph->ack){ + tstate->ack =1; + tstate->tstamp = tstamp; + if(local_diag->verbose){ + event.tracking_code = INGRESS_SERVER_SYN_ACK_RCVD; + send_event(&event); + } + return TC_ACT_OK; + } + else if(tcph->fin){ + if(tstate->est){ + tstate->tstamp = tstamp; + tstate->sfin = 1; + tstate->sfseq = tcph->seq; + if(local_diag->verbose){ + event.tracking_code = INGRESS_SERVER_FIN_RCVD; + send_event(&event); + } + return TC_ACT_OK; + } + } + else if(tcph->rst){ + del_tcp(tcp_state_key); + tstate = get_ingress_tcp(tcp_state_key); + if(!tstate){ + if(local_diag->verbose){ + event.tracking_code = INGRESS_SERVER_RST_RCVD; + send_event(&event); + } + } + return TC_ACT_OK; + } + else if(tcph->ack){ + if((tstate->est) && (tstate->sfin == 1) && (tstate->cfin == 1) && (bpf_htonl(tcph->ack_seq) == (bpf_htonl(tstate->cfseq) + 1))){ + del_ingress_tcp(tcp_state_key); + tstate = get_ingress_tcp(tcp_state_key); + if(!tstate){ + if(local_diag->verbose){ + event.tracking_code = INGRESS_SERVER_FINAL_ACK_RCVD; + send_event(&event); + } + } + + } + else if((tstate->est) && (tstate->cfin == 1) && (bpf_htonl(tcph->ack_seq) == (bpf_htonl(tstate->cfseq) + 1))){ + tstate->sfack = 1; + tstate->tstamp = tstamp; + return TC_ACT_OK; + } + else if(tstate->est){ + tstate->tstamp = tstamp; + return TC_ACT_OK; + } + } + return TC_ACT_OK; + } + else if(tstate){ + del_ingress_tcp(tcp_state_key); + } + } + } + else + { + event.proto = IPPROTO_UDP; + udp_state_key.__in46_u_dst.ip = tuple->ipv4.saddr; + udp_state_key.__in46_u_src.ip = tuple->ipv4.daddr; + udp_state_key.sport = tuple->ipv4.dport; + udp_state_key.dport = tuple->ipv4.sport; + unsigned long long tstamp = bpf_ktime_get_ns(); + struct udp_state *ustate = get_udp_ingress(udp_state_key); + if(ustate) + { + /*if udp outbound state has been up for 30 seconds without traffic remove it from hashmap*/ + if(tstamp > (ustate->tstamp + 30000000000)){ + del_udp_ingress(udp_state_key); + ustate = get_udp_ingress(udp_state_key); + if(!ustate){ + if(local_diag->verbose){ + event.tracking_code = INGRESS_UDP_MATCHED_EXPIRED_STATE; + send_event(&event); + } + } + } + else{ + if(local_diag->verbose){ + event.tracking_code = INGRESS_UDP_MATCHED_ACTIVE_STATE; + send_event(&event); + } + ustate->tstamp = tstamp; + return TC_ACT_OK; + } + } + /* forward DHCP messages to local system */ + if((bpf_ntohs(tuple->ipv4.sport) == 68) && (bpf_ntohs(tuple->ipv4.dport) == 67)){ + return TC_ACT_OK; + } + + } + 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 && (local_diag->ipv6_enable || skb->ifindex == 1)){ + if(skb->ifindex == 1){ + return TC_ACT_OK; + } + if(!local_diag->outbound_filter){ + return TC_ACT_PIPE; + } + struct ipv6hdr *ip6h = (struct ipv6hdr *)(skb->data + sizeof(*eth)); + if ((unsigned long)(ip6h + 1) > (unsigned long)skb->data_end){ + return TC_ACT_SHOT; + } + __u8 protocol = ip6h->nexthdr; + if(protocol == IPPROTO_TCP){ + tcp = true; + } + tuple_len = sizeof(tuple->ipv6); + if ((unsigned long)tuple + tuple_len > (unsigned long)skb->data_end){ + if(local_diag->verbose){ + event.error_code = IPV6_TUPLE_TOO_BIG; + send_event(&event); + } + return TC_ACT_SHOT; + } + memcpy(event.saddr,tuple->ipv6.saddr, sizeof(tuple->ipv6.saddr)); + memcpy(event.daddr,tuple->ipv6.daddr, sizeof(tuple->ipv6.daddr)); + event.sport = tuple->ipv6.sport; + event.dport = tuple->ipv6.dport; + /* allow ssh to local interface ip addresses */ + if(!local_diag->ssh_disable){ + if(tcp && (bpf_ntohs(tuple->ipv6.sport) == 22)){ + if((!local_ip6 || !local_ip6->count)){ + return TC_ACT_OK; + }else{ + uint8_t addresses = 0; + if(local_ip6->count < MAX_ADDRESSES){ + addresses = local_ip6->count; + }else{ + addresses = MAX_ADDRESSES; + } + + for(int x = 0; x < addresses; x++){ + if((local_ip6->ipaddr[x][0] == tuple->ipv6.saddr[0]) && (local_ip6->ipaddr[x][1] == tuple->ipv6.saddr[1]) && + (local_ip6->ipaddr[x][2] == tuple->ipv6.saddr[2]) && (local_ip6->ipaddr[x][3] == tuple->ipv6.saddr[3])){ + if(local_diag->verbose && ((event.tstamp % 2) == 0)){ + event.proto = IPPROTO_TCP; + send_event(&event); + } + return TC_ACT_OK; + } + } + } + } + } + if(tcp){ + event.proto = IPPROTO_TCP; + struct tcphdr *tcph = (struct tcphdr *)((unsigned long)ip6h + sizeof(*ip6h)); + if ((unsigned long)(tcph + 1) > (unsigned long)skb->data_end){ + return TC_ACT_SHOT; + } + memcpy(reverse_tuple.ipv6.daddr, tuple->ipv6.saddr, sizeof(tuple->ipv6.saddr)); + reverse_tuple.ipv6.dport = tuple->ipv6.sport; + memcpy(reverse_tuple.ipv6.saddr, tuple->ipv6.daddr, sizeof(tuple->ipv6.daddr)); + reverse_tuple.ipv6.sport = tuple->ipv6.dport; + sk = bpf_skc_lookup_tcp(skb, &reverse_tuple, sizeof(reverse_tuple.ipv6),BPF_F_CURRENT_NETNS, 0); + if(sk && sk->dst_ip6[0]){ + if ((sk->state != BPF_TCP_LISTEN) && (sk->state != BPF_TCP_SYN_SENT)){ + bpf_sk_release(sk); + if(local_diag->verbose){ + send_event(&event); + } + return TC_ACT_OK; + } + bpf_sk_release(sk); + }else{ + if(sk){ + bpf_sk_release(sk); + } + memcpy(tcp_state_key.__in46_u_dst.ip6,tuple->ipv6.saddr, sizeof(tuple->ipv6.saddr)); + memcpy(tcp_state_key.__in46_u_src.ip6,tuple->ipv6.daddr, sizeof(tuple->ipv6.daddr)); + tcp_state_key.sport = tuple->ipv6.dport; + tcp_state_key.dport = tuple->ipv6.sport; + unsigned long long tstamp = bpf_ktime_get_ns(); + struct tcp_state *tstate = get_ingress_tcp(tcp_state_key); + /*check tcp state and timeout if greater than 60 minutes without traffic*/ + if(tstate && (tstamp < (tstate->tstamp + 3600000000000))) + { + if(tcph->syn && tcph->ack){ + tstate->ack =1; + tstate->tstamp = tstamp; + if(local_diag->verbose){ + event.tracking_code = INGRESS_SERVER_SYN_ACK_RCVD; + send_event(&event); + } + return TC_ACT_OK; + } + else if(tcph->fin){ + if(tstate->est){ + tstate->tstamp = tstamp; + tstate->sfin = 1; + tstate->sfseq = tcph->seq; + if(local_diag->verbose){ + event.tracking_code = INGRESS_SERVER_FIN_RCVD; + send_event(&event); + } + return TC_ACT_OK; + } + } + else if(tcph->rst){ + del_ingress_tcp(tcp_state_key); + tstate = get_ingress_tcp(tcp_state_key); + if(!tstate){ + if(local_diag->verbose){ + event.tracking_code = INGRESS_SERVER_RST_RCVD; + send_event(&event); + } + } + return TC_ACT_OK; + } + else if(tcph->ack){ + if((tstate->est) && (tstate->sfin == 1) && (tstate->cfin == 1) && (bpf_htonl(tcph->ack_seq) == (bpf_htonl(tstate->cfseq) + 1))){ + del_ingress_tcp(tcp_state_key); + tstate = get_ingress_tcp(tcp_state_key); + if(!tstate){ + if(local_diag->verbose){ + event.tracking_code = INGRESS_SERVER_FINAL_ACK_RCVD; + send_event(&event); + } + } + + } + else if((tstate->est) && (tstate->cfin == 1) && (bpf_htonl(tcph->ack_seq) == (bpf_htonl(tstate->cfseq) + 1))){ + tstate->sfack = 1; + tstate->tstamp = tstamp; + return TC_ACT_OK; + } + else if(tstate->est){ + tstate->tstamp = tstamp; + return TC_ACT_OK; + } + } + return TC_ACT_OK; + } + else if(tstate){ + del_ingress_tcp(tcp_state_key); + } + } + }else + { + event.proto = IPPROTO_UDP; + memcpy(udp_state_key.__in46_u_dst.ip6,tuple->ipv6.saddr, sizeof(tuple->ipv6.saddr)); + memcpy(udp_state_key.__in46_u_src.ip6,tuple->ipv6.daddr, sizeof(tuple->ipv6.daddr)); + udp_state_key.sport = tuple->ipv6.dport; + udp_state_key.dport = tuple->ipv6.sport; + unsigned long long tstamp = bpf_ktime_get_ns(); + struct udp_state *ustate = get_udp_ingress(udp_state_key); + if(ustate){ + /*if udp outbound state has been up for 30 seconds without traffic remove it from hashmap*/ + if(tstamp > (ustate->tstamp + 30000000000)){ + del_udp_ingress(udp_state_key); + ustate = get_udp_ingress(udp_state_key); + if(!ustate){ + if(local_diag->verbose){ + event.tracking_code = INGRESS_UDP_MATCHED_EXPIRED_STATE; + send_event(&event); + } + } + } + else{ + if(local_diag->verbose){ + event.tracking_code = INGRESS_UDP_MATCHED_ACTIVE_STATE; + send_event(&event); + } + ustate->tstamp = tstamp; + return TC_ACT_OK; + } + } + } + struct match6_key mkey = {0}; + memcpy(mkey.daddr, tuple->ipv6.daddr, sizeof(tuple->ipv6.daddr)); + memcpy(mkey.saddr, tuple->ipv6.saddr, sizeof(tuple->ipv6.saddr)); + mkey.sport = tuple->ipv6.sport; + mkey.dport = tuple->ipv6.dport; + mkey.ifindex = skb->ifindex; + mkey.protocol = event.proto; + clear_match6_tracker(mkey); + return TC_ACT_PIPE; + } + return TC_ACT_SHOT; +} + +SEC("action/1") +int bpf_sk_splice1(struct __sk_buff *skb){ + /*look up attached interface inbound diag status*/ + struct diag_ip4 *local_diag = get_diag_ip4(skb->ifindex); + if(!local_diag){ + return TC_ACT_SHOT; + } + if(!local_diag->outbound_filter){ + return TC_ACT_PIPE; + } + struct bpf_sock_tuple *tuple; + int tuple_len; + __u8 protocol; + + /* find ethernet header from skb->data pointer */ + struct ethhdr *eth = (struct ethhdr *)(unsigned long)(skb->data); + if ((unsigned long)(eth + 1) > (unsigned long)skb->data_end){ + return TC_ACT_SHOT; + } + struct tproxy_tuple *tproxy = NULL; + if(eth->h_proto == bpf_htons(ETH_P_IP)){ + /* check if incoming packet is a UDP or TCP tuple */ + struct iphdr *iph = (struct iphdr *)(skb->data + sizeof(*eth)); + if ((unsigned long)(iph + 1) > (unsigned long)skb->data_end){ + return TC_ACT_SHOT; + } + protocol = iph->protocol; + tuple = (struct bpf_sock_tuple *)(void*)(long)&iph->saddr; + tuple_len = sizeof(tuple->ipv4); + if ((unsigned long)tuple + tuple_len > (unsigned long)skb->data_end){ + return TC_ACT_SHOT; + } + __u32 dexponent=24; /* unsigned integer used to calculate prefix matches */ + __u32 dmask = 0xffffffff; /* starting mask value used in prefix match calculation */ + __u32 sexponent=24; /* unsigned integer used to calculate prefix matches */ + __u32 smask = 0xffffffff; /* starting mask value used in prefix match calculation */ + __u8 maxlen = 8; /* max number ip ipv4 prefixes */ + __u8 smaxlen = 32; /* max number ip ipv4 prefixes */ + /*Main loop to lookup tproxy prefix matches in the zt_tproxy_map*/ + struct match_tracker key_tracker = {0,{}}; + struct match_key mkey = {tuple->ipv4.saddr, tuple->ipv4.daddr, tuple->ipv4.sport, tuple->ipv4.dport, skb->ifindex, protocol}; + insert_matched_key(key_tracker, mkey); + struct match_tracker *tracked_key_data = get_matched_keys(mkey); + if(!tracked_key_data){ + return TC_ACT_SHOT; + } + for (__u16 dcount = 0;dcount <= maxlen; dcount++){ + + /* + * lookup based on tuple-ipv4.daddr logically ANDed with + * cidr mask starting with /32 and working down to /1 if no match packet is discarded + */ + for (__u16 scount = 0; scount <= smaxlen; scount++){ + + struct tproxy_key key = {(tuple->ipv4.daddr & dmask),(tuple->ipv4.saddr & smask), 32-dcount, smaxlen-scount, protocol, 0}; + if ((tproxy = get_egress(key))){ + if(tracked_key_data->count < MATCHED_KEY_DEPTH){ + tracked_key_data->matched_keys[tracked_key_data->count] = key; + tracked_key_data->count++; + } + if(tracked_key_data->count == MATCHED_KEY_DEPTH){ + return TC_ACT_PIPE; + } + } + if(smask == 0x00000000){ + break; + } + iterate_masks(&smask, &sexponent); + sexponent++; + } + /*algorithm used to calculate mask while traversing + each octet. + */ + if(dmask == 0x80ffffff){ + return TC_ACT_PIPE; + } + iterate_masks(&dmask, &dexponent); + smask = 0xffffffff; + sexponent = 24; + dexponent++; + } + }else{ + struct ipv6hdr *ip6h = (struct ipv6hdr *)(skb->data + sizeof(*eth)); + /* ensure ip header is in packet bounds */ + if ((unsigned long)(ip6h + 1) > (unsigned long)skb->data_end){ + return TC_ACT_SHOT; + } + protocol = ip6h->nexthdr; + tuple = (struct bpf_sock_tuple *)(void*)(long)&ip6h->saddr; + tuple_len = sizeof(tuple->ipv6); + if ((unsigned long)tuple + tuple_len > (unsigned long)skb->data_end){ + return TC_ACT_SHOT; + } + unsigned int saddr[4] = {0,0,0,0}; + __u32 maxlen = 32; /* max number ip ipv6 prefixes in quad */ + __u32 mask0 = 0xffffffff; /* starting mask value used in prefix match calculation */ + __u32 mask1 = 0xffffffff; /* starting mask value used in prefix match calculation */ + __u32 mask2 = 0xffffffff; /* starting mask value used in prefix match calculation */ + __u32 mask3 = 0xffffffff; /* starting mask value used in prefix match calculation */ + __u32 exponent3 = 24; /* unsigned integer used to calculate prefix matches */ + struct match6_key mkey = {0}; + memcpy(mkey.daddr, tuple->ipv6.daddr, sizeof(tuple->ipv6.daddr)); + memcpy(mkey.saddr, tuple->ipv6.saddr, sizeof(tuple->ipv6.saddr)); + mkey.sport = tuple->ipv6.sport; + mkey.dport = tuple->ipv6.dport; + mkey.ifindex = skb->ifindex; + mkey.protocol = protocol; + struct tproxy6_key key = {0}; + key.sprefix_len = 0; + key.protocol = protocol; + key.dprefix_len = 128; + key.pad = 0; + + for (__u16 dcount3 = 0; dcount3 < maxlen; dcount3++){ + unsigned int daddr[4] = {tuple->ipv6.daddr[0], tuple->ipv6.daddr[1], tuple->ipv6.daddr[2], tuple->ipv6.daddr[3] & mask3}; + memcpy(key.dst_ip ,daddr, sizeof(daddr)); + memcpy(key.src_ip, saddr, sizeof(saddr)); + if ((tproxy = get_egress6(key))){ + insert_matched6_key(key, mkey); + return TC_ACT_PIPE; + } + key.dprefix_len--; + if(mask3 == 0x00000000){ + break; + } + iterate_masks(&mask3, &exponent3); + exponent3++; + } + __u32 exponent2 = 24; //unsigned integer used to calculate prefix matches + for (__u16 dcount2 = 0; dcount2 < maxlen; dcount2++){ + unsigned int daddr[4] = {tuple->ipv6.daddr[0], tuple->ipv6.daddr[1], tuple->ipv6.daddr[2] & mask2, tuple->ipv6.daddr[3] & mask3}; + memcpy(key.dst_ip ,daddr, sizeof(daddr)); + memcpy(key.src_ip, saddr, sizeof(saddr)); + if ((tproxy = get_egress6(key))){ + insert_matched6_key(key, mkey); + return TC_ACT_PIPE; + } + key.dprefix_len--; + if(mask2 == 0x00000000){ + break; + } + iterate_masks(&mask2, &exponent2); + exponent2++; + } + __u32 exponent1 = 24; //unsigned integer used to calculate prefix matches + for (__u16 dcount1 = 0; dcount1 < maxlen; dcount1++){ + unsigned int daddr[4] = {tuple->ipv6.daddr[0], tuple->ipv6.daddr[1] & mask1, tuple->ipv6.daddr[2] & mask2, tuple->ipv6.daddr[3] & mask3}; + memcpy(key.dst_ip ,daddr, sizeof(daddr)); + memcpy(key.src_ip, saddr, sizeof(saddr)); + if ((tproxy = get_egress6(key))){ + insert_matched6_key(key, mkey); + return TC_ACT_PIPE; + } + key.dprefix_len--; + if(mask1 == 0x00000000){ + break; + } + iterate_masks(&mask1, &exponent1); + exponent1++; + } + __u32 exponent0 = 24; // unsigned integer used to calculate prefix matches + for (__u16 dcount0 = 0; dcount0 <= maxlen; dcount0++){ + unsigned int daddr[4] = {tuple->ipv6.daddr[0] & mask0, tuple->ipv6.daddr[1] & mask1, tuple->ipv6.daddr[2] & mask2, tuple->ipv6.daddr[3] & mask3}; + memcpy(key.dst_ip ,daddr, sizeof(daddr)); + memcpy(key.src_ip, saddr, sizeof(saddr)); + if ((tproxy = get_egress6(key))){ + insert_matched6_key(key, mkey); + return TC_ACT_PIPE; + } + key.dprefix_len--; + if(mask0 == 0x00000000){ + break; + } + iterate_masks(&mask0, &exponent0); + exponent0++; + } + } + if(skb->ifindex == 1){ + return TC_ACT_OK; + } + return TC_ACT_SHOT; +} + +SEC("action/2") +int bpf_sk_splice2(struct __sk_buff *skb){ + struct bpf_sock_tuple *tuple; + int tuple_len; + __u8 protocol; + + struct diag_ip4 *local_diag = get_diag_ip4(skb->ifindex); + if(!local_diag){ + return TC_ACT_SHOT; + } + if(!local_diag->outbound_filter){ + return TC_ACT_PIPE; + } + /* find ethernet header from skb->data pointer */ + struct ethhdr *eth = (struct ethhdr *)(unsigned long)(skb->data); + if ((unsigned long)(eth + 1) > (unsigned long)skb->data_end){ + return TC_ACT_SHOT; + } + if(eth->h_proto == bpf_htons(ETH_P_IPV6)){ + return TC_ACT_PIPE; + } + /* check if incomming packet is a UDP or TCP tuple */ + struct iphdr *iph = (struct iphdr *)(skb->data + sizeof(*eth)); + if ((unsigned long)(iph + 1) > (unsigned long)skb->data_end){ + return TC_ACT_SHOT; + } + protocol = iph->protocol; + tuple = (struct bpf_sock_tuple *)(void*)(long)&iph->saddr; + tuple_len = sizeof(tuple->ipv4); + if ((unsigned long)tuple + tuple_len > (unsigned long)skb->data_end){ + return TC_ACT_SHOT; + } + struct tproxy_tuple *tproxy; + __u32 dexponent=16; /* unsigned integer used to calulate prefix matches */ + __u32 dmask = 0xffffff; /* starting mask value used in prfix match calculation */ + __u32 sexponent=24; /* unsigned integer used to calulate prefix matches */ + __u32 smask = 0xffffffff; /* starting mask value used in prfix match calculation */ + __u8 maxlen = 8; /* max number ip ipv4 prefixes */ + __u8 smaxlen = 32; /* max number ip ipv4 prefixes */ + /*Main loop to lookup tproxy prefix matches in the zt_tproxy_map*/ + struct match_key mkey = {tuple->ipv4.saddr, tuple->ipv4.daddr, tuple->ipv4.sport, tuple->ipv4.dport, skb->ifindex, protocol}; + struct match_tracker *tracked_key_data = get_matched_keys(mkey); + if(!tracked_key_data){ + return TC_ACT_SHOT; + } + for (__u16 dcount = 0;dcount <= maxlen; dcount++){ + + /* + * lookup based on tuple-ipv4.daddr logically ANDed with + * cidr mask starting with /32 and working down to /1 if no match packet is discarded + */ + for (__u16 scount = 0; scount <= smaxlen; scount++){ + + struct tproxy_key key = {(tuple->ipv4.daddr & dmask),(tuple->ipv4.saddr & smask), 24-dcount, smaxlen-scount, protocol, 0}; + + if ((tproxy = get_egress(key))){ + if(tracked_key_data->count < MATCHED_KEY_DEPTH){ + tracked_key_data->matched_keys[tracked_key_data->count] = key; + tracked_key_data->count++; + } + if(tracked_key_data->count == MATCHED_KEY_DEPTH){ + return TC_ACT_PIPE; + } + } + if(smask == 0x00000000){ + break; + } + iterate_masks(&smask, &sexponent); + sexponent++; + } + /*algorithm used to calculate mask while traversing + each octet. + */ + if(dmask == 0x80ffff){ + return TC_ACT_PIPE; + } + iterate_masks(&dmask, &dexponent); + smask = 0xffffffff; + sexponent = 24; + dexponent++; + } + return TC_ACT_SHOT; +} + +SEC("action/3") +int bpf_sk_splice3(struct __sk_buff *skb){ + struct bpf_sock_tuple *tuple; + int tuple_len; + __u8 protocol; -/*get entry from tcp state table*/ -static inline struct tcp_state *get_tcp(struct tuple_key key){ - struct tcp_state *ts; - ts = bpf_map_lookup_elem(&tcp_map, &key); - return ts; + struct diag_ip4 *local_diag = get_diag_ip4(skb->ifindex); + if(!local_diag){ + return TC_ACT_SHOT; + } + if(!local_diag->outbound_filter){ + return TC_ACT_PIPE; + } + /* find ethernet header from skb->data pointer */ + struct ethhdr *eth = (struct ethhdr *)(unsigned long)(skb->data); + if ((unsigned long)(eth + 1) > (unsigned long)skb->data_end){ + return TC_ACT_SHOT; + } + if(eth->h_proto == bpf_htons(ETH_P_IPV6)){ + return TC_ACT_PIPE; + } + /* check if incomming packet is a UDP or TCP tuple */ + struct iphdr *iph = (struct iphdr *)(skb->data + sizeof(*eth)); + if ((unsigned long)(iph + 1) > (unsigned long)skb->data_end){ + return TC_ACT_SHOT; + } + protocol = iph->protocol; + tuple = (struct bpf_sock_tuple *)(void*)(long)&iph->saddr; + tuple_len = sizeof(tuple->ipv4); + if ((unsigned long)tuple + tuple_len > (unsigned long)skb->data_end){ + return TC_ACT_SHOT; + } + struct tproxy_tuple *tproxy; + __u32 dexponent=8; /* unsigned integer used to calulate prefix matches */ + __u32 dmask = 0xffff; /* starting mask value used in prfix match calculation */ + __u32 sexponent=24; /* unsigned integer used to calulate prefix matches */ + __u32 smask = 0xffffffff; /* starting mask value used in prfix match calculation */ + __u8 maxlen = 8; /* max number ip ipv4 prefixes */ + __u8 smaxlen = 32; /* max number ip ipv4 prefixes */ + /*Main loop to lookup tproxy prefix matches in the zt_tproxy_map*/ + struct match_key mkey = {tuple->ipv4.saddr, tuple->ipv4.daddr, tuple->ipv4.sport, tuple->ipv4.dport, skb->ifindex, protocol}; + struct match_tracker *tracked_key_data = get_matched_keys(mkey); + if(!tracked_key_data){ + return TC_ACT_SHOT; + } + for (__u16 dcount = 0;dcount <= maxlen; dcount++){ + + /* + * lookup based on tuple-ipv4.daddr logically ANDed with + * cidr mask starting with /32 and working down to /1 if no match packet is discarded + */ + for (__u16 scount = 0; scount <= smaxlen; scount++){ + + struct tproxy_key key = {(tuple->ipv4.daddr & dmask),(tuple->ipv4.saddr & smask), 16-dcount, smaxlen-scount, protocol, 0}; + if ((tproxy = get_egress(key))){ + if(tracked_key_data->count < MATCHED_KEY_DEPTH){ + tracked_key_data->matched_keys[tracked_key_data->count] = key; + tracked_key_data->count++; + } + if(tracked_key_data->count == MATCHED_KEY_DEPTH){ + return TC_ACT_PIPE; + } + } + if(smask == 0x00000000){ + break; + } + iterate_masks(&smask, &sexponent); + sexponent++; + } + /*algorithm used to calculate mask while traversing + each octet. + */ + if(dmask == 0x80ff){ + return TC_ACT_PIPE; + } + iterate_masks(&dmask, &dexponent); + smask = 0xffffffff; + sexponent = 24; + dexponent++; + } + return TC_ACT_SHOT; } -/*Insert entry into udp state table*/ -static inline void insert_udp(struct udp_state ustate, struct tuple_key key){ - bpf_map_update_elem(&udp_map, &key, &ustate,0); -} +SEC("action/4") +int bpf_sk_splice4(struct __sk_buff *skb){ + struct bpf_sock_tuple *tuple; + int tuple_len; + __u8 protocol; -/*get entry from udp state table*/ -static inline struct udp_state *get_udp(struct tuple_key key){ - struct udp_state *us; - us = bpf_map_lookup_elem(&udp_map, &key); - return us; + struct diag_ip4 *local_diag = get_diag_ip4(skb->ifindex); + if(!local_diag){ + return TC_ACT_SHOT; + } + if(!local_diag->outbound_filter){ + return TC_ACT_PIPE; + } + /* find ethernet header from skb->data pointer */ + struct ethhdr *eth = (struct ethhdr *)(unsigned long)(skb->data); + if ((unsigned long)(eth + 1) > (unsigned long)skb->data_end){ + return TC_ACT_SHOT; + } + if(eth->h_proto == bpf_htons(ETH_P_IPV6)){ + return TC_ACT_PIPE; + } + /* check if incomming packet is a UDP or TCP tuple */ + struct iphdr *iph = (struct iphdr *)(skb->data + sizeof(*eth)); + if ((unsigned long)(iph + 1) > (unsigned long)skb->data_end){ + return TC_ACT_SHOT; + } + protocol = iph->protocol; + tuple = (struct bpf_sock_tuple *)(void*)(long)&iph->saddr; + tuple_len = sizeof(tuple->ipv4); + if ((unsigned long)tuple + tuple_len > (unsigned long)skb->data_end){ + return TC_ACT_SHOT; + } + struct tproxy_tuple *tproxy; + __u32 dexponent=0; /* unsigned integer used to calulate prefix matches */ + __u32 dmask = 0xff; /* starting mask value used in prfix match calculation */ + __u32 sexponent=24; /* unsigned integer used to calulate prefix matches */ + __u32 smask = 0xffffffff; /* starting mask value used in prfix match calculation */ + __u8 maxlen = 8; /* max number ip ipv4 prefixes */ + __u8 smaxlen = 32; /* max number ip ipv4 prefixes */ + /*Main loop to lookup tproxy prefix matches in the zt_tproxy_map*/ + struct match_key mkey = {tuple->ipv4.saddr, tuple->ipv4.daddr, tuple->ipv4.sport, tuple->ipv4.dport, skb->ifindex, protocol}; + struct match_tracker *tracked_key_data = get_matched_keys(mkey); + if(!tracked_key_data){ + return TC_ACT_SHOT; + } + for (__u16 dcount = 0;dcount <= maxlen; dcount++){ + + /* + * lookup based on tuple-ipv4.daddr logically ANDed with + * cidr mask starting with /32 and working down to /1 if no match packet is discarded + */ + for (__u16 scount = 0; scount <= smaxlen; scount++){ + + struct tproxy_key key = {(tuple->ipv4.daddr & dmask),(tuple->ipv4.saddr & smask), 8-dcount, smaxlen-scount, protocol, 0}; + if ((tproxy = get_egress(key))){ + if(tracked_key_data->count < MATCHED_KEY_DEPTH){ + tracked_key_data->matched_keys[tracked_key_data->count] = key; + tracked_key_data->count++; + } + if(tracked_key_data->count == MATCHED_KEY_DEPTH){ + return TC_ACT_PIPE; + } + } + if(smask == 0x00000000){ + break; + } + iterate_masks(&smask, &sexponent); + sexponent++; + } + /*algorithm used to calculate mask while traversing + each octet. + */ + if(dmask == 0x00000000){ + if((tracked_key_data->count > 0)){ + return TC_ACT_PIPE; + }else if(skb->ifindex == 1){ + return TC_ACT_OK; + } + } + iterate_masks(&dmask, &dexponent); + smask = 0xffffffff; + sexponent = 24; + dexponent++; + } + return TC_ACT_SHOT; } -static inline struct diag_ip4 *get_diag_ip4(__u32 key){ - struct diag_ip4 *if_diag; - if_diag = bpf_map_lookup_elem(&diag_map, &key); - - return if_diag; -} +SEC("action/5") +int bpf_sk_splice5(struct __sk_buff *skb){ + struct bpf_sock_tuple *tuple,sockcheck = {0}; + int tuple_len; -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); - if(rb_event){ - rb_event->version = new_event->version; - rb_event->ifindex = new_event->ifindex; - rb_event->tun_ifindex = new_event->tun_ifindex; - rb_event->tstamp = new_event->tstamp; - memcpy(rb_event->daddr, new_event->daddr, sizeof(rb_event->daddr)); - memcpy(rb_event->saddr, new_event->saddr, sizeof(rb_event->saddr)); - rb_event->dport = new_event->dport; - rb_event->sport = new_event->sport; - rb_event->tport = new_event->tport; - rb_event->proto = new_event->proto; - rb_event->direction = new_event->direction; - rb_event->tracking_code = new_event->tracking_code; - rb_event->error_code = new_event->error_code; - bpf_ringbuf_submit(rb_event, 0); + /*look up attached interface inbound diag status*/ + struct diag_ip4 *local_diag = get_diag_ip4(skb->ifindex); + if(!local_diag){ + return TC_ACT_SHOT; + } + if(!local_diag->outbound_filter){ + return TC_ACT_PIPE; } -} -/* function to determine if an incoming packet is a udp/tcp IP tuple -* or not. If not returns NULL. If true returns a struct bpf_sock_tuple -* 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 bpf_event *event,struct diag_ip4 *local_diag){ - struct bpf_sock_tuple *result = NULL; - __u8 proto = 0; - - /* check if ARP */ - if (eth_proto == bpf_htons(ETH_P_ARP)) { - *arp = true; - return NULL; + /* find ethernet header from skb->data pointer */ + struct ethhdr *eth = (struct ethhdr *)(unsigned long)(skb->data); + if ((unsigned long)(eth + 1) > (unsigned long)skb->data_end){ + return TC_ACT_SHOT; } - - /* check IP */ - struct iphdr *iph = NULL; - struct ipv6hdr *ip6h = NULL; - if (eth_proto == bpf_htons(ETH_P_IP)) - { - event->version = 4; - /* find ip hdr */ - iph = (struct iphdr *)(skb->data + nh_off); - /* ensure ip header is in packet bounds */ + + unsigned long long tstamp = bpf_ktime_get_ns(); + struct bpf_event event = { + 0, + tstamp, + skb->ifindex, + 0, + {0}, + {0}, + 0, + 0, + 0, + 0, + EGRESS, + 0, + 0, + {}, + {} + }; + + struct tproxy_tuple *tproxy = NULL; + if(eth->h_proto == bpf_htons(ETH_P_IP)){ + struct tproxy_key key; + /* check if incomming packet is a UDP or TCP tuple */ + struct iphdr *iph = (struct iphdr *)(skb->data + sizeof(*eth)); if ((unsigned long)(iph + 1) > (unsigned long)skb->data_end){ - event->error_code = IP_HEADER_TOO_BIG; - send_event(event); - return NULL; + return TC_ACT_SHOT; } - /* ip options not allowed */ - if (iph->ihl != 5){ - if(local_diag->verbose){ - event->error_code = NO_IP_OPTIONS_ALLOWED; - send_event(event); - } - return NULL; + __u8 protocol = iph->protocol; + tuple = (struct bpf_sock_tuple *)(void*)(long)&iph->saddr; + if(!tuple){ + return TC_ACT_SHOT; } - *ipv4 = true; - proto = iph->protocol; - }else if(eth_proto == bpf_htons(ETH_P_IPV6)){ - event->version = 6; - ip6h = (struct ipv6hdr *)(skb->data + nh_off); - /* ensure ip header is in packet bounds */ - if ((unsigned long)(ip6h + 1) > (unsigned long)skb->data_end){ - event->error_code = IP6_HEADER_TOO_BIG; - send_event(event); - return NULL; + /* determine length of tuple */ + tuple_len = sizeof(tuple->ipv4); + if ((unsigned long)tuple + tuple_len > (unsigned long)skb->data_end){ + return TC_ACT_SHOT; + } + event.version = iph->version; + uint32_t daddr[4] = {tuple->ipv4.daddr,0,0,0}; + uint32_t saddr[4] = {tuple->ipv4.saddr,0,0,0}; + memcpy(event.daddr, daddr, sizeof(event.daddr)); + memcpy(event.saddr, saddr, sizeof(event.saddr)); + event.dport = tuple->ipv4.dport; + event.sport = tuple->ipv4.sport; + struct match_tracker *key_tracker; + struct match_key mkey = {tuple->ipv4.saddr, tuple->ipv4.daddr, tuple->ipv4.sport, tuple->ipv4.dport, skb->ifindex, protocol}; + __u16 match_count = get_matched_count(mkey); + if (match_count > MATCHED_KEY_DEPTH){ + match_count = MATCHED_KEY_DEPTH; + } + for(__u16 count =0; count < match_count; count++) + { + key_tracker = get_matched_keys(mkey); + if(key_tracker){ + key = key_tracker->matched_keys[count]; + }else{ + break; + } + + if((tproxy = get_egress(key)) && tuple) + { + __u16 max_entries = tproxy->index_len; + if (max_entries > MAX_INDEX_ENTRIES) { + max_entries = MAX_INDEX_ENTRIES; + } + for (int index = 0; index < max_entries; index++){ + __u16 port_key = tproxy->index_table[index]; + struct port_extension_key ext_key = {0}; + ext_key.__in46_u_dst.ip = key.dst_ip; + ext_key.__in46_u_src.ip = key.src_ip; + ext_key.low_port = port_key; + ext_key.dprefix_len = key.dprefix_len; + ext_key.sprefix_len = key.sprefix_len; + ext_key.protocol = key.protocol; + ext_key.pad = 0; + struct range_mapping *range = get_range_ports(ext_key); + //check if there is a udp or tcp destination port match + if (range && ((bpf_ntohs(tuple->ipv4.dport) >= bpf_ntohs(port_key)) + && (bpf_ntohs(tuple->ipv4.dport) <= bpf_ntohs(range->high_port)))) + { + event.proto = key.protocol; + event.tport = range->tproxy_port; + /*check if interface is set for per interface rule awarness and if yes check if it is in the rules interface list. If not in + the interface list drop it on all interfaces accept loopback. If its not aware then forward based on mapping*/ + sockcheck.ipv4.daddr = 0x0100007f; + sockcheck.ipv4.dport = range->tproxy_port; + if(!local_diag->per_interface){ + if(range->tproxy_port == 0){ + if(local_diag->verbose){ + send_event(&event); + } + return TC_ACT_PIPE; + } + } + struct if_list_extension_mapping *ext_mapping = get_if_list_ext_mapping(ext_key); + if(ext_mapping){ + for(int x = 0; x < MAX_IF_LIST_ENTRIES; x++){ + if(ext_mapping->if_list[x] == skb->ifindex){ + if(range->tproxy_port == 0) + { + if(local_diag->verbose){ + send_event(&event); + } + return TC_ACT_PIPE; + } + + } + } + } + event.error_code = IF_LIST_MATCH_ERROR; + send_event(&event); + return TC_ACT_SHOT; + + } + } + } } - *ipv6 = true; - proto = ip6h->nexthdr; - }else{ - return NULL; - } - /* check if ip protocol is UDP */ - if (proto == IPPROTO_UDP) { - *udp = true; - } - - /* check if ip protocol is TCP */ - if (proto == IPPROTO_TCP) { - *tcp = true; - } - if((proto == IPPROTO_ICMP) || (proto == IPPROTO_ICMPV6)){ - *icmp = 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; - } - /*return bpf_sock_tuple*/ - if(*ipv4){ - result = (struct bpf_sock_tuple *)(void*)(long)&iph->saddr; }else { - result = (struct bpf_sock_tuple *)(void*)(long)&ip6h->saddr; + struct ipv6hdr *ip6h = (struct ipv6hdr *)(skb->data + sizeof(*eth)); + // ensure ip header is in packet bounds + if ((unsigned long)(ip6h + 1) > (unsigned long)skb->data_end){ + return TC_ACT_SHOT; + } + tuple = (struct bpf_sock_tuple *)(void*)(long)&ip6h->saddr; + if(!tuple){ + return TC_ACT_SHOT; + } + // determine length of tuple + tuple_len = sizeof(tuple->ipv6); + if ((unsigned long)tuple + tuple_len > (unsigned long)skb->data_end){ + return TC_ACT_SHOT; + } + memcpy(event.daddr, tuple->ipv6.daddr, sizeof(event.daddr)); + memcpy(event.saddr, tuple->ipv6.saddr, sizeof(event.saddr)); + event.dport = tuple->ipv6.dport; + event.sport = tuple->ipv6.sport; + event.version = ip6h->version; + __u8 protocol = ip6h->nexthdr; + tuple = (struct bpf_sock_tuple *)(void*)(long)&ip6h->saddr; + tuple_len = sizeof(tuple->ipv6); + if ((unsigned long)tuple + tuple_len > (unsigned long)skb->data_end){ + return TC_ACT_SHOT; + } + struct match6_key mkey = {0}; + memcpy(mkey.daddr, tuple->ipv6.daddr, sizeof(tuple->ipv6.daddr)); + memcpy(mkey.saddr, tuple->ipv6.saddr, sizeof(tuple->ipv6.saddr)); + mkey.sport = tuple->ipv6.sport; + mkey.dport = tuple->ipv6.dport; + mkey.ifindex = skb->ifindex; + mkey.protocol = protocol; + struct tproxy6_key *key = get_matched6_key(mkey); + if(key) + { + if((tproxy = get_egress6(*key)) && tuple) + { + __u16 max_entries = tproxy->index_len; + if (max_entries > MAX_INDEX_ENTRIES) { + max_entries = MAX_INDEX_ENTRIES; + } + struct port_extension_key ext_key = {0}; + memcpy(ext_key.__in46_u_dst.ip6, key->dst_ip, sizeof(key->dst_ip)); + memcpy(ext_key.__in46_u_src.ip6, key->src_ip, sizeof(key->src_ip)); + ext_key.dprefix_len = key->dprefix_len; + ext_key.sprefix_len = key->sprefix_len; + ext_key.protocol = key->protocol; + ext_key.pad = 0; + for (int index = 0; index < max_entries; index++){ + __u16 port_key = tproxy->index_table[index]; + ext_key.low_port = port_key; + struct range_mapping *range = get_range_ports(ext_key); + //check if there is a udp or tcp destination port match + if (range && ((bpf_ntohs(tuple->ipv6.dport) >= bpf_ntohs(port_key)) + && (bpf_ntohs(tuple->ipv6.dport) <= bpf_ntohs(range->high_port)))) + { + event.proto = key->protocol; + event.tport = range->tproxy_port; + /*check if interface is set for per interface rule awarness and if yes check if it is in the rules interface list. If not in + the interface list drop it on all interfaces accept loopback. If its not aware then forward based on mapping*/ + sockcheck.ipv6.daddr[0]= 0; + sockcheck.ipv6.daddr[1]= 0; + sockcheck.ipv6.daddr[2]= 0; + sockcheck.ipv6.daddr[3]= 0x1000000; + sockcheck.ipv6.dport = range->tproxy_port; + if(!local_diag->per_interface){ + if(range->tproxy_port == 0){ + if(local_diag->verbose){ + send_event(&event); + } + return TC_ACT_PIPE; + } + } + struct if_list_extension_mapping *ext_mapping = get_if_list_ext_mapping(ext_key); + if(ext_mapping) + { + for(int x = 0; x < MAX_IF_LIST_ENTRIES; x++){ + if(ext_mapping->if_list[x] == skb->ifindex){ + if(range->tproxy_port == 0){ + if(local_diag->verbose){ + send_event(&event); + } + return TC_ACT_PIPE; + } + } + } + } + event.error_code = IF_LIST_MATCH_ERROR; + send_event(&event); + return TC_ACT_SHOT; + } + } + } + } } - return result; + return TC_ACT_SHOT; } //ebpf tc code entry program -SEC("action") -int bpf_sk_splice(struct __sk_buff *skb){ +SEC("action/6") +int bpf_sk_splice6(struct __sk_buff *skb){ struct bpf_sock *sk; struct bpf_sock_tuple *tuple, reverse_tuple = {0}; int tuple_len; + bool tcp = false; bool ipv4 = false; bool ipv6 = false; - bool udp=false; - bool tcp=false; - bool arp=false; - bool icmp=false; struct tuple_key tcp_state_key = {0}; struct tuple_key udp_state_key ={0}; @@ -363,18 +1963,40 @@ int bpf_sk_splice(struct __sk_buff *skb){ return TC_ACT_SHOT; } + if(eth->h_proto == bpf_ntohs(ETH_P_IP)){ + ipv4 = true; + } + + if(eth->h_proto == bpf_ntohs(ETH_P_IPV6)){ + ipv6 = true; + } + /* 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, &event, local_diag); + tuple = get_tuple(skb, &event, local_diag); /* if not tuple forward */ if (!tuple){ return TC_ACT_OK; } if(ipv4){ + /* determine length of tuple */ + /* check if incomming packet is a UDP or TCP tuple */ + struct iphdr *iph = (struct iphdr *)(skb->data + sizeof(*eth)); + if ((unsigned long)(iph + 1) > (unsigned long)skb->data_end){ + return TC_ACT_SHOT; + } + __u8 protocol = iph->protocol; + tuple = (struct bpf_sock_tuple *)(void*)(long)&iph->saddr; + if(!tuple){ + return TC_ACT_SHOT; + } /* determine length of tuple */ tuple_len = sizeof(tuple->ipv4); if ((unsigned long)tuple + tuple_len > (unsigned long)skb->data_end){ - return TC_ACT_SHOT; + return TC_ACT_SHOT; + } + if(protocol == IPPROTO_TCP){ + tcp = true; } __u32 saddr_array[4] = {tuple->ipv4.saddr,0,0,0}; __u32 daddr_array[4] = {tuple->ipv4.daddr,0,0,0}; @@ -399,10 +2021,6 @@ int bpf_sk_splice(struct __sk_buff *skb){ */ if(tcp){ event.proto = IPPROTO_TCP; - struct iphdr *iph = (struct iphdr *)(skb->data + sizeof(*eth)); - if ((unsigned long)(iph + 1) > (unsigned long)skb->data_end){ - return TC_ACT_SHOT; - } struct tcphdr *tcph = (struct tcphdr *)((unsigned long)iph + sizeof(*iph)); if ((unsigned long)(tcph + 1) > (unsigned long)skb->data_end){ return TC_ACT_SHOT; @@ -510,16 +2128,12 @@ int bpf_sk_splice(struct __sk_buff *skb){ * setup our own state to track the outbound pass through connections in via shared hashmap * with with ingress tc program */ event.proto = IPPROTO_UDP; - struct iphdr *iph = (struct iphdr *)(skb->data + sizeof(*eth)); - if ((unsigned long)(iph + 1) > (unsigned long)skb->data_end){ - return TC_ACT_SHOT; - } struct udphdr *udph = (struct udphdr *)((unsigned long)iph + sizeof(*iph)); if ((unsigned long)(udph + 1) > (unsigned long)skb->data_end){ return TC_ACT_SHOT; } if ((unsigned long)tuple + tuple_len > (unsigned long)skb->data_end){ - return TC_ACT_SHOT; + return TC_ACT_SHOT; } reverse_tuple.ipv4.daddr = tuple->ipv4.saddr; reverse_tuple.ipv4.dport = tuple->ipv4.sport; @@ -552,9 +2166,21 @@ int bpf_sk_splice(struct __sk_buff *skb){ } }else if(ipv6 && local_diag->ipv6_enable){ /* determine length of tuple */ + struct ipv6hdr *ip6h = (struct ipv6hdr *)(skb->data + sizeof(*eth)); + if ((unsigned long)(ip6h + 1) > (unsigned long)skb->data_end){ + return TC_ACT_SHOT; + } + __u8 protocol = ip6h->nexthdr; + tuple = (struct bpf_sock_tuple *)(void*)(long)&ip6h->saddr; + if(!tuple){ + return TC_ACT_SHOT; + } tuple_len = sizeof(tuple->ipv6); if ((unsigned long)tuple + tuple_len > (unsigned long)skb->data_end){ - return TC_ACT_SHOT; + return TC_ACT_SHOT; + } + if(protocol == IPPROTO_TCP){ + tcp = true; } memcpy(event.saddr,tuple->ipv6.saddr, sizeof(tuple->ipv6.saddr)); memcpy(event.daddr,tuple->ipv6.daddr, sizeof(tuple->ipv6.daddr)); @@ -567,10 +2193,6 @@ int bpf_sk_splice(struct __sk_buff *skb){ */ if(tcp){ event.proto = IPPROTO_TCP; - struct ipv6hdr *ip6h = (struct ipv6hdr *)(skb->data + sizeof(*eth)); - if ((unsigned long)(ip6h + 1) > (unsigned long)skb->data_end){ - return TC_ACT_SHOT; - } struct tcphdr *tcph = (struct tcphdr *)((unsigned long)ip6h + sizeof(*ip6h)); if ((unsigned long)(tcph + 1) > (unsigned long)skb->data_end){ return TC_ACT_SHOT; @@ -678,17 +2300,10 @@ int bpf_sk_splice(struct __sk_buff *skb){ * setup our own state to track the outbound pass through connections in via shared hashmap * with with ingress tc program */ event.proto = IPPROTO_UDP; - struct ipv6hdr *ip6h = (struct ipv6hdr *)(skb->data + sizeof(*eth)); - if ((unsigned long)(ip6h + 1) > (unsigned long)skb->data_end){ - return TC_ACT_SHOT; - } struct udphdr *udph = (struct udphdr *)((unsigned long)ip6h + sizeof(*ip6h)); if ((unsigned long)(udph + 1) > (unsigned long)skb->data_end){ return TC_ACT_SHOT; } - if ((unsigned long)tuple + tuple_len > (unsigned long)skb->data_end){ - return TC_ACT_SHOT; - } memcpy(reverse_tuple.ipv6.daddr, tuple->ipv6.saddr, sizeof(tuple->ipv6.saddr)); reverse_tuple.ipv6.dport = tuple->ipv6.sport; memcpy(reverse_tuple.ipv6.saddr, tuple->ipv6.daddr, sizeof(tuple->ipv6.daddr)); diff --git a/src/zfw_tunnel_wrapper.c b/src/zfw_tunnel_wrapper.c index 9773c8e..b9a9a75 100644 --- a/src/zfw_tunnel_wrapper.c +++ b/src/zfw_tunnel_wrapper.c @@ -815,7 +815,7 @@ __u16 len2u16(char *len) { char *endPtr; int32_t tmpint = strtol(len, &endPtr, 10); - if ((tmpint < 0) || (tmpint > 32) || (!(*(endPtr) == '\0'))) + if ((tmpint < 0) || (tmpint > 255) || (!(*(endPtr) == '\0'))) { printf("Invalid Prefix Length: %s\n", len); return 32; @@ -1094,8 +1094,14 @@ int process_bind(json_object *jobj, char *action) { struct json_object *prefix_obj = json_object_object_get(address_obj, "Prefix"); if(prefix_obj){ - char ip[strlen(json_object_get_string(ip_obj) + 1)]; + if(!strlen(json_object_get_string(ip_obj)) || (strlen(json_object_get_string(ip_obj)) > 15)){ + continue; + } + char ip[strlen(json_object_get_string(ip_obj)) + 1]; sprintf(ip,"%s", json_object_get_string(ip_obj)); + if((json_object_get_int(prefix_obj) < 0) || (json_object_get_int(prefix_obj) > 32)){ + continue; + } sprintf(mask, "%d", json_object_get_int(prefix_obj)); printf("Service_IP=%s\n", ip); struct in_addr tuncidr; @@ -1400,8 +1406,14 @@ int process_dial(json_object *jobj, char *action){ if(ip_obj) { struct json_object *prefix_obj = json_object_object_get(address_obj, "Prefix"); - char ip[strlen(json_object_get_string(ip_obj) + 1)]; + if(!strlen(json_object_get_string(ip_obj)) || (strlen(json_object_get_string(ip_obj)) > 15)){ + continue; + } + char ip[strlen(json_object_get_string(ip_obj)) + 1]; sprintf(ip,"%s", json_object_get_string(ip_obj)); + if((json_object_get_int(prefix_obj) < 0) || (json_object_get_int(prefix_obj) > 32)){ + continue; + } sprintf(mask, "%d", json_object_get_int(prefix_obj)); printf("Service_IP=%s\n", ip); printf("Protocol=%s\n", protocol); diff --git a/src/zfw_xdp_tun_ingress.c b/src/zfw_xdp_tun_ingress.c index 11b0f46..e0ab26a 100644 --- a/src/zfw_xdp_tun_ingress.c +++ b/src/zfw_xdp_tun_ingress.c @@ -28,9 +28,9 @@ #ifndef memcpy #define memcpy(dest, src, n) __builtin_memcpy((dest), (src), (n)) #endif -#define MAX_IF_ENTRIES 30 -#define BPF_MAX_SESSIONS 10000 -#define INGRESS 0 +#define MAX_IF_ENTRIES 30 +#define BPF_MAX_TUN_SESSIONS 10000 +#define INGRESS 0 #define NO_REDIRECT_STATE_FOUND 10 struct bpf_event{ @@ -102,7 +102,7 @@ struct { __uint(type, BPF_MAP_TYPE_LRU_HASH); __uint(key_size, sizeof(struct tun_key)); __uint(value_size,sizeof(struct tun_state)); - __uint(max_entries, BPF_MAX_SESSIONS); + __uint(max_entries, BPF_MAX_TUN_SESSIONS); __uint(pinning, LIBBPF_PIN_BY_NAME); } tun_map SEC(".maps");