diff --git a/src/core/NetworkManagerUtils.c b/src/core/NetworkManagerUtils.c index 84e6ab0c2c..7d3e80be4c 100644 --- a/src/core/NetworkManagerUtils.c +++ b/src/core/NetworkManagerUtils.c @@ -1638,363 +1638,6 @@ nm_utils_ip_routes_to_dbus(int addr_family, /*****************************************************************************/ -#define _SHARE_IPTABLES_SUBNET_TO_STR_LEN (INET_ADDRSTRLEN + 1 + 2 + 1) - -static const char * -_share_iptables_subnet_to_str(char buf[static _SHARE_IPTABLES_SUBNET_TO_STR_LEN], - in_addr_t addr, - guint8 plen) -{ - char buf_addr[INET_ADDRSTRLEN]; - in_addr_t netmask; - int l; - - netmask = _nm_utils_ip4_prefix_to_netmask(plen); - - l = g_snprintf(buf, - _SHARE_IPTABLES_SUBNET_TO_STR_LEN, - "%s/%u", - _nm_utils_inet4_ntop(addr & netmask, buf_addr), - plen); - nm_assert(l < _SHARE_IPTABLES_SUBNET_TO_STR_LEN); - return buf; -} - -static char * -_share_iptables_get_name(gboolean is_comment, const char *prefix, const char *ip_iface) -{ - NMStrBuf strbuf = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_40, FALSE); - gsize ip_iface_len; - - nm_assert(prefix); - nm_assert(ip_iface); - - /* This function is used to generate iptables chain names and comments. - * Chain names must be shorter than 29 chars. Comments don't have this - * limitation. - * - * Below we sanitize the ip_iface. If it's all benign, we use - * - either "-$IP_IFACE" (at most 16 chars) - * - otherwise, we base64 encode the name as "$(base64 $IP_IFACE)", at - * most 20 chars. - * - * Since for benign names we already add a '-', prefix probably should not - * contain a '-'. The '-' is necessary to distinguish between base64 encoding - * an plain name. - * - * That means, for chain names the prefix must be at most 8 chars long. */ - nm_assert(is_comment || (strlen(prefix) <= 8)); - - nm_str_buf_append(&strbuf, prefix); - - ip_iface_len = strlen(ip_iface); - G_STATIC_ASSERT_EXPR(NMP_IFNAMSIZ == 16); - if (ip_iface_len >= NMP_IFNAMSIZ) { - nm_assert_not_reached(); - ip_iface_len = NMP_IFNAMSIZ - 1; - } - - if (NM_STRCHAR_ALL(ip_iface, - ch, - (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'z') - || (ch >= 'A' && ch <= 'Z') || NM_IN_SET(ch, '.', '_', '-', '+'))) { - nm_str_buf_append_c(&strbuf, '-'); - nm_str_buf_append(&strbuf, ip_iface); - } else { - gs_free char *s = NULL; - - s = g_base64_encode((const guchar *) ip_iface, ip_iface_len); - nm_str_buf_append(&strbuf, s); - } - - return nm_str_buf_finalize(&strbuf, NULL); -} - -static gboolean -_share_iptables_call_v(const char *const *argv) -{ - gs_free_error GError *error = NULL; - gs_free char * argv_str = NULL; - int status; - - nm_log_dbg(LOGD_SHARING, "iptables: %s", (argv_str = g_strjoinv(" ", (char **) argv))); - - if (!g_spawn_sync("/", - (char **) argv, - (char **) NM_PTRARRAY_EMPTY(const char *), - G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL, - NULL, - NULL, - NULL, - NULL, - &status, - &error)) { - nm_log_warn(LOGD_SHARING, - "iptables: error executing command %s: %s", - argv[0], - error->message); - return FALSE; - } - - if (!g_spawn_check_exit_status(status, &error)) { - nm_log_warn(LOGD_SHARING, "iptables: command %s failed: %s", argv[0], error->message); - return FALSE; - } - - return TRUE; -} - -#define _share_iptables_call(...) _share_iptables_call_v(NM_MAKE_STRV(__VA_ARGS__)) - -static gboolean -_share_iptables_chain_op(const char *table, const char *chain, const char *op) -{ - return _share_iptables_call("" IPTABLES_PATH "", "--table", table, op, chain); -} - -static gboolean -_share_iptables_chain_delete(const char *table, const char *chain) -{ - _share_iptables_chain_op(table, chain, "--flush"); - return _share_iptables_chain_op(table, chain, "--delete-chain"); -} - -static gboolean -_share_iptables_chain_add(const char *table, const char *chain) -{ - if (_share_iptables_chain_op(table, chain, "--new-chain")) - return TRUE; - - _share_iptables_chain_delete(table, chain); - return _share_iptables_chain_op(table, chain, "--new-chain"); -} - -static void -_share_iptables_set_masquerade(gboolean add, const char *ip_iface, in_addr_t addr, guint8 plen) -{ - char str_subnet[_SHARE_IPTABLES_SUBNET_TO_STR_LEN]; - gs_free char *comment_name = NULL; - - comment_name = _share_iptables_get_name(TRUE, "nm-shared", ip_iface); - - _share_iptables_subnet_to_str(str_subnet, addr, plen); - _share_iptables_call("" IPTABLES_PATH "", - "--table", - "nat", - add ? "--insert" : "--delete", - "POSTROUTING", - "--source", - str_subnet, - "!", - "--destination", - str_subnet, - "--jump", - "MASQUERADE", - "-m", - "comment", - "--comment", - comment_name); -} - -static void -_share_iptables_set_shared_chains_add(const char *chain_input, - const char *chain_forward, - const char *ip_iface, - in_addr_t addr, - guint plen) -{ - const char *const input_params[][2] = { - { - "tcp", - "67", - }, - { - "udp", - "67", - }, - { - "tcp", - "53", - }, - { - "udp", - "53", - }, - }; - char str_subnet[_SHARE_IPTABLES_SUBNET_TO_STR_LEN]; - int i; - - _share_iptables_subnet_to_str(str_subnet, addr, plen); - - _share_iptables_chain_add("filter", chain_input); - - for (i = 0; i < (int) G_N_ELEMENTS(input_params); i++) { - _share_iptables_call("" IPTABLES_PATH "", - "--table", - "filter", - "--append", - chain_input, - "--protocol", - input_params[i][0], - "--destination-port", - input_params[i][1], - "--jump", - "ACCEPT"); - } - - _share_iptables_chain_add("filter", chain_forward); - - _share_iptables_call("" IPTABLES_PATH "", - "--table", - "filter", - "--append", - chain_forward, - "--destination", - str_subnet, - "--out-interface", - ip_iface, - "--match", - "state", - "--state", - "ESTABLISHED,RELATED", - "--jump", - "ACCEPT"); - _share_iptables_call("" IPTABLES_PATH "", - "--table", - "filter", - "--append", - chain_forward, - "--source", - str_subnet, - "--in-interface", - ip_iface, - "--jump", - "ACCEPT"); - _share_iptables_call("" IPTABLES_PATH "", - "--table", - "filter", - "--append", - chain_forward, - "--in-interface", - ip_iface, - "--out-interface", - ip_iface, - "--jump", - "ACCEPT"); - _share_iptables_call("" IPTABLES_PATH "", - "--table", - "filter", - "--append", - chain_forward, - "--out-interface", - ip_iface, - "--jump", - "REJECT"); - _share_iptables_call("" IPTABLES_PATH "", - "--table", - "filter", - "--append", - chain_forward, - "--in-interface", - ip_iface, - "--jump", - "REJECT"); -} - -static void -_share_iptables_set_shared_chains_delete(const char *chain_input, const char *chain_forward) -{ - _share_iptables_chain_delete("filter", chain_input); - _share_iptables_chain_delete("filter", chain_forward); -} - -_nm_unused static void -_share_iptables_set_shared(gboolean add, const char *ip_iface, in_addr_t addr, guint plen) -{ - gs_free char *comment_name = NULL; - gs_free char *chain_input = NULL; - gs_free char *chain_forward = NULL; - - comment_name = _share_iptables_get_name(TRUE, "nm-shared", ip_iface); - chain_input = _share_iptables_get_name(FALSE, "nm-sh-in", ip_iface); - chain_forward = _share_iptables_get_name(FALSE, "nm-sh-fw", ip_iface); - - if (add) - _share_iptables_set_shared_chains_add(chain_input, chain_forward, ip_iface, addr, plen); - - _share_iptables_call("" IPTABLES_PATH "", - "--table", - "filter", - add ? "--insert" : "--delete", - "INPUT", - "--in-interface", - ip_iface, - "--jump", - chain_input, - "-m", - "comment", - "--comment", - comment_name); - - _share_iptables_call("" IPTABLES_PATH "", - "--table", - "filter", - add ? "--insert" : "--delete", - "FORWARD", - "--jump", - chain_forward, - "-m", - "comment", - "--comment", - comment_name); - - if (!add) - _share_iptables_set_shared_chains_delete(chain_input, chain_forward); -} - -struct _NMUtilsShareRules { - char * ip_iface; - in_addr_t addr; - guint8 plen; -}; - -NMUtilsShareRules * -nm_utils_share_rules_new(const char *ip_iface, in_addr_t addr, guint8 plen) -{ - NMUtilsShareRules *self; - - nm_assert(ip_iface); - nm_assert(addr != 0u); - nm_assert(plen <= 32); - - self = g_slice_new(NMUtilsShareRules); - *self = (NMUtilsShareRules){ - .ip_iface = g_strdup(ip_iface), - .addr = addr, - .plen = plen, - }; - return self; -} - -void -nm_utils_share_rules_free(NMUtilsShareRules *self) -{ - if (!self) - return; - - g_free(self->ip_iface); - nm_g_slice_free(self); -} - -void -nm_utils_share_rules_apply(NMUtilsShareRules *self, gboolean shared) -{ - _share_iptables_set_masquerade(shared, self->ip_iface, self->addr, self->plen); - _share_iptables_set_shared(shared, self->ip_iface, self->addr, self->plen); -} - -/*****************************************************************************/ - /* Singleton NMPlatform subclass instance and cached class object */ NM_DEFINE_SINGLETON_INSTANCE(NMPlatform); diff --git a/src/core/NetworkManagerUtils.h b/src/core/NetworkManagerUtils.h index 6cdc490113..405f90de46 100644 --- a/src/core/NetworkManagerUtils.h +++ b/src/core/NetworkManagerUtils.h @@ -224,16 +224,6 @@ NM_AUTO_DEFINE_FCN(NMDhcpLease *, _nm_auto_unref_dhcplease, nm_dhcp_lease_unref) /*****************************************************************************/ -typedef struct _NMUtilsShareRules NMUtilsShareRules; - -NMUtilsShareRules *nm_utils_share_rules_new(const char *ip_iface, in_addr_t addr, guint8 plen); - -void nm_utils_share_rules_free(NMUtilsShareRules *self); - -void nm_utils_share_rules_apply(NMUtilsShareRules *self, gboolean shared); - -/*****************************************************************************/ - void nm_platform_setup(NMPlatform *instance); NMPlatform *nm_platform_get(void); diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c index 6badddab2b..e119694748 100644 --- a/src/core/devices/nm-device.c +++ b/src/core/devices/nm-device.c @@ -52,6 +52,7 @@ #include "dnsmasq/nm-dnsmasq-manager.h" #include "nm-dhcp-config.h" #include "nm-rfkill-manager.h" +#include "nm-firewall-utils.h" #include "nm-firewalld-manager.h" #include "settings/nm-settings-connection.h" #include "settings/nm-settings.h" diff --git a/src/core/nm-act-request.c b/src/core/nm-act-request.c index cb4b0260a5..0fc3e1ef0c 100644 --- a/src/core/nm-act-request.c +++ b/src/core/nm-act-request.c @@ -13,13 +13,15 @@ #include #include "c-list/src/c-list.h" +#include "libnm-core-aux-intern/nm-auth-subject.h" -#include "nm-setting-wireless-security.h" #include "nm-setting-8021x.h" +#include "nm-setting-wireless-security.h" + #include "devices/nm-device.h" #include "nm-active-connection.h" +#include "nm-firewall-utils.h" #include "settings/nm-settings-connection.h" -#include "libnm-core-aux-intern/nm-auth-subject.h" typedef struct { CList call_ids_lst_head; diff --git a/src/core/nm-firewall-utils.c b/src/core/nm-firewall-utils.c index 3d2c72af0c..fc3490b831 100644 --- a/src/core/nm-firewall-utils.c +++ b/src/core/nm-firewall-utils.c @@ -7,3 +7,363 @@ #include "src/core/nm-default-daemon.h" #include "nm-firewall-utils.h" + +#include "libnm-glib-aux/nm-str-buf.h" +#include "libnm-platform/nm-platform.h" + +/*****************************************************************************/ + +#define _SHARE_IPTABLES_SUBNET_TO_STR_LEN (INET_ADDRSTRLEN + 1 + 2 + 1) + +static const char * +_share_iptables_subnet_to_str(char buf[static _SHARE_IPTABLES_SUBNET_TO_STR_LEN], + in_addr_t addr, + guint8 plen) +{ + char buf_addr[INET_ADDRSTRLEN]; + in_addr_t netmask; + int l; + + netmask = _nm_utils_ip4_prefix_to_netmask(plen); + + l = g_snprintf(buf, + _SHARE_IPTABLES_SUBNET_TO_STR_LEN, + "%s/%u", + _nm_utils_inet4_ntop(addr & netmask, buf_addr), + plen); + nm_assert(l < _SHARE_IPTABLES_SUBNET_TO_STR_LEN); + return buf; +} + +static char * +_share_iptables_get_name(gboolean is_comment, const char *prefix, const char *ip_iface) +{ + NMStrBuf strbuf = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_40, FALSE); + gsize ip_iface_len; + + nm_assert(prefix); + nm_assert(ip_iface); + + /* This function is used to generate iptables chain names and comments. + * Chain names must be shorter than 29 chars. Comments don't have this + * limitation. + * + * Below we sanitize the ip_iface. If it's all benign, we use + * - either "-$IP_IFACE" (at most 16 chars) + * - otherwise, we base64 encode the name as "$(base64 $IP_IFACE)", at + * most 20 chars. + * + * Since for benign names we already add a '-', prefix probably should not + * contain a '-'. The '-' is necessary to distinguish between base64 encoding + * an plain name. + * + * That means, for chain names the prefix must be at most 8 chars long. */ + nm_assert(is_comment || (strlen(prefix) <= 8)); + + nm_str_buf_append(&strbuf, prefix); + + ip_iface_len = strlen(ip_iface); + G_STATIC_ASSERT_EXPR(NMP_IFNAMSIZ == 16); + if (ip_iface_len >= NMP_IFNAMSIZ) { + nm_assert_not_reached(); + ip_iface_len = NMP_IFNAMSIZ - 1; + } + + if (NM_STRCHAR_ALL(ip_iface, + ch, + (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'z') + || (ch >= 'A' && ch <= 'Z') || NM_IN_SET(ch, '.', '_', '-', '+'))) { + nm_str_buf_append_c(&strbuf, '-'); + nm_str_buf_append(&strbuf, ip_iface); + } else { + gs_free char *s = NULL; + + s = g_base64_encode((const guchar *) ip_iface, ip_iface_len); + nm_str_buf_append(&strbuf, s); + } + + return nm_str_buf_finalize(&strbuf, NULL); +} + +static gboolean +_share_iptables_call_v(const char *const *argv) +{ + gs_free_error GError *error = NULL; + gs_free char * argv_str = NULL; + int status; + + nm_log_dbg(LOGD_SHARING, "iptables: %s", (argv_str = g_strjoinv(" ", (char **) argv))); + + if (!g_spawn_sync("/", + (char **) argv, + (char **) NM_PTRARRAY_EMPTY(const char *), + G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL, + NULL, + NULL, + NULL, + NULL, + &status, + &error)) { + nm_log_warn(LOGD_SHARING, + "iptables: error executing command %s: %s", + argv[0], + error->message); + return FALSE; + } + + if (!g_spawn_check_exit_status(status, &error)) { + nm_log_warn(LOGD_SHARING, "iptables: command %s failed: %s", argv[0], error->message); + return FALSE; + } + + return TRUE; +} + +#define _share_iptables_call(...) _share_iptables_call_v(NM_MAKE_STRV(__VA_ARGS__)) + +static gboolean +_share_iptables_chain_op(const char *table, const char *chain, const char *op) +{ + return _share_iptables_call("" IPTABLES_PATH "", "--table", table, op, chain); +} + +static gboolean +_share_iptables_chain_delete(const char *table, const char *chain) +{ + _share_iptables_chain_op(table, chain, "--flush"); + return _share_iptables_chain_op(table, chain, "--delete-chain"); +} + +static gboolean +_share_iptables_chain_add(const char *table, const char *chain) +{ + if (_share_iptables_chain_op(table, chain, "--new-chain")) + return TRUE; + + _share_iptables_chain_delete(table, chain); + return _share_iptables_chain_op(table, chain, "--new-chain"); +} + +static void +_share_iptables_set_masquerade(gboolean add, const char *ip_iface, in_addr_t addr, guint8 plen) +{ + char str_subnet[_SHARE_IPTABLES_SUBNET_TO_STR_LEN]; + gs_free char *comment_name = NULL; + + comment_name = _share_iptables_get_name(TRUE, "nm-shared", ip_iface); + + _share_iptables_subnet_to_str(str_subnet, addr, plen); + _share_iptables_call("" IPTABLES_PATH "", + "--table", + "nat", + add ? "--insert" : "--delete", + "POSTROUTING", + "--source", + str_subnet, + "!", + "--destination", + str_subnet, + "--jump", + "MASQUERADE", + "-m", + "comment", + "--comment", + comment_name); +} + +static void +_share_iptables_set_shared_chains_add(const char *chain_input, + const char *chain_forward, + const char *ip_iface, + in_addr_t addr, + guint plen) +{ + const char *const input_params[][2] = { + { + "tcp", + "67", + }, + { + "udp", + "67", + }, + { + "tcp", + "53", + }, + { + "udp", + "53", + }, + }; + char str_subnet[_SHARE_IPTABLES_SUBNET_TO_STR_LEN]; + int i; + + _share_iptables_subnet_to_str(str_subnet, addr, plen); + + _share_iptables_chain_add("filter", chain_input); + + for (i = 0; i < (int) G_N_ELEMENTS(input_params); i++) { + _share_iptables_call("" IPTABLES_PATH "", + "--table", + "filter", + "--append", + chain_input, + "--protocol", + input_params[i][0], + "--destination-port", + input_params[i][1], + "--jump", + "ACCEPT"); + } + + _share_iptables_chain_add("filter", chain_forward); + + _share_iptables_call("" IPTABLES_PATH "", + "--table", + "filter", + "--append", + chain_forward, + "--destination", + str_subnet, + "--out-interface", + ip_iface, + "--match", + "state", + "--state", + "ESTABLISHED,RELATED", + "--jump", + "ACCEPT"); + _share_iptables_call("" IPTABLES_PATH "", + "--table", + "filter", + "--append", + chain_forward, + "--source", + str_subnet, + "--in-interface", + ip_iface, + "--jump", + "ACCEPT"); + _share_iptables_call("" IPTABLES_PATH "", + "--table", + "filter", + "--append", + chain_forward, + "--in-interface", + ip_iface, + "--out-interface", + ip_iface, + "--jump", + "ACCEPT"); + _share_iptables_call("" IPTABLES_PATH "", + "--table", + "filter", + "--append", + chain_forward, + "--out-interface", + ip_iface, + "--jump", + "REJECT"); + _share_iptables_call("" IPTABLES_PATH "", + "--table", + "filter", + "--append", + chain_forward, + "--in-interface", + ip_iface, + "--jump", + "REJECT"); +} + +static void +_share_iptables_set_shared_chains_delete(const char *chain_input, const char *chain_forward) +{ + _share_iptables_chain_delete("filter", chain_input); + _share_iptables_chain_delete("filter", chain_forward); +} + +_nm_unused static void +_share_iptables_set_shared(gboolean add, const char *ip_iface, in_addr_t addr, guint plen) +{ + gs_free char *comment_name = NULL; + gs_free char *chain_input = NULL; + gs_free char *chain_forward = NULL; + + comment_name = _share_iptables_get_name(TRUE, "nm-shared", ip_iface); + chain_input = _share_iptables_get_name(FALSE, "nm-sh-in", ip_iface); + chain_forward = _share_iptables_get_name(FALSE, "nm-sh-fw", ip_iface); + + if (add) + _share_iptables_set_shared_chains_add(chain_input, chain_forward, ip_iface, addr, plen); + + _share_iptables_call("" IPTABLES_PATH "", + "--table", + "filter", + add ? "--insert" : "--delete", + "INPUT", + "--in-interface", + ip_iface, + "--jump", + chain_input, + "-m", + "comment", + "--comment", + comment_name); + + _share_iptables_call("" IPTABLES_PATH "", + "--table", + "filter", + add ? "--insert" : "--delete", + "FORWARD", + "--jump", + chain_forward, + "-m", + "comment", + "--comment", + comment_name); + + if (!add) + _share_iptables_set_shared_chains_delete(chain_input, chain_forward); +} + +struct _NMUtilsShareRules { + char * ip_iface; + in_addr_t addr; + guint8 plen; +}; + +NMUtilsShareRules * +nm_utils_share_rules_new(const char *ip_iface, in_addr_t addr, guint8 plen) +{ + NMUtilsShareRules *self; + + nm_assert(ip_iface); + nm_assert(addr != 0u); + nm_assert(plen <= 32); + + self = g_slice_new(NMUtilsShareRules); + *self = (NMUtilsShareRules){ + .ip_iface = g_strdup(ip_iface), + .addr = addr, + .plen = plen, + }; + return self; +} + +void +nm_utils_share_rules_free(NMUtilsShareRules *self) +{ + if (!self) + return; + + g_free(self->ip_iface); + nm_g_slice_free(self); +} + +void +nm_utils_share_rules_apply(NMUtilsShareRules *self, gboolean shared) +{ + _share_iptables_set_masquerade(shared, self->ip_iface, self->addr, self->plen); + _share_iptables_set_shared(shared, self->ip_iface, self->addr, self->plen); +} diff --git a/src/core/nm-firewall-utils.h b/src/core/nm-firewall-utils.h index 868e242887..fc153c1b48 100644 --- a/src/core/nm-firewall-utils.h +++ b/src/core/nm-firewall-utils.h @@ -7,4 +7,12 @@ #ifndef __NM_FIREWALL_UTILS_H__ #define __NM_FIREWALL_UTILS_H__ +typedef struct _NMUtilsShareRules NMUtilsShareRules; + +NMUtilsShareRules *nm_utils_share_rules_new(const char *ip_iface, in_addr_t addr, guint8 plen); + +void nm_utils_share_rules_free(NMUtilsShareRules *self); + +void nm_utils_share_rules_apply(NMUtilsShareRules *self, gboolean shared); + #endif /* __NM_FIREWALL_UTILS_H__ */