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 *
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);

View File

@@ -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",

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_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);

View File

@@ -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);