From 63cc41a45671dccadaa0723915fc1389327530cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Tue, 13 Dec 2016 20:11:24 -0500 Subject: daemon: add basic support for sd_is_socket_sockaddr Later on a proper wrapper in daemon.py should be added. --- setup.py | 3 +- systemd/_daemon.c | 55 ++++++++++++++++-- systemd/util.c | 169 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ systemd/util.h | 33 +++++++++++ 4 files changed, 254 insertions(+), 6 deletions(-) create mode 100644 systemd/util.c create mode 100644 systemd/util.h diff --git a/setup.py b/setup.py index 529f613..1acfbc5 100644 --- a/setup.py +++ b/setup.py @@ -61,7 +61,8 @@ _reader = Extension('systemd/_reader', **lib('libsystemd', 'libsystemd-journal', **defines)) _daemon = Extension('systemd/_daemon', sources = ['systemd/_daemon.c', - 'systemd/pyutil.c'], + 'systemd/pyutil.c', + 'systemd/util.c'], extra_compile_args=['-Werror=implicit-function-declaration'], **lib('libsystemd', 'libsystemd-daemon', **defines)) id128 = Extension('systemd/id128', diff --git a/systemd/_daemon.c b/systemd/_daemon.c index 87a33f0..f122722 100644 --- a/systemd/_daemon.c +++ b/systemd/_daemon.c @@ -2,7 +2,7 @@ /*** - Copyright 2013 Zbigniew Jędrzejewski-Szmek + Copyright 2013-2016 Zbigniew Jędrzejewski-Szmek python-systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -31,12 +31,18 @@ #include "systemd/sd-daemon.h" #include "pyutil.h" #include "macro.h" +#include "util.h" #if LIBSYSTEMD_VERSION >= 214 # define HAVE_PID_NOTIFY -# if LIBSYSTEMD_VERSION >= 219 -# define HAVE_PID_NOTIFY_WITH_FDS -# endif +#endif + +#if LIBSYSTEMD_VERSION >= 219 +# define HAVE_PID_NOTIFY_WITH_FDS +#endif + +#if LIBSYSTEMD_VERSION >= 233 +# define HAVE_IS_SOCKET_SOCKADDR #endif PyDoc_STRVAR(module__doc__, @@ -311,6 +317,42 @@ static PyObject* is_socket_inet(PyObject *self, PyObject *args) { return PyBool_FromLong(r); } +#ifdef HAVE_IS_SOCKET_SOCKADDR +PyDoc_STRVAR(is_socket_sockaddr__doc__, + "_is_socket_sockaddr(fd, address, type=0, listening=-1) -> bool\n\n" + "Wraps sd_is_socket_inet_sockaddr(3).\n" + "`address` is a systemd-style numerical IPv4 or IPv6 address as used in\n" + "ListenStream=. A port may be included after a colon (\":\"). See\n" + "systemd.socket(5) for details.\n\n" + "Constants for `family` are defined in the socket module." +); + +static PyObject* is_socket_sockaddr(PyObject *self, PyObject *args) { + int r; + int fd, type = 0, listening = -1; + const char *address; + union sockaddr_union addr = {}; + unsigned addr_len; + + if (!PyArg_ParseTuple(args, "is|ii:_is_socket_sockaddr", + &fd, + &address, + &type, &listening)) + return NULL; + + r = parse_sockaddr(address, &addr, &addr_len); + if (r < 0) { + set_error(r, NULL, "Cannot parse address"); + return NULL; + } + + r = sd_is_socket_sockaddr(fd, type, &addr.sa, addr_len, listening); + if (set_error(r, NULL, NULL) < 0) + return NULL; + + return PyBool_FromLong(r); +} +#endif PyDoc_STRVAR(is_socket_unix__doc__, "_is_socket_unix(fd, type, listening, path) -> bool\n\n" @@ -355,8 +397,11 @@ static PyMethodDef methods[] = { { "_is_mq", is_mq, METH_VARARGS, is_mq__doc__}, { "_is_socket", is_socket, METH_VARARGS, is_socket__doc__}, { "_is_socket_inet", is_socket_inet, METH_VARARGS, is_socket_inet__doc__}, +#ifdef HAVE_IS_SOCKET_SOCKADDR + { "_is_socket_sockaddr", is_socket_sockaddr, METH_VARARGS, is_socket_sockaddr__doc__}, +#endif { "_is_socket_unix", is_socket_unix, METH_VARARGS, is_socket_unix__doc__}, - { NULL, NULL, 0, NULL } /* Sentinel */ + {} /* Sentinel */ }; #if PY_MAJOR_VERSION < 3 diff --git a/systemd/util.c b/systemd/util.c new file mode 100644 index 0000000..c6ec3b2 --- /dev/null +++ b/systemd/util.c @@ -0,0 +1,169 @@ +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +/* stuff imported from systemd without any changes */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" + +int safe_atou(const char *s, unsigned *ret_u) { + char *x = NULL; + unsigned long l; + + assert(s); + assert(ret_u); + + /* strtoul() is happy to parse negative values, and silently + * converts them to unsigned values without generating an + * error. We want a clean error, hence let's look for the "-" + * prefix on our own, and generate an error. But let's do so + * only after strtoul() validated that the string is clean + * otherwise, so that we return EINVAL preferably over + * ERANGE. */ + + errno = 0; + l = strtoul(s, &x, 0); + if (errno > 0) + return -errno; + if (!x || x == s || *x) + return -EINVAL; + if (s[0] == '-') + return -ERANGE; + if ((unsigned long) (unsigned) l != l) + return -ERANGE; + + *ret_u = (unsigned) l; + return 0; +} + +static bool socket_ipv6_is_supported(void) { + if (access("/proc/net/if_inet6", F_OK) != 0) + return false; + + return true; +} + +int parse_sockaddr(const char *s, + union sockaddr_union *addr, unsigned *addr_len) { + + char *e, *n; + unsigned u; + int r; + + if (*s == '[') { + /* IPv6 in [x:.....:z]:p notation */ + + e = strchr(s+1, ']'); + if (!e) + return -EINVAL; + + n = strndupa(s+1, e-s-1); + + errno = 0; + if (inet_pton(AF_INET6, n, &addr->in6.sin6_addr) <= 0) + return errno > 0 ? -errno : -EINVAL; + + e++; + if (*e != ':') + return -EINVAL; + + e++; + r = safe_atou(e, &u); + if (r < 0) + return r; + + if (u <= 0 || u > 0xFFFF) + return -EINVAL; + + addr->in6.sin6_family = AF_INET6; + addr->in6.sin6_port = htobe16((uint16_t)u); + *addr_len = sizeof(struct sockaddr_in6); + + } else { + e = strchr(s, ':'); + if (e) { + r = safe_atou(e+1, &u); + if (r < 0) + return r; + + if (u <= 0 || u > 0xFFFF) + return -EINVAL; + + n = strndupa(s, e-s); + + /* 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; + + if (u <= 0 || u > 0xFFFF) + return -EINVAL; + + if (socket_ipv6_is_supported()) { + addr->in6.sin6_family = AF_INET6; + addr->in6.sin6_port = htobe16((uint16_t)u); + addr->in6.sin6_addr = in6addr_any; + *addr_len = sizeof(struct sockaddr_in6); + } else { + addr->in.sin_family = AF_INET; + addr->in.sin_port = htobe16((uint16_t)u); + addr->in.sin_addr.s_addr = INADDR_ANY; + *addr_len = sizeof(struct sockaddr_in); + } + } + } + + return 0; +} diff --git a/systemd/util.h b/systemd/util.h new file mode 100644 index 0000000..337920c --- /dev/null +++ b/systemd/util.h @@ -0,0 +1,33 @@ +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +union sockaddr_union { + struct sockaddr sa; + struct sockaddr_in in; + struct sockaddr_in6 in6; +}; + +int safe_atou(const char *s, unsigned *ret_u); +int parse_sockaddr(const char *s, + union sockaddr_union *addr, unsigned *addr_len); -- cgit v1.2.1