summaryrefslogtreecommitdiffstats
path: root/src/shared
diff options
context:
space:
mode:
authorJulia Kartseva <hex@fb.com>2021-06-30 01:04:32 +0200
committerJulia Kartseva <hex@fb.com>2021-06-30 09:36:26 +0200
commit8bd095aa9a1ec03dd8ccbbf1963d069fb7b2bdda (patch)
treec05d12d44f332bec95559c9cf5623d32b46f65d3 /src/shared
parentshared: add ip_protocol_{from|to}_tcp_udp helpers (diff)
downloadsystemd-8bd095aa9a1ec03dd8ccbbf1963d069fb7b2bdda.tar.xz
systemd-8bd095aa9a1ec03dd8ccbbf1963d069fb7b2bdda.zip
shared: add parser for SocketBind{Allow|Deny}=
Parse address family, ip protocol and ports, any of them can be optional. If neither is specified, a special value 'any' is expected. Helper is placed in shared to be reused in both fragment and dbus. Add unit tests with valid and invalid examples.
Diffstat (limited to 'src/shared')
-rw-r--r--src/shared/meson.build2
-rw-r--r--src/shared/parse-socket-bind-item.c146
-rw-r--r--src/shared/parse-socket-bind-item.h12
3 files changed, 160 insertions, 0 deletions
diff --git a/src/shared/meson.build b/src/shared/meson.build
index 5008cda500..7eb7050062 100644
--- a/src/shared/meson.build
+++ b/src/shared/meson.build
@@ -225,6 +225,8 @@ shared_sources = files('''
pager.h
parse-argument.c
parse-argument.h
+ parse-socket-bind-item.c
+ parse-socket-bind-item.h
pe-header.h
pkcs11-util.c
pkcs11-util.h
diff --git a/src/shared/parse-socket-bind-item.c b/src/shared/parse-socket-bind-item.c
new file mode 100644
index 0000000000..214abd8b4f
--- /dev/null
+++ b/src/shared/parse-socket-bind-item.c
@@ -0,0 +1,146 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "af-list.h"
+#include "extract-word.h"
+#include "ip-protocol-list.h"
+#include "parse-socket-bind-item.h"
+#include "parse-util.h"
+
+static int parse_af_token(
+ const char *token,
+ int *family,
+ int *ip_protocol,
+ uint16_t *nr_ports,
+ uint16_t *port_min) {
+ int af;
+
+ assert(token);
+ assert(family);
+
+ af = af_from_ipv4_ipv6(token);
+ if (af == AF_UNSPEC)
+ return -EINVAL;
+
+ *family = af;
+ return 0;
+}
+
+static int parse_ip_protocol_token(
+ const char *token,
+ int *family,
+ int *ip_protocol,
+ uint16_t *nr_ports,
+ uint16_t *port_min) {
+ int proto;
+
+ assert(token);
+ assert(ip_protocol);
+
+ proto = ip_protocol_from_tcp_udp(token);
+ if (proto < 0)
+ return -EINVAL;
+
+ *ip_protocol = proto;
+ return 0;
+}
+
+static int parse_ip_ports_token(
+ const char *token,
+ int *family,
+ int *ip_protocol,
+ uint16_t *nr_ports,
+ uint16_t *port_min) {
+ assert(token);
+ assert(nr_ports);
+ assert(port_min);
+
+ if (streq(token, "any"))
+ *nr_ports = *port_min = 0;
+ else {
+ uint16_t mn = 0, mx = 0;
+ int r = parse_ip_port_range(token, &mn, &mx);
+ if (r < 0)
+ return r;
+
+ *nr_ports = mx - mn + 1;
+ *port_min = mn;
+ }
+
+ return 0;
+}
+
+typedef int (*parse_token_f)(
+ const char *,
+ int *,
+ int *,
+ uint16_t *,
+ uint16_t *);
+
+int parse_socket_bind_item(
+ const char *str,
+ int *address_family,
+ int *ip_protocol,
+ uint16_t *nr_ports,
+ uint16_t *port_min) {
+ /* Order of token parsers is important. */
+ const parse_token_f parsers[] = {
+ &parse_af_token,
+ &parse_ip_protocol_token,
+ &parse_ip_ports_token,
+ };
+ parse_token_f const *parser_ptr = parsers;
+ int af = AF_UNSPEC, proto = 0, r;
+ uint16_t nr = 0, mn = 0;
+ const char *p = str;
+
+ assert(str);
+ assert(address_family);
+ assert(ip_protocol);
+ assert(nr_ports);
+ assert(port_min);
+
+ if (isempty(p))
+ return -EINVAL;
+
+ for (;;) {
+ _cleanup_free_ char *token = NULL;
+
+ r = extract_first_word(&p, &token, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
+ if (r == 0)
+ break;
+ if (r < 0)
+ return r;
+
+ if (isempty(token))
+ return -EINVAL;
+
+ while (parser_ptr != parsers + ELEMENTSOF(parsers)) {
+ r = (*parser_ptr)(token, &af, &proto, &nr, &mn);
+ if (r == -ENOMEM)
+ return r;
+
+ ++parser_ptr;
+ /* Continue to next token if parsing succeeded,
+ * otherwise apply next parser to the same token.
+ */
+ if (r >= 0)
+ break;
+ }
+ if (parser_ptr == parsers + ELEMENTSOF(parsers))
+ break;
+ }
+
+ /* Failed to parse a token. */
+ if (r < 0)
+ return r;
+
+ /* Parsers applied succesfully, but end of the string not reached. */
+ if (p)
+ return -EINVAL;
+
+ *address_family = af;
+ *ip_protocol = proto;
+ *nr_ports = nr;
+ *port_min = mn;
+ return 0;
+}
diff --git a/src/shared/parse-socket-bind-item.h b/src/shared/parse-socket-bind-item.h
new file mode 100644
index 0000000000..c8cff8d730
--- /dev/null
+++ b/src/shared/parse-socket-bind-item.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#pragma once
+
+#include <stdint.h>
+
+int parse_socket_bind_item(
+ const char *str,
+ int *address_family,
+ int *ip_protocol,
+ uint16_t *nr_ports,
+ uint16_t *port_min);