diff options
author | Glenn Strauss <gstrauss@gluelogic.com> | 2021-06-19 22:39:20 -0400 |
---|---|---|
committer | Glenn Strauss <gstrauss@gluelogic.com> | 2021-08-27 02:16:54 -0400 |
commit | 4b9da9f1e8fb12dc136d1a384d003ac502385159 (patch) | |
tree | 0cf73a1d4836d2749508cdcd9915a9a04a3106b0 /src/configfile.c | |
parent | e34ce5f2177eb70089549662f42d61e176a75421 (diff) | |
download | lighttpd-git-4b9da9f1e8fb12dc136d1a384d003ac502385159.tar.gz |
[core] parse $HTTP["remote-ip"] CIDR mask at start
parse $HTTP["remote-ip"] CIDR mask into structured data at startup
note: adds buffer_move() to configparser.y to reduce memory copying
for all config values, and is required for remote-ip to preserve the
structured data added after the config value string. (Alternatively,
could have normalized the remote-ip value after copying into dc->string)
Diffstat (limited to 'src/configfile.c')
-rw-r--r-- | src/configfile.c | 69 |
1 files changed, 69 insertions, 0 deletions
diff --git a/src/configfile.c b/src/configfile.c index a673ad99..74b61aad 100644 --- a/src/configfile.c +++ b/src/configfile.c @@ -13,6 +13,7 @@ #include "configfile.h" #include "plugin.h" #include "reqpool.h" +#include "sock_addr.h" #include "stat_cache.h" #include "sys-crypto.h" @@ -2393,6 +2394,74 @@ int config_parse_cmd(server *srv, config_t *context, const char *cmd) { return ret; } +static int config_remoteip_normalize_ipv6(buffer * const b, buffer * const tb) { + /* $HTTP["remote-ip"] IPv6 accepted with or without '[]' for config compat + * http_request_host_normalize() expects IPv6 with '[]', + * and config processing at runtime expects COMP_HTTP_REMOTE_IP + * compared without '[]', so strip '[]' after normalization */ + buffer_clear(tb); + if (b->ptr[0] != '[') + buffer_append_str3(tb, + CONST_STR_LEN("["), + BUF_PTR_LEN(b), + CONST_STR_LEN("]")); + else + buffer_append_string_buffer(tb, b); + + int rc = http_request_host_normalize(tb, 0); + if (0 == rc) { + /* remove surrounding '[]' */ + size_t blen = buffer_clen(tb); + if (blen > 1) buffer_copy_string_len(b, tb->ptr+1, blen-2); + } + return rc; +} + +int config_remoteip_normalize(buffer * const b, buffer * const tb) { + if (b->ptr[0] == '/') return 1; /*(skip AF_UNIX /path/file)*/ + + const char * const slash = strchr(b->ptr, '/'); /* CIDR mask */ + const char * const colon = strchr(b->ptr, ':'); /* IPv6 */ + unsigned long nm_bits = 0; + + if (NULL != slash) { + char *nptr; + nm_bits = strtoul(slash + 1, &nptr, 10); + if (*nptr || 0 == nm_bits || nm_bits > (NULL != colon ? 128 : 32)) { + /*(also rejects (slash+1 == nptr) which results in nm_bits = 0)*/ + return -1; + } + buffer_truncate(b, (size_t)(slash - b->ptr)); + } + + int family = colon ? AF_INET6 : AF_INET; + int rc = (family == AF_INET) + ? http_request_host_normalize(b, 0) + : config_remoteip_normalize_ipv6(b, tb); + + uint32_t len = buffer_clen(b); /*(save len before adding CIDR mask)*/ + if (nm_bits) { + buffer_append_string_len(b, CONST_STR_LEN("/")); + buffer_append_int(b, (int)nm_bits); + } + + if (0 != rc) { + return -1; + } + + /* extend b to hold structured data after end of string: + * nm_bits and memory-aligned sock_addr for AF_INET or AF_INET6 (28 bytes)*/ + char *after = buffer_string_prepare_append(b, 1 + 7 + 28); + ++after; /*(increment to pos after string end '\0')*/ + *(unsigned char *)after = (unsigned char)nm_bits; + sock_addr * const addr = (sock_addr *)(((uintptr_t)after+1+7) & ~7); + if (nm_bits) b->ptr[len] = '\0'; /*(sock_addr_inet_pton() w/o CIDR mask)*/ + rc = sock_addr_inet_pton(addr, b->ptr, family, 0); + if (nm_bits) b->ptr[len] = '/'; + return (1 == rc); +} + + static void context_init(server *srv, config_t *context) { context->srv = srv; context->ok = 1; |