diff --git a/src/basic/in-addr-util.c b/src/basic/in-addr-util.c index d83658eaa7..4cf6ab6974 100644 --- a/src/basic/in-addr-util.c +++ b/src/basic/in-addr-util.c @@ -314,6 +314,7 @@ int in_addr_from_string_auto(const char *s, int *ret_family, union in_addr_union } int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex) { + _cleanup_free_ char *buf = NULL; const char *suffix; int r, ifi = 0; @@ -341,7 +342,11 @@ int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_u } } - s = strndupa(s, suffix - s); + buf = strndup(s, suffix - s); + if (!buf) + return -ENOMEM; + + s = buf; } r = in_addr_from_string_auto(s, family, ret); @@ -490,12 +495,14 @@ int in_addr_parse_prefixlen(int family, const char *p, unsigned char *ret) { return 0; } -int in_addr_prefix_from_string( +int in_addr_prefix_from_string_internal( const char *p, + bool use_default_prefixlen, int family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen) { + _cleanup_free_ char *str = NULL; union in_addr_union buffer; const char *e, *l; unsigned char k; @@ -507,9 +514,13 @@ int in_addr_prefix_from_string( return -EAFNOSUPPORT; e = strchr(p, '/'); - if (e) - l = strndupa(p, e - p); - else + if (e) { + str = strndup(p, e - p); + if (!str) + return -ENOMEM; + + l = str; + } else l = p; r = in_addr_from_string(family, l, &buffer); @@ -520,6 +531,10 @@ int in_addr_prefix_from_string( r = in_addr_parse_prefixlen(family, e+1, &k); if (r < 0) return r; + } else if (family == AF_INET && use_default_prefixlen) { + r = in4_addr_default_prefixlen(&buffer.in, &k); + if (r < 0) + return r; } else k = FAMILY_ADDRESS_SIZE(family) * 8; @@ -531,12 +546,14 @@ int in_addr_prefix_from_string( return 0; } -int in_addr_prefix_from_string_auto( +int in_addr_prefix_from_string_auto_internal( const char *p, + bool use_default_prefixlen, int *ret_family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen) { + _cleanup_free_ char *str = NULL; union in_addr_union buffer; const char *e, *l; unsigned char k; @@ -545,9 +562,13 @@ int in_addr_prefix_from_string_auto( assert(p); e = strchr(p, '/'); - if (e) - l = strndupa(p, e - p); - else + if (e) { + str = strndup(p, e - p); + if (!str) + return -ENOMEM; + + l = str; + } else l = p; r = in_addr_from_string_auto(l, &family, &buffer); @@ -558,6 +579,10 @@ int in_addr_prefix_from_string_auto( r = in_addr_parse_prefixlen(family, e+1, &k); if (r < 0) return r; + } else if (family == AF_INET && use_default_prefixlen) { + r = in4_addr_default_prefixlen(&buffer.in, &k); + if (r < 0) + return r; } else k = FAMILY_ADDRESS_SIZE(family) * 8; diff --git a/src/basic/in-addr-util.h b/src/basic/in-addr-util.h index e4be30dc0d..2dafa3c084 100644 --- a/src/basic/in-addr-util.h +++ b/src/basic/in-addr-util.h @@ -45,8 +45,20 @@ int in4_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mas int in_addr_mask(int family, union in_addr_union *addr, unsigned char prefixlen); int in_addr_prefix_covers(int family, const union in_addr_union *prefix, unsigned char prefixlen, const union in_addr_union *address); int in_addr_parse_prefixlen(int family, const char *p, unsigned char *ret); -int in_addr_prefix_from_string(const char *p, int family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen); -int in_addr_prefix_from_string_auto(const char *p, int *ret_family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen); +int in_addr_prefix_from_string_internal(const char *p, bool use_default_prefixlen, int family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen); +int in_addr_prefix_from_string_auto_internal(const char *p, bool use_default_prefixlen, int *ret_family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen); +static inline int in_addr_prefix_from_string(const char *p, int family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen) { + return in_addr_prefix_from_string_internal(p, false, family, ret_prefix, ret_prefixlen); +} +static inline int in_addr_prefix_from_string_auto(const char *p, int *ret_family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen) { + return in_addr_prefix_from_string_auto_internal(p, false, ret_family, ret_prefix, ret_prefixlen); +} +static inline int in_addr_default_prefix_from_string(const char *p, int family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen) { + return in_addr_prefix_from_string_internal(p, true, family, ret_prefix, ret_prefixlen); +} +static inline int in_addr_default_prefix_from_string_auto(const char *p, int *ret_family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen) { + return in_addr_prefix_from_string_auto_internal(p, true, ret_family, ret_prefix, ret_prefixlen); +} static inline size_t FAMILY_ADDRESS_SIZE(int family) { assert(IN_SET(family, AF_INET, AF_INET6)); diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index cf33563bdd..a87786876b 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -706,8 +706,8 @@ int config_parse_address(const char *unit, Network *network = userdata; _cleanup_(address_freep) Address *n = NULL; - const char *address, *e; union in_addr_union buffer; + unsigned char prefixlen; int r, f; assert(filename); @@ -727,44 +727,19 @@ int config_parse_address(const char *unit, return r; /* Address=address/prefixlen */ - - /* prefixlen */ - e = strchr(rvalue, '/'); - if (e) { - unsigned i; - - r = safe_atou(e + 1, &i); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, "Prefix length is invalid, ignoring assignment: %s", e + 1); - return 0; - } - - n->prefixlen = (unsigned char) i; - - address = strndupa(rvalue, e - rvalue); - } else - address = rvalue; - - r = in_addr_from_string_auto(address, &f, &buffer); + r = in_addr_default_prefix_from_string_auto(rvalue, &f, &buffer, &prefixlen); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, "Address is invalid, ignoring assignment: %s", address); + log_syntax(unit, LOG_ERR, filename, line, r, "Invalid address '%s', ignoring assignment: %m", rvalue); return 0; } - if (!e && f == AF_INET) { - r = in4_addr_default_prefixlen(&buffer.in, &n->prefixlen); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, "Prefix length not specified, and a default one cannot be deduced for '%s', ignoring assignment", address); - return 0; - } - } - if (n->family != AF_UNSPEC && f != n->family) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Address is incompatible, ignoring assignment: %s", address); + log_syntax(unit, LOG_ERR, filename, line, 0, "Address is incompatible, ignoring assignment: %s", rvalue); return 0; } n->family = f; + n->prefixlen = prefixlen; if (streq(lvalue, "Address")) n->in_addr = buffer; diff --git a/src/network/test-networkd-conf.c b/src/network/test-networkd-conf.c index d05680d7e1..a906630b38 100644 --- a/src/network/test-networkd-conf.c +++ b/src/network/test-networkd-conf.c @@ -168,6 +168,49 @@ static void test_config_parse_hwaddr(void) { test_config_parse_hwaddrs_one("123.4567.89ab aa:bb:cc:dd:ee:fx hogehoge 01-23-45-67-89-ab aaaa aa:Bb:CC:dd:ee:ff", t, 2); } +static void test_config_parse_address_one(const char *rvalue, int family, unsigned n_addresses, const union in_addr_union *u, unsigned char prefixlen) { + _cleanup_(network_freep) Network *network = NULL; + + assert_se(network = new0(Network, 1)); + assert_se(network->addresses_by_section = hashmap_new(NULL)); + assert_se(config_parse_address("network", "filename", 1, "section", 1, "Address", 0, rvalue, network, network) == 0); + assert_se(network->n_static_addresses == n_addresses); + if (n_addresses > 0) { + assert_se(network->static_addresses); + assert_se(network->static_addresses->prefixlen == prefixlen); + assert_se(network->static_addresses->family == family); + assert_se(in_addr_equal(family, &network->static_addresses->in_addr, u)); + /* TODO: check Address.in_addr and Address.broadcast */ + } +} + +static void test_config_parse_address(void) { + test_config_parse_address_one("", AF_INET, 0, NULL, 0); + test_config_parse_address_one("/", AF_INET, 0, NULL, 0); + test_config_parse_address_one("/8", AF_INET, 0, NULL, 0); + test_config_parse_address_one("1.2.3.4", AF_INET, 1, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 8); + test_config_parse_address_one("1.2.3.4/0", AF_INET, 1, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 0); + test_config_parse_address_one("1.2.3.4/1", AF_INET, 1, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 1); + test_config_parse_address_one("1.2.3.4/2", AF_INET, 1, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 2); + test_config_parse_address_one("1.2.3.4/32", AF_INET, 1, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 32); + test_config_parse_address_one("1.2.3.4/33", AF_INET, 0, NULL, 0); + test_config_parse_address_one("1.2.3.4/-1", AF_INET, 0, NULL, 0); + + test_config_parse_address_one("", AF_INET6, 0, NULL, 0); + test_config_parse_address_one("/", AF_INET6, 0, NULL, 0); + test_config_parse_address_one("/8", AF_INET6, 0, NULL, 0); + test_config_parse_address_one("::1", AF_INET6, 1, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 128); + test_config_parse_address_one("::1/0", AF_INET6, 1, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 0); + test_config_parse_address_one("::1/1", AF_INET6, 1, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 1); + test_config_parse_address_one("::1/2", AF_INET6, 1, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 2); + test_config_parse_address_one("::1/32", AF_INET6, 1, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 32); + test_config_parse_address_one("::1/33", AF_INET6, 1, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 33); + test_config_parse_address_one("::1/64", AF_INET6, 1, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 64); + test_config_parse_address_one("::1/128", AF_INET6, 1, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 128); + test_config_parse_address_one("::1/129", AF_INET6, 0, NULL, 0); + test_config_parse_address_one("::1/-1", AF_INET6, 0, NULL, 0); +} + int main(int argc, char **argv) { log_parse_environment(); log_open(); @@ -175,6 +218,7 @@ int main(int argc, char **argv) { test_config_parse_duid_type(); test_config_parse_duid_rawdata(); test_config_parse_hwaddr(); + test_config_parse_address(); return 0; } diff --git a/src/test/test-in-addr-util.c b/src/test/test-in-addr-util.c index 5b6e87bf5a..849166391f 100644 --- a/src/test/test-in-addr-util.c +++ b/src/test/test-in-addr-util.c @@ -4,12 +4,12 @@ #include "in-addr-util.h" -static void test_in_addr_prefix_from_string(const char *p, int family, int ret, const union in_addr_union *u, unsigned char prefixlen) { +static void test_in_addr_prefix_from_string(const char *p, int family, int ret, const union in_addr_union *u, unsigned char prefixlen, bool use_default) { union in_addr_union q; unsigned char l; int r; - r = in_addr_prefix_from_string(p, family, &q, &l); + r = in_addr_prefix_from_string_internal(p, use_default, family, &q, &l); assert_se(r == ret); if (r >= 0) { @@ -18,7 +18,7 @@ static void test_in_addr_prefix_from_string(const char *p, int family, int ret, assert_se(in_addr_equal(family, &q, u)); assert_se(l == prefixlen); - r = in_addr_prefix_from_string_auto(p, &f, &q, &l); + r = in_addr_prefix_from_string_auto_internal(p, use_default, &f, &q, &l); assert_se(r >= 0); assert_se(f == family); @@ -28,31 +28,57 @@ static void test_in_addr_prefix_from_string(const char *p, int family, int ret, } int main(int argc, char *argv[]) { - test_in_addr_prefix_from_string("", AF_INET, -EINVAL, NULL, 0); - test_in_addr_prefix_from_string("/", AF_INET, -EINVAL, NULL, 0); - test_in_addr_prefix_from_string("/8", AF_INET, -EINVAL, NULL, 0); - test_in_addr_prefix_from_string("1.2.3.4", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 32); - test_in_addr_prefix_from_string("1.2.3.4/0", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 0); - test_in_addr_prefix_from_string("1.2.3.4/1", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 1); - test_in_addr_prefix_from_string("1.2.3.4/2", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 2); - test_in_addr_prefix_from_string("1.2.3.4/32", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 32); - test_in_addr_prefix_from_string("1.2.3.4/33", AF_INET, -ERANGE, NULL, 0); - test_in_addr_prefix_from_string("1.2.3.4/-1", AF_INET, -ERANGE, NULL, 0); - test_in_addr_prefix_from_string("::1", AF_INET, -EINVAL, NULL, 0); + test_in_addr_prefix_from_string("", AF_INET, -EINVAL, NULL, 0, false); + test_in_addr_prefix_from_string("/", AF_INET, -EINVAL, NULL, 0, false); + test_in_addr_prefix_from_string("/8", AF_INET, -EINVAL, NULL, 0, false); + test_in_addr_prefix_from_string("1.2.3.4", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 32, false); + test_in_addr_prefix_from_string("1.2.3.4/0", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 0, false); + test_in_addr_prefix_from_string("1.2.3.4/1", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 1, false); + test_in_addr_prefix_from_string("1.2.3.4/2", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 2, false); + test_in_addr_prefix_from_string("1.2.3.4/32", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 32, false); + test_in_addr_prefix_from_string("1.2.3.4/33", AF_INET, -ERANGE, NULL, 0, false); + test_in_addr_prefix_from_string("1.2.3.4/-1", AF_INET, -ERANGE, NULL, 0, false); + test_in_addr_prefix_from_string("::1", AF_INET, -EINVAL, NULL, 0, false); - test_in_addr_prefix_from_string("", AF_INET6, -EINVAL, NULL, 0); - test_in_addr_prefix_from_string("/", AF_INET6, -EINVAL, NULL, 0); - test_in_addr_prefix_from_string("/8", AF_INET6, -EINVAL, NULL, 0); - test_in_addr_prefix_from_string("::1", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 128); - test_in_addr_prefix_from_string("::1/0", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 0); - test_in_addr_prefix_from_string("::1/1", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 1); - test_in_addr_prefix_from_string("::1/2", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 2); - test_in_addr_prefix_from_string("::1/32", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 32); - test_in_addr_prefix_from_string("::1/33", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 33); - test_in_addr_prefix_from_string("::1/64", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 64); - test_in_addr_prefix_from_string("::1/128", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 128); - test_in_addr_prefix_from_string("::1/129", AF_INET6, -ERANGE, NULL, 0); - test_in_addr_prefix_from_string("::1/-1", AF_INET6, -ERANGE, NULL, 0); + test_in_addr_prefix_from_string("", AF_INET6, -EINVAL, NULL, 0, false); + test_in_addr_prefix_from_string("/", AF_INET6, -EINVAL, NULL, 0, false); + test_in_addr_prefix_from_string("/8", AF_INET6, -EINVAL, NULL, 0, false); + test_in_addr_prefix_from_string("::1", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 128, false); + test_in_addr_prefix_from_string("::1/0", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 0, false); + test_in_addr_prefix_from_string("::1/1", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 1, false); + test_in_addr_prefix_from_string("::1/2", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 2, false); + test_in_addr_prefix_from_string("::1/32", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 32, false); + test_in_addr_prefix_from_string("::1/33", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 33, false); + test_in_addr_prefix_from_string("::1/64", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 64, false); + test_in_addr_prefix_from_string("::1/128", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 128, false); + test_in_addr_prefix_from_string("::1/129", AF_INET6, -ERANGE, NULL, 0, false); + test_in_addr_prefix_from_string("::1/-1", AF_INET6, -ERANGE, NULL, 0, false); + + test_in_addr_prefix_from_string("", AF_INET, -EINVAL, NULL, 0, true); + test_in_addr_prefix_from_string("/", AF_INET, -EINVAL, NULL, 0, true); + test_in_addr_prefix_from_string("/8", AF_INET, -EINVAL, NULL, 0, true); + test_in_addr_prefix_from_string("1.2.3.4", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 8, true); + test_in_addr_prefix_from_string("1.2.3.4/0", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 0, true); + test_in_addr_prefix_from_string("1.2.3.4/1", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 1, true); + test_in_addr_prefix_from_string("1.2.3.4/2", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 2, true); + test_in_addr_prefix_from_string("1.2.3.4/32", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 32, true); + test_in_addr_prefix_from_string("1.2.3.4/33", AF_INET, -ERANGE, NULL, 0, true); + test_in_addr_prefix_from_string("1.2.3.4/-1", AF_INET, -ERANGE, NULL, 0, true); + test_in_addr_prefix_from_string("::1", AF_INET, -EINVAL, NULL, 0, true); + + test_in_addr_prefix_from_string("", AF_INET6, -EINVAL, NULL, 0, true); + test_in_addr_prefix_from_string("/", AF_INET6, -EINVAL, NULL, 0, true); + test_in_addr_prefix_from_string("/8", AF_INET6, -EINVAL, NULL, 0, true); + test_in_addr_prefix_from_string("::1", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 128, true); + test_in_addr_prefix_from_string("::1/0", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 0, true); + test_in_addr_prefix_from_string("::1/1", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 1, true); + test_in_addr_prefix_from_string("::1/2", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 2, true); + test_in_addr_prefix_from_string("::1/32", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 32, true); + test_in_addr_prefix_from_string("::1/33", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 33, true); + test_in_addr_prefix_from_string("::1/64", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 64, true); + test_in_addr_prefix_from_string("::1/128", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 128, true); + test_in_addr_prefix_from_string("::1/129", AF_INET6, -ERANGE, NULL, 0, true); + test_in_addr_prefix_from_string("::1/-1", AF_INET6, -ERANGE, NULL, 0, true); return 0; }