diff options
author | Julia Kartseva <hex@fb.com> | 2021-06-30 01:04:32 +0200 |
---|---|---|
committer | Julia Kartseva <hex@fb.com> | 2021-06-30 09:36:26 +0200 |
commit | 8bd095aa9a1ec03dd8ccbbf1963d069fb7b2bdda (patch) | |
tree | c05d12d44f332bec95559c9cf5623d32b46f65d3 /src/shared | |
parent | shared: add ip_protocol_{from|to}_tcp_udp helpers (diff) | |
download | systemd-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.build | 2 | ||||
-rw-r--r-- | src/shared/parse-socket-bind-item.c | 146 | ||||
-rw-r--r-- | src/shared/parse-socket-bind-item.h | 12 |
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); |