libnm: rework validating route attributes to avoid duplicate check

_nm_ip_route_attribute_validate_all() validates all attributes together.
As such, it calls to nm_ip_route_attribute_validate(), which in turn
validates one attribute at a time.

Such full validation needs to check that (potentially conflicting)
attributes are valid together. Hence, _nm_ip_route_attribute_validate_all()
needs again peek into the attributes.

Refactor the code, so that we can extract the pieces that we need and
not need to parse them twice.
This commit is contained in:
Thomas Haller
2022-02-03 16:56:05 +01:00
parent 6f277d8fa6
commit 0413b1bf8a

View File

@@ -1243,7 +1243,8 @@ static const NMVariantAttributeSpec *const ip_route_attribute_spec[] = {
.v6 = TRUE, ), .v6 = TRUE, ),
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE(NM_IP_ROUTE_ATTRIBUTE_SCOPE, NM_VARIANT_ATTRIBUTE_SPEC_DEFINE(NM_IP_ROUTE_ATTRIBUTE_SCOPE,
G_VARIANT_TYPE_BYTE, G_VARIANT_TYPE_BYTE,
.v4 = TRUE, ), .v4 = TRUE,
.type_detail = 's'),
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE(NM_IP_ROUTE_ATTRIBUTE_SRC, NM_VARIANT_ATTRIBUTE_SPEC_DEFINE(NM_IP_ROUTE_ATTRIBUTE_SRC,
G_VARIANT_TYPE_STRING, G_VARIANT_TYPE_STRING,
.v4 = TRUE, .v4 = TRUE,
@@ -1279,35 +1280,26 @@ nm_ip_route_get_variant_attribute_spec(void)
return ip_route_attribute_spec; return ip_route_attribute_spec;
} }
/** typedef struct {
* nm_ip_route_attribute_validate: int type;
* @name: the attribute name int scope;
* @value: the attribute value } IPRouteAttrParseData;
* @family: IP address family of the route
* @known: (out): on return, whether the attribute name is a known one static gboolean
* @error: (allow-none): return location for a #GError, or %NULL _ip_route_attribute_validate(const char *name,
* GVariant *value,
* Validates a route attribute, i.e. checks that the attribute is a known one int family,
* and the value is of the correct type and well-formed. IPRouteAttrParseData *parse_data,
* gboolean *known,
* Returns: %TRUE if the attribute is valid, %FALSE otherwise GError **error)
*
* Since: 1.8
*/
gboolean
nm_ip_route_attribute_validate(const char *name,
GVariant *value,
int family,
gboolean *known,
GError **error)
{ {
const NMVariantAttributeSpec *spec; const NMVariantAttributeSpec *spec;
const char *string; const char *string;
g_return_val_if_fail(name, FALSE); nm_assert(name);
g_return_val_if_fail(value, FALSE); nm_assert(value);
g_return_val_if_fail(family == AF_INET || family == AF_INET6, FALSE); nm_assert(family == AF_INET || family == AF_INET6);
g_return_val_if_fail(!error || !*error, FALSE); nm_assert(!error || !*error);
spec = _nm_variant_attribute_spec_find_binary_search(ip_route_attribute_spec, spec = _nm_variant_attribute_spec_find_binary_search(ip_route_attribute_spec,
G_N_ELEMENTS(ip_route_attribute_spec) - 1, G_N_ELEMENTS(ip_route_attribute_spec) - 1,
@@ -1388,8 +1380,12 @@ nm_ip_route_attribute_validate(const char *name,
break; break;
} }
case 'T': /* route type. */ case 'T': /* route type. */
{
int type;
string = g_variant_get_string(value, NULL); string = g_variant_get_string(value, NULL);
if (!NM_IN_SET(nm_net_aux_rtnl_rtntype_a2n(string), RTN_UNICAST, RTN_LOCAL)) { type = nm_net_aux_rtnl_rtntype_a2n(string);
if (!NM_IN_SET(type, RTN_UNICAST, RTN_LOCAL)) {
g_set_error(error, g_set_error(error,
NM_CONNECTION_ERROR, NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY, NM_CONNECTION_ERROR_INVALID_PROPERTY,
@@ -1397,6 +1393,14 @@ nm_ip_route_attribute_validate(const char *name,
string); string);
return FALSE; return FALSE;
} }
if (parse_data)
parse_data->type = type;
break;
}
case 's': /* scope */
if (parse_data)
parse_data->scope = g_variant_get_byte(value);
break; break;
case '\0': case '\0':
break; break;
@@ -1408,6 +1412,36 @@ nm_ip_route_attribute_validate(const char *name,
return TRUE; return TRUE;
} }
/**
* nm_ip_route_attribute_validate:
* @name: the attribute name
* @value: the attribute value
* @family: IP address family of the route
* @known: (out): on return, whether the attribute name is a known one
* @error: (allow-none): return location for a #GError, or %NULL
*
* Validates a route attribute, i.e. checks that the attribute is a known one
* and the value is of the correct type and well-formed.
*
* Returns: %TRUE if the attribute is valid, %FALSE otherwise
*
* Since: 1.8
*/
gboolean
nm_ip_route_attribute_validate(const char *name,
GVariant *value,
int family,
gboolean *known,
GError **error)
{
g_return_val_if_fail(name, FALSE);
g_return_val_if_fail(value, FALSE);
g_return_val_if_fail(family == AF_INET || family == AF_INET6, FALSE);
g_return_val_if_fail(!error || !*error, FALSE);
return _ip_route_attribute_validate(name, value, family, NULL, known, error);
}
gboolean gboolean
_nm_ip_route_attribute_validate_all(const NMIPRoute *route, GError **error) _nm_ip_route_attribute_validate_all(const NMIPRoute *route, GError **error)
{ {
@@ -1415,9 +1449,11 @@ _nm_ip_route_attribute_validate_all(const NMIPRoute *route, GError **error)
gs_free NMUtilsNamedValue *attrs_free = NULL; gs_free NMUtilsNamedValue *attrs_free = NULL;
const NMUtilsNamedValue *attrs; const NMUtilsNamedValue *attrs;
guint attrs_len; guint attrs_len;
GVariant *val;
guint i; guint i;
guint8 u8; IPRouteAttrParseData parse_data = {
.type = RTN_UNICAST,
.scope = -1,
};
g_return_val_if_fail(route, FALSE); g_return_val_if_fail(route, FALSE);
g_return_val_if_fail(!error || !*error, FALSE); g_return_val_if_fail(!error || !*error, FALSE);
@@ -1430,34 +1466,26 @@ _nm_ip_route_attribute_validate_all(const NMIPRoute *route, GError **error)
attrs_static, attrs_static,
&attrs_free); &attrs_free);
for (i = 0; i < attrs_len; i++) { for (i = 0; i < attrs_len; i++) {
const char *key = attrs[i].name; if (!_ip_route_attribute_validate(attrs[i].name,
GVariant *val2 = attrs[i].value_ptr; attrs[i].value_ptr,
route->family,
if (!nm_ip_route_attribute_validate(key, val2, route->family, NULL, error)) &parse_data,
NULL,
error))
return FALSE; return FALSE;
} }
if ((val = g_hash_table_lookup(route->attributes, NM_IP_ROUTE_ATTRIBUTE_TYPE))) { switch (parse_data.type) {
int v_i; case RTN_LOCAL:
if (route->family == AF_INET && parse_data.scope >= 0
nm_assert(g_variant_is_of_type(val, G_VARIANT_TYPE_STRING)); && !NM_IN_SET(parse_data.scope, RT_SCOPE_HOST, RT_SCOPE_NOWHERE)) {
g_set_error(error,
v_i = nm_net_aux_rtnl_rtntype_a2n(g_variant_get_string(val, NULL)); NM_CONNECTION_ERROR,
nm_assert(v_i >= 0); NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("route scope is invalid for local route"));
if (v_i == RTN_LOCAL && route->family == AF_INET return FALSE;
&& (val = g_hash_table_lookup(route->attributes, NM_IP_ROUTE_ATTRIBUTE_SCOPE))) {
nm_assert(g_variant_is_of_type(val, G_VARIANT_TYPE_BYTE));
u8 = g_variant_get_byte(val);
if (!NM_IN_SET(u8, RT_SCOPE_HOST, RT_SCOPE_NOWHERE)) {
g_set_error(error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("route scope is invalid"));
return FALSE;
}
} }
break;
} }
return TRUE; return TRUE;