From: Yu Watanabe Date: Fri, 9 Aug 2024 05:41:07 +0000 (+0900) Subject: network-generator: use extract_first_word() X-Git-Tag: v257-rc1~707^2~2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=b3b4d626ce9ff763496ebe56bead92395754a708;p=thirdparty%2Fsystemd.git network-generator: use extract_first_word() Now, ip= with trailing colon is refused. --- diff --git a/src/network/generator/network-generator.c b/src/network/generator/network-generator.c index e4a9a22f404..a8c81c6d113 100644 --- a/src/network/generator/network-generator.c +++ b/src/network/generator/network-generator.c @@ -443,6 +443,12 @@ static int network_set_hostname(Context *context, const char *ifname, const char assert(context); assert(ifname); + if (isempty(hostname)) + return 0; + + if (!hostname_is_valid(hostname, 0)) + return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid hostname '%s'.", hostname); + r = network_acquire(context, ifname, &network); if (r < 0) return log_debug_errno(r, "Failed to acquire network for '%s': %m", ifname); @@ -477,7 +483,9 @@ static int network_set_mac_address(Context *context, const char *ifname, const c assert(context); assert(ifname); - assert(mac); + + if (isempty(mac)) + return 0; r = network_acquire(context, ifname, &network); if (r < 0) @@ -542,20 +550,17 @@ static int network_set_route( return route_new(network, family, prefixlen, dest, gateway, NULL); } -static int network_set_dns(Context *context, const char *ifname, int family, const char *dns) { - union in_addr_union a; +static int network_set_dns(Context *context, const char *ifname, const char *dns) { Network *network; int r; assert(context); assert(ifname); - assert(IN_SET(family, AF_UNSPEC, AF_INET, AF_INET6)); - assert(dns); - if (family == AF_UNSPEC) - r = in_addr_from_string_auto(dns, &family, &a); - else - r = in_addr_from_string(family, dns, &a); + if (isempty(dns)) + return 0; + + r = in_addr_from_string_auto(dns, NULL, NULL); if (r < 0) return log_debug_errno(r, "Invalid DNS address '%s' for '%s'", dns, ifname); @@ -631,158 +636,132 @@ static int network_set_bond(Context *context, const char *ifname, const char *va } static int parse_cmdline_ip_mtu_mac(Context *context, const char *ifname, const char *value) { - const char *mtu, *p; + _cleanup_free_ char *mtu = NULL; int r; assert(context); assert(ifname); - assert(value); /* [][:] */ - p = strchr(value, ':'); - if (!p) - mtu = value; - else - mtu = strndupa_safe(value, p - value); - - r = network_set_mtu(context, ifname, mtu); - if (r < 0) + const char *p = value; + r = extract_first_word(&p, &mtu, ":", EXTRACT_DONT_COALESCE_SEPARATORS); + if (r <= 0) return r; - if (!p || isempty(p + 1)) - return 0; - - r = network_set_mac_address(context, ifname, p + 1); + r = network_set_mtu(context, ifname, mtu); if (r < 0) return r; - return 0; + return network_set_mac_address(context, ifname, p); } -static int parse_ip_address_one(int family, const char **value, union in_addr_union *ret) { - const char *p, *q, *buf; +static int extract_ip_address_str(int family, const char **ptr, char **ret) { + _cleanup_free_ char *buf = NULL; + const char *p; int r; - assert(IN_SET(family, AF_INET, AF_INET6)); - assert(value); + assert(IN_SET(family, AF_UNSPEC, AF_INET, AF_INET6)); + assert(ptr); assert(ret); - p = ASSERT_PTR(*value); - - if (p[0] == ':') { - *value = p + 1; + if (isempty(*ptr)) { + *ptr = NULL; + *ret = NULL; return 0; } - if (family == AF_INET6) { - if (p[0] != '[') - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid IPv6 address '%s'", p); - - q = strchr(p + 1, ']'); - if (!q) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid IPv6 address '%s'", p); + if (**ptr != '[') + return extract_first_word(ptr, ret, ":", EXTRACT_DONT_COALESCE_SEPARATORS); - if (q[1] != ':') - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid IPv6 address '%s'", p); + if (family == AF_INET) + return -EINVAL; - buf = strndupa_safe(p + 1, q - p - 1); - p = q + 2; - } else { - q = strchr(p, ':'); - if (!q) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid IPv4 address '%s'", p); + p = *ptr + 1; + r = extract_first_word(&p, &buf, "]", EXTRACT_DONT_COALESCE_SEPARATORS); + if (r < 0) + return r; + if (r == 0) + return -EINVAL; /* Missing "]". */ - buf = strndupa_safe(p, q - p); - p = q + 1; + if (!isempty(p)) { + if (p[0] != ':') + return -EINVAL; /* Missing ":" after "]". */ + p++; } - r = in_addr_from_string(family, buf, ret); - if (r < 0) - return log_debug_errno(r, "Invalid IP address '%s': %m", buf); - - *value = p; + *ptr = p; + *ret = TAKE_PTR(buf); return 1; } -static int parse_netmask_or_prefixlen(int family, const char **value, unsigned char *ret) { - union in_addr_union netmask; - const char *p, *q; - int r; +static int extract_ip_address(int family, const char **ptr, union in_addr_union *ret) { + _cleanup_free_ char *buf = NULL; + const char *p; + int r, k; assert(IN_SET(family, AF_INET, AF_INET6)); - assert(value); - assert(*value); + assert(ptr); assert(ret); - r = parse_ip_address_one(family, value, &netmask); - if (r > 0) { - if (family == AF_INET6) - /* TODO: Not supported yet. */ - return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "IPv6 prefix length is not supported yet"); - - *ret = in4_addr_netmask_to_prefixlen(&netmask.in); - } else if (r == 0) - *ret = family == AF_INET6 ? 128 : 32; - else { - p = strchr(*value, ':'); - if (!p) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid netmask or prefix length '%s'", *value); - - q = strndupa_safe(*value, p - *value); - r = safe_atou8(q, ret); - if (r < 0) - return log_debug_errno(r, "Invalid netmask or prefix length '%s': %m", q); + p = *ptr; + r = extract_ip_address_str(family, &p, &buf); + if (r < 0) + return r; - *value = p + 1; + if (isempty(buf)) { + *ret = IN_ADDR_NULL; + r = 0; + } else { + assert(r > 0); + k = in_addr_from_string(family, buf, ret); + if (k < 0) + return k; } - return 0; + *ptr = p; + return r; } -static int parse_ip_dns_address_one(Context *context, const char *ifname, const char **value) { - const char *p, *q, *buf; - int r, family; - - assert(context); - assert(ifname); - assert(value); - - p = ASSERT_PTR(*value); +static int extract_netmask_or_prefixlen(int family, const char **ptr, unsigned char *ret) { + _cleanup_free_ char *buf = NULL; + const char *p; + int r; - if (isempty(p)) - return 0; + assert(IN_SET(family, AF_INET, AF_INET6)); + assert(ptr); + assert(ret); - if (p[0] == '[') { - q = strchr(p + 1, ']'); - if (!q || !IN_SET(q[1], ':', '\0')) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid IP DNS address '%s'", p); + if (family == AF_INET) { + union in_addr_union netmask; - buf = strndupa_safe(p + 1, q - p - 1); - p = q + 1; - family = AF_INET6; - } else { - q = strchr(p, ':'); - if (!q) - buf = *value; - else - buf = strndupa_safe(*value, q - *value); - - p += strlen(buf); - family = AF_INET; + p = *ptr; + r = extract_ip_address(family, &p, &netmask); + if (r > 0) { + *ptr = p; + *ret = in4_addr_netmask_to_prefixlen(&netmask.in); + return 0; + } } - r = network_set_dns(context, ifname, family, buf); + p = *ptr; + r = extract_first_word(&p, &buf, ":", EXTRACT_DONT_COALESCE_SEPARATORS); if (r < 0) return r; + if (isempty(buf)) + *ret = family == AF_INET6 ? 128 : 32; + else { + r = safe_atou8(buf, ret); + if (r < 0) + return r; + } - *value = p; + *ptr = p; return 0; } static int parse_cmdline_ip_address(Context *context, int family, const char *value) { - union in_addr_union addr = {}, peer = {}, gateway = {}; - const char *hostname = NULL, *ifname, *dhcp_type, *p; + union in_addr_union addr, peer = {}, gateway = {}; unsigned char prefixlen; int r; @@ -791,95 +770,95 @@ static int parse_cmdline_ip_address(Context *context, int family, const char *va assert(value); /* ip=:[]:::::{none|off|dhcp|on|any|dhcp6|auto6|ibft|link6}[:[][:]] - * ip=:[]:::::{none|off|dhcp|on|any|dhcp6|auto6|ibft|link6}[:[][:]] */ + * ip=:[]:::::{none|off|dhcp|on|any|dhcp6|auto6|ibft|link6}[:[][:]] + * + * Here, only DHCP type is mandatory. */ - r = parse_ip_address_one(family, &value, &addr); + const char *p = value; + r = extract_ip_address(family, &p, &addr); if (r < 0) - return r; - r = parse_ip_address_one(family, &value, &peer); + return log_debug_errno(r, "Failed to parse IP address in ip=%s: %m", value); + r = extract_ip_address(family, &p, &peer); if (r < 0) - return r; - r = parse_ip_address_one(family, &value, &gateway); + return log_debug_errno(r, "Failed to parse peer address in ip=%s: %m", value); + r = extract_ip_address(family, &p, &gateway); if (r < 0) - return r; - r = parse_netmask_or_prefixlen(family, &value, &prefixlen); + return log_debug_errno(r, "Failed to parse gateway address in ip=%s: %m", value); + r = extract_netmask_or_prefixlen(family, &p, &prefixlen); if (r < 0) - return r; + return log_debug_errno(r, "Failed to parse netmask in ip=%s: %m", value); /* hostname */ - p = strchr(value, ':'); - if (!p) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid IP address '%s'", value); - - if (p != value) { - hostname = strndupa_safe(value, p - value); - if (!hostname_is_valid(hostname, 0)) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid hostname '%s'", hostname); - } - - value = p + 1; + _cleanup_free_ char *hostname = NULL; + r = extract_first_word(&p, &hostname, ":", EXTRACT_DONT_COALESCE_SEPARATORS); + if (r < 0) + return log_debug_errno(r, "Failed to parse hostname in ip=%s: %m", value); /* ifname */ - p = strchr(value, ':'); - if (!p) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid IP address '%s'", value); - - ifname = strndupa_safe(value, p - value); - - value = p + 1; + _cleanup_free_ char *ifname = NULL; + r = extract_first_word(&p, &ifname, ":", EXTRACT_DONT_COALESCE_SEPARATORS); + if (r <= 0) + return log_debug_errno(r < 0 ? r : SYNTHETIC_ERRNO(EINVAL), "Failed to parse interface name in ip=%s: %m", value); /* dhcp_type */ - p = strchr(value, ':'); - if (!p) - dhcp_type = value; - else - dhcp_type = strndupa_safe(value, p - value); + _cleanup_free_ char *dhcp_type = NULL; + r = extract_first_word(&p, &dhcp_type, ":", EXTRACT_DONT_COALESCE_SEPARATORS); + if (r <= 0) + return log_debug_errno(r < 0 ? r : SYNTHETIC_ERRNO(EINVAL), "Failed to parse DHCP type name in ip=%s: %m", value); - r = network_set_dhcp_type(context, ifname, dhcp_type); + /* set values */ + r = network_set_address(context, ifname, family, prefixlen, &addr, &peer); if (r < 0) return r; - /* set values */ - r = network_set_hostname(context, ifname, hostname); + r = network_set_route(context, ifname, family, 0, NULL, &gateway); if (r < 0) return r; - r = network_set_address(context, ifname, family, prefixlen, &addr, &peer); + r = network_set_hostname(context, ifname, hostname); if (r < 0) return r; - r = network_set_route(context, ifname, family, 0, NULL, &gateway); + r = network_set_dhcp_type(context, ifname, dhcp_type); if (r < 0) return r; - if (!p) + /* First, try [][:] if an interface name is specified. */ + if (!isempty(ifname) && parse_cmdline_ip_mtu_mac(context, ifname, p) >= 0) return 0; - /* First, try [][:] */ - r = parse_cmdline_ip_mtu_mac(context, ifname, p + 1); - if (r >= 0) + /* Next, try [][:] */ + _cleanup_free_ char *dns = NULL; + r = extract_ip_address_str(AF_UNSPEC, &p, &dns); + if (r < 0) + return log_debug_errno(r, "Failed to parse DNS address in ip=%s: %m", value); + if (r == 0) return 0; - /* Next, try [][:] */ - value = p + 1; - r = parse_ip_dns_address_one(context, ifname, &value); + r = network_set_dns(context, ifname, dns); if (r < 0) return r; - value += *value == ':'; - r = parse_ip_dns_address_one(context, ifname, &value); + dns = mfree(dns); + r = extract_ip_address_str(AF_UNSPEC, &p, &dns); + if (r < 0) + return log_debug_errno(r, "Failed to parse DNS address in ip=%s: %m", value); + if (r == 0) + return 0; + + r = network_set_dns(context, ifname, dns); if (r < 0) return r; /* refuse unexpected trailing strings */ - if (!isempty(value)) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid IP address '%s'", value); + if (!isempty(p)) + return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Unexpected trailing string in 'ip=%s'.", value); return 0; } static int parse_cmdline_ip_interface(Context *context, const char *value) { - const char *ifname, *dhcp_type, *p; + _cleanup_free_ char *ifname = NULL, *dhcp_type = NULL; int r; assert(context); @@ -887,27 +866,23 @@ static int parse_cmdline_ip_interface(Context *context, const char *value) { /* ip=:{dhcp|on|any|dhcp6|auto6|link6}[:[][:]] */ - p = strchr(value, ':'); - if (!p) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid IP address '%s'", value); + const char *p = value; + r = extract_first_word(&p, &ifname, ":", EXTRACT_DONT_COALESCE_SEPARATORS); + if (r <= 0) + return log_debug_errno(r < 0 ? r : SYNTHETIC_ERRNO(EINVAL), "Failed to parse interface name in ip=%s: %m", value); - ifname = strndupa_safe(value, p - value); + if (isempty(ifname)) + return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Missing interface name in ip=%s: %m", value); - value = p + 1; - p = strchr(value, ':'); - if (!p) - dhcp_type = value; - else - dhcp_type = strndupa_safe(value, p - value); + r = extract_first_word(&p, &dhcp_type, ":", EXTRACT_DONT_COALESCE_SEPARATORS); + if (r <= 0) + return log_debug_errno(r < 0 ? r : SYNTHETIC_ERRNO(EINVAL), "Failed to parse DHCP type in ip=%s: %m", value); r = network_set_dhcp_type(context, ifname, dhcp_type); if (r < 0) return r; - if (!p) - return 0; - - return parse_cmdline_ip_mtu_mac(context, ifname, p + 1); + return parse_cmdline_ip_mtu_mac(context, ifname, p); } static int parse_cmdline_ip(Context *context, const char *key, const char *value) { @@ -925,6 +900,10 @@ static int parse_cmdline_ip(Context *context, const char *key, const char *value /* ip={dhcp|on|any|dhcp6|auto6|either6|link6} */ return network_set_dhcp_type(context, "", value); + /* extract_first_word() eats the trailing separator, so check this earlier. */ + if (endswith(value, ":")) + return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Unexpected trailing colon in 'ip=%s'.", value); + if (value[0] == '[') return parse_cmdline_ip_address(context, AF_INET6, value); @@ -936,9 +915,9 @@ static int parse_cmdline_ip(Context *context, const char *key, const char *value } static int parse_cmdline_rd_route(Context *context, const char *key, const char *value) { - union in_addr_union addr = {}, gateway = {}; + _cleanup_free_ char *buf = NULL; + union in_addr_union dest, gateway; unsigned char prefixlen; - const char *buf, *p; int family, r; assert(context); @@ -949,40 +928,21 @@ static int parse_cmdline_rd_route(Context *context, const char *key, const char if (proc_cmdline_value_missing(key, value)) return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Missing value for '%s'", key); - if (value[0] == '[') { - p = strchr(value, ']'); - if (!p) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid IPv6 address '%s'", value); - - if (p[1] != ':') - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid IPv6 address '%s'", value); - - buf = strndupa_safe(value + 1, p - value - 1); - value = p + 2; - family = AF_INET6; - } else { - p = strchr(value, ':'); - if (!p) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid IPv4 address '%s'", value); + const char *p = value; + r = extract_ip_address_str(AF_UNSPEC, &p, &buf); + if (r <= 0) + return log_debug_errno(r < 0 ? r : SYNTHETIC_ERRNO(EINVAL), "Failed to parse destination address in %s=%s: %m", key, value); - buf = strndupa_safe(value, p - value); - value = p + 1; - family = AF_INET; - } - - r = in_addr_prefix_from_string(buf, family, &addr, &prefixlen); + r = in_addr_prefix_from_string_auto(buf, &family, &dest, &prefixlen); if (r < 0) - return log_debug_errno(r, "Invalid IP address '%s': %m", buf); - - p = strchr(value, ':'); - if (!p) - value = strjoina(value, ":"); + return log_debug_errno(r, "Failed to parse route destination '%s': %m", buf); - r = parse_ip_address_one(family, &value, &gateway); - if (r < 0) - return r; + buf = mfree(buf); + r = extract_ip_address(family, &p, &gateway); + if (r <= 0) + return log_debug_errno(r < 0 ? r : SYNTHETIC_ERRNO(EINVAL), "Failed to parse gateway address in %s=%s: %m", key, value); - return network_set_route(context, value, family, prefixlen, &addr, &gateway); + return network_set_route(context, strempty(p), family, prefixlen, &dest, &gateway); } static int parse_cmdline_nameserver(Context *context, const char *key, const char *value) { @@ -992,7 +952,7 @@ static int parse_cmdline_nameserver(Context *context, const char *key, const cha if (proc_cmdline_value_missing(key, value)) return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Missing value for '%s'", key); - return network_set_dns(context, "", AF_UNSPEC, value); + return network_set_dns(context, "", value); } static int parse_cmdline_rd_peerdns(Context *context, const char *key, const char *value) { @@ -1030,21 +990,22 @@ static int extract_vlan_id(const char *vlan_name, uint16_t *ret) { } static int parse_cmdline_vlan(Context *context, const char *key, const char *value) { - const char *name, *p; + _cleanup_free_ char *name = NULL; NetDev *netdev; int r; assert(context); assert(key); + /* vlan=: */ + if (proc_cmdline_value_missing(key, value)) return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Missing value for '%s'", key); - p = strchr(value, ':'); - if (!p) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid VLAN value '%s'", value); - - name = strndupa_safe(value, p - value); + const char *p = value; + r = extract_first_word(&p, &name, ":", EXTRACT_DONT_COALESCE_SEPARATORS); + if (r <= 0) + return log_debug_errno(r < 0 ? r : SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s=%s: %m", key, value); r = netdev_acquire(context, "vlan", name, &netdev); if (r < 0) @@ -1054,32 +1015,31 @@ static int parse_cmdline_vlan(Context *context, const char *key, const char *val if (r < 0) return log_debug_errno(r, "Failed to parse VLAN ID from VLAN device name '%s': %m", name); - return network_set_vlan(context, p + 1, name); + return network_set_vlan(context, p, name); } static int parse_cmdline_bridge(Context *context, const char *key, const char *value) { - const char *name, *p; + _cleanup_free_ char *name = NULL; NetDev *netdev; int r; assert(context); assert(key); + /* bridge=: */ + if (proc_cmdline_value_missing(key, value)) return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Missing value for '%s'", key); - p = strchr(value, ':'); - if (!p) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid bridge value '%s'", value); - - name = strndupa_safe(value, p - value); + const char *p = value; + r = extract_first_word(&p, &name, ":", EXTRACT_DONT_COALESCE_SEPARATORS); + if (r <= 0) + return log_debug_errno(r < 0 ? r : SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s=%s: %m", key, value); r = netdev_acquire(context, "bridge", name, &netdev); if (r < 0) return log_debug_errno(r, "Failed to acquire bridge device for '%s': %m", name); - p++; - for (;;) { _cleanup_free_ char *word = NULL; @@ -1096,32 +1056,30 @@ static int parse_cmdline_bridge(Context *context, const char *key, const char *v } static int parse_cmdline_bond(Context *context, const char *key, const char *value) { - const char *name, *slaves, *p; + _cleanup_free_ char *name = NULL, *slaves = NULL, *options = NULL; NetDev *netdev; int r; assert(context); assert(key); + /* bond=[::[:[:]]] */ + if (proc_cmdline_value_missing(key, value)) return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Missing value for '%s'", key); - p = strchr(value, ':'); - if (!p) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid bond value '%s'", value); - - name = strndupa_safe(value, p - value); + const char *p = value; + r = extract_first_word(&p, &name, ":", EXTRACT_DONT_COALESCE_SEPARATORS); + if (r <= 0) + return log_debug_errno(r < 0 ? r : SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s=%s: %m", key, value); r = netdev_acquire(context, "bond", name, &netdev); if (r < 0) return log_debug_errno(r, "Failed to acquire bond device for '%s': %m", name); - value = p + 1; - p = strchr(value, ':'); - if (!p) - slaves = value; - else - slaves = strndupa_safe(value, p - value); + r = extract_first_word(&p, &slaves, ":", EXTRACT_DONT_COALESCE_SEPARATORS); + if (r < 0) + return log_debug_errno(r, "Failed to parse %s=%s: %m", key, value); for (const char *q = slaves; ; ) { _cleanup_free_ char *word = NULL; @@ -1137,21 +1095,24 @@ static int parse_cmdline_bond(Context *context, const char *key, const char *val return r; } - if (!p) - return 0; + r = extract_first_word(&p, &options, ":", EXTRACT_DONT_COALESCE_SEPARATORS); + if (r < 0) + return log_debug_errno(r, "Failed to parse %s=%s: %m", key, value); - value = p + 1; - p = strchr(value, ':'); - if (!p) - /* TODO: set bonding options */ - return 0; + /* TODO: set bonding options */ + + if (!isempty(p)) { + r = parse_mtu(AF_UNSPEC, p, &netdev->mtu); + if (r < 0) + return log_debug_errno(r, "Invalid MTU '%s' for '%s': %m", p, name); + } - return parse_mtu(AF_UNSPEC, p + 1, &netdev->mtu); + return 0; } static int parse_cmdline_ifname(Context *context, const char *key, const char *value) { + _cleanup_free_ char *name = NULL; struct hw_addr_data mac; - const char *name, *p; int r; assert(context); @@ -1162,15 +1123,17 @@ static int parse_cmdline_ifname(Context *context, const char *key, const char *v if (proc_cmdline_value_missing(key, value)) return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Missing value for '%s'", key); - p = strchr(value, ':'); - if (!p) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid ifname value '%s'", value); + const char *p = value; + r = extract_first_word(&p, &name, ":", EXTRACT_DONT_COALESCE_SEPARATORS); + if (r <= 0) + return log_debug_errno(r < 0 ? r : SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s=%s: %m", key, value); - name = strndupa_safe(value, p - value); + if (isempty(p)) + return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Missing MAC address for '%s'", name); - r = parse_hw_addr(p + 1, &mac); + r = parse_hw_addr(p, &mac); if (r < 0) - return log_debug_errno(r, "Invalid MAC address '%s' for '%s'", p + 1, name); + return log_debug_errno(r, "Invalid MAC address '%s' for '%s'", p, name); r = link_new(context, name, &mac, NULL); if (r < 0) diff --git a/test/test-network-generator-conversion.sh b/test/test-network-generator-conversion.sh index 12254acdab9..f8d97e5de35 100755 --- a/test/test-network-generator-conversion.sh +++ b/test/test-network-generator-conversion.sh @@ -261,7 +261,6 @@ COMMAND_LINES=( "ip=1.2.3.4:2.3.4.5:1.2.3.1:255.255.255.0:hello-world.local:dummy99:off:123" "ip=1.2.3.4:2.3.4.5:1.2.3.1:255.255.255.0:hello-world.local:dummy99:off:123:52:54:00:a7:8f:ac" "ip=1.2.3.4:2.3.4.5:1.2.3.1:255.255.255.0:hello-world.local:dummy99:off::52:54:00:a7:8f:ac" - "ip=1.2.3.4:2.3.4.5:1.2.3.1:255.255.255.0:hello-world.local:dummy99:off::" "ip=1.2.3.4:2.3.4.5:1.2.3.1:255.255.255.0:hello-world.local:dummy99:off:1.2.3.2" "ip=1.2.3.4:2.3.4.5:1.2.3.1:255.255.255.0:hello-world.local:dummy99:off:1.2.3.2:1.2.3.3" "ip=192.168.0.2::192.168.0.1:255.255.128.0::foo1:off" @@ -272,7 +271,6 @@ COMMAND_LINES=( "ip=[fdef:c400:bd01:1096::2]::[fdef:c400:bd01:1096::1]:64::ipv6:off:666" "ip=[fdef:c400:bd01:1096::2]::[fdef:c400:bd01:1096::1]:64::ipv6:off:666:52:54:00:a7:8f:ac" "ip=[fdef:c400:bd01:1096::2]::[fdef:c400:bd01:1096::1]:64::ipv6:off::52:54:00:a7:8f:ac" - "ip=[fdef:c400:bd01:1096::2]::[fdef:c400:bd01:1096::1]:64::ipv6:off::" "ip=[fdef:c400:bd01:1096::2]::[fdef:c400:bd01:1096::1]:64::ipv6:off:[fdef:c400:bd01:1096::aaaa]" "ip=[fdef:c400:bd01:1096::2]::[fdef:c400:bd01:1096::1]:64::ipv6:off:[fdef:c400:bd01:1096::aaaa]:[fdef:c400:bd01:1096::bbbb]" "ip=:::::dhcp99:any" @@ -299,7 +297,9 @@ INVALID_COMMAND_LINES=( "ip=:::::dhcp99:dhcp6:4294967296" "ip=:::::dhcp99:dhcp6:-1" "ip=:::::dhcp99:dhcp6:666:52:54:00" + "ip=1.2.3.4:2.3.4.5:1.2.3.1:255.255.255.0:hello-world.local:dummy99:off::" "ip=fdef:c400:bd01:1096::2::[fdef:c400:bd01:1096::1]:64::ipv6:off:[fdef:c400:bd01:1096::aaaa]" + "ip=[fdef:c400:bd01:1096::2]::[fdef:c400:bd01:1096::1]:64::ipv6:off::" "ip=[fdef:c400:bd01:1096::2]::[fdef:c400:bd01:1096::1]:64::ipv6:off:foo" "ip=[fdef:c400:bd01:1096::2]::[fdef:c400:bd01:1096::1]:64::ipv6:off:[fdef:c400:bd01:1096::aaaa]:foo" "ip=[fdef:c400:bd01:1096::2]::[fdef:c400:bd01:1096::1]:64::ipv6:off:[fdef:c400:bd01:1096::aaaa]:[fdef:c400:bd01:1096::bbbb]:"