From bc691d8e293a593fbd14ad1d592d06f4f490ed29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Thu, 15 Dec 2016 20:47:10 -0500 Subject: Fix handling of addresses without port and add tests --- systemd/test/test_daemon.py | 19 +++++----- systemd/util.c | 90 ++++++++++++++++++++++++++------------------- 2 files changed, 62 insertions(+), 47 deletions(-) diff --git a/systemd/test/test_daemon.py b/systemd/test/test_daemon.py index 272c46f..5e9f5b8 100644 --- a/systemd/test/test_daemon.py +++ b/systemd/test/test_daemon.py @@ -158,27 +158,28 @@ def test_is_socket_sockaddr(): with contextlib.closing(socket.socket(socket.AF_INET)) as sock: sock.bind(('127.0.0.1', 0)) addr, port = sock.getsockname() + port = ':{}'.format(port) for listening in (0, 1): for arg in (sock, sock.fileno()): - # assert is_socket_sockaddr(arg, '127.0.0.1', socket.SOCK_STREAM) - assert is_socket_sockaddr(arg, '127.0.0.1:{}'.format(port), socket.SOCK_STREAM) + assert is_socket_sockaddr(arg, '127.0.0.1', socket.SOCK_STREAM) + assert is_socket_sockaddr(arg, '127.0.0.1' + port, socket.SOCK_STREAM) - assert is_socket_sockaddr(arg, '127.0.0.1:{}'.format(port), listening=listening) - assert is_socket_sockaddr(arg, '127.0.0.1:{}'.format(port), listening=-1) - assert not is_socket_sockaddr(arg, '127.0.0.1:{}'.format(port), listening=not listening) + assert is_socket_sockaddr(arg, '127.0.0.1' + port, listening=listening) + assert is_socket_sockaddr(arg, '127.0.0.1' + port, listening=-1) + assert not is_socket_sockaddr(arg, '127.0.0.1' + port, listening=not listening) with pytest.raises(ValueError): is_socket_sockaddr(arg, '127.0.0.1', flowinfo=123456) - assert not is_socket_sockaddr(arg, '129.168.11.11:23'.format(port), socket.SOCK_STREAM) - #assert not is_socket_sockaddr(arg, '127.0.0.1', socket.SOCK_DGRAM) + assert not is_socket_sockaddr(arg, '129.168.11.11:23', socket.SOCK_STREAM) + assert not is_socket_sockaddr(arg, '127.0.0.1', socket.SOCK_DGRAM) with pytest.raises(ValueError): _is_socket_sockaddr(arg, '127.0.0.1', 0, 123456) - assert not _is_socket_sockaddr(arg, '129.168.11.11:23'.format(port), socket.SOCK_STREAM) - #assert not _is_socket_sockaddr(arg, '127.0.0.1', socket.SOCK_DGRAM) + assert not _is_socket_sockaddr(arg, '129.168.11.11:23', socket.SOCK_STREAM) + assert not _is_socket_sockaddr(arg, '127.0.0.1', socket.SOCK_DGRAM) sock.listen(11) diff --git a/systemd/util.c b/systemd/util.c index f4551c3..e02c825 100644 --- a/systemd/util.c +++ b/systemd/util.c @@ -71,6 +71,43 @@ static bool socket_ipv6_is_supported(void) { return true; } +static int assign_address(const char *s, + uint16_t port, + union sockaddr_union *addr, unsigned *addr_len) { + int r; + + /* IPv4 in w.x.y.z:p notation? */ + r = inet_pton(AF_INET, s, &addr->in.sin_addr); + if (r < 0) + return -errno; + + if (r > 0) { + /* Gotcha, it's a traditional IPv4 address */ + addr->in.sin_family = AF_INET; + addr->in.sin_port = htobe16(port); + *addr_len = sizeof(struct sockaddr_in); + } else { + unsigned idx; + + if (strlen(s) > IF_NAMESIZE-1) + return -EINVAL; + + /* Uh, our last resort, an interface name */ + idx = if_nametoindex(s); + if (idx == 0) + return -EINVAL; + + addr->in6.sin6_family = AF_INET6; + addr->in6.sin6_port = htobe16(port); + addr->in6.sin6_scope_id = idx; + addr->in6.sin6_addr = in6addr_any; + *addr_len = sizeof(struct sockaddr_in6); + } + + return 0; +} + + int parse_sockaddr(const char *s, union sockaddr_union *addr, unsigned *addr_len) { @@ -92,19 +129,22 @@ int parse_sockaddr(const char *s, return errno > 0 ? -errno : -EINVAL; e++; - if (*e != ':') - return -EINVAL; + if (*e) { + if (*e != ':') + return -EINVAL; - e++; - r = safe_atou(e, &u); - if (r < 0) - return r; + e++; + r = safe_atou(e, &u); + if (r < 0) + return r; - if (u <= 0 || u > 0xFFFF) - return -EINVAL; + if (u <= 0 || u > 0xFFFF) + return -EINVAL; + + addr->in6.sin6_port = htobe16((uint16_t)u); + } addr->in6.sin6_family = AF_INET6; - addr->in6.sin6_port = htobe16((uint16_t)u); *addr_len = sizeof(struct sockaddr_in6); } else { @@ -118,40 +158,14 @@ int parse_sockaddr(const char *s, return -EINVAL; n = strndupa(s, e-s); + return assign_address(n, u, addr, addr_len); - /* IPv4 in w.x.y.z:p notation? */ - r = inet_pton(AF_INET, n, &addr->in.sin_addr); - if (r < 0) - return -errno; - - if (r > 0) { - /* Gotcha, it's a traditional IPv4 address */ - addr->in.sin_family = AF_INET; - addr->in.sin_port = htobe16((uint16_t)u); - *addr_len = sizeof(struct sockaddr_in); - } else { - unsigned idx; - - if (strlen(n) > IF_NAMESIZE-1) - return -EINVAL; - - /* Uh, our last resort, an interface name */ - idx = if_nametoindex(n); - if (idx == 0) - return -EINVAL; - - addr->in6.sin6_family = AF_INET6; - addr->in6.sin6_port = htobe16((uint16_t)u); - addr->in6.sin6_scope_id = idx; - addr->in6.sin6_addr = in6addr_any; - *addr_len = sizeof(struct sockaddr_in6); - } } else { - /* Just a port */ r = safe_atou(s, &u); if (r < 0) - return r; + return assign_address(s, 0, addr, addr_len); + /* Just a port */ if (u <= 0 || u > 0xFFFF) return -EINVAL; -- cgit v1.2.1