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?
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2020-09-03 15:33:25 +02:00
parent c4c6ee3a95
commit a07ab56a49
3 changed files with 52 additions and 33 deletions

View File

@ -200,22 +200,24 @@
</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>
<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>
<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
<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>[<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:<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

View 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),
};

View 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[]) {