diff options
author | Yu Watanabe <watanabe.yu+github@gmail.com> | 2020-07-13 06:49:41 +0900 |
---|---|---|
committer | Yu Watanabe <watanabe.yu+github@gmail.com> | 2020-07-21 03:55:34 +0900 |
commit | a723fb85dac86fb975e52aeed68dcd62d3f2b3b4 (patch) | |
tree | 211d5bb4338b3bf3fbd457fc9c43b986a5eba4f8 /src/shared/socket-netlink.c | |
parent | cbe194b39e12122b0691cff06d110d369d5e8b44 (diff) | |
download | systemd-a723fb85dac86fb975e52aeed68dcd62d3f2b3b4.tar.gz |
util: introduce in_addr_port_ifindex_name_from_string_auto() and in_addr_port_ifindex_name_to_string()
Diffstat (limited to 'src/shared/socket-netlink.c')
-rw-r--r-- | src/shared/socket-netlink.c | 144 |
1 files changed, 103 insertions, 41 deletions
diff --git a/src/shared/socket-netlink.c b/src/shared/socket-netlink.c index 16b0e6a5c3..b95407f10e 100644 --- a/src/shared/socket-netlink.c +++ b/src/shared/socket-netlink.c @@ -327,68 +327,130 @@ int make_socket_fd(int log_level, const char* address, int type, int flags) { return fd; } -int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_union *ret_addr, int *ret_ifindex) { - _cleanup_free_ char *buf = NULL; - const char *suffix; - int r, ifindex = 0; +int in_addr_port_ifindex_name_from_string_auto( + const char *s, + int *ret_family, + union in_addr_union *ret_address, + uint16_t *ret_port, + int *ret_ifindex, + char **ret_server_name) { + + _cleanup_free_ char *buf1 = NULL, *buf2 = NULL, *name = NULL; + int family, ifindex = 0, r; + union in_addr_union a; + uint16_t port = 0; + const char *m; assert(s); - assert(family); - assert(ret_addr); - /* Similar to in_addr_from_string_auto() but also parses an optionally appended IPv6 zone suffix ("scope id") - * if one is found. */ + /* This accepts the following: + * 192.168.0.1:53#example.com + * [2001:4860:4860::8888]:53%eth0#example.com */ + + /* if ret_port is NULL, then strings with port cannot be specified. + * Also, if ret_server_name is NULL, then server_name cannot be specified. */ + + m = strchr(s, '#'); + if (m) { + if (!ret_server_name) + return -EINVAL; + + if (isempty(m + 1)) + return -EINVAL; + + name = strdup(m + 1); + if (!name) + return -ENOMEM; + + s = buf1 = strndup(s, m - s); + if (!buf1) + return -ENOMEM; + } + + m = strchr(s, '%'); + if (m) { + if (isempty(m + 1)) + return -EINVAL; - suffix = strchr(s, '%'); - if (suffix) { if (ret_ifindex) { /* If we shall return the interface index, try to parse it */ - ifindex = resolve_interface(NULL, suffix + 1); + ifindex = resolve_interface(NULL, m + 1); if (ifindex < 0) return ifindex; } - s = buf = strndup(s, suffix - s); - if (!buf) + s = buf2 = strndup(s, m - s); + if (!buf2) return -ENOMEM; } - r = in_addr_from_string_auto(s, family, ret_addr); - if (r < 0) - return r; - - if (ret_ifindex) - *ret_ifindex = ifindex; + m = strrchr(s, ':'); + if (m) { + if (*s == '[') { + _cleanup_free_ char *ip_str = NULL; - return r; -} + if (!ret_port) + return -EINVAL; -int in_addr_ifindex_name_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex, char **server_name) { - _cleanup_free_ char *buf = NULL, *name = NULL; - const char *m; - int r; + if (*(m - 1) != ']') + return -EINVAL; - assert(s); + family = AF_INET6; - m = strchr(s, '#'); - if (m) { - name = strdup(m+1); - if (!name) - return -ENOMEM; + r = parse_ip_port(m + 1, &port); + if (r < 0) + return r; - buf = strndup(s, m - s); - if (!buf) - return -ENOMEM; + ip_str = strndup(s + 1, m - s - 2); + if (!ip_str) + return -ENOMEM; - s = buf; + r = in_addr_from_string(family, ip_str, &a); + if (r < 0) + return r; + } else { + /* First try to parse the string as IPv6 address without port number */ + r = in_addr_from_string(AF_INET6, s, &a); + if (r < 0) { + /* Then the input should be IPv4 address with port number */ + _cleanup_free_ char *ip_str = NULL; + + if (!ret_port) + return -EINVAL; + + family = AF_INET; + + ip_str = strndup(s, m - s); + if (!ip_str) + return -ENOMEM; + + r = in_addr_from_string(family, ip_str, &a); + if (r < 0) + return r; + + r = parse_ip_port(m + 1, &port); + if (r < 0) + return r; + } else + family = AF_INET6; + } + } else { + family = AF_INET; + r = in_addr_from_string(family, s, &a); + if (r < 0) + return r; } - r = in_addr_ifindex_from_string_auto(s, family, ret, ifindex); - if (r < 0) - return r; - - if (server_name) - *server_name = TAKE_PTR(name); + if (ret_family) + *ret_family = family; + if (ret_address) + *ret_address = a; + if (ret_port) + *ret_port = port; + if (ret_ifindex) + *ret_ifindex = ifindex; + if (ret_server_name) + *ret_server_name = TAKE_PTR(name); return r; } |