summaryrefslogtreecommitdiff
path: root/src/shared/socket-netlink.c
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2020-07-13 06:49:41 +0900
committerYu Watanabe <watanabe.yu+github@gmail.com>2020-07-21 03:55:34 +0900
commita723fb85dac86fb975e52aeed68dcd62d3f2b3b4 (patch)
tree211d5bb4338b3bf3fbd457fc9c43b986a5eba4f8 /src/shared/socket-netlink.c
parentcbe194b39e12122b0691cff06d110d369d5e8b44 (diff)
downloadsystemd-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.c144
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;
}