mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-01-04 22:40:16 +01:00
cli: allow missing next hop for routes (bgo #727615)
https://bugzilla.gnome.org/show_bug.cgi?id=727615
This commit is contained in:
parent
e8fb3864d1
commit
700f5ec0ef
3 changed files with 162 additions and 104 deletions
218
cli/src/common.c
218
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;
|
||||
int max_prefix;
|
||||
char *tmp, *plen;
|
||||
gboolean success = FALSE;
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
tmp = g_strdup (ip_str);
|
||||
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 (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 success;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
NMIP4Route *
|
||||
nmc_parse_and_build_ip4_route (const char *first,
|
||||
const char *second,
|
||||
const char *third,
|
||||
GError **error)
|
||||
{
|
||||
ParsedRoute tmp_route;
|
||||
NMIP4Route *route = 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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
* ip_str is the IPv6 route in the form address/prefix
|
||||
* next_hop_str is the next hop
|
||||
* metric_str is the route metric
|
||||
*
|
||||
* Returns: route as a NMIP6Route 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)
|
||||
nmc_parse_and_build_ip6_route (const char *first,
|
||||
const char *second,
|
||||
const char *third,
|
||||
GError **error)
|
||||
{
|
||||
ParsedRoute tmp_route;
|
||||
NMIP6Route *route = NULL;
|
||||
struct in6_addr ip_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 (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_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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue