From 972d1ba0469b3a43fcee0ba3e04cccf06f6e2a00 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 19 Mar 2021 07:45:09 +0100 Subject: [PATCH] libnm,core: support "uidrange" parameter for routing rules --- src/core/NetworkManagerUtils.c | 12 ++ src/libnm-core-impl/nm-setting-ip-config.c | 162 +++++++++++++++++-- src/libnm-core-intern/nm-core-internal.h | 2 + src/libnm-core-public/nm-setting-ip-config.h | 9 ++ 4 files changed, 176 insertions(+), 9 deletions(-) diff --git a/src/core/NetworkManagerUtils.c b/src/core/NetworkManagerUtils.c index 586974638..59a65b069 100644 --- a/src/core/NetworkManagerUtils.c +++ b/src/core/NetworkManagerUtils.c @@ -904,10 +904,16 @@ nm_match_spec_device_by_pllink(const NMPlatformLink *pllink, NMPlatformRoutingRule * nm_ip_routing_rule_to_platform(const NMIPRoutingRule *rule, NMPlatformRoutingRule *out_pl) { + gboolean uid_range_has; + guint32 uid_range_start = 0; + guint32 uid_range_end = 0; + nm_assert(rule); nm_assert(nm_ip_routing_rule_validate(rule, NULL)); nm_assert(out_pl); + uid_range_has = nm_ip_routing_rule_get_uid_range(rule, &uid_range_start, &uid_range_end); + *out_pl = (NMPlatformRoutingRule){ .addr_family = nm_ip_routing_rule_get_addr_family(rule), .flags = (nm_ip_routing_rule_get_invert(rule) ? FIB_RULE_INVERT : 0), @@ -934,6 +940,12 @@ nm_ip_routing_rule_to_platform(const NMIPRoutingRule *rule, NMPlatformRoutingRul .table = nm_ip_routing_rule_get_table(rule), .suppress_prefixlen_inverse = ~((guint32) nm_ip_routing_rule_get_suppress_prefixlength(rule)), + .uid_range_has = uid_range_has, + .uid_range = + { + .start = uid_range_start, + .end = uid_range_end, + }, }; nm_ip_routing_rule_get_xifname_bin(rule, TRUE, out_pl->iifname); diff --git a/src/libnm-core-impl/nm-setting-ip-config.c b/src/libnm-core-impl/nm-setting-ip-config.c index 729c21ddb..8526b5fe1 100644 --- a/src/libnm-core-impl/nm-setting-ip-config.c +++ b/src/libnm-core-impl/nm-setting-ip-config.c @@ -1473,6 +1473,8 @@ struct NMIPRoutingRule { gint32 suppress_prefixlength; guint32 fwmark; guint32 fwmask; + guint32 uid_range_start; + guint32 uid_range_end; guint16 sport_start; guint16 sport_end; guint16 dport_start; @@ -1485,6 +1487,7 @@ struct NMIPRoutingRule { bool is_v4 : 1; bool sealed : 1; bool priority_has : 1; + bool uid_range_has : 1; bool from_has : 1; bool from_valid : 1; bool to_has : 1; @@ -1597,6 +1600,10 @@ nm_ip_routing_rule_new_clone(const NMIPRoutingRule *rule) .dport_start = rule->dport_start, .dport_end = rule->dport_end, + .uid_range_start = rule->uid_range_start, + .uid_range_end = rule->uid_range_end, + .uid_range_has = rule->uid_range_has, + .ipproto = rule->ipproto, .from_len = rule->from_len, @@ -2412,6 +2419,61 @@ nm_ip_routing_rule_set_suppress_prefixlength(NMIPRoutingRule *self, gint32 suppr self->suppress_prefixlength = suppress_prefixlength; } +/** + * nm_ip_routing_rule_get_uid_range: + * @self: the #NMIPRoutingRule instance + * @out_range_start: (out) (allow-none): returns the start of the range + * or 0 if the range is not set. + * @out_range_end: (out) (allow-none): returns the end of the range + * or 0 if the range is not set. + * + * Returns: %TRUE if a uid range is set. + * + * Since: 1.32 + */ +gboolean +nm_ip_routing_rule_get_uid_range(const NMIPRoutingRule *self, + guint32 * out_range_start, + guint32 * out_range_end) +{ + g_return_val_if_fail(NM_IS_IP_ROUTING_RULE(self, TRUE), -1); + + nm_assert(self->uid_range_has || (self->uid_range_start == 0 && self->uid_range_end == 0)); + + NM_SET_OUT(out_range_start, self->uid_range_start); + NM_SET_OUT(out_range_end, self->uid_range_end); + return self->uid_range_has; +} + +/** + * nm_ip_routing_rule_set_uid_range: + * @self: the #NMIPRoutingRule instance + * @uid_range_start: the uid_range start to set. + * @uid_range_end: the uid_range start to set. + * + * For a valid range, start must be less or equal to end. + * If set to an invalid range, the range gets unset. + * + * Since: 1.32 + */ +void +nm_ip_routing_rule_set_uid_range(NMIPRoutingRule *self, + guint32 uid_range_start, + guint32 uid_range_end) +{ + g_return_if_fail(NM_IS_IP_ROUTING_RULE(self, FALSE)); + + if (uid_range_start > uid_range_end) { + self->uid_range_start = 0; + self->uid_range_end = 0; + self->uid_range_has = FALSE; + return; + } + self->uid_range_start = uid_range_start; + self->uid_range_end = uid_range_end; + self->uid_range_has = TRUE; +} + /** * nm_ip_routing_rule_cmp: * @rule: (allow-none): the #NMIPRoutingRule instance to compare @@ -2456,6 +2518,12 @@ nm_ip_routing_rule_cmp(const NMIPRoutingRule *rule, const NMIPRoutingRule *other NM_CMP_FIELD(rule, other, ipproto); + NM_CMP_FIELD_UNSAFE(rule, other, uid_range_has); + if (rule->uid_range_has) { + NM_CMP_FIELD(rule, other, uid_range_end); + NM_CMP_FIELD(rule, other, uid_range_start); + } + /* We compare the plain strings, not the binary values after utf8safe unescaping. * * The reason is, that the rules differ already when the direct strings differ, not @@ -2728,6 +2796,8 @@ typedef enum { RR_DBUS_ATTR_TO, RR_DBUS_ATTR_TO_LEN, RR_DBUS_ATTR_TOS, + RR_DBUS_ATTR_UID_RANGE_END, + RR_DBUS_ATTR_UID_RANGE_START, _RR_DBUS_ATTR_NUM, } RRDbusAttr; @@ -2765,6 +2835,10 @@ static const RRDbusData rr_dbus_data[_RR_DBUS_ATTR_NUM] = { _D(RR_DBUS_ATTR_TO, NM_IP_ROUTING_RULE_ATTR_TO, G_VARIANT_TYPE_STRING), _D(RR_DBUS_ATTR_TOS, NM_IP_ROUTING_RULE_ATTR_TOS, G_VARIANT_TYPE_BYTE), _D(RR_DBUS_ATTR_TO_LEN, NM_IP_ROUTING_RULE_ATTR_TO_LEN, G_VARIANT_TYPE_BYTE), + _D(RR_DBUS_ATTR_UID_RANGE_END, NM_IP_ROUTING_RULE_ATTR_UID_RANGE_END, G_VARIANT_TYPE_UINT32), + _D(RR_DBUS_ATTR_UID_RANGE_START, + NM_IP_ROUTING_RULE_ATTR_UID_RANGE_START, + G_VARIANT_TYPE_UINT32), #undef _D }; @@ -2819,6 +2893,8 @@ nm_ip_routing_rule_from_dbus(GVariant *variant, gboolean strict, GError **error) GVariant * iter_val; int addr_family; int i; + GVariant * v_start; + GVariant * v_end; g_variant_iter_init(&iter, variant); @@ -2899,22 +2975,19 @@ nm_ip_routing_rule_from_dbus(GVariant *variant, gboolean strict, GError **error) nm_ip_routing_rule_set_ipproto(self, g_variant_get_byte(variants[RR_DBUS_ATTR_IPPROTO])); for (i = 0; i < 2; i++) { - GVariant *v_start = variants[i ? RR_DBUS_ATTR_SPORT_START : RR_DBUS_ATTR_DPORT_START]; - GVariant *v_end = variants[i ? RR_DBUS_ATTR_SPORT_END : RR_DBUS_ATTR_DPORT_END]; - guint16 start, end; + guint16 start, end; + v_start = variants[i ? RR_DBUS_ATTR_SPORT_START : RR_DBUS_ATTR_DPORT_START]; + v_end = variants[i ? RR_DBUS_ATTR_SPORT_END : RR_DBUS_ATTR_DPORT_END]; if (!v_start && !v_end) continue; /* if start or end is missing, it defaults to the other parameter, respectively. */ - if (v_start) - start = g_variant_get_uint16(v_start); - else - start = g_variant_get_uint16(v_end); - if (v_end) + start = g_variant_get_uint16(v_start ?: v_end); + if (v_end && v_start) end = g_variant_get_uint16(v_end); else - end = g_variant_get_uint16(v_start); + end = start; if (i) nm_ip_routing_rule_set_source_port(self, start, end); @@ -2922,6 +2995,32 @@ nm_ip_routing_rule_from_dbus(GVariant *variant, gboolean strict, GError **error) nm_ip_routing_rule_set_destination_port(self, start, end); } + v_start = variants[RR_DBUS_ATTR_UID_RANGE_START]; + v_end = variants[RR_DBUS_ATTR_UID_RANGE_END]; + if (v_start || v_end) { + guint32 start, end; + + /* if start or end is missing, it defaults to the other parameter, respectively. */ + start = g_variant_get_uint32(v_start ?: v_end); + if (v_end && v_start) + end = g_variant_get_uint32(v_end); + else + end = start; + + if (end < start) { + if (strict) { + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("\"" NM_IP_ROUTING_RULE_ATTR_UID_RANGE_START + "\" is greater than \"" NM_IP_ROUTING_RULE_ATTR_UID_RANGE_END + "\"")); + return FALSE; + } + } else + nm_ip_routing_rule_set_uid_range(self, start, end); + } + if (variants[RR_DBUS_ATTR_FWMARK] || variants[RR_DBUS_ATTR_FWMASK]) { nm_ip_routing_rule_set_fwmark( self, @@ -3075,6 +3174,16 @@ nm_ip_routing_rule_to_dbus(const NMIPRoutingRule *self) RR_DBUS_ATTR_SUPPRESS_PREFIXLENGTH, g_variant_new_int32(self->suppress_prefixlength)); + if (self->uid_range_has) { + _rr_to_dbus_add(&builder, + RR_DBUS_ATTR_UID_RANGE_START, + g_variant_new_uint32(self->uid_range_start)); + if (self->uid_range_start != self->uid_range_end) + _rr_to_dbus_add(&builder, + RR_DBUS_ATTR_UID_RANGE_END, + g_variant_new_uint32(self->uid_range_end)); + } + return g_variant_builder_end(&builder); } @@ -3159,6 +3268,9 @@ nm_ip_routing_rule_from_string(const char * str, guint16 sport_end = 0; gint64 i64_dport_start = -1; guint16 dport_end = 0; + guint32 uid_range_start = 0; + guint32 uid_range_end = 0; + gboolean uid_range_has = FALSE; gboolean val_invert = FALSE; int addr_family = AF_UNSPEC; NMIPAddr val_from = {}; @@ -3356,6 +3468,28 @@ nm_ip_routing_rule_from_string(const char * str, goto next_fail_word1_invalid_value; goto next_words_consumed; } + if (NM_IN_STRSET(word0, "uidrange")) { + if (!word1) + continue; + if (uid_range_has) + goto next_fail_word0_duplicate_key; + s = strchr(word1, '-'); + if (s) + (s++)[0] = '\0'; + uid_range_start = _nm_utils_ascii_str_to_int64(word1, 0, 0, G_MAXUINT32, 0); + if (errno) + goto next_fail_word1_invalid_value; + if (s) { + uid_range_end = _nm_utils_ascii_str_to_int64(s, 0, 0, G_MAXUINT32, 0); + if (errno) + goto next_fail_word1_invalid_value; + if (uid_range_end < uid_range_start) + goto next_fail_word1_invalid_value; + } else + uid_range_end = uid_range_start; + uid_range_has = TRUE; + goto next_words_consumed; + } /* also the action is still unsupported. For the moment, we only support * FR_ACT_TO_TBL, which is the default (by not expressing it on the command @@ -3485,6 +3619,9 @@ next_words_consumed: if (i64_table != -1) nm_ip_routing_rule_set_table(self, i64_table); + if (uid_range_has) + nm_ip_routing_rule_set_uid_range(self, uid_range_start, uid_range_end); + if (NM_FLAGS_HAS(to_string_flags, NM_IP_ROUTING_RULE_AS_STRING_FLAGS_VALIDATE)) { gs_free_error GError *local = NULL; @@ -3669,6 +3806,13 @@ nm_ip_routing_rule_to_string(const NMIPRoutingRule * self, nm_utils_escaped_tokens_escape_strbuf(self->oifname, NM_ASCII_SPACES, &str); } + if (self->uid_range_has) { + nm_str_buf_append_printf(nm_str_buf_append_required_delimiter(&str, ' '), + "uidrange %u-%u", + self->uid_range_start, + self->uid_range_end); + } + if (self->table != 0) { nm_str_buf_append_printf(nm_str_buf_append_required_delimiter(&str, ' '), "table %u", diff --git a/src/libnm-core-intern/nm-core-internal.h b/src/libnm-core-intern/nm-core-internal.h index d026520d7..bd607b45b 100644 --- a/src/libnm-core-intern/nm-core-internal.h +++ b/src/libnm-core-intern/nm-core-internal.h @@ -655,6 +655,8 @@ gboolean nm_ip_routing_rule_get_xifname_bin(const NMIPRoutingRule *self, #define NM_IP_ROUTING_RULE_ATTR_TO "to" #define NM_IP_ROUTING_RULE_ATTR_TOS "tos" #define NM_IP_ROUTING_RULE_ATTR_TO_LEN "to-len" +#define NM_IP_ROUTING_RULE_ATTR_UID_RANGE_START "uid-range-start" +#define NM_IP_ROUTING_RULE_ATTR_UID_RANGE_END "uid-range-end" NMIPRoutingRule *nm_ip_routing_rule_from_dbus(GVariant *variant, gboolean strict, GError **error); GVariant * nm_ip_routing_rule_to_dbus(const NMIPRoutingRule *self); diff --git a/src/libnm-core-public/nm-setting-ip-config.h b/src/libnm-core-public/nm-setting-ip-config.h index 1cb167171..f4e0f6033 100644 --- a/src/libnm-core-public/nm-setting-ip-config.h +++ b/src/libnm-core-public/nm-setting-ip-config.h @@ -245,6 +245,15 @@ NM_AVAILABLE_IN_1_20 void nm_ip_routing_rule_set_suppress_prefixlength(NMIPRoutingRule *self, gint32 suppress_prefixlength); +NM_AVAILABLE_IN_1_32 +gboolean nm_ip_routing_rule_get_uid_range(const NMIPRoutingRule *self, + guint32 * out_range_start, + guint32 * out_range_end); +NM_AVAILABLE_IN_1_32 +void nm_ip_routing_rule_set_uid_range(NMIPRoutingRule *self, + guint32 uid_range_start, + guint32 uid_range_end); + NM_AVAILABLE_IN_1_18 int nm_ip_routing_rule_cmp(const NMIPRoutingRule *rule, const NMIPRoutingRule *other);