mirror of
				https://github.com/openresty/openresty.git
				synced 2024-10-13 00:29:41 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			264 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			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];
 |