openresty/patches/nginx-1.19.3-resolver_conf_...

264 lines
7.6 KiB
C

diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c
index cd55520c..dade1846 100644
--- a/src/core/ngx_resolver.c
+++ b/src/core/ngx_resolver.c
@@ -9,12 +9,26 @@
#include <ngx_core.h>
#include <ngx_event.h>
+#if !(NGX_WIN32)
+#include <resolv.h>
+#endif
+
#define NGX_RESOLVER_UDP_SIZE 4096
#define NGX_RESOLVER_TCP_RSIZE (2 + 65535)
#define NGX_RESOLVER_TCP_WSIZE 8192
+#if !(NGX_WIN32)
+/*
+ * note that 2KB should be more than enough for majority of the
+ * resolv.conf files out there. it also acts as a safety guard to prevent
+ * abuse.
+ */
+#define NGX_RESOLVER_FILE_BUF_SIZE 2048
+#define NGX_RESOLVER_FILE_NAME "/etc/resolv.conf"
+#endif
+
typedef struct {
u_char ident_hi;
@@ -131,6 +145,191 @@ static ngx_resolver_node_t *ngx_resolver_lookup_addr6(ngx_resolver_t *r,
#endif
+#if !(NGX_WIN32)
+static ngx_int_t
+ngx_resolver_read_resolv_conf(ngx_conf_t *cf, ngx_resolver_t *r, u_char *path,
+ size_t path_len)
+{
+ ngx_url_t u;
+ ngx_resolver_connection_t *rec;
+ ngx_fd_t fd;
+ ngx_file_t file;
+ u_char buf[NGX_RESOLVER_FILE_BUF_SIZE];
+ u_char ipv6_buf[NGX_INET6_ADDRSTRLEN];
+ ngx_uint_t address = 0, j, total = 0;
+ ssize_t n, i;
+ enum {
+ sw_nameserver,
+ sw_spaces,
+ sw_address,
+ sw_skip
+ } state;
+
+ file.name.data = path;
+ file.name.len = path_len;
+
+ if (ngx_conf_full_name(cf->cycle, &file.name, 1) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ fd = ngx_open_file(file.name.data, NGX_FILE_RDONLY,
+ NGX_FILE_OPEN, 0);
+
+ if (fd == NGX_INVALID_FILE) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
+ ngx_open_file_n " \"%s\" failed", file.name.data);
+
+ return NGX_ERROR;
+ }
+
+ ngx_memzero(&file, sizeof(ngx_file_t));
+
+ file.fd = fd;
+ file.log = cf->log;
+
+ state = sw_nameserver;
+
+ n = ngx_read_file(&file, buf, NGX_RESOLVER_FILE_BUF_SIZE, 0);
+
+ if (n == NGX_ERROR) {
+ ngx_conf_log_error(NGX_LOG_ALERT, cf, ngx_errno,
+ ngx_read_file_n " \"%s\" failed", file.name.data);
+ }
+
+ if (ngx_close_file(file.fd) == NGX_FILE_ERROR) {
+ ngx_conf_log_error(NGX_LOG_ALERT, cf, ngx_errno,
+ ngx_close_file_n " \"%s\" failed", file.name.data);
+ }
+
+ if (n == NGX_ERROR) {
+ return NGX_ERROR;
+ }
+
+ if (n == 0) {
+ return NGX_OK;
+ }
+
+ for (i = 0; i < n && total < MAXNS; /* void */) {
+ if (buf[i] == '#' || buf[i] == ';') {
+ state = sw_skip;
+ }
+
+ switch (state) {
+
+ case sw_nameserver:
+
+ if ((size_t) n - i >= sizeof("nameserver") - 1
+ && ngx_memcmp(buf + i, "nameserver",
+ sizeof("nameserver") - 1) == 0)
+ {
+ state = sw_spaces;
+ i += sizeof("nameserver") - 1;
+
+ continue;
+ }
+
+ break;
+
+ case sw_spaces:
+ if (buf[i] != '\t' && buf[i] != ' ') {
+ address = i;
+ state = sw_address;
+ }
+
+ break;
+
+ case sw_address:
+
+ if (buf[i] == CR || buf[i] == LF || i == n - 1) {
+ ngx_memzero(&u, sizeof(ngx_url_t));
+
+ u.url.data = buf + address;
+
+ if (i == n - 1 && buf[i] != CR && buf[i] != LF) {
+ u.url.len = n - address;
+
+ } else {
+ u.url.len = i - address;
+ }
+
+ u.default_port = 53;
+
+ /* IPv6? */
+ if (ngx_strlchr(u.url.data, u.url.data + u.url.len,
+ ':') != NULL)
+ {
+ if (u.url.len + 2 > sizeof(ipv6_buf)) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "IPv6 resolver address is too long:"
+ " \"%V\"", &u.url);
+
+ return NGX_ERROR;
+ }
+
+ ipv6_buf[0] = '[';
+ ngx_memcpy(ipv6_buf + 1, u.url.data, u.url.len);
+ ipv6_buf[u.url.len + 1] = ']';
+
+ u.url.data = ipv6_buf;
+ u.url.len = u.url.len + 2;
+ }
+
+ if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
+ if (u.err) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "%s in resolver \"%V\"",
+ u.err, &u.url);
+ }
+
+ return NGX_ERROR;
+ }
+
+ rec = ngx_array_push_n(&r->connections, u.naddrs);
+ if (rec == NULL) {
+ return NGX_ERROR;
+ }
+
+ ngx_memzero(rec, u.naddrs * sizeof(ngx_resolver_connection_t));
+
+ for (j = 0; j < u.naddrs; j++) {
+ rec[j].sockaddr = u.addrs[j].sockaddr;
+ rec[j].socklen = u.addrs[j].socklen;
+ rec[j].server = u.addrs[j].name;
+ rec[j].resolver = r;
+ }
+
+ total++;
+
+#if (NGX_DEBUG)
+ /*
+ * logs with level below NGX_LOG_NOTICE will not be printed
+ * in this early phase
+ */
+ ngx_conf_log_error(NGX_LOG_NOTICE, cf, 0,
+ "parsed a resolver: \"%V\"", &u.url);
+#endif
+
+ state = sw_nameserver;
+ }
+
+ break;
+
+ case sw_skip:
+ if (buf[i] == CR || buf[i] == LF) {
+ state = sw_nameserver;
+ }
+
+ break;
+ }
+
+ i++;
+ }
+
+ return NGX_OK;
+}
+#endif
+
+
ngx_resolver_t *
ngx_resolver_create(ngx_conf_t *cf, ngx_str_t *names, ngx_uint_t n)
{
@@ -246,6 +445,39 @@ ngx_resolver_create(ngx_conf_t *cf, ngx_str_t *names, ngx_uint_t n)
}
#endif
+#if !(NGX_WIN32)
+ if (ngx_strncmp(names[i].data, "local=", 6) == 0) {
+
+ if (ngx_strcmp(&names[i].data[6], "on") == 0) {
+ if (ngx_resolver_read_resolv_conf(cf, r,
+ (u_char *)
+ NGX_RESOLVER_FILE_NAME,
+ sizeof(NGX_RESOLVER_FILE_NAME)
+ - 1)
+ != NGX_OK)
+ {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "unable to parse local resolver");
+ return NULL;
+ }
+
+ } else if (ngx_strcmp(&names[i].data[6], "off") != 0) {
+ if (ngx_resolver_read_resolv_conf(cf, r,
+ &names[i].data[6],
+ names[i].len - 6)
+ != NGX_OK)
+ {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "unable to parse local resolver");
+ return NULL;
+ }
+
+ }
+
+ continue;
+ }
+#endif
+
ngx_memzero(&u, sizeof(ngx_url_t));
u.url = names[i];