diff options
author | Jiří Klimeš <jklimes@redhat.com> | 2014-06-10 16:50:57 +0200 |
---|---|---|
committer | Jiří Klimeš <jklimes@redhat.com> | 2014-06-11 09:58:39 +0200 |
commit | 700f5ec0ef584b17b44cc0e1968712d97ba95263 (patch) | |
tree | 0205ad09269f0452174f6da15e1e1de4657b26e9 | |
parent | e8fb3864d1d29f137b4eef42dee8c1214f474a0f (diff) | |
download | NetworkManager-700f5ec0ef584b17b44cc0e1968712d97ba95263.tar.gz |
cli: allow missing next hop for routes (bgo #727615)
https://bugzilla.gnome.org/show_bug.cgi?id=727615
-rw-r--r-- | cli/src/common.c | 220 | ||||
-rw-r--r-- | cli/src/common.h | 4 | ||||
-rw-r--r-- | cli/src/settings.c | 44 |
3 files changed, 163 insertions, 105 deletions
diff --git a/cli/src/common.c b/cli/src/common.c index 939a00ea5e..9635011cd7 100644 --- a/cli/src/common.c +++ b/cli/src/common.c @@ -487,131 +487,181 @@ finish: return addr; } +typedef struct { + long int prefix; + long int metric; + union _IpDest { + guint32 ip4_dst; + struct in6_addr ip6_dst; + } dst; + union _IpNextHop { + guint32 ip4_nh; + struct in6_addr ip6_nh; + } nh; +} ParsedRoute; + /* - * Parse IPv4 routes from strings to NMIP4Route stucture. - * ip_str is the IPv4 route in the form of address/prefix - * next_hop_str is the next_hop address - * metric_str is the route metric + * _parse_and_build_route: + * @family: AF_INET or AF_INET6 + * @first: the route destination in the form of "address/prefix" + (/prefix is optional) + * @second: (allow-none): next hop address, if third is not NULL. Otherwise it could be + either next hop address or metric. (It can be NULL when @third is NULL). + * @third: (allow-none): route metric + * @out: (out): route struct to fill + * @error: location to store GError + * + * Parse route from strings and fill @out parameter. + * + * Returns: %TRUE on success, %FALSE on failure */ -NMIP4Route * -nmc_parse_and_build_ip4_route (const char *ip_str, const char *next_hop_str, const char *metric_str, GError **error) +static gboolean +_parse_and_build_route (int family, + const char *first, + const char *second, + const char *third, + ParsedRoute *out, + GError **error) { - NMIP4Route *route = NULL; - guint32 ip4_addr, next_hop_addr; - char *tmp; - char *plen; - long int prefix, metric; - - g_return_val_if_fail (ip_str != NULL, NULL); - g_return_val_if_fail (next_hop_str != NULL, NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); + int max_prefix; + char *tmp, *plen; + gboolean success = FALSE; + + g_return_val_if_fail (family == AF_INET || family == AF_INET6, FALSE); + g_return_val_if_fail (first != NULL, FALSE); + g_return_val_if_fail (second || !third, FALSE); + g_return_val_if_fail (out, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + max_prefix = (family == AF_INET) ? 32 : 128; + /* initialize default values */ + out->prefix = max_prefix; + out->metric = 0; + if (family == AF_INET) + out->nh.ip4_nh = 0; + else + out->nh.ip6_nh = in6addr_any; - tmp = g_strdup (ip_str); + tmp = g_strdup (first); plen = strchr (tmp, '/'); /* prefix delimiter */ if (plen) *plen++ = '\0'; - if (inet_pton (AF_INET, tmp, &ip4_addr) < 1) { + if (inet_pton (family, tmp, family == AF_INET ? (void *) &out->dst.ip4_dst : (void *) &out->dst.ip6_dst) < 1) { g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, - _("invalid IPv4 route '%s'"), tmp); + _("invalid route destination address '%s'"), tmp); goto finish; } - prefix = 32; if (plen) { - if (!nmc_string_to_int (plen, TRUE, 0, 32, &prefix)) { + if (!nmc_string_to_int (plen, TRUE, 0, max_prefix, &out->prefix)) { g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, - _("invalid prefix '%s'; <0-32> allowed"), plen); + _("invalid prefix '%s'; <0-%d> allowed"), + plen, max_prefix); goto finish; } } - if (inet_pton (AF_INET, next_hop_str, &next_hop_addr) < 1) { - g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, - _("invalid next hop address '%s'"), next_hop_str); - goto finish; + if (second) { + if (inet_pton (family, second, family == AF_INET ? (void *) &out->nh.ip4_nh : (void *) &out->nh.ip6_nh) < 1) { + if (third) { + g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, + _("invalid next hop address '%s'"), second); + goto finish; + } else { + /* 'second' can be a metric */ + if (!nmc_string_to_int (second, TRUE, 0, G_MAXUINT32, &out->metric)) { + g_set_error (error, 1, 0, _("the second component of route ('%s') is neither " + "a next hop address nor a metric"), second); + goto finish; + } + } + } } - metric = 0; - if (metric_str) { - if (!nmc_string_to_int (metric_str, TRUE, 0, G_MAXUINT32, &metric)) { - g_set_error (error, 1, 0, _("invalid metric '%s'"), metric_str); + if (third) { + if (!nmc_string_to_int (third, TRUE, 0, G_MAXUINT32, &out->metric)) { + g_set_error (error, 1, 0, _("invalid metric '%s'"), third); goto finish; } } - route = nm_ip4_route_new (); - nm_ip4_route_set_dest (route, ip4_addr); - nm_ip4_route_set_prefix (route, (guint32) prefix); - nm_ip4_route_set_next_hop (route, next_hop_addr); - nm_ip4_route_set_metric (route, (guint32) metric); + success = TRUE; finish: g_free (tmp); - return route; + return success; } /* - * Parse IPv6 route from strings to NMIP6Route stucture. - * ip_str is the IPv6 route in the form address/prefix - * next_hop_str is the next hop - * metric_str is the route metric + * nmc_parse_and_build_ip4_route: + * @first: the IPv4 route destination in the form of "address/prefix" + (/prefix is optional) + * @second: (allow-none): next hop address, if third is not NULL. Otherwise it could be + either next hop address or metric. (It can be NULL when @third is NULL). + * @third: (allow-none): route metric + * @error: location to store GError + * + * Parse IPv4 route from strings to NMIP4Route stucture. + * + * Returns: route as a NMIP4Route object, or %NULL on failure */ -NMIP6Route * -nmc_parse_and_build_ip6_route (const char *ip_str, const char *next_hop_str, const char *metric_str, GError **error) +NMIP4Route * +nmc_parse_and_build_ip4_route (const char *first, + const char *second, + const char *third, + GError **error) { - NMIP6Route *route = NULL; - struct in6_addr ip_addr, next_hop_addr; - char *tmp; - char *plen; - long int prefix, metric; + ParsedRoute tmp_route; + NMIP4Route *route = NULL; - g_return_val_if_fail (ip_str != NULL, NULL); + g_return_val_if_fail (first != NULL, NULL); + g_return_val_if_fail (second || !third, NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); - tmp = g_strdup (ip_str); - plen = strchr (tmp, '/'); /* prefix delimiter */ - if (plen) - *plen++ = '\0'; - - if (inet_pton (AF_INET6, tmp, &ip_addr) < 1) { - g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, - _("invalid IPv6 route '%s'"), tmp); - goto finish; + if (_parse_and_build_route (AF_INET, first, second, third, &tmp_route, error)) { + route = nm_ip4_route_new (); + nm_ip4_route_set_dest (route, tmp_route.dst.ip4_dst); + nm_ip4_route_set_prefix (route, (guint32) tmp_route.prefix); + nm_ip4_route_set_next_hop (route, tmp_route.nh.ip4_nh); + nm_ip4_route_set_metric (route, (guint32) tmp_route.metric); } + return route; +} - prefix = 128; - if (plen) { - if (!nmc_string_to_int (plen, TRUE, 0, 128, &prefix)) { - g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, - _("invalid prefix '%s'; <0-128> allowed"), plen); - goto finish; - } - } +/* + * nmc_parse_and_build_ip6_route: + * @first: the IPv6 route destination in the form of "address/prefix" + (/prefix is optional) + * @second: (allow-none): next hop address, if third is not NULL. Otherwise it could be + either next hop address or metric. (It can be NULL when @third is NULL). + * @third: (allow-none): route metric + * @error: location to store GError + * + * Parse IPv6 route from strings to NMIP6Route stucture. + * + * Returns: route as a NMIP6Route object, or %NULL on failure + */ +NMIP6Route * +nmc_parse_and_build_ip6_route (const char *first, + const char *second, + const char *third, + GError **error) +{ + ParsedRoute tmp_route; + NMIP6Route *route = NULL; - if (inet_pton (AF_INET6, next_hop_str, &next_hop_addr) < 1) { - g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, - _("invalid next hop address '%s'"), next_hop_str); - goto finish; - } + g_return_val_if_fail (first != NULL, NULL); + g_return_val_if_fail (second || !third, NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); - metric = 0; - if (metric_str) { - if (!nmc_string_to_int (metric_str, TRUE, 0, G_MAXUINT32, &metric)) { - g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, - _("invalid metric '%s'"), metric_str); - goto finish; - } + if (_parse_and_build_route (AF_INET6, first, second, third, &tmp_route, error)) { + route = nm_ip6_route_new (); + nm_ip6_route_set_dest (route, &tmp_route.dst.ip6_dst); + nm_ip6_route_set_prefix (route, (guint32) tmp_route.prefix); + nm_ip6_route_set_next_hop (route, &tmp_route.nh.ip6_nh); + nm_ip6_route_set_metric (route, (guint32) tmp_route.metric); } - - route = nm_ip6_route_new (); - nm_ip6_route_set_dest (route, &ip_addr); - nm_ip6_route_set_prefix (route, (guint32) prefix); - nm_ip6_route_set_next_hop (route, &next_hop_addr); - nm_ip6_route_set_metric (route, (guint32) metric); - -finish: - g_free (tmp); return route; } diff --git a/cli/src/common.h b/cli/src/common.h index 31f4ab3f34..228375b97e 100644 --- a/cli/src/common.h +++ b/cli/src/common.h @@ -40,8 +40,8 @@ gboolean print_dhcp6_config (NMDHCP6Config *dhcp6, NmCli *nmc, const char *group NMIP4Address *nmc_parse_and_build_ip4_address (const char *ip_str, const char *gw_str, GError **error); NMIP6Address *nmc_parse_and_build_ip6_address (const char *ip_str, const char *gw_str, GError **error); -NMIP4Route *nmc_parse_and_build_ip4_route (const char *ip_str, const char *next_hop_str, const char *metric_str, GError **error); -NMIP6Route *nmc_parse_and_build_ip6_route (const char *ip_str, const char *next_hop_str, const char *metric_str, GError **error); +NMIP4Route *nmc_parse_and_build_ip4_route (const char *first, const char *second, const char *third, GError **error); +NMIP6Route *nmc_parse_and_build_ip6_route (const char *first, const char *second, const char *third, GError **error); const char * nmc_device_state_to_string (NMDeviceState state); const char * nmc_device_reason_to_string (NMDeviceStateReason reason); diff --git a/cli/src/settings.c b/cli/src/settings.c index b0c1ecad99..d4f34eaf39 100644 --- a/cli/src/settings.c +++ b/cli/src/settings.c @@ -3218,17 +3218,19 @@ _parse_ipv4_route (const char *route, GError **error) { char *value = g_strdup (route); char **routev; - NMIP4Route *ip4route; + guint len; + NMIP4Route *ip4route = NULL; routev = nmc_strsplit_set (g_strstrip (value), " \t", 0); - if (g_strv_length (routev) < 2 || g_strv_length (routev) > 3) { - g_set_error (error, 1, 0, _("'%s' is not valid (use ip/[prefix] next-hop [metric])"), + len = g_strv_length (routev); + if (len < 1 || len > 3) { + g_set_error (error, 1, 0, _("'%s' is not valid (the format is: ip[/prefix] [next-hop] [metric])"), route); - g_free (value); - g_strfreev (routev); - return NULL; + goto finish; } - ip4route = nmc_parse_and_build_ip4_route (routev[0], routev[1], routev[2], error); + ip4route = nmc_parse_and_build_ip4_route (routev[0], routev[1], len >= 2 ? routev[2] : NULL, error); + +finish: g_free (value); g_strfreev (routev); return ip4route; @@ -3284,10 +3286,12 @@ static const char * nmc_property_ipv4_describe_routes (NMSetting *setting, const char *prop) { return _("Enter a list of IPv4 routes formatted as:\n" - " ip/[prefix] next-hop [metric],...\n" + " ip[/prefix] [next-hop] [metric],...\n\n" "Missing prefix is regarded as a prefix of 32.\n" + "Missing next-hop is regarded as 0.0.0.0.\n" "Missing metric is regarded as a metric of 0.\n\n" - "Example: 192.168.2.0/24 192.168.2.1 3, 10.1.0.0/16 10.0.0.254\n"); + "Examples: 192.168.2.0/24 192.168.2.1 3, 10.1.0.0/16 10.0.0.254\n" + " 10.1.2.0/24\n"); } static char * @@ -3529,17 +3533,19 @@ _parse_ipv6_route (const char *route, GError **error) { char *value = g_strdup (route); char **routev; - NMIP6Route *ip6route; + guint len; + NMIP6Route *ip6route = NULL; routev = nmc_strsplit_set (g_strstrip (value), " \t", 0); - if (g_strv_length (routev) < 2 || g_strv_length (routev) > 3) { - g_set_error (error, 1, 0, _("'%s' is not valid (use <dest IP>/prefix <next-hop IP> [metric])"), + len = g_strv_length (routev); + if (len < 1 || len > 3) { + g_set_error (error, 1, 0, _("'%s' is not valid (the format is: ip[/prefix] [next-hop] [metric])"), route); - g_free (value); - g_strfreev (routev); - return NULL; + goto finish; } - ip6route = nmc_parse_and_build_ip6_route (routev[0], routev[1], routev[2], error); + ip6route = nmc_parse_and_build_ip6_route (routev[0], routev[1], len >= 2 ? routev[2] : NULL, error); + +finish: g_free (value); g_strfreev (routev); return ip6route; @@ -3595,10 +3601,12 @@ static const char * nmc_property_ipv6_describe_routes (NMSetting *setting, const char *prop) { return _("Enter a list of IPv6 routes formatted as:\n" - " ip/[prefix] next-hop [metric],...\n" + " ip[/prefix] [next-hop] [metric],...\n\n" "Missing prefix is regarded as a prefix of 128.\n" + "Missing next-hop is regarded as \"::\".\n" "Missing metric is regarded as a metric of 0.\n\n" - "Example: 2001:db8:beef:2::/64 2001:db8:beef::2, 2001:db8:beef:3::/64 2001:db8:beef::3 2\n"); + "Examples: 2001:db8:beef:2::/64 2001:db8:beef::2, 2001:db8:beef:3::/64 2001:db8:beef::3 2\n" + " abbe::/64 55\n"); } static gboolean |