libnm,core: support "uidrange" parameter for routing rules

This commit is contained in:
Thomas Haller
2021-03-19 07:45:09 +01:00
parent ba72d5a7e7
commit 972d1ba046
4 changed files with 176 additions and 9 deletions

View File

@@ -904,10 +904,16 @@ nm_match_spec_device_by_pllink(const NMPlatformLink *pllink,
NMPlatformRoutingRule * NMPlatformRoutingRule *
nm_ip_routing_rule_to_platform(const NMIPRoutingRule *rule, NMPlatformRoutingRule *out_pl) 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(rule);
nm_assert(nm_ip_routing_rule_validate(rule, NULL)); nm_assert(nm_ip_routing_rule_validate(rule, NULL));
nm_assert(out_pl); nm_assert(out_pl);
uid_range_has = nm_ip_routing_rule_get_uid_range(rule, &uid_range_start, &uid_range_end);
*out_pl = (NMPlatformRoutingRule){ *out_pl = (NMPlatformRoutingRule){
.addr_family = nm_ip_routing_rule_get_addr_family(rule), .addr_family = nm_ip_routing_rule_get_addr_family(rule),
.flags = (nm_ip_routing_rule_get_invert(rule) ? FIB_RULE_INVERT : 0), .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), .table = nm_ip_routing_rule_get_table(rule),
.suppress_prefixlen_inverse = .suppress_prefixlen_inverse =
~((guint32) nm_ip_routing_rule_get_suppress_prefixlength(rule)), ~((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); nm_ip_routing_rule_get_xifname_bin(rule, TRUE, out_pl->iifname);

View File

@@ -1473,6 +1473,8 @@ struct NMIPRoutingRule {
gint32 suppress_prefixlength; gint32 suppress_prefixlength;
guint32 fwmark; guint32 fwmark;
guint32 fwmask; guint32 fwmask;
guint32 uid_range_start;
guint32 uid_range_end;
guint16 sport_start; guint16 sport_start;
guint16 sport_end; guint16 sport_end;
guint16 dport_start; guint16 dport_start;
@@ -1485,6 +1487,7 @@ struct NMIPRoutingRule {
bool is_v4 : 1; bool is_v4 : 1;
bool sealed : 1; bool sealed : 1;
bool priority_has : 1; bool priority_has : 1;
bool uid_range_has : 1;
bool from_has : 1; bool from_has : 1;
bool from_valid : 1; bool from_valid : 1;
bool to_has : 1; bool to_has : 1;
@@ -1597,6 +1600,10 @@ nm_ip_routing_rule_new_clone(const NMIPRoutingRule *rule)
.dport_start = rule->dport_start, .dport_start = rule->dport_start,
.dport_end = rule->dport_end, .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, .ipproto = rule->ipproto,
.from_len = rule->from_len, .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; 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: * nm_ip_routing_rule_cmp:
* @rule: (allow-none): the #NMIPRoutingRule instance to compare * @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(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. /* 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 * 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,
RR_DBUS_ATTR_TO_LEN, RR_DBUS_ATTR_TO_LEN,
RR_DBUS_ATTR_TOS, RR_DBUS_ATTR_TOS,
RR_DBUS_ATTR_UID_RANGE_END,
RR_DBUS_ATTR_UID_RANGE_START,
_RR_DBUS_ATTR_NUM, _RR_DBUS_ATTR_NUM,
} RRDbusAttr; } 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_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_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_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 #undef _D
}; };
@@ -2819,6 +2893,8 @@ nm_ip_routing_rule_from_dbus(GVariant *variant, gboolean strict, GError **error)
GVariant * iter_val; GVariant * iter_val;
int addr_family; int addr_family;
int i; int i;
GVariant * v_start;
GVariant * v_end;
g_variant_iter_init(&iter, variant); 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])); nm_ip_routing_rule_set_ipproto(self, g_variant_get_byte(variants[RR_DBUS_ATTR_IPPROTO]));
for (i = 0; i < 2; i++) { 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) if (!v_start && !v_end)
continue; continue;
/* if start or end is missing, it defaults to the other parameter, respectively. */ /* if start or end is missing, it defaults to the other parameter, respectively. */
if (v_start) start = g_variant_get_uint16(v_start ?: v_end);
start = g_variant_get_uint16(v_start); if (v_end && v_start)
else
start = g_variant_get_uint16(v_end);
if (v_end)
end = g_variant_get_uint16(v_end); end = g_variant_get_uint16(v_end);
else else
end = g_variant_get_uint16(v_start); end = start;
if (i) if (i)
nm_ip_routing_rule_set_source_port(self, start, end); 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); 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]) { if (variants[RR_DBUS_ATTR_FWMARK] || variants[RR_DBUS_ATTR_FWMASK]) {
nm_ip_routing_rule_set_fwmark( nm_ip_routing_rule_set_fwmark(
self, self,
@@ -3075,6 +3174,16 @@ nm_ip_routing_rule_to_dbus(const NMIPRoutingRule *self)
RR_DBUS_ATTR_SUPPRESS_PREFIXLENGTH, RR_DBUS_ATTR_SUPPRESS_PREFIXLENGTH,
g_variant_new_int32(self->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); return g_variant_builder_end(&builder);
} }
@@ -3159,6 +3268,9 @@ nm_ip_routing_rule_from_string(const char * str,
guint16 sport_end = 0; guint16 sport_end = 0;
gint64 i64_dport_start = -1; gint64 i64_dport_start = -1;
guint16 dport_end = 0; guint16 dport_end = 0;
guint32 uid_range_start = 0;
guint32 uid_range_end = 0;
gboolean uid_range_has = FALSE;
gboolean val_invert = FALSE; gboolean val_invert = FALSE;
int addr_family = AF_UNSPEC; int addr_family = AF_UNSPEC;
NMIPAddr val_from = {}; NMIPAddr val_from = {};
@@ -3356,6 +3468,28 @@ nm_ip_routing_rule_from_string(const char * str,
goto next_fail_word1_invalid_value; goto next_fail_word1_invalid_value;
goto next_words_consumed; 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 /* 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 * 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) if (i64_table != -1)
nm_ip_routing_rule_set_table(self, i64_table); 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)) { if (NM_FLAGS_HAS(to_string_flags, NM_IP_ROUTING_RULE_AS_STRING_FLAGS_VALIDATE)) {
gs_free_error GError *local = NULL; 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); 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) { if (self->table != 0) {
nm_str_buf_append_printf(nm_str_buf_append_required_delimiter(&str, ' '), nm_str_buf_append_printf(nm_str_buf_append_required_delimiter(&str, ' '),
"table %u", "table %u",

View File

@@ -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_TO "to"
#define NM_IP_ROUTING_RULE_ATTR_TOS "tos" #define NM_IP_ROUTING_RULE_ATTR_TOS "tos"
#define NM_IP_ROUTING_RULE_ATTR_TO_LEN "to-len" #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); NMIPRoutingRule *nm_ip_routing_rule_from_dbus(GVariant *variant, gboolean strict, GError **error);
GVariant * nm_ip_routing_rule_to_dbus(const NMIPRoutingRule *self); GVariant * nm_ip_routing_rule_to_dbus(const NMIPRoutingRule *self);

View File

@@ -245,6 +245,15 @@ NM_AVAILABLE_IN_1_20
void nm_ip_routing_rule_set_suppress_prefixlength(NMIPRoutingRule *self, void nm_ip_routing_rule_set_suppress_prefixlength(NMIPRoutingRule *self,
gint32 suppress_prefixlength); 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 NM_AVAILABLE_IN_1_18
int nm_ip_routing_rule_cmp(const NMIPRoutingRule *rule, const NMIPRoutingRule *other); int nm_ip_routing_rule_cmp(const NMIPRoutingRule *rule, const NMIPRoutingRule *other);