From: Lennart Poettering Date: Fri, 20 Mar 2026 14:16:19 +0000 (+0100) Subject: json-util: add json_dispatch_in6_addr() X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=9eb207356c9c75e80e976ee4cb1ad8a11ce8972f;p=thirdparty%2Fsystemd.git json-util: add json_dispatch_in6_addr() --- diff --git a/src/libsystemd/sd-json/json-util.c b/src/libsystemd/sd-json/json-util.c index 32578168db0..c321579ef50 100644 --- a/src/libsystemd/sd-json/json-util.c +++ b/src/libsystemd/sd-json/json-util.c @@ -214,6 +214,40 @@ int json_dispatch_in_addr(const char *name, sd_json_variant *variant, sd_json_di return 0; } +int json_dispatch_in6_addr(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) { + struct in6_addr *address = ASSERT_PTR(userdata); + _cleanup_(iovec_done) struct iovec iov = {}; + int r; + + if (sd_json_variant_is_null(variant)) { + *address = (struct in6_addr) {}; + return 0; + } + + /* We support both a more human readable string based encoding and an array based encoding */ + if (sd_json_variant_is_string(variant)) { + union in_addr_union a; + r = in_addr_from_string(AF_INET6, sd_json_variant_string(variant), &a); + if (r < 0) + return json_log(variant, flags, r, + "JSON field '%s' is not a valid IPv6 address string: %s", strna(name), sd_json_variant_string(variant)); + + *address = a.in6; + return 0; + } + + r = json_dispatch_byte_array_iovec(name, variant, flags, &iov); + if (r < 0) + return r; + + if (iov.iov_len != sizeof(struct in6_addr)) + return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), + "Expected JSON field '%s' to be an array of %zu bytes.", strna(name), sizeof(struct in6_addr)); + + memcpy(address, iov.iov_base, iov.iov_len); + return 0; +} + int json_dispatch_const_path(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) { const char **p = ASSERT_PTR(userdata), *path; diff --git a/src/libsystemd/sd-json/json-util.h b/src/libsystemd/sd-json/json-util.h index 847725a41e2..478d2a2a212 100644 --- a/src/libsystemd/sd-json/json-util.h +++ b/src/libsystemd/sd-json/json-util.h @@ -115,6 +115,7 @@ int json_dispatch_user_group_name(const char *name, sd_json_variant *variant, sd int json_dispatch_const_user_group_name(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata); int json_dispatch_const_unit_name(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata); int json_dispatch_in_addr(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata); +int json_dispatch_in6_addr(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata); int json_dispatch_path(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata); int json_dispatch_const_path(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata); int json_dispatch_strv_path(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata); diff --git a/src/test/test-json.c b/src/test/test-json.c index e9650339a1a..d6308b23e7d 100644 --- a/src/test/test-json.c +++ b/src/test/test-json.c @@ -1733,4 +1733,98 @@ TEST(json_dispatch_in_addr) { &dummy), EINVAL); } +TEST(json_dispatch_in6_addr) { + _cleanup_(sd_json_variant_unrefp) sd_json_variant *j = NULL; + + /* ::1 */ + ASSERT_OK(sd_json_build(&j, SD_JSON_BUILD_OBJECT( + SD_JSON_BUILD_PAIR("addr", JSON_BUILD_IN6_ADDR(&(const struct in6_addr) { .s6_addr = { [15] = 1 } })), + SD_JSON_BUILD_PAIR("null_addr", SD_JSON_BUILD_NULL)))); + + struct { + struct in6_addr addr; + struct in6_addr null_addr; + } data = {}; + + ASSERT_OK(sd_json_dispatch(j, + (const sd_json_dispatch_field[]) { + { "addr", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_in6_addr, offsetof(typeof(data), addr) }, + { "null_addr", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_in6_addr, offsetof(typeof(data), null_addr) }, + {}, + }, + /* flags= */ 0, + &data)); + + ASSERT_EQ(data.addr.s6_addr[15], 1); + for (size_t i = 0; i < 15; i++) + ASSERT_EQ(data.addr.s6_addr[i], 0); + for (size_t i = 0; i < 16; i++) + ASSERT_EQ(data.null_addr.s6_addr[i], 0); + + struct in6_addr dummy = {}; + + /* Too few bytes (15 instead of 16) */ + j = sd_json_variant_unref(j); + ASSERT_OK(sd_json_build(&j, SD_JSON_BUILD_OBJECT( + SD_JSON_BUILD_PAIR("addr", SD_JSON_BUILD_ARRAY( + SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), + SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), + SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), + SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(1)))))); + ASSERT_ERROR(sd_json_dispatch(j, + (const sd_json_dispatch_field[]) { + { "addr", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_in6_addr, 0 }, + {}, + }, + /* flags= */ 0, + &dummy), EINVAL); + + /* Too many bytes (17 instead of 16) */ + j = sd_json_variant_unref(j); + ASSERT_OK(sd_json_build(&j, SD_JSON_BUILD_OBJECT( + SD_JSON_BUILD_PAIR("addr", SD_JSON_BUILD_ARRAY( + SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), + SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), + SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), + SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(1), + SD_JSON_BUILD_UNSIGNED(0)))))); + ASSERT_ERROR(sd_json_dispatch(j, + (const sd_json_dispatch_field[]) { + { "addr", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_in6_addr, 0 }, + {}, + }, + /* flags= */ 0, + &dummy), EINVAL); + + /* Not an array */ + j = sd_json_variant_unref(j); + ASSERT_OK(sd_json_build(&j, SD_JSON_BUILD_OBJECT( + SD_JSON_BUILD_PAIR("addr", SD_JSON_BUILD_BOOLEAN(true))))); + ASSERT_ERROR(sd_json_dispatch(j, + (const sd_json_dispatch_field[]) { + { "addr", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_in6_addr, 0 }, + {}, + }, + /* flags= */ 0, + &dummy), EINVAL); + + /* A string */ + j = sd_json_variant_unref(j); + ASSERT_OK(sd_json_build(&j, SD_JSON_BUILD_OBJECT( + SD_JSON_BUILD_PAIR("addr", JSON_BUILD_CONST_STRING("::1"))))); + + zero(data); + ASSERT_OK(sd_json_dispatch(j, + (const sd_json_dispatch_field[]) { + { "addr", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_in6_addr, 0 }, + {}, + }, + /* flags= */ 0, + &data)); + + ASSERT_EQ(data.addr.s6_addr[15], 1); + for (size_t i = 0; i < 15; i++) + ASSERT_EQ(data.addr.s6_addr[i], 0); +} + DEFINE_TEST_MAIN(LOG_DEBUG);