]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Allow interface scopes to be specified in ListenStream=
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Thu, 3 Sep 2020 13:33:25 +0000 (15:33 +0200)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Wed, 9 Sep 2020 22:46:44 +0000 (00:46 +0200)
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
src/shared/socket-netlink.c
src/test/test-socket-netlink.c

index 1bcbef20332f029a08d5116c925c90d1bae4d813..253da8a6d4deb4b39ace5dc1bd768bb16a5c8623 100644 (file)
         </para>
 
         <para>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.</para>
+        <literal><replaceable>v.w.x.y</replaceable>:<replaceable>z</replaceable></literal>, it is interpeted
+        as IPv4 address <replaceable>v.w.x.y</replaceable> and port <replaceable>z</replaceable>.</para>
 
-        <para>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
-        <varname>BindIPv6Only=</varname> setting (see below).
-        </para>
+        <para>If the address string is a string in the format
+        <literal>[<replaceable>x</replaceable>]:<replaceable>y</replaceable></literal>, it is interpreted as
+        IPv6 address <replaceable>x</replaceable> and port <replaceable>y</replaceable>. An optional
+        interface scope (interface name or number) may be specifed after a <literal>%</literal> symbol:
+        <literal>[<replaceable>x</replaceable>]:<replaceable>y</replaceable>%<replaceable>dev</replaceable></literal>.
+        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 <varname>BindIPv6Only=</varname> setting (see below).</para>
 
         <para>If the address string is a string in the format
-        <literal>vsock:x:y</literal>, it is read as CID <literal>x</literal> on
-        a port <literal>y</literal> address in the
-        <constant>AF_VSOCK</constant> family.  The CID is a unique 32-bit
-        integer identifier in <constant>AF_VSOCK</constant> analogous to an IP
-        address.  Specifying the CID is optional, and may be set to the empty
-        string.</para>
+        <literal>vsock:<replaceable>x</replaceable>:<replaceable>y</replaceable></literal>, it is read as CID
+        <replaceable>x</replaceable> on a port <replaceable>y</replaceable> address in the
+        <constant>AF_VSOCK</constant> family.  The CID is a unique 32-bit integer identifier in
+        <constant>AF_VSOCK</constant> analogous to an IP address.  Specifying the CID is optional, and may be
+        set to the empty string.</para>
 
         <para>Note that <constant>SOCK_SEQPACKET</constant> (i.e.
         <varname>ListenSequentialPacket=</varname>) is only available
index 198892b007f526c8127fdc83d959162fa222b5d7..0ecbf7dee01659a7ba6955491a1cfbe1ec1da33c 100644 (file)
@@ -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),
                                 };
index b87cb7b126880e5521eafde90362815a17f25a63..ac191851faaa75632fe4b1fafc2c529fa4a01d97 100644 (file)
@@ -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[]) {