summary refs log tree commit diff
path: root/src/libnm-core-impl/nm-setting-ip-config.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libnm-core-impl/nm-setting-ip-config.c')
-rw-r--r--src/libnm-core-impl/nm-setting-ip-config.c816
1 files changed, 405 insertions, 411 deletions
diff --git a/src/libnm-core-impl/nm-setting-ip-config.c b/src/libnm-core-impl/nm-setting-ip-config.c
index 33779ed9..52aa6515 100644
--- a/src/libnm-core-impl/nm-setting-ip-config.c
+++ b/src/libnm-core-impl/nm-setting-ip-config.c
@@ -54,56 +54,24 @@ const NMUtilsDNSOptionDesc _nm_utils_dns_option_descs[] = {
     {NULL, FALSE, FALSE}};
 
 static char *
-canonicalize_ip(int family, const char *ip, gboolean null_any)
+canonicalize_ip_binary(int family, const NMIPAddr *ip, gboolean null_any)
 {
-    guint8 addr_bytes[sizeof(struct in6_addr)];
-    char   addr_str[NM_UTILS_INET_ADDRSTRLEN];
-    int    ret;
-
     if (!ip) {
         if (null_any)
             return NULL;
-        if (family == AF_INET)
+        if (NM_IS_IPv4(family))
             return g_strdup("0.0.0.0");
-        if (family == AF_INET6)
-            return g_strdup("::");
-        g_return_val_if_reached(NULL);
+        return g_strdup("::");
     }
 
-    ret = inet_pton(family, ip, addr_bytes);
-    g_return_val_if_fail(ret == 1, NULL);
-
-    if (null_any) {
-        if (!memcmp(addr_bytes, &in6addr_any, nm_utils_addr_family_to_size(family)))
-            return NULL;
-    }
+    if (null_any && nm_ip_addr_is_null(family, ip))
+        return NULL;
 
-    return g_strdup(inet_ntop(family, addr_bytes, addr_str, sizeof(addr_str)));
-}
-
-static char *
-canonicalize_ip_binary(int family, gconstpointer ip, gboolean null_any)
-{
-    char string[NM_UTILS_INET_ADDRSTRLEN];
-
-    if (!ip) {
-        if (null_any)
-            return NULL;
-        if (family == AF_INET)
-            return g_strdup("0.0.0.0");
-        if (family == AF_INET6)
-            return g_strdup("::");
-        g_return_val_if_reached(NULL);
-    }
-    if (null_any) {
-        if (!memcmp(ip, &in6addr_any, nm_utils_addr_family_to_size(family)))
-            return NULL;
-    }
-    return g_strdup(inet_ntop(family, ip, string, sizeof(string)));
+    return nm_utils_inet_ntop_dup(family, ip);
 }
 
 static gboolean
-valid_ip(int family, const char *ip, GError **error)
+valid_ip(int family, const char *ip, NMIPAddr *addr, GError **error)
 {
     if (!ip) {
         g_set_error(error,
@@ -112,7 +80,7 @@ valid_ip(int family, const char *ip, GError **error)
                     family == AF_INET ? _("Missing IPv4 address") : _("Missing IPv6 address"));
         return FALSE;
     }
-    if (!nm_utils_ipaddr_is_valid(family, ip)) {
+    if (!nm_utils_parse_inaddr_bin(family, ip, NULL, addr)) {
         g_set_error(error,
                     NM_CONNECTION_ERROR,
                     NM_CONNECTION_ERROR_FAILED,
@@ -120,8 +88,9 @@ valid_ip(int family, const char *ip, GError **error)
                                       : _("Invalid IPv6 address '%s'"),
                     ip);
         return FALSE;
-    } else
-        return TRUE;
+    }
+
+    return TRUE;
 }
 
 static gboolean
@@ -169,9 +138,10 @@ G_DEFINE_BOXED_TYPE(NMIPAddress, nm_ip_address, nm_ip_address_dup, nm_ip_address
 struct NMIPAddress {
     guint refcount;
 
-    char *address;
-    int   prefix, family;
+    gint8  family;
+    guint8 prefix;
 
+    char       *address;
     GHashTable *attributes;
 };
 
@@ -191,21 +161,23 @@ NMIPAddress *
 nm_ip_address_new(int family, const char *addr, guint prefix, GError **error)
 {
     NMIPAddress *address;
+    NMIPAddr     addr_bin;
 
     g_return_val_if_fail(family == AF_INET || family == AF_INET6, NULL);
     g_return_val_if_fail(addr != NULL, NULL);
 
-    if (!valid_ip(family, addr, error))
+    if (!valid_ip(family, addr, &addr_bin, error))
         return NULL;
     if (!valid_prefix(family, prefix, error))
         return NULL;
 
-    address           = g_slice_new0(NMIPAddress);
-    address->refcount = 1;
-
-    address->family  = family;
-    address->address = canonicalize_ip(family, addr, FALSE);
-    address->prefix  = prefix;
+    address  = g_slice_new(NMIPAddress);
+    *address = (NMIPAddress){
+        .refcount = 1,
+        .family   = family,
+        .address  = canonicalize_ip_binary(family, &addr_bin, FALSE),
+        .prefix   = prefix,
+    };
 
     return address;
 }
@@ -227,7 +199,6 @@ NMIPAddress *
 nm_ip_address_new_binary(int family, gconstpointer addr, guint prefix, GError **error)
 {
     NMIPAddress *address;
-    char         string[NM_UTILS_INET_ADDRSTRLEN];
 
     g_return_val_if_fail(family == AF_INET || family == AF_INET6, NULL);
     g_return_val_if_fail(addr != NULL, NULL);
@@ -235,12 +206,13 @@ nm_ip_address_new_binary(int family, gconstpointer addr, guint prefix, GError **
     if (!valid_prefix(family, prefix, error))
         return NULL;
 
-    address           = g_slice_new0(NMIPAddress);
-    address->refcount = 1;
-
-    address->family  = family;
-    address->address = g_strdup(inet_ntop(family, addr, string, sizeof(string)));
-    address->prefix  = prefix;
+    address  = g_slice_new(NMIPAddress);
+    *address = (NMIPAddress){
+        .refcount = 1,
+        .family   = family,
+        .address  = nm_utils_inet_ntop_dup(family, addr),
+        .prefix   = prefix,
+    };
 
     return address;
 }
@@ -276,9 +248,8 @@ nm_ip_address_unref(NMIPAddress *address)
     address->refcount--;
     if (address->refcount == 0) {
         g_free(address->address);
-        if (address->attributes)
-            g_hash_table_unref(address->attributes);
-        g_slice_free(NMIPAddress, address);
+        nm_g_hash_table_unref(address->attributes);
+        nm_g_slice_free(address);
     }
 }
 
@@ -311,8 +282,8 @@ nm_ip_address_cmp_full(const NMIPAddress *a, const NMIPAddress *b, NMIPAddressCm
 
     if (NM_FLAGS_HAS(cmp_flags, NM_IP_ADDRESS_CMP_FLAGS_WITH_ATTRS)) {
         GHashTableIter iter;
-        const char *   key;
-        GVariant *     value, *value2;
+        const char    *key;
+        GVariant      *value, *value2;
         guint          n;
 
         n = a->attributes ? g_hash_table_size(a->attributes) : 0u;
@@ -382,8 +353,8 @@ nm_ip_address_dup(NMIPAddress *address)
     copy = nm_ip_address_new(address->family, address->address, address->prefix, NULL);
     if (address->attributes) {
         GHashTableIter iter;
-        const char *   key;
-        GVariant *     value;
+        const char    *key;
+        GVariant      *value;
 
         g_hash_table_iter_init(&iter, address->attributes);
         while (g_hash_table_iter_next(&iter, (gpointer *) &key, (gpointer *) &value))
@@ -441,12 +412,18 @@ nm_ip_address_get_address(NMIPAddress *address)
 void
 nm_ip_address_set_address(NMIPAddress *address, const char *addr)
 {
+    NMIPAddr addr_bin;
+
     g_return_if_fail(address != NULL);
-    g_return_if_fail(addr != NULL);
-    g_return_if_fail(nm_utils_ipaddr_is_valid(address->family, addr));
+
+    if (!valid_ip(address->family, addr, &addr_bin, NULL)) {
+        g_return_if_fail(addr != NULL);
+        g_return_if_fail(nm_utils_ipaddr_is_valid(address->family, addr));
+        nm_assert_not_reached();
+    }
 
     g_free(address->address);
-    address->address = canonicalize_ip(address->family, addr, FALSE);
+    address->address = canonicalize_ip_binary(address->family, &addr_bin, FALSE);
 }
 
 /**
@@ -479,13 +456,11 @@ nm_ip_address_get_address_binary(NMIPAddress *address, gpointer addr)
 void
 nm_ip_address_set_address_binary(NMIPAddress *address, gconstpointer addr)
 {
-    char string[NM_UTILS_INET_ADDRSTRLEN];
-
     g_return_if_fail(address != NULL);
     g_return_if_fail(addr != NULL);
 
     g_free(address->address);
-    address->address = g_strdup(inet_ntop(address->family, addr, string, sizeof(string)));
+    address->address = nm_utils_inet_ntop_dup(address->family, addr);
 }
 
 /**
@@ -608,13 +583,14 @@ G_DEFINE_BOXED_TYPE(NMIPRoute, nm_ip_route, nm_ip_route_dup, nm_ip_route_unref)
 struct NMIPRoute {
     guint refcount;
 
-    int    family;
-    char * dest;
-    guint  prefix;
-    char * next_hop;
-    gint64 metric;
+    gint8  family;
+    guint8 prefix;
 
+    char       *dest;
+    char       *next_hop;
     GHashTable *attributes;
+
+    gint64 metric;
 };
 
 /**
@@ -637,30 +613,33 @@ nm_ip_route_new(int         family,
                 guint       prefix,
                 const char *next_hop,
                 gint64      metric,
-                GError **   error)
+                GError    **error)
 {
     NMIPRoute *route;
+    NMIPAddr   dest_bin;
+    NMIPAddr   next_hop_bin;
 
     g_return_val_if_fail(family == AF_INET || family == AF_INET6, NULL);
     g_return_val_if_fail(dest, NULL);
 
-    if (!valid_ip(family, dest, error))
+    if (!valid_ip(family, dest, &dest_bin, error))
         return NULL;
     if (!valid_prefix(family, prefix, error))
         return NULL;
-    if (next_hop && !valid_ip(family, next_hop, error))
+    if (next_hop && !valid_ip(family, next_hop, &next_hop_bin, error))
         return NULL;
     if (!valid_metric(metric, error))
         return NULL;
 
-    route           = g_slice_new0(NMIPRoute);
-    route->refcount = 1;
-
-    route->family   = family;
-    route->dest     = canonicalize_ip(family, dest, FALSE);
-    route->prefix   = prefix;
-    route->next_hop = canonicalize_ip(family, next_hop, TRUE);
-    route->metric   = metric;
+    route  = g_slice_new(NMIPRoute);
+    *route = (NMIPRoute){
+        .refcount = 1,
+        .family   = family,
+        .dest     = canonicalize_ip_binary(family, &dest_bin, FALSE),
+        .prefix   = prefix,
+        .next_hop = canonicalize_ip_binary(family, next_hop ? &next_hop_bin : NULL, TRUE),
+        .metric   = metric,
+    };
 
     return route;
 }
@@ -686,7 +665,7 @@ nm_ip_route_new_binary(int           family,
                        guint         prefix,
                        gconstpointer next_hop,
                        gint64        metric,
-                       GError **     error)
+                       GError      **error)
 {
     NMIPRoute *route;
 
@@ -698,14 +677,15 @@ nm_ip_route_new_binary(int           family,
     if (!valid_metric(metric, error))
         return NULL;
 
-    route           = g_slice_new0(NMIPRoute);
-    route->refcount = 1;
-
-    route->family   = family;
-    route->dest     = canonicalize_ip_binary(family, dest, FALSE);
-    route->prefix   = prefix;
-    route->next_hop = canonicalize_ip_binary(family, next_hop, TRUE);
-    route->metric   = metric;
+    route  = g_slice_new0(NMIPRoute);
+    *route = (NMIPRoute){
+        .refcount = 1,
+        .family   = family,
+        .dest     = canonicalize_ip_binary(family, dest, FALSE),
+        .prefix   = prefix,
+        .next_hop = canonicalize_ip_binary(family, next_hop, TRUE),
+        .metric   = metric,
+    };
 
     return route;
 }
@@ -742,9 +722,8 @@ nm_ip_route_unref(NMIPRoute *route)
     if (route->refcount == 0) {
         g_free(route->dest);
         g_free(route->next_hop);
-        if (route->attributes)
-            g_hash_table_unref(route->attributes);
-        g_slice_free(NMIPRoute, route);
+        nm_g_hash_table_unref(route->attributes);
+        nm_g_slice_free(route);
     }
 }
 
@@ -783,8 +762,8 @@ nm_ip_route_equal_full(NMIPRoute *route, NMIPRoute *other, guint cmp_flags)
         return FALSE;
     if (cmp_flags == NM_IP_ROUTE_EQUAL_CMP_FLAGS_WITH_ATTRS) {
         GHashTableIter iter;
-        const char *   key;
-        GVariant *     value, *value2;
+        const char    *key;
+        GVariant      *value, *value2;
         guint          n;
 
         n = route->attributes ? g_hash_table_size(route->attributes) : 0u;
@@ -850,8 +829,8 @@ nm_ip_route_dup(NMIPRoute *route)
                            NULL);
     if (route->attributes) {
         GHashTableIter iter;
-        const char *   key;
-        GVariant *     value;
+        const char    *key;
+        GVariant      *value;
 
         g_hash_table_iter_init(&iter, route->attributes);
         while (g_hash_table_iter_next(&iter, (gpointer *) &key, (gpointer *) &value))
@@ -909,11 +888,17 @@ nm_ip_route_get_dest(NMIPRoute *route)
 void
 nm_ip_route_set_dest(NMIPRoute *route, const char *dest)
 {
+    NMIPAddr dest_bin;
+
     g_return_if_fail(route != NULL);
-    g_return_if_fail(nm_utils_ipaddr_is_valid(route->family, dest));
+
+    if (!valid_ip(route->family, dest, &dest_bin, NULL)) {
+        g_return_if_fail(nm_utils_ipaddr_is_valid(route->family, dest));
+        nm_assert_not_reached();
+    }
 
     g_free(route->dest);
-    route->dest = canonicalize_ip(route->family, dest, FALSE);
+    route->dest = canonicalize_ip_binary(route->family, &dest_bin, FALSE);
 }
 
 /**
@@ -946,13 +931,11 @@ nm_ip_route_get_dest_binary(NMIPRoute *route, gpointer dest)
 void
 nm_ip_route_set_dest_binary(NMIPRoute *route, gconstpointer dest)
 {
-    char string[NM_UTILS_INET_ADDRSTRLEN];
-
     g_return_if_fail(route != NULL);
     g_return_if_fail(dest != NULL);
 
     g_free(route->dest);
-    route->dest = g_strdup(inet_ntop(route->family, dest, string, sizeof(string)));
+    route->dest = nm_utils_inet_ntop_dup(route->family, dest);
 }
 
 /**
@@ -1020,11 +1003,17 @@ nm_ip_route_get_next_hop(NMIPRoute *route)
 void
 nm_ip_route_set_next_hop(NMIPRoute *route, const char *next_hop)
 {
+    NMIPAddr next_hop_bin;
+
     g_return_if_fail(route != NULL);
-    g_return_if_fail(!next_hop || nm_utils_ipaddr_is_valid(route->family, next_hop));
+
+    if (next_hop && !valid_ip(route->family, next_hop, &next_hop_bin, NULL)) {
+        g_return_if_fail(!next_hop || nm_utils_ipaddr_is_valid(route->family, next_hop));
+        nm_assert_not_reached();
+    }
 
     g_free(route->next_hop);
-    route->next_hop = canonicalize_ip(route->family, next_hop, TRUE);
+    route->next_hop = canonicalize_ip_binary(route->family, next_hop ? &next_hop_bin : NULL, TRUE);
 }
 
 /**
@@ -1214,8 +1203,8 @@ static const NMVariantAttributeSpec *const ip_route_attribute_spec[] = {
                                      .v6 = TRUE, ),
     NM_VARIANT_ATTRIBUTE_SPEC_DEFINE(NM_IP_ROUTE_ATTRIBUTE_FROM,
                                      G_VARIANT_TYPE_STRING,
-                                     .v6       = TRUE,
-                                     .str_type = 'p', ),
+                                     .v6          = TRUE,
+                                     .type_detail = 'p', ),
     NM_VARIANT_ATTRIBUTE_SPEC_DEFINE(NM_IP_ROUTE_ATTRIBUTE_INITCWND,
                                      G_VARIANT_TYPE_UINT32,
                                      .v4 = TRUE,
@@ -1254,12 +1243,13 @@ static const NMVariantAttributeSpec *const ip_route_attribute_spec[] = {
                                      .v6 = TRUE, ),
     NM_VARIANT_ATTRIBUTE_SPEC_DEFINE(NM_IP_ROUTE_ATTRIBUTE_SCOPE,
                                      G_VARIANT_TYPE_BYTE,
-                                     .v4 = TRUE, ),
+                                     .v4          = TRUE,
+                                     .type_detail = 's'),
     NM_VARIANT_ATTRIBUTE_SPEC_DEFINE(NM_IP_ROUTE_ATTRIBUTE_SRC,
                                      G_VARIANT_TYPE_STRING,
-                                     .v4       = TRUE,
-                                     .v6       = TRUE,
-                                     .str_type = 'a', ),
+                                     .v4          = TRUE,
+                                     .v6          = TRUE,
+                                     .type_detail = 'a', ),
     NM_VARIANT_ATTRIBUTE_SPEC_DEFINE(NM_IP_ROUTE_ATTRIBUTE_TABLE,
                                      G_VARIANT_TYPE_UINT32,
                                      .v4 = TRUE,
@@ -1267,9 +1257,9 @@ static const NMVariantAttributeSpec *const ip_route_attribute_spec[] = {
     NM_VARIANT_ATTRIBUTE_SPEC_DEFINE(NM_IP_ROUTE_ATTRIBUTE_TOS, G_VARIANT_TYPE_BYTE, .v4 = TRUE, ),
     NM_VARIANT_ATTRIBUTE_SPEC_DEFINE(NM_IP_ROUTE_ATTRIBUTE_TYPE,
                                      G_VARIANT_TYPE_STRING,
-                                     .v4       = TRUE,
-                                     .v6       = TRUE,
-                                     .str_type = 'T', ),
+                                     .v4          = TRUE,
+                                     .v6          = TRUE,
+                                     .type_detail = 'T', ),
     NM_VARIANT_ATTRIBUTE_SPEC_DEFINE(NM_IP_ROUTE_ATTRIBUTE_WINDOW,
                                      G_VARIANT_TYPE_UINT32,
                                      .v4 = TRUE,
@@ -1290,34 +1280,26 @@ nm_ip_route_get_variant_attribute_spec(void)
     return ip_route_attribute_spec;
 }
 
-/**
- * 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)
+typedef struct {
+    int type;
+    int scope;
+} IPRouteAttrParseData;
+
+static gboolean
+_ip_route_attribute_validate(const char           *name,
+                             GVariant             *value,
+                             int                   family,
+                             IPRouteAttrParseData *parse_data,
+                             gboolean             *known,
+                             GError              **error)
 {
     const NMVariantAttributeSpec *spec;
+    const char                   *string;
 
-    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);
+    nm_assert(name);
+    nm_assert(value);
+    nm_assert(family == AF_INET || family == AF_INET6);
+    nm_assert(!error || !*error);
 
     spec = _nm_variant_attribute_spec_find_binary_search(ip_route_attribute_spec,
                                                          G_N_ELEMENTS(ip_route_attribute_spec) - 1,
@@ -1351,80 +1333,132 @@ nm_ip_route_attribute_validate(const char *name,
         return FALSE;
     }
 
-    if (g_variant_type_equal(spec->type, G_VARIANT_TYPE_STRING)) {
-        const char *string = g_variant_get_string(value, NULL);
-
-        switch (spec->str_type) {
-        case 'a': /* IP address */
-            if (!nm_utils_ipaddr_is_valid(family, string)) {
-                g_set_error(error,
-                            NM_CONNECTION_ERROR,
-                            NM_CONNECTION_ERROR_FAILED,
-                            family == AF_INET ? _("'%s' is not a valid IPv4 address")
-                                              : _("'%s' is not a valid IPv6 address"),
-                            string);
-                return FALSE;
-            }
-            break;
-        case 'p': /* IP address + optional prefix */
-        {
-            gs_free char *addr_free = NULL;
-            const char *  addr      = string;
-            const char *  str;
-
-            str = strchr(addr, '/');
-            if (str) {
-                addr = nm_strndup_a(200, addr, str - addr, &addr_free);
-                str++;
-                if (_nm_utils_ascii_str_to_int64(str, 10, 0, family == AF_INET ? 32 : 128, -1)
-                    < 0) {
-                    g_set_error(error,
-                                NM_CONNECTION_ERROR,
-                                NM_CONNECTION_ERROR_FAILED,
-                                _("invalid prefix %s"),
-                                str);
-                    return FALSE;
-                }
-            }
-            if (!nm_utils_ipaddr_is_valid(family, addr)) {
+    switch (spec->type_detail) {
+    case 'a': /* IP address */
+        string = g_variant_get_string(value, NULL);
+        if (!nm_utils_ipaddr_is_valid(family, string)) {
+            g_set_error(error,
+                        NM_CONNECTION_ERROR,
+                        NM_CONNECTION_ERROR_FAILED,
+                        family == AF_INET ? _("'%s' is not a valid IPv4 address")
+                                          : _("'%s' is not a valid IPv6 address"),
+                        string);
+            return FALSE;
+        }
+        break;
+    case 'p': /* IP address + optional prefix */
+    {
+        gs_free char *addr_free = NULL;
+        const char   *addr;
+        const char   *str;
+
+        string = g_variant_get_string(value, NULL);
+        addr   = string;
+
+        str = strchr(addr, '/');
+        if (str) {
+            addr = nm_strndup_a(200, addr, str - addr, &addr_free);
+            str++;
+            if (_nm_utils_ascii_str_to_int64(str, 10, 0, family == AF_INET ? 32 : 128, -1) < 0) {
                 g_set_error(error,
                             NM_CONNECTION_ERROR,
                             NM_CONNECTION_ERROR_FAILED,
-                            family == AF_INET ? _("'%s' is not a valid IPv4 address")
-                                              : _("'%s' is not a valid IPv6 address"),
-                            string);
+                            _("invalid prefix %s"),
+                            str);
                 return FALSE;
             }
-            break;
         }
-        case 'T': /* route type. */
-            if (!NM_IN_SET(nm_net_aux_rtnl_rtntype_a2n(string), RTN_UNICAST, RTN_LOCAL)) {
-                g_set_error(error,
-                            NM_CONNECTION_ERROR,
-                            NM_CONNECTION_ERROR_INVALID_PROPERTY,
-                            _("%s is not a valid route type"),
-                            string);
-                return FALSE;
-            }
-            break;
-        default:
-            break;
+        if (!nm_utils_ipaddr_is_valid(family, addr)) {
+            g_set_error(error,
+                        NM_CONNECTION_ERROR,
+                        NM_CONNECTION_ERROR_FAILED,
+                        family == AF_INET ? _("'%s' is not a valid IPv4 address")
+                                          : _("'%s' is not a valid IPv6 address"),
+                        string);
+            return FALSE;
         }
+        break;
+    }
+    case 'T': /* route type. */
+    {
+        int type;
+
+        string = g_variant_get_string(value, NULL);
+        type   = nm_net_aux_rtnl_rtntype_a2n(string);
+        if (!NM_IN_SET(type,
+                       RTN_UNICAST,
+                       RTN_LOCAL,
+                       RTN_BLACKHOLE,
+                       RTN_UNREACHABLE,
+                       RTN_PROHIBIT)) {
+            g_set_error(error,
+                        NM_CONNECTION_ERROR,
+                        NM_CONNECTION_ERROR_INVALID_PROPERTY,
+                        _("%s is not a valid route type"),
+                        string);
+            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;
+    case '\0':
+        break;
+    default:
+        nm_assert_not_reached();
+        break;
     }
 
     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
 _nm_ip_route_attribute_validate_all(const NMIPRoute *route, GError **error)
 {
-    NMUtilsNamedValue attrs_static[G_N_ELEMENTS(ip_route_attribute_spec)];
+    NMUtilsNamedValue          attrs_static[G_N_ELEMENTS(ip_route_attribute_spec)];
     gs_free NMUtilsNamedValue *attrs_free = NULL;
-    const NMUtilsNamedValue *  attrs;
+    const NMUtilsNamedValue   *attrs;
     guint                      attrs_len;
-    GVariant *                 val;
     guint                      i;
-    guint8                     u8;
+    IPRouteAttrParseData       parse_data = {
+              .type  = RTN_UNICAST,
+              .scope = -1,
+    };
 
     g_return_val_if_fail(route, FALSE);
     g_return_val_if_fail(!error || !*error, FALSE);
@@ -1437,34 +1471,38 @@ _nm_ip_route_attribute_validate_all(const NMIPRoute *route, GError **error)
                                                attrs_static,
                                                &attrs_free);
     for (i = 0; i < attrs_len; i++) {
-        const char *key  = attrs[i].name;
-        GVariant *  val2 = attrs[i].value_ptr;
-
-        if (!nm_ip_route_attribute_validate(key, val2, route->family, NULL, error))
+        if (!_ip_route_attribute_validate(attrs[i].name,
+                                          attrs[i].value_ptr,
+                                          route->family,
+                                          &parse_data,
+                                          NULL,
+                                          error))
             return FALSE;
     }
 
-    if ((val = g_hash_table_lookup(route->attributes, NM_IP_ROUTE_ATTRIBUTE_TYPE))) {
-        int v_i;
-
-        nm_assert(g_variant_is_of_type(val, G_VARIANT_TYPE_STRING));
-
-        v_i = nm_net_aux_rtnl_rtntype_a2n(g_variant_get_string(val, NULL));
-        nm_assert(v_i >= 0);
-
-        if (v_i == RTN_LOCAL && route->family == AF_INET
-            && (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;
-            }
+    switch (parse_data.type) {
+    case RTN_LOCAL:
+        if (route->family == AF_INET && parse_data.scope >= 0
+            && !NM_IN_SET(parse_data.scope, RT_SCOPE_HOST, RT_SCOPE_NOWHERE)) {
+            g_set_error(error,
+                        NM_CONNECTION_ERROR,
+                        NM_CONNECTION_ERROR_INVALID_PROPERTY,
+                        _("route scope is invalid for local route"));
+            return FALSE;
         }
+        break;
+    case RTN_BLACKHOLE:
+    case RTN_UNREACHABLE:
+    case RTN_PROHIBIT:
+        if (route->next_hop) {
+            g_set_error(error,
+                        NM_CONNECTION_ERROR,
+                        NM_CONNECTION_ERROR_INVALID_PROPERTY,
+                        _("a %s route cannot have a next-hop"),
+                        nm_net_aux_rtnl_rtntype_n2a(parse_data.type));
+            return FALSE;
+        }
+        break;
     }
 
     return TRUE;
@@ -1475,10 +1513,10 @@ _nm_ip_route_attribute_validate_all(const NMIPRoute *route, GError **error)
 struct NMIPRoutingRule {
     NMIPAddr from_bin;
     NMIPAddr to_bin;
-    char *   from_str;
-    char *   to_str;
-    char *   iifname;
-    char *   oifname;
+    char    *from_str;
+    char    *to_str;
+    char    *iifname;
+    char    *oifname;
     guint    ref_count;
     guint32  priority;
     guint32  table;
@@ -1692,7 +1730,7 @@ nm_ip_routing_rule_unref(NMIPRoutingRule *self)
     g_free(self->iifname);
     g_free(self->oifname);
 
-    g_slice_free(NMIPRoutingRule, self);
+    nm_g_slice_free(self);
 }
 
 /**
@@ -2254,7 +2292,7 @@ nm_ip_routing_rule_get_xifname_bin(const NMIPRoutingRule *self,
                                    char                   out_xifname[static 16 /* IFNAMSIZ */])
 {
     gs_free gpointer bin_to_free = NULL;
-    const char *     xifname;
+    const char      *xifname;
     gconstpointer    bin;
     gsize            len;
 
@@ -2448,8 +2486,8 @@ nm_ip_routing_rule_set_suppress_prefixlength(NMIPRoutingRule *self, gint32 suppr
  */
 gboolean
 nm_ip_routing_rule_get_uid_range(const NMIPRoutingRule *self,
-                                 guint32 *              out_range_start,
-                                 guint32 *              out_range_end)
+                                 guint32               *out_range_start,
+                                 guint32               *out_range_end)
 {
     g_return_val_if_fail(NM_IS_IP_ROUTING_RULE(self, TRUE), -1);
 
@@ -2590,7 +2628,7 @@ _rr_xport_range_parse(char *str, gint64 *out_start, guint16 *out_end)
 {
     guint16 start, end;
     gint64  i64;
-    char *  s;
+    char   *s;
 
     s = strchr(str, '-');
     if (s)
@@ -2823,7 +2861,7 @@ typedef enum {
 } RRDbusAttr;
 
 typedef struct {
-    const char *        name;
+    const char         *name;
     const GVariantType *dbus_type;
 } RRDbusData;
 
@@ -2905,16 +2943,16 @@ _rr_variants_free(GVariant *(*p_variants)[])
 NMIPRoutingRule *
 nm_ip_routing_rule_from_dbus(GVariant *variant, gboolean strict, GError **error)
 {
-    nm_auto(_rr_variants_free) GVariant *variants[_RR_DBUS_ATTR_NUM] = {};
-    nm_auto_unref_ip_routing_rule NMIPRoutingRule *self              = NULL;
+    nm_auto(_rr_variants_free) GVariant           *variants[_RR_DBUS_ATTR_NUM] = {};
+    nm_auto_unref_ip_routing_rule NMIPRoutingRule *self                        = NULL;
     RRDbusAttr                                     attr;
     GVariantIter                                   iter;
-    const char *                                   iter_key;
-    GVariant *                                     iter_val;
+    const char                                    *iter_key;
+    GVariant                                      *iter_val;
     int                                            addr_family;
     int                                            i;
-    GVariant *                                     v_start;
-    GVariant *                                     v_end;
+    GVariant                                      *v_start;
+    GVariant                                      *v_end;
 
     g_variant_iter_init(&iter, variant);
 
@@ -3216,8 +3254,8 @@ nm_ip_routing_rule_to_dbus(const NMIPRoutingRule *self)
 static gboolean
 _rr_string_validate(gboolean                     for_from /* or else to-string */,
                     NMIPRoutingRuleAsStringFlags to_string_flags,
-                    GHashTable *                 extra_args,
-                    GError **                    error)
+                    GHashTable                  *extra_args,
+                    GError                     **error)
 {
     if (NM_FLAGS_ANY(to_string_flags,
                      ~(NM_IP_ROUTING_RULE_AS_STRING_FLAGS_AF_INET
@@ -3266,21 +3304,21 @@ _rr_string_addr_family_from_flags(NMIPRoutingRuleAsStringFlags to_string_flags)
  * Since: 1.18
  */
 NMIPRoutingRule *
-nm_ip_routing_rule_from_string(const char *                 str,
+nm_ip_routing_rule_from_string(const char                  *str,
                                NMIPRoutingRuleAsStringFlags to_string_flags,
-                               GHashTable *                 extra_args,
-                               GError **                    error)
+                               GHashTable                  *extra_args,
+                               GError                     **error)
 {
     nm_auto_unref_ip_routing_rule NMIPRoutingRule *self   = NULL;
-    gs_free const char **                          tokens = NULL;
+    gs_free const char                           **tokens = NULL;
     gsize                                          i_token;
     gboolean                                       any_words                 = FALSE;
-    char *                                         word0                     = NULL;
-    char *                                         word1                     = NULL;
-    char *                                         word_from                 = NULL;
-    char *                                         word_to                   = NULL;
-    char *                                         word_iifname              = NULL;
-    char *                                         word_oifname              = NULL;
+    char                                          *word0                     = NULL;
+    char                                          *word1                     = NULL;
+    char                                          *word_from                 = NULL;
+    char                                          *word_to                   = NULL;
+    char                                          *word_iifname              = NULL;
+    char                                          *word_oifname              = NULL;
     gint64                                         i64_priority              = -1;
     gint64                                         i64_table                 = -1;
     gint64                                         i64_tos                   = -1;
@@ -3302,7 +3340,7 @@ nm_ip_routing_rule_from_string(const char *                 str,
     NMIPAddr                                       val_to                    = {};
     int                                            val_from_len              = -1;
     int                                            val_to_len                = -1;
-    char *                                         s;
+    char                                          *s;
 
     g_return_val_if_fail(str, NULL);
 
@@ -3688,7 +3726,7 @@ next_words_consumed:
 }
 
 static void
-_rr_string_append_inet_addr(NMStrBuf *      str,
+_rr_string_append_inet_addr(NMStrBuf       *str,
                             gboolean        is_from /* or else is-to */,
                             gboolean        required,
                             int             addr_family,
@@ -3730,10 +3768,10 @@ _rr_string_append_inet_addr(NMStrBuf *      str,
  * Since: 1.18
  */
 char *
-nm_ip_routing_rule_to_string(const NMIPRoutingRule *      self,
+nm_ip_routing_rule_to_string(const NMIPRoutingRule       *self,
                              NMIPRoutingRuleAsStringFlags to_string_flags,
-                             GHashTable *                 extra_args,
-                             GError **                    error)
+                             GHashTable                  *extra_args,
+                             GError                     **error)
 {
     int      addr_family;
     NMStrBuf str;
@@ -4000,25 +4038,31 @@ gboolean
 nm_setting_ip_config_add_dns(NMSettingIPConfig *setting, const char *dns)
 {
     NMSettingIPConfigPrivate *priv;
-    char *                    dns_canonical;
+    int                       addr_family;
+    NMIPAddr                  dns_bin;
+    char                      dns_canonical[NM_UTILS_INET_ADDRSTRLEN];
     guint                     i;
 
     g_return_val_if_fail(NM_IS_SETTING_IP_CONFIG(setting), FALSE);
-    g_return_val_if_fail(dns != NULL, FALSE);
-    g_return_val_if_fail(nm_utils_ipaddr_is_valid(NM_SETTING_IP_CONFIG_GET_FAMILY(setting), dns),
-                         FALSE);
+
+    addr_family = NM_SETTING_IP_CONFIG_GET_FAMILY(setting);
+
+    if (!valid_ip(addr_family, dns, &dns_bin, NULL)) {
+        g_return_val_if_fail(dns != NULL, FALSE);
+        g_return_val_if_fail(nm_utils_ipaddr_is_valid(addr_family, dns), FALSE);
+        nm_assert_not_reached();
+    }
 
     priv = NM_SETTING_IP_CONFIG_GET_PRIVATE(setting);
 
-    dns_canonical = canonicalize_ip(NM_SETTING_IP_CONFIG_GET_FAMILY(setting), dns, FALSE);
+    nm_utils_inet_ntop(addr_family, &dns_bin, dns_canonical);
+
     for (i = 0; i < priv->dns->len; i++) {
-        if (!strcmp(dns_canonical, priv->dns->pdata[i])) {
-            g_free(dns_canonical);
+        if (nm_streq(dns_canonical, priv->dns->pdata[i]))
             return FALSE;
-        }
     }
 
-    g_ptr_array_add(priv->dns, dns_canonical);
+    g_ptr_array_add(priv->dns, g_strdup(dns_canonical));
     _notify(setting, PROP_DNS);
     return TRUE;
 }
@@ -4057,26 +4101,32 @@ gboolean
 nm_setting_ip_config_remove_dns_by_value(NMSettingIPConfig *setting, const char *dns)
 {
     NMSettingIPConfigPrivate *priv;
-    char *                    dns_canonical;
+    int                       addr_family;
+    NMIPAddr                  dns_bin;
+    char                      dns_canonical[NM_UTILS_INET_ADDRSTRLEN];
     guint                     i;
 
     g_return_val_if_fail(NM_IS_SETTING_IP_CONFIG(setting), FALSE);
-    g_return_val_if_fail(dns != NULL, FALSE);
-    g_return_val_if_fail(nm_utils_ipaddr_is_valid(NM_SETTING_IP_CONFIG_GET_FAMILY(setting), dns),
-                         FALSE);
+
+    addr_family = NM_SETTING_IP_CONFIG_GET_FAMILY(setting);
+
+    if (!valid_ip(addr_family, dns, &dns_bin, NULL)) {
+        g_return_val_if_fail(dns != NULL, FALSE);
+        g_return_val_if_fail(nm_utils_ipaddr_is_valid(addr_family, dns), FALSE);
+        nm_assert_not_reached();
+    }
 
     priv = NM_SETTING_IP_CONFIG_GET_PRIVATE(setting);
 
-    dns_canonical = canonicalize_ip(NM_SETTING_IP_CONFIG_GET_FAMILY(setting), dns, FALSE);
+    nm_utils_inet_ntop(addr_family, &dns_bin, dns_canonical);
+
     for (i = 0; i < priv->dns->len; i++) {
-        if (!strcmp(dns_canonical, priv->dns->pdata[i])) {
+        if (nm_streq(dns_canonical, priv->dns->pdata[i])) {
             g_ptr_array_remove_index(priv->dns, i);
             _notify(setting, PROP_DNS);
-            g_free(dns_canonical);
             return TRUE;
         }
     }
-    g_free(dns_canonical);
     return FALSE;
 }
 
@@ -4951,7 +5001,7 @@ nm_setting_ip_config_clear_routing_rules(NMSettingIPConfig *setting)
 static GVariant *
 _routing_rules_dbus_only_synth(_NM_SETT_INFO_PROP_TO_DBUS_FCN_ARGS _nm_nil)
 {
-    NMSettingIPConfig *       self = NM_SETTING_IP_CONFIG(setting);
+    NMSettingIPConfig        *self = NM_SETTING_IP_CONFIG(setting);
     NMSettingIPConfigPrivate *priv;
     GVariantBuilder           builder;
     gboolean                  any = FALSE;
@@ -4983,7 +5033,7 @@ static gboolean
 _routing_rules_dbus_only_set(_NM_SETT_INFO_PROP_FROM_DBUS_FCN_ARGS _nm_nil)
 {
     GVariantIter iter_rules;
-    GVariant *   rule_var;
+    GVariant    *rule_var;
     guint        i_rule;
     gboolean     success       = FALSE;
     gboolean     rules_changed = FALSE;
@@ -4994,9 +5044,9 @@ _routing_rules_dbus_only_set(_NM_SETT_INFO_PROP_FROM_DBUS_FCN_ARGS _nm_nil)
 
     i_rule = 0;
     while (g_variant_iter_next(&iter_rules, "@a{sv}", &rule_var)) {
-        _nm_unused gs_unref_variant GVariant *rule_var_unref = rule_var;
-        nm_auto_unref_ip_routing_rule NMIPRoutingRule *rule  = NULL;
-        gs_free_error GError *local                          = NULL;
+        _nm_unused gs_unref_variant GVariant          *rule_var_unref = rule_var;
+        nm_auto_unref_ip_routing_rule NMIPRoutingRule *rule           = NULL;
+        gs_free_error GError                          *local          = NULL;
 
         i_rule++;
 
@@ -5322,7 +5372,7 @@ static gboolean
 verify_label(const char *label)
 {
     const char *p;
-    char *      iface;
+    char       *iface;
 
     p = strchr(label, ':');
     if (!p)
@@ -5390,7 +5440,7 @@ verify(NMSetting *setting, NMConnection *connection, GError **error)
     /* Validate addresses */
     for (i = 0; i < priv->addresses->len; i++) {
         NMIPAddress *addr = (NMIPAddress *) priv->addresses->pdata[i];
-        GVariant *   label;
+        GVariant    *label;
 
         if (nm_ip_address_get_family(addr) != NM_SETTING_IP_CONFIG_GET_FAMILY(setting)) {
             g_set_error(error,
@@ -5465,7 +5515,7 @@ verify(NMSetting *setting, NMConnection *connection, GError **error)
     /* Validate routes */
     for (i = 0; i < priv->routes->len; i++) {
         gs_free_error GError *local = NULL;
-        NMIPRoute *           route = (NMIPRoute *) priv->routes->pdata[i];
+        NMIPRoute            *route = (NMIPRoute *) priv->routes->pdata[i];
 
         if (nm_ip_route_get_family(route) != NM_SETTING_IP_CONFIG_GET_FAMILY(setting)) {
             g_set_error(error,
@@ -5496,7 +5546,7 @@ verify(NMSetting *setting, NMConnection *connection, GError **error)
 
     if (priv->routing_rules) {
         for (i = 0; i < priv->routing_rules->len; i++) {
-            NMIPRoutingRule *rule       = priv->routing_rules->pdata[i];
+            NMIPRoutingRule      *rule  = priv->routing_rules->pdata[i];
             gs_free_error GError *local = NULL;
 
             if (_ip_routing_rule_get_addr_family(rule)
@@ -5555,9 +5605,10 @@ verify(NMSetting *setting, NMConnection *connection, GError **error)
         return FALSE;
     }
 
-    if (!_nm_utils_validate_dhcp_hostname_flags(priv->dhcp_hostname_flags,
-                                                NM_SETTING_IP_CONFIG_GET_FAMILY(setting),
-                                                error)) {
+    if (priv->dhcp_hostname_flags != (NMDhcpHostnameFlags) priv->dhcp_hostname_flags
+        || !_nm_utils_validate_dhcp_hostname_flags(priv->dhcp_hostname_flags,
+                                                   NM_SETTING_IP_CONFIG_GET_FAMILY(setting),
+                                                   error)) {
         g_prefix_error(error,
                        "%s.%s: ",
                        nm_setting_get_name(setting),
@@ -5720,14 +5771,14 @@ duplicate_copy_properties(const NMSettInfoSetting *sett_info, NMSetting *src, NM
 
 static void
 enumerate_values(const NMSettInfoProperty *property_info,
-                 NMSetting *               setting,
+                 NMSetting                *setting,
                  NMSettingValueIterFn      func,
                  gpointer                  user_data)
 {
     if (nm_streq(property_info->name, NM_SETTING_IP_CONFIG_ROUTING_RULES)) {
-        NMSettingIPConfigPrivate *  priv  = NM_SETTING_IP_CONFIG_GET_PRIVATE(setting);
+        NMSettingIPConfigPrivate   *priv  = NM_SETTING_IP_CONFIG_GET_PRIVATE(setting);
         nm_auto_unset_gvalue GValue value = G_VALUE_INIT;
-        GPtrArray *                 ptr   = NULL;
+        GPtrArray                  *ptr   = NULL;
         guint                       i;
 
         if (priv->routing_rules && priv->routing_rules->len > 0) {
@@ -5788,7 +5839,8 @@ _nm_sett_info_property_override_create_array_ip_config(int addr_family)
             .to_dbus_fcn   = _nm_setting_property_to_dbus_fcn_direct,
             .from_dbus_fcn = _nm_setting_property_from_dbus_fcn_direct_ip_config_gateway),
         .direct_offset = NM_STRUCT_OFFSET_ENSURE_TYPE(char *, NMSettingIPConfigPrivate, gateway),
-        .direct_set_string_ip_address_addr_family = addr_family);
+        .direct_set_string_ip_address_addr_family                  = addr_family + 1,
+        .direct_set_string_ip_address_addr_family_map_zero_to_null = TRUE);
 
     _nm_properties_override_gobj(
         properties_override,
@@ -5826,6 +5878,20 @@ _nm_sett_info_property_override_create_array_ip_config(int addr_family)
 
     _nm_properties_override_gobj(
         properties_override,
+        obj_properties[PROP_ROUTE_TABLE],
+        &nm_sett_info_propert_type_direct_uint32,
+        .direct_offset =
+            NM_STRUCT_OFFSET_ENSURE_TYPE(guint32, NMSettingIPConfigPrivate, route_table));
+
+    _nm_properties_override_gobj(
+        properties_override,
+        obj_properties[PROP_ROUTE_METRIC],
+        &nm_sett_info_propert_type_direct_int64,
+        .direct_offset =
+            NM_STRUCT_OFFSET_ENSURE_TYPE(gint64, NMSettingIPConfigPrivate, route_metric));
+
+    _nm_properties_override_gobj(
+        properties_override,
         obj_properties[PROP_IGNORE_AUTO_DNS],
         &nm_sett_info_propert_type_direct_boolean,
         .direct_offset =
@@ -5833,6 +5899,34 @@ _nm_sett_info_property_override_create_array_ip_config(int addr_family)
 
     _nm_properties_override_gobj(
         properties_override,
+        obj_properties[PROP_DNS_PRIORITY],
+        &nm_sett_info_propert_type_direct_int32,
+        .direct_offset =
+            NM_STRUCT_OFFSET_ENSURE_TYPE(gint32, NMSettingIPConfigPrivate, dns_priority));
+
+    _nm_properties_override_gobj(
+        properties_override,
+        obj_properties[PROP_DHCP_TIMEOUT],
+        &nm_sett_info_propert_type_direct_int32,
+        .direct_offset =
+            NM_STRUCT_OFFSET_ENSURE_TYPE(gint32, NMSettingIPConfigPrivate, dhcp_timeout));
+
+    _nm_properties_override_gobj(
+        properties_override,
+        obj_properties[PROP_REQUIRED_TIMEOUT],
+        &nm_sett_info_propert_type_direct_int32,
+        .direct_offset =
+            NM_STRUCT_OFFSET_ENSURE_TYPE(gint32, NMSettingIPConfigPrivate, required_timeout));
+
+    _nm_properties_override_gobj(
+        properties_override,
+        obj_properties[PROP_DAD_TIMEOUT],
+        &nm_sett_info_propert_type_direct_int32,
+        .direct_offset =
+            NM_STRUCT_OFFSET_ENSURE_TYPE(gint32, NMSettingIPConfigPrivate, dad_timeout));
+
+    _nm_properties_override_gobj(
+        properties_override,
         obj_properties[PROP_DHCP_SEND_HOSTNAME],
         &nm_sett_info_propert_type_direct_boolean,
         .direct_offset =
@@ -5840,6 +5934,13 @@ _nm_sett_info_property_override_create_array_ip_config(int addr_family)
 
     _nm_properties_override_gobj(
         properties_override,
+        obj_properties[PROP_DHCP_HOSTNAME_FLAGS],
+        &nm_sett_info_propert_type_direct_uint32,
+        .direct_offset =
+            NM_STRUCT_OFFSET_ENSURE_TYPE(guint32, NMSettingIPConfigPrivate, dhcp_hostname_flags));
+
+    _nm_properties_override_gobj(
+        properties_override,
         obj_properties[PROP_NEVER_DEFAULT],
         &nm_sett_info_propert_type_direct_boolean,
         .direct_offset =
@@ -5859,13 +5960,10 @@ _nm_sett_info_property_override_create_array_ip_config(int addr_family)
 static void
 get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
 {
-    NMSettingIPConfig *       setting = NM_SETTING_IP_CONFIG(object);
+    NMSettingIPConfig        *setting = NM_SETTING_IP_CONFIG(object);
     NMSettingIPConfigPrivate *priv    = NM_SETTING_IP_CONFIG_GET_PRIVATE(setting);
 
     switch (prop_id) {
-    case PROP_METHOD:
-        g_value_set_string(value, nm_setting_ip_config_get_method(setting));
-        break;
     case PROP_DNS:
         g_value_take_boxed(value, _nm_utils_ptrarray_to_strv(priv->dns));
         break;
@@ -5877,68 +5975,23 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
                            priv->dns_options ? _nm_utils_ptrarray_to_strv(priv->dns_options)
                                              : NULL);
         break;
-    case PROP_DNS_PRIORITY:
-        g_value_set_int(value, priv->dns_priority);
-        break;
     case PROP_ADDRESSES:
         g_value_take_boxed(value,
                            _nm_utils_copy_array(priv->addresses,
                                                 (NMUtilsCopyFunc) nm_ip_address_dup,
                                                 (GDestroyNotify) nm_ip_address_unref));
         break;
-    case PROP_GATEWAY:
-        g_value_set_string(value, nm_setting_ip_config_get_gateway(setting));
-        break;
     case PROP_ROUTES:
         g_value_take_boxed(value,
                            _nm_utils_copy_array(priv->routes,
                                                 (NMUtilsCopyFunc) nm_ip_route_dup,
                                                 (GDestroyNotify) nm_ip_route_unref));
         break;
-    case PROP_ROUTE_METRIC:
-        g_value_set_int64(value, priv->route_metric);
-        break;
-    case PROP_ROUTE_TABLE:
-        g_value_set_uint(value, priv->route_table);
-        break;
-    case PROP_IGNORE_AUTO_ROUTES:
-        g_value_set_boolean(value, nm_setting_ip_config_get_ignore_auto_routes(setting));
-        break;
-    case PROP_IGNORE_AUTO_DNS:
-        g_value_set_boolean(value, nm_setting_ip_config_get_ignore_auto_dns(setting));
-        break;
-    case PROP_DHCP_HOSTNAME:
-        g_value_set_string(value, nm_setting_ip_config_get_dhcp_hostname(setting));
-        break;
-    case PROP_DHCP_SEND_HOSTNAME:
-        g_value_set_boolean(value, nm_setting_ip_config_get_dhcp_send_hostname(setting));
-        break;
-    case PROP_NEVER_DEFAULT:
-        g_value_set_boolean(value, priv->never_default);
-        break;
-    case PROP_MAY_FAIL:
-        g_value_set_boolean(value, priv->may_fail);
-        break;
-    case PROP_DAD_TIMEOUT:
-        g_value_set_int(value, nm_setting_ip_config_get_dad_timeout(setting));
-        break;
-    case PROP_DHCP_TIMEOUT:
-        g_value_set_int(value, nm_setting_ip_config_get_dhcp_timeout(setting));
-        break;
-    case PROP_REQUIRED_TIMEOUT:
-        g_value_set_int(value, nm_setting_ip_config_get_required_timeout(setting));
-        break;
-    case PROP_DHCP_IAID:
-        g_value_set_string(value, nm_setting_ip_config_get_dhcp_iaid(setting));
-        break;
-    case PROP_DHCP_HOSTNAME_FLAGS:
-        g_value_set_uint(value, nm_setting_ip_config_get_dhcp_hostname_flags(setting));
-        break;
     case PROP_DHCP_REJECT_SERVERS:
         g_value_set_boxed(value, nm_strvarray_get_strv_non_empty(priv->dhcp_reject_servers, NULL));
         break;
     default:
-        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+        _nm_setting_property_get_property_direct(object, prop_id, value, pspec);
         break;
     }
 }
@@ -5946,16 +5999,12 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
 static void
 set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
 {
-    NMSettingIPConfig *       setting = NM_SETTING_IP_CONFIG(object);
+    NMSettingIPConfig        *setting = NM_SETTING_IP_CONFIG(object);
     NMSettingIPConfigPrivate *priv    = NM_SETTING_IP_CONFIG_GET_PRIVATE(setting);
-    char **                   strv;
+    char                    **strv;
     guint                     i;
 
     switch (prop_id) {
-    case PROP_METHOD:
-        g_free(priv->method);
-        priv->method = g_value_dup_string(value);
-        break;
     case PROP_DNS:
         g_ptr_array_unref(priv->dns);
         priv->dns = nm_strv_to_ptrarray(g_value_get_boxed(value));
@@ -5983,73 +6032,23 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps
             }
         }
         break;
-    case PROP_DNS_PRIORITY:
-        priv->dns_priority = g_value_get_int(value);
-        break;
     case PROP_ADDRESSES:
         g_ptr_array_unref(priv->addresses);
         priv->addresses = _nm_utils_copy_array(g_value_get_boxed(value),
                                                (NMUtilsCopyFunc) nm_ip_address_dup,
                                                (GDestroyNotify) nm_ip_address_unref);
         break;
-    case PROP_GATEWAY:
-        g_free(priv->gateway);
-        priv->gateway =
-            _nm_utils_ipaddr_canonical_or_invalid(NM_SETTING_IP_CONFIG_GET_FAMILY(setting),
-                                                  g_value_get_string(value));
-        break;
     case PROP_ROUTES:
         g_ptr_array_unref(priv->routes);
         priv->routes = _nm_utils_copy_array(g_value_get_boxed(value),
                                             (NMUtilsCopyFunc) nm_ip_route_dup,
                                             (GDestroyNotify) nm_ip_route_unref);
         break;
-    case PROP_ROUTE_METRIC:
-        priv->route_metric = g_value_get_int64(value);
-        break;
-    case PROP_ROUTE_TABLE:
-        priv->route_table = g_value_get_uint(value);
-        break;
-    case PROP_IGNORE_AUTO_ROUTES:
-        priv->ignore_auto_routes = g_value_get_boolean(value);
-        break;
-    case PROP_IGNORE_AUTO_DNS:
-        priv->ignore_auto_dns = g_value_get_boolean(value);
-        break;
-    case PROP_DHCP_HOSTNAME:
-        g_free(priv->dhcp_hostname);
-        priv->dhcp_hostname = g_value_dup_string(value);
-        break;
-    case PROP_DHCP_SEND_HOSTNAME:
-        priv->dhcp_send_hostname = g_value_get_boolean(value);
-        break;
-    case PROP_NEVER_DEFAULT:
-        priv->never_default = g_value_get_boolean(value);
-        break;
-    case PROP_MAY_FAIL:
-        priv->may_fail = g_value_get_boolean(value);
-        break;
-    case PROP_DAD_TIMEOUT:
-        priv->dad_timeout = g_value_get_int(value);
-        break;
-    case PROP_DHCP_TIMEOUT:
-        priv->dhcp_timeout = g_value_get_int(value);
-        break;
-    case PROP_REQUIRED_TIMEOUT:
-        priv->required_timeout = g_value_get_int(value);
-        break;
-    case PROP_DHCP_IAID:
-        g_free(priv->dhcp_iaid);
-        priv->dhcp_iaid = g_value_dup_string(value);
-        break;
-    case PROP_DHCP_HOSTNAME_FLAGS:
-        priv->dhcp_hostname_flags = g_value_get_uint(value);
-        break;
     case PROP_DHCP_REJECT_SERVERS:
         nm_strvarray_set_strv(&priv->dhcp_reject_servers, g_value_get_boxed(value));
         break;
     default:
-        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+        _nm_setting_property_set_property_direct(object, prop_id, value, pspec);
         break;
     }
 }
@@ -6061,13 +6060,10 @@ _nm_setting_ip_config_private_init(gpointer self, NMSettingIPConfigPrivate *priv
 {
     nm_assert(NM_IS_SETTING_IP_CONFIG(self));
 
-    priv->dns              = g_ptr_array_new_with_free_func(g_free);
-    priv->dns_search       = g_ptr_array_new_with_free_func(g_free);
-    priv->addresses        = g_ptr_array_new_with_free_func((GDestroyNotify) nm_ip_address_unref);
-    priv->routes           = g_ptr_array_new_with_free_func((GDestroyNotify) nm_ip_route_unref);
-    priv->route_metric     = -1;
-    priv->dad_timeout      = -1;
-    priv->required_timeout = -1;
+    priv->dns        = g_ptr_array_new_with_free_func(g_free);
+    priv->dns_search = g_ptr_array_new_with_free_func(g_free);
+    priv->addresses  = g_ptr_array_new_with_free_func((GDestroyNotify) nm_ip_address_unref);
+    priv->routes     = g_ptr_array_new_with_free_func((GDestroyNotify) nm_ip_route_unref);
 }
 
 static void
@@ -6079,18 +6075,16 @@ nm_setting_ip_config_init(NMSettingIPConfig *setting)
 static void
 finalize(GObject *object)
 {
-    NMSettingIPConfig *       self = NM_SETTING_IP_CONFIG(object);
+    NMSettingIPConfig        *self = NM_SETTING_IP_CONFIG(object);
     NMSettingIPConfigPrivate *priv = NM_SETTING_IP_CONFIG_GET_PRIVATE(self);
 
     g_ptr_array_unref(priv->dns);
     g_ptr_array_unref(priv->dns_search);
-    if (priv->dns_options)
-        g_ptr_array_unref(priv->dns_options);
+    nm_g_ptr_array_unref(priv->dns_options);
     g_ptr_array_unref(priv->addresses);
     g_ptr_array_unref(priv->routes);
-    if (priv->routing_rules)
-        g_ptr_array_unref(priv->routing_rules);
-    nm_clear_pointer(&priv->dhcp_reject_servers, g_array_unref);
+    nm_g_ptr_array_unref(priv->routing_rules);
+    nm_g_array_unref(priv->dhcp_reject_servers);
 
     G_OBJECT_CLASS(nm_setting_ip_config_parent_class)->finalize(object);
 }
@@ -6098,7 +6092,7 @@ finalize(GObject *object)
 static void
 nm_setting_ip_config_class_init(NMSettingIPConfigClass *klass)
 {
-    GObjectClass *  object_class  = G_OBJECT_CLASS(klass);
+    GObjectClass   *object_class  = G_OBJECT_CLASS(klass);
     NMSettingClass *setting_class = NM_SETTING_CLASS(klass);
 
     object_class->get_property = get_property;