diff options
| -rw-r--r-- | Makefile | 1 | ||||
| -rw-r--r-- | conf.c | 6 | ||||
| -rw-r--r-- | fwd_rule.c | 21 | ||||
| -rw-r--r-- | inany.c | 24 | ||||
| -rw-r--r-- | inany.h | 1 | ||||
| -rw-r--r-- | parse.c | 91 | ||||
| -rw-r--r-- | parse.h | 4 |
7 files changed, 109 insertions, 39 deletions
@@ -227,4 +227,5 @@ pesto.cppcheck: CPPCHECK_FLAGS += --suppress=unusedFunction:inany.c pesto.cppcheck: CPPCHECK_FLAGS += --suppress=unusedFunction:ip.h pesto.cppcheck: CPPCHECK_FLAGS += --suppress=unusedFunction:serialise.c pesto.cppcheck: CPPCHECK_FLAGS += --suppress=staticFunction:fwd_rule.c +pesto.cppcheck: CPPCHECK_FLAGS += --suppress=staticFunction:parse.c pesto.cppcheck: $(PESTO_SRCS) $(PESTO_HEADERS) seccomp_pesto.h @@ -357,7 +357,7 @@ static uint8_t conf_ip4_prefix(const char *arg) struct in_addr mask; unsigned long len; - if (inet_pton(AF_INET, arg, &mask)) { + if (parse_ipv4(&p, &mask) && parse_eoi(p)) { in_addr_t hmask = ntohl(mask.s_addr); len = __builtin_popcount(hmask); if ((hmask << len) == 0) @@ -1577,7 +1577,9 @@ void conf(struct ctx *c, int argc, char **argv) if (addr_has_prefix_len && prefix_len_from_opt) die("Redundant prefix length specification"); - if (!addr_has_prefix_len && !inany_pton(optarg, &addr)) + p = optarg; + if (!addr_has_prefix_len && + !(parse_inany(&p, &addr) && parse_eoi(p))) die("Invalid address: %s", optarg); if (prefix_len_from_opt && inany_v4(&addr)) @@ -595,6 +595,8 @@ void fwd_rule_parse(char optname, bool del, const char *optarg, strncpy(buf, optarg, sizeof(buf) - 1); if ((spec = strchr(buf, '/'))) { + const char *p = buf; + *spec = 0; spec++; @@ -616,22 +618,11 @@ void fwd_rule_parse(char optname, bool del, const char *optarg, } } - if (ifname == buf + 1) { /* Interface without address */ + if (ifname == buf + 1 || /* Interface without address */ + !strcmp(buf, "*")) /* Explicit wildcard address */ addr = NULL; - } else { - char *p = buf; - - /* Allow square brackets for IPv4 too for convenience */ - if (*p == '[' && p[strlen(p) - 1] == ']') { - p[strlen(p) - 1] = '\0'; - p++; - } - - if (strcmp(p, "*") == 0) - addr = NULL; - else if (!inany_pton(p, &addr_buf)) - die("Bad forwarding address '%s'", p); - } + else if (!parse_inany(&p, &addr_buf) && parse_eoi(p)) + die("Bad forwarding address '%s'", buf); } else { spec = buf; @@ -27,6 +27,7 @@ #include "ip.h" #include "inany.h" #include "fwd.h" +#include "parse.h" const union inany_addr inany_loopback4 = INANY_INIT4(IN4ADDR_LOOPBACK_INIT); const union inany_addr inany_any4 = INANY_INIT4(IN4ADDR_ANY_INIT); @@ -70,26 +71,6 @@ const char *inany_ntop(const union inany_addr *src, char *dst, socklen_t size) return inet_ntop(AF_INET6, &src->a6, dst, size); } -/** inany_pton - Parse an IPv[46] address from text format - * @src: IPv[46] address - * @dst: output buffer, filled with parsed address - * - * Return: on success, 1, if no parseable address is found, 0 - */ -int inany_pton(const char *src, union inany_addr *dst) -{ - if (inet_pton(AF_INET, src, &dst->v4mapped.a4)) { - memset(&dst->v4mapped.zero, 0, sizeof(dst->v4mapped.zero)); - memset(&dst->v4mapped.one, 0xff, sizeof(dst->v4mapped.one)); - return 1; - } - - if (inet_pton(AF_INET6, src, &dst->a6)) - return 1; - - return 0; -} - /** * inany_prefix_pton() - Parse an IPv[46] address with prefix length * @src: IPv[46] address and prefix length string in CIDR format @@ -104,6 +85,7 @@ int inany_prefix_pton(const char *src, union inany_addr *dst, char astr[INANY_ADDRSTRLEN] = { 0 }; size_t alen = strcspn(src, "/"); const char *pstr = &src[alen + 1]; + const char *p = astr; unsigned long plen; char *end; @@ -129,7 +111,7 @@ int inany_prefix_pton(const char *src, union inany_addr *dst, return 1; } - if (inany_pton(astr, dst)) { + if (parse_inany(&p, dst) && parse_eoi(p)) { if (plen > 32) return 0; *prefix_len = plen + 96; @@ -303,7 +303,6 @@ static inline int inany_from_sockaddr(union inany_addr *dst, in_port_t *port, bool inany_matches(const union inany_addr *a, const union inany_addr *b); const char *inany_ntop(const union inany_addr *src, char *dst, socklen_t size); -int inany_pton(const char *src, union inany_addr *dst); int inany_prefix_pton(const char *src, union inany_addr *dst, uint8_t *prefix_len); @@ -16,9 +16,12 @@ #include <stddef.h> #include <stdlib.h> #include <string.h> +#include <limits.h> +#include <arpa/inet.h> #include "common.h" #include "parse.h" +#include "inany.h" /** * DOC: Theory of Operation @@ -111,3 +114,91 @@ bool parse_port_range(const char **cursor, struct port_range *range) *cursor = p; return true; } + +/** + * parse_ipv4() - Parse an IPv4 address from a string + * @abuf: On success, updated with parsed address + */ +bool parse_ipv4(const char **cursor, struct in_addr *abuf) +{ + /* Brackets are not typical on IPv4, but allow for consistency */ + const char *p = *cursor; + bool bracket = parse_literal(&p, "["); + char buf[INET_ADDRSTRLEN]; + struct in_addr addr; + size_t len; + + if (bracket) + len = strcspn(p, "]"); + else + len = strspn(p, "0123456789."); + + if (len >= sizeof(buf)) + return false; + memcpy(buf, p, len); + buf[len] = '\0'; + p += len; + + if (!inet_pton(AF_INET, buf, &addr)) + return false; + + if (bracket && !parse_literal(&p, "]")) + return false; + + *cursor = p; + *abuf = addr; + return true; +} + +/** + * parse_ipv6() - Parse an IPv6 address from a string + * @abuf: On success, updated with parsed address + */ +static bool parse_ipv6(const char **cursor, struct in6_addr *abuf) +{ + const char *p = *cursor; + bool bracket = parse_literal(&p, "["); + char buf[INET6_ADDRSTRLEN]; + struct in6_addr addr; + size_t len; + + if (bracket) + len = strcspn(p, "]"); + else + len = strspn(p, "0123456789aAbBcCdDeEfF:."); + + if (len >= sizeof(buf)) + return false; + memcpy(buf, p, len); + buf[len] = '\0'; + p += len; + + if (!inet_pton(AF_INET6, buf, &addr)) + return false; + + if (bracket && !parse_literal(&p, "]")) + return false; + + *cursor = p; + *abuf = addr; + return true; +} + +/** + * parse_inany() - Parse an IPv4 or IPv6 address from a string + * @addr: On success, updated with parsed address + */ +bool parse_inany(const char **cursor, union inany_addr *addr) +{ + struct in_addr a4; + + if (parse_ipv6(cursor, &addr->a6)) + return true; + + if (parse_ipv4(cursor, &a4)) { + *addr = inany_from_v4(a4); + return true; + } + + return false; +} @@ -9,6 +9,8 @@ #include <stdbool.h> #include <netinet/in.h> +union inany_addr; + /** * port_range() - Represents a non-empty range of ports * @first: First port number in the range @@ -24,5 +26,7 @@ bool parse_literal(const char **cursor, const char *lit); bool parse_eoi(const char *cursor); bool parse_unsigned(const char **cursor, int base, unsigned long *valp); bool parse_port_range(const char **cursor, struct port_range *range); +bool parse_ipv4(const char **cursor, struct in_addr *abuf); +bool parse_inany(const char **cursor, union inany_addr *addr); #endif /* _PARSE_H */ |
