From d1bee89db753f7380c35738f8d435b8358bb775f Mon Sep 17 00:00:00 2001 From: Tom Carroll <34632752+tomc797@users.noreply.github.com> Date: Sun, 7 Jul 2024 12:04:54 -0700 Subject: [PATCH] Manage routes in a routing table dedicated to ZET. ZET routes are managed in a dedicated routing table, distinct from main and default. The routing policy database is configured to prefer the routes managed in the ZET table over those stored in the main and default routing tables. This approach provides isolation, and thus additional security for ZET routes. Signed-off-by: Tom Carroll <4632752+tomc797@users.noreply.github.com> --- .../ziti-edge-tunnel/netif_driver/linux/tun.c | 137 +++++++++++++++++- .../ziti-edge-tunnel/netif_driver/linux/tun.h | 2 +- 2 files changed, 133 insertions(+), 6 deletions(-) diff --git a/programs/ziti-edge-tunnel/netif_driver/linux/tun.c b/programs/ziti-edge-tunnel/netif_driver/linux/tun.c index 1ce47e41e..bda151d70 100644 --- a/programs/ziti-edge-tunnel/netif_driver/linux/tun.c +++ b/programs/ziti-edge-tunnel/netif_driver/linux/tun.c @@ -38,6 +38,27 @@ #define DEVTUN "/dev/net/tun" #endif +/** + * Let's keep the ZET_RT_TABLE in 0..255: + * - busybox routing tables ids are restricted to 0..1023. + * - iproute2 stores table ids 0..255 in rtmsg.rtm_table; otherwise rtattr RTA_TABLE is used + */ +#ifndef ZET_RT_TABLE +#define ZET_RT_TABLE ((unsigned char)'Z') +#endif + +/** + * ZET_POLICY_PREF_BASE in 0..32767 + * 0: local + * 32766: main + * 32767: default + * + * 'Ze' = 0x5A65 = 23141 + */ +#ifndef ZET_POLICY_PREF_BASE +#define ZET_POLICY_PREF_BASE (((unsigned char)'Z')<<8|'e') +#endif + /* * ip link set tun0 up * ip addr add 169.254.1.1 remote 169.254.0.0/16 dev tun0 @@ -153,7 +174,8 @@ static void process_routes_updates(uv_work_t *wr) { // action == 1: add unsigned action = (uintptr_t) value; if (action == i) { - int len = snprintf(buf, sizeof(buf), "route %s %s dev %s\n", verb, prefix, cmd->tun->name); + int len = snprintf(buf, sizeof(buf), "route %s %s dev %s table %d\n", + verb, prefix, cmd->tun->name, cmd->tun->route_table); if (len < 0 || (size_t) len >= sizeof buf) { if (len > 0) errno = ENOMEM; ZITI_LOG(ERROR, "route updates failed %d/%s", -errno, strerror(errno)); @@ -394,7 +416,109 @@ static int tun_exclude_rt(netif_handle dev, uv_loop_t *l, const char *addr) { ZITI_LOG(DEBUG, "route is %s %s", addr, route); - return run_command("ip route replace %s %s", addr, route); + return run_command("ip route replace %s %s table %d", + addr, route, dev->route_table); +} + +static int tun_exclude_rt_v2(netif_handle dev, uv_loop_t *l, const char *addr) { + return run_command("ip route replace throw %s table %d", + addr, dev->route_table); +} + +static int +ZET__route_table(const struct netif_options *opts) +{ + return (opts->use_rt_main || run_command("ip -4 rule show >/dev/null") != 0) + ? RT_TABLE_MAIN : ZET_RT_TABLE; +} + +static int +ZET__rpdb_add_rules(int af, int policy_pref_base, const char *iif, int route_table) +{ + const char *family; + + switch (af) { + case 0: + /* FALLTHROUGH */ + case AF_INET: + family = "-4"; + break; + case AF_INET6: + family = "-6"; + break; + default: + return -EAFNOSUPPORT; + } + + /* insert lookup rule in the route policy database */ + int rc = run_command("ip %s rule add pref %d table %d", + family, policy_pref_base, route_table); + /* if the insertion fails, check rule existence */ + if (rc > 0) { + rc = run_command_ex(false, "ip %s rule show pref %d >/dev/null", + family, policy_pref_base); + if (rc == 0) + ZITI_LOG(ERROR, "please disregard previous error."); + } + + if (rc != 0) + return 0; + + /** + * insert bypass rule before lookup + * + * If the packet arrives on the ziti interface go immediately to main, default + */ + int offset; + if (sscanf(iif, "ziti%d", &offset) != 1) { + ZITI_LOG(ERROR, "failed to parse index from interface name '%s'", iif); + return 0; + } + + int pref = policy_pref_base - 256 + offset; + + rc = run_command("ip %s rule add pref %d iif %s goto 32766", + family, pref, iif); + if (rc > 0) { + /* If a rule exists, assume it is ours */ + rc = run_command_ex(false, "ip %s rule show pref %d >/dev/null", + family, pref); + if (rc == 0) + ZITI_LOG(ERROR, "please disregard previous error."); + } + + return rc == 0; +} + +static int +ZET__is_ipv6_enabled(void) +{ + int sd; + int rc; + + sd = socket(AF_INET6, SOCK_STREAM|SOCK_CLOEXEC, 0); + rc = sd >= 0 ? (close(sd), 1) : (errno == EAFNOSUPPORT ? 0 : -1); + return rc > 0 ? run_command("ip -6 route show >/dev/null") == 0 : rc; +} + +static int +ZET__is_rt_main(struct netif_handle_s *tun) +{ + return tun->route_table == RT_TABLE_MAIN; +} + +static void +ZET__rpdb_init(struct netif_handle_s *tun) +{ + if (ZET__is_rt_main(tun)) + return; + + if (ZET__rpdb_add_rules(AF_INET, ZET_POLICY_PREF_BASE, tun->name, tun->route_table) < 0) + ZITI_LOG(ERROR, "error(s) encountered while updating ipv4 routing policy database."); + + if (ZET__rpdb_add_rules(AF_INET6, ZET_POLICY_PREF_BASE, tun->name, tun->route_table) < 0 + && ZET__is_ipv6_enabled() > 0) + ZITI_LOG(ERROR, "error(s) encountered while updating ipv6 routing policy database."); } netif_driver tun_open(uv_loop_t *loop, uint32_t tun_ip, uint32_t dns_ip, const char *dns_block, char *error, size_t error_len, @@ -432,7 +556,7 @@ netif_driver tun_open(uv_loop_t *loop, uint32_t tun_ip, uint32_t dns_ip, const c strncpy(tun->name, ifr.ifr_name, sizeof(tun->name)); - tun->rt_table = ZET__select_routing_table(opts); + tun->route_table = ZET__route_table(opts); struct netif_driver_s *driver = calloc(1, sizeof(struct netif_driver_s)); if (driver == NULL) { @@ -450,18 +574,21 @@ netif_driver tun_open(uv_loop_t *loop, uint32_t tun_ip, uint32_t dns_ip, const c driver->add_route = tun_add_route; driver->delete_route = tun_delete_route; driver->close = tun_close; - driver->exclude_rt = tun_exclude_rt; + driver->exclude_rt = ZET__is_rt_main(tun) ? tun_exclude_rt : tun_exclude_rt_v2; driver->commit_routes = tun_commit_routes; run_command("ip link set %s up", tun->name); run_command("ip addr add %s dev %s", inet_ntoa(*(struct in_addr*)&tun_ip), tun->name); + ZET__rpdb_init(tun); + if (dns_ip) { init_dns_maintainer(loop, tun->name, dns_ip); } if (dns_block) { - run_command("ip route add %s dev %s", dns_block, tun->name); + run_command("ip route add %s dev %s table %d", + dns_block, tun->name, tun->route_table); } return driver; diff --git a/programs/ziti-edge-tunnel/netif_driver/linux/tun.h b/programs/ziti-edge-tunnel/netif_driver/linux/tun.h index 7d818531b..a816c7729 100644 --- a/programs/ziti-edge-tunnel/netif_driver/linux/tun.h +++ b/programs/ziti-edge-tunnel/netif_driver/linux/tun.h @@ -29,7 +29,7 @@ struct netif_handle_s { int fd; char name[IFNAMSIZ]; - int rt_table; + int route_table; model_map *route_updates; };