From a07ab56a4975f1159fd466530f150bfd2230f83c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Thu, 3 Sep 2020 15:33:25 +0200 Subject: [PATCH] Allow interface scopes to be specified in ListenStream= Closes #12624. The formatting in systemd.socket.xml is updated a bit. Currently in_addr_port_ifindex_name_to_string() always prints the ifindex numerically. This is not super useful since the interface numbers are semi-random. Should we use interface names in preference? --- man/systemd.socket.xml | 30 ++++++++++---------- src/shared/socket-netlink.c | 5 ++-- src/test/test-socket-netlink.c | 50 ++++++++++++++++++++++------------ 3 files changed, 52 insertions(+), 33 deletions(-) diff --git a/man/systemd.socket.xml b/man/systemd.socket.xml index 1bcbef2033..253da8a6d4 100644 --- a/man/systemd.socket.xml +++ b/man/systemd.socket.xml @@ -200,22 +200,24 @@ If the address string is a string in the format - v.w.x.y:z, it is read as IPv4 specifier for listening on an - address v.w.x.y on a port z. - - If the address string is a string in the format [x]:y, - it is read as IPv6 address x on a port y. Note that this might - make the service available via IPv4, too, depending on the - BindIPv6Only= setting (see below). - + v.w.x.y:z, it is interpeted + as IPv4 address v.w.x.y and port z. If the address string is a string in the format - vsock:x:y, it is read as CID x on - a port y address in the - AF_VSOCK family. The CID is a unique 32-bit - integer identifier in AF_VSOCK analogous to an IP - address. Specifying the CID is optional, and may be set to the empty - string. + [x]:y, it is interpreted as + IPv6 address x and port y. An optional + interface scope (interface name or number) may be specifed after a % symbol: + [x]:y%dev. + Interface scopes are only useful with link-local addresses, because the kernel ignores them in other + cases. Note that if an address is specified as IPv6, it might still make the service available via + IPv4 too, depending on the BindIPv6Only= setting (see below). + + If the address string is a string in the format + vsock:x:y, it is read as CID + x on a port y address in the + AF_VSOCK family. The CID is a unique 32-bit integer identifier in + AF_VSOCK analogous to an IP address. Specifying the CID is optional, and may be + set to the empty string. Note that SOCK_SEQPACKET (i.e. ListenSequentialPacket=) is only available diff --git a/src/shared/socket-netlink.c b/src/shared/socket-netlink.c index 198892b007..0ecbf7dee0 100644 --- a/src/shared/socket-netlink.c +++ b/src/shared/socket-netlink.c @@ -157,9 +157,9 @@ int socket_address_parse(SocketAddress *a, const char *s) { } else { union in_addr_union address; - int family; + int family, ifindex; - r = in_addr_port_ifindex_name_from_string_auto(s, &family, &address, &port, NULL, NULL); + r = in_addr_port_ifindex_name_from_string_auto(s, &family, &address, &port, &ifindex, NULL); if (r < 0) return r; @@ -181,6 +181,7 @@ int socket_address_parse(SocketAddress *a, const char *s) { .sin6_family = AF_INET6, .sin6_addr = address.in6, .sin6_port = htobe16(port), + .sin6_scope_id = ifindex, }, .size = sizeof(struct sockaddr_in6), }; diff --git a/src/test/test-socket-netlink.c b/src/test/test-socket-netlink.c index b87cb7b126..ac191851fa 100644 --- a/src/test/test-socket-netlink.c +++ b/src/test/test-socket-netlink.c @@ -59,11 +59,21 @@ static void test_socket_address_parse(void) { test_socket_address_parse_one("[::1]:0", -EINVAL, 0, NULL); test_socket_address_parse_one("[::1]:65536", -ERANGE, 0, NULL); test_socket_address_parse_one("[a:b:1]:8888", -EINVAL, 0, NULL); + test_socket_address_parse_one("[::1]%lo:1234", -EINVAL, 0, NULL); + test_socket_address_parse_one("[::1]%lo:0", -EINVAL, 0, NULL); + test_socket_address_parse_one("[::1]%lo", -EINVAL, 0, NULL); + test_socket_address_parse_one("[::1]%lo%lo:1234", -EINVAL, 0, NULL); + test_socket_address_parse_one("[::1]% lo:1234", -EINVAL, 0, NULL); test_socket_address_parse_one("8888", 0, default_family, "[::]:8888"); test_socket_address_parse_one("[2001:0db8:0000:85a3:0000:0000:ac1f:8001]:8888", 0, AF_INET6, "[2001:db8:0:85a3::ac1f:8001]:8888"); test_socket_address_parse_one("[::1]:8888", 0, AF_INET6, NULL); + test_socket_address_parse_one("[::1]:1234%lo", 0, AF_INET6, NULL); + test_socket_address_parse_one("[::1]:0%lo", -EINVAL, 0, NULL); + test_socket_address_parse_one("[::1]%lo", -EINVAL, 0, NULL); + test_socket_address_parse_one("[::1]:1234%lo%lo", -ENODEV, 0, NULL); + test_socket_address_parse_one("[::1]:1234%xxxxasdf", -ENODEV, 0, NULL); test_socket_address_parse_one("192.168.1.254:8888", 0, AF_INET, NULL); test_socket_address_parse_one("/foo/bar", 0, AF_UNIX, NULL); test_socket_address_parse_one("/", 0, AF_UNIX, NULL); @@ -297,7 +307,8 @@ static void test_in_addr_ifindex_name_from_string_auto(void) { test_in_addr_ifindex_name_from_string_auto_one("fe80::18%19#another.test.com", "another.test.com"); } -static void test_in_addr_port_ifindex_name_from_string_auto_one(const char *str, int family, uint16_t port, int ifindex, const char *server_name) { +static void test_in_addr_port_ifindex_name_from_string_auto_one(const char *str, int family, uint16_t port, int ifindex, + const char *server_name, const char *str_repr) { union in_addr_union a; uint16_t p; int f, i; @@ -313,7 +324,7 @@ static void test_in_addr_port_ifindex_name_from_string_auto_one(const char *str, assert_se(ifindex == i); assert_se(streq_ptr(server_name, name)); assert_se(in_addr_port_ifindex_name_to_string(f, &a, p, i, name, &x) >= 0); - assert_se(streq(str, x)); + assert_se(streq(str_repr ?: str, x)); } if (port > 0) @@ -325,7 +336,7 @@ static void test_in_addr_port_ifindex_name_from_string_auto_one(const char *str, assert_se(ifindex == i); assert_se(streq_ptr(server_name, name)); assert_se(in_addr_port_ifindex_name_to_string(f, &a, 0, i, name, &x) >= 0); - assert_se(streq(str, x)); + assert_se(streq(str_repr ?: str, x)); } if (ifindex > 0) @@ -337,7 +348,7 @@ static void test_in_addr_port_ifindex_name_from_string_auto_one(const char *str, assert_se(port == p); assert_se(streq_ptr(server_name, name)); assert_se(in_addr_port_ifindex_name_to_string(f, &a, p, 0, name, &x) >= 0); - assert_se(streq(str, x)); + assert_se(streq(str_repr ?: str, x)); } if (server_name) @@ -349,25 +360,30 @@ static void test_in_addr_port_ifindex_name_from_string_auto_one(const char *str, assert_se(port == p); assert_se(ifindex == i); assert_se(in_addr_port_ifindex_name_to_string(f, &a, p, i, NULL, &x) >= 0); - assert_se(streq(str, x)); + assert_se(streq(str_repr ?: str, x)); } } static void test_in_addr_port_ifindex_name_from_string_auto(void) { log_info("/* %s */", __func__); - test_in_addr_port_ifindex_name_from_string_auto_one("192.168.0.1", AF_INET, 0, 0, NULL); - test_in_addr_port_ifindex_name_from_string_auto_one("192.168.0.1#test.com", AF_INET, 0, 0, "test.com"); - test_in_addr_port_ifindex_name_from_string_auto_one("192.168.0.1:53", AF_INET, 53, 0, NULL); - test_in_addr_port_ifindex_name_from_string_auto_one("192.168.0.1:53#example.com", AF_INET, 53, 0, "example.com"); - test_in_addr_port_ifindex_name_from_string_auto_one("fe80::18", AF_INET6, 0, 0, NULL); - test_in_addr_port_ifindex_name_from_string_auto_one("fe80::18#hoge.com", AF_INET6, 0, 0, "hoge.com"); - test_in_addr_port_ifindex_name_from_string_auto_one("fe80::18%19", AF_INET6, 0, 19, NULL); - test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53", AF_INET6, 53, 0, NULL); - test_in_addr_port_ifindex_name_from_string_auto_one("fe80::18%19#hoge.com", AF_INET6, 0, 19, "hoge.com"); - test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53#hoge.com", AF_INET6, 53, 0, "hoge.com"); - test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53%19", AF_INET6, 53, 19, NULL); - test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53%19#hoge.com", AF_INET6, 53, 19, "hoge.com"); + test_in_addr_port_ifindex_name_from_string_auto_one("192.168.0.1", AF_INET, 0, 0, NULL, NULL); + test_in_addr_port_ifindex_name_from_string_auto_one("192.168.0.1#test.com", AF_INET, 0, 0, "test.com", NULL); + test_in_addr_port_ifindex_name_from_string_auto_one("192.168.0.1:53", AF_INET, 53, 0, NULL, NULL); + test_in_addr_port_ifindex_name_from_string_auto_one("192.168.0.1:53#example.com", AF_INET, 53, 0, "example.com", NULL); + test_in_addr_port_ifindex_name_from_string_auto_one("fe80::18", AF_INET6, 0, 0, NULL, NULL); + test_in_addr_port_ifindex_name_from_string_auto_one("fe80::18#hoge.com", AF_INET6, 0, 0, "hoge.com", NULL); + test_in_addr_port_ifindex_name_from_string_auto_one("fe80::18%19", AF_INET6, 0, 19, NULL, NULL); + test_in_addr_port_ifindex_name_from_string_auto_one("fe80::18%lo", AF_INET6, 0, 1, NULL, "fe80::18%1"); + test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53", AF_INET6, 53, 0, NULL, NULL); + test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53%19", AF_INET6, 53, 19, NULL, NULL); + test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53%lo", AF_INET6, 53, 1, NULL, "[fe80::18]:53%1"); + test_in_addr_port_ifindex_name_from_string_auto_one("fe80::18%19#hoge.com", AF_INET6, 0, 19, "hoge.com", NULL); + test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53#hoge.com", AF_INET6, 53, 0, "hoge.com", NULL); + test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53%19", AF_INET6, 53, 19, NULL, NULL); + test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53%19#hoge.com", AF_INET6, 53, 19, "hoge.com", NULL); + test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53%lo", AF_INET6, 53, 1, NULL, "[fe80::18]:53%1"); + test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53%lo#hoge.com", AF_INET6, 53, 1, "hoge.com", "[fe80::18]:53%1#hoge.com"); } int main(int argc, char *argv[]) {