From: Lennart Poettering Date: Fri, 1 Sep 2017 12:25:59 +0000 (+0200) Subject: in-addr-util: add new helper call in_addr_prefix_from_string_auto() X-Git-Tag: v235~60^2~34 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=f4912f3a74a1f55be371a515418083bd5d05169c;p=platform%2Fupstream%2Fsystemd.git in-addr-util: add new helper call in_addr_prefix_from_string_auto() This is much like in_addr_prefix_from_string(), but automatically determines whether IPv4 or IPv6 addresses are specified. Also adds a test for it. --- diff --git a/src/basic/in-addr-util.c b/src/basic/in-addr-util.c index 2198783..94f0625 100644 --- a/src/basic/in-addr-util.c +++ b/src/basic/in-addr-util.c @@ -465,10 +465,33 @@ int in_addr_mask(int family, union in_addr_union *addr, unsigned char prefixlen) return -EAFNOSUPPORT; } -int in_addr_prefix_from_string(const char *p, int family, union in_addr_union *ret_prefix, uint8_t *ret_prefixlen) { +int in_addr_parse_prefixlen(int family, const char *p, unsigned char *ret) { + uint8_t u; + int r; + + if (!IN_SET(family, AF_INET, AF_INET6)) + return -EAFNOSUPPORT; + + r = safe_atou8(p, &u); + if (r < 0) + return r; + + if (u > FAMILY_ADDRESS_SIZE(family) * 8) + return -ERANGE; + + *ret = u; + return 0; +} + +int in_addr_prefix_from_string( + const char *p, + int family, + union in_addr_union *ret_prefix, + unsigned char *ret_prefixlen) { + union in_addr_union buffer; const char *e, *l; - uint8_t k; + unsigned char k; int r; assert(p); @@ -486,23 +509,58 @@ int in_addr_prefix_from_string(const char *p, int family, union in_addr_union *r if (r < 0) return r; - k = FAMILY_ADDRESS_SIZE(family) * 8; - if (e) { - uint8_t n; - - r = safe_atou8(e + 1, &n); + r = in_addr_parse_prefixlen(family, e+1, &k); if (r < 0) return r; + } else + k = FAMILY_ADDRESS_SIZE(family) * 8; - if (n > k) - return -ERANGE; + if (ret_prefix) + *ret_prefix = buffer; + if (ret_prefixlen) + *ret_prefixlen = k; - k = n; - } + return 0; +} - *ret_prefix = buffer; - *ret_prefixlen = k; +int in_addr_prefix_from_string_auto( + const char *p, + int *ret_family, + union in_addr_union *ret_prefix, + unsigned char *ret_prefixlen) { + + union in_addr_union buffer; + const char *e, *l; + unsigned char k; + int family, r; + + assert(p); + + e = strchr(p, '/'); + if (e) + l = strndupa(p, e - p); + else + l = p; + + r = in_addr_from_string_auto(l, &family, &buffer); + if (r < 0) + return r; + + if (e) { + r = in_addr_parse_prefixlen(family, e+1, &k); + if (r < 0) + return r; + } else + k = FAMILY_ADDRESS_SIZE(family) * 8; + + if (ret_family) + *ret_family = family; + if (ret_prefix) + *ret_prefix = buffer; + if (ret_prefixlen) + *ret_prefixlen = k; return 0; + } diff --git a/src/basic/in-addr-util.h b/src/basic/in-addr-util.h index 8401d66..bb57c08 100644 --- a/src/basic/in-addr-util.h +++ b/src/basic/in-addr-util.h @@ -60,7 +60,9 @@ struct in_addr* in4_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned cha int in4_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen); int in4_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask); int in_addr_mask(int family, union in_addr_union *addr, unsigned char prefixlen); -int in_addr_prefix_from_string(const char *p, int family, union in_addr_union *ret_prefix, uint8_t *ret_prefixlen); +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); static inline size_t FAMILY_ADDRESS_SIZE(int family) { assert(family == AF_INET || family == AF_INET6); diff --git a/src/test/meson.build b/src/test/meson.build index 57f7655..b1543cd 100644 --- a/src/test/meson.build +++ b/src/test/meson.build @@ -277,6 +277,10 @@ tests += [ [], []], + [['src/test/test-in-addr-util.c'], + [], + []], + [['src/test/test-barrier.c'], [], []], diff --git a/src/test/test-in-addr-util.c b/src/test/test-in-addr-util.c new file mode 100644 index 0000000..8b7a122 --- /dev/null +++ b/src/test/test-in-addr-util.c @@ -0,0 +1,75 @@ +/*** + This file is part of systemd + + Copyright 2017 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#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) { + union in_addr_union q; + unsigned char l; + int r; + + r = in_addr_prefix_from_string(p, family, &q, &l); + assert_se(r == ret); + + if (r >= 0) { + int f; + + assert_se(in_addr_equal(family, &q, u)); + assert_se(l == prefixlen); + + r = in_addr_prefix_from_string_auto(p, &f, &q, &l); + assert_se(r >= 0); + + assert_se(f == family); + assert_se(in_addr_equal(family, &q, u)); + assert_se(l == prefixlen); + } +} + +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_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); + + return 0; +}