├── CHANGES ├── LICENSE ├── README.md ├── config ├── http-upstream-dynamic.patch ├── http-upstream-dynamic.patch-1.14.0+ └── ngx_http_upstream_dynamic_module.c /CHANGES: -------------------------------------------------------------------------------- 1 | * Initial check in, forked from https://github.com/alibaba/tengine 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2002-2013 Igor Sysoev 3 | * Copyright (C) 2011,2013 Nginx, Inc. 4 | * Copyright (C) 2010-2015 Alibaba Group Holding Limited 5 | * Copyright (C) 2011-2013 Xiaozhe "chaoslawful" Wang 6 | * Copyright (C) 2011-2013 Zhang "agentzh" Yichun 7 | * Copyright (C) 2011-2013 Weibin Yao 8 | * Copyright (C) 2012-2013 Sogou, Inc. 9 | * Copyright (C) 2012-2013 NetEase, Inc. 10 | * All rights reserved. 11 | * 12 | * Redistribution and use in source and binary forms, with or without 13 | * modification, are permitted provided that the following conditions 14 | * are met: 15 | * 1. Redistributions of source code must retain the above copyright 16 | * notice, this list of conditions and the following disclaimer. 17 | * 2. Redistributions in binary form must reproduce the above copyright 18 | * notice, this list of conditions and the following disclaimer in the 19 | * documentation and/or other materials provided with the distribution. 20 | * 21 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 | * SUCH DAMAGE. 32 | */ 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Name 2 | ==== 3 | 4 | * ngx_http_upstream_dynamic_module 5 | 6 | Description 7 | =========== 8 | 9 | * This module provides the functionality to resolve domain names into IP addresses in an upstream at run-time. 10 | * It comes from Taobao Tengine @ http://tengine.taobao.org 11 | 12 | Compilation 13 | =========== 14 | 15 | ``` 16 | \#for nginx 1.10 or lower, use the patch http-upstream-dynamic.patch 17 | \#for nginx 1.14 or higher, use the patch http-upstream-dynamic.patch-1.14.0+ 18 | 19 | patch -p0 < /path/to/nginx-http-upstream-dynamic-module/http-upstream-dynamic.patch 20 | 21 | ./configure --add-module=/path/to/nginx-http-upstream-dynamic-module 22 | ``` 23 | 24 | Examples 25 | ======== 26 | 27 | upstream backend { 28 | dynamic_resolve fallback=stale fail_timeout=30s; 29 | 30 | server a.com; 31 | server b.com; 32 | } 33 | 34 | server { 35 | ... 36 | 37 | proxy_pass http://backend; 38 | } 39 | 40 | Directives 41 | ========== 42 | 43 | dynamic_resolve 44 | --------------- 45 | 46 | **Syntax**: *dynamic_resolve [fallback=stale|next|shutdown] [fail_timeout=time]* 47 | 48 | **Default**: *-* 49 | 50 | **Context**: *upstream* 51 | 52 | Enable dynamic DNS resolving functionality in an upstream. 53 | 54 | The 'fallback' parameter specifies what action to take if a domain name can not be resolved into an IP address: 55 | 56 | * stale, use the original IP addresses resolved when tengine starts. 57 | * next, go to next availiable server in the upstream. 58 | * shutdown, finalize current request. 59 | 60 | The 'fail_timeout' parameter specifies how long time tengine considers the DNS server as unavailiable if a DNS query fails for a server in the upstream. In this period of time, all requests comming will follow what 'fallback' specifies. 61 | 62 | Notes 63 | ===== 64 | 65 | * It is a tengine module from 66 | https://github.com/alibaba/tengine/blob/master/src/http/modules/ngx_http_upstream_dynamic_module.c 67 | and made to work with nginx 1.9 68 | * It follows original tengine license. 69 | -------------------------------------------------------------------------------- /config: -------------------------------------------------------------------------------- 1 | ngx_addon_name=ngx_http_upstream_dynamic 2 | HTTP_MODULES="$HTTP_MODULES ngx_http_upstream_dynamic_module" 3 | NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_upstream_dynamic_module.c" 4 | -------------------------------------------------------------------------------- /http-upstream-dynamic.patch: -------------------------------------------------------------------------------- 1 | diff -u ./src/core/ngx_core.h.orig ./src/core/ngx_core.h 2 | --- ./src/core/ngx_core.h.orig 2016-02-24 14:53:23.000000000 +0000 3 | +++ ./src/core/ngx_core.h 2016-03-18 06:42:53.646390429 +0000 4 | @@ -40,6 +40,7 @@ 5 | #define NGX_DONE -4 6 | #define NGX_DECLINED -5 7 | #define NGX_ABORT -6 8 | +#define NGX_YIELD -7 9 | 10 | 11 | #include 12 | diff -u ./src/event/ngx_event_connect.h.orig ./src/event/ngx_event_connect.h 13 | --- ./src/event/ngx_event_connect.h.orig 2016-02-24 14:53:23.000000000 +0000 14 | +++ ./src/event/ngx_event_connect.h 2016-03-18 06:56:06.607130656 +0000 15 | @@ -40,6 +40,7 @@ 16 | struct sockaddr *sockaddr; 17 | socklen_t socklen; 18 | ngx_str_t *name; 19 | + ngx_str_t *host; 20 | 21 | ngx_uint_t tries; 22 | ngx_msec_t start_time; 23 | @@ -61,6 +62,8 @@ 24 | 25 | unsigned cached:1; 26 | 27 | + unsigned resolved:2; 28 | + 29 | /* ngx_connection_log_error_e */ 30 | unsigned log_error:2; 31 | }; 32 | diff -u ./src/http/ngx_http_upstream.c.orig ./src/http/ngx_http_upstream.c 33 | --- ./src/http/ngx_http_upstream.c.orig 2016-03-18 06:40:52.374968579 +0000 34 | +++ ./src/http/ngx_http_upstream.c 2016-03-18 07:11:39.349626985 +0000 35 | @@ -31,7 +31,7 @@ 36 | static void ngx_http_upstream_wr_check_broken_connection(ngx_http_request_t *r); 37 | static void ngx_http_upstream_check_broken_connection(ngx_http_request_t *r, 38 | ngx_event_t *ev); 39 | -static void ngx_http_upstream_connect(ngx_http_request_t *r, 40 | +void ngx_http_upstream_connect(ngx_http_request_t *r, 41 | ngx_http_upstream_t *u); 42 | static ngx_int_t ngx_http_upstream_reinit(ngx_http_request_t *r, 43 | ngx_http_upstream_t *u); 44 | @@ -88,7 +88,7 @@ 45 | static void ngx_http_upstream_next(ngx_http_request_t *r, 46 | ngx_http_upstream_t *u, ngx_uint_t ft_type); 47 | static void ngx_http_upstream_cleanup(void *data); 48 | -static void ngx_http_upstream_finalize_request(ngx_http_request_t *r, 49 | +void ngx_http_upstream_finalize_request(ngx_http_request_t *r, 50 | ngx_http_upstream_t *u, ngx_int_t rc); 51 | 52 | static ngx_int_t ngx_http_upstream_process_header_line(ngx_http_request_t *r, 53 | @@ -1318,7 +1318,7 @@ 54 | } 55 | 56 | 57 | -static void 58 | +void 59 | ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u) 60 | { 61 | ngx_int_t rc; 62 | @@ -1344,6 +1344,9 @@ 63 | u->state->header_time = (ngx_msec_t) -1; 64 | 65 | rc = ngx_event_connect_peer(&u->peer); 66 | + if (rc == NGX_YIELD) { 67 | + return; 68 | + } 69 | 70 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 71 | "http upstream connect: %i", rc); 72 | @@ -3942,7 +3945,7 @@ 73 | } 74 | 75 | 76 | -static void 77 | +void 78 | ngx_http_upstream_finalize_request(ngx_http_request_t *r, 79 | ngx_http_upstream_t *u, ngx_int_t rc) 80 | { 81 | diff -u ./src/http/ngx_http_upstream.h.orig ./src/http/ngx_http_upstream.h 82 | --- ./src/http/ngx_http_upstream.h.orig 2016-02-24 14:53:24.000000000 +0000 83 | +++ ./src/http/ngx_http_upstream.h 2016-03-18 07:02:23.077597084 +0000 84 | @@ -95,6 +95,8 @@ 85 | ngx_uint_t weight; 86 | ngx_uint_t max_fails; 87 | time_t fail_timeout; 88 | + ngx_str_t id; 89 | + ngx_str_t host; 90 | 91 | unsigned down:1; 92 | unsigned backup:1; 93 | @@ -315,6 +317,7 @@ 94 | ngx_http_upstream_headers_in_t headers_in; 95 | 96 | ngx_http_upstream_resolved_t *resolved; 97 | + ngx_resolver_ctx_t *dyn_resolve_ctx; 98 | 99 | ngx_buf_t from_client; 100 | 101 | -------------------------------------------------------------------------------- /http-upstream-dynamic.patch-1.14.0+: -------------------------------------------------------------------------------- 1 | diff -u ./src/http/ngx_http_upstream.c.orig ./src/http/ngx_http_upstream.c 2 | --- ./src/http/ngx_http_upstream.c.orig 2018-09-23 18:24:30.789203079 +0000 3 | +++ ./src/http/ngx_http_upstream.c 2018-09-23 18:30:00.857943573 +0000 4 | @@ -35,7 +35,7 @@ 5 | static void ngx_http_upstream_wr_check_broken_connection(ngx_http_request_t *r); 6 | static void ngx_http_upstream_check_broken_connection(ngx_http_request_t *r, 7 | ngx_event_t *ev); 8 | -static void ngx_http_upstream_connect(ngx_http_request_t *r, 9 | +void ngx_http_upstream_connect(ngx_http_request_t *r, 10 | ngx_http_upstream_t *u); 11 | static ngx_int_t ngx_http_upstream_reinit(ngx_http_request_t *r, 12 | ngx_http_upstream_t *u); 13 | @@ -99,7 +99,7 @@ 14 | static void ngx_http_upstream_next(ngx_http_request_t *r, 15 | ngx_http_upstream_t *u, ngx_uint_t ft_type); 16 | static void ngx_http_upstream_cleanup(void *data); 17 | -static void ngx_http_upstream_finalize_request(ngx_http_request_t *r, 18 | +void ngx_http_upstream_finalize_request(ngx_http_request_t *r, 19 | ngx_http_upstream_t *u, ngx_int_t rc); 20 | 21 | static ngx_int_t ngx_http_upstream_process_header_line(ngx_http_request_t *r, 22 | @@ -1492,7 +1492,7 @@ 23 | } 24 | 25 | 26 | -static void 27 | +void 28 | ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u) 29 | { 30 | ngx_int_t rc; 31 | @@ -1518,6 +1518,9 @@ 32 | u->state->header_time = (ngx_msec_t) -1; 33 | 34 | rc = ngx_event_connect_peer(&u->peer); 35 | + if (rc == NGX_YIELD) { 36 | + return; 37 | + } 38 | 39 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 40 | "http upstream connect: %i", rc); 41 | @@ -4243,7 +4246,7 @@ 42 | } 43 | 44 | 45 | -static void 46 | +void 47 | ngx_http_upstream_finalize_request(ngx_http_request_t *r, 48 | ngx_http_upstream_t *u, ngx_int_t rc) 49 | { 50 | diff -u ./src/http/ngx_http_upstream.h.orig ./src/http/ngx_http_upstream.h 51 | --- ./src/http/ngx_http_upstream.h.orig 2018-09-23 18:30:14.223973009 +0000 52 | +++ ./src/http/ngx_http_upstream.h 2018-09-23 18:32:10.516227564 +0000 53 | @@ -100,6 +100,8 @@ 54 | time_t fail_timeout; 55 | ngx_msec_t slow_start; 56 | ngx_uint_t down; 57 | + ngx_str_t id; 58 | + ngx_str_t host; 59 | 60 | unsigned backup:1; 61 | 62 | @@ -336,6 +338,7 @@ 63 | ngx_http_upstream_headers_in_t headers_in; 64 | 65 | ngx_http_upstream_resolved_t *resolved; 66 | + ngx_resolver_ctx_t *dyn_resolve_ctx; 67 | 68 | ngx_buf_t from_client; 69 | 70 | diff -u ./src/event/ngx_event_connect.h.orig ./src/event/ngx_event_connect.h 71 | --- ./src/event/ngx_event_connect.h.orig 2018-09-23 18:22:03.120861835 +0000 72 | +++ ./src/event/ngx_event_connect.h 2018-09-23 18:23:55.077121192 +0000 73 | @@ -39,6 +39,7 @@ 74 | struct sockaddr *sockaddr; 75 | socklen_t socklen; 76 | ngx_str_t *name; 77 | + ngx_str_t *host; 78 | 79 | ngx_uint_t tries; 80 | ngx_msec_t start_time; 81 | @@ -63,6 +64,8 @@ 82 | unsigned cached:1; 83 | unsigned transparent:1; 84 | 85 | + unsigned resolved:2; 86 | + 87 | /* ngx_connection_log_error_e */ 88 | unsigned log_error:2; 89 | 90 | diff -u ./src/core/ngx_core.h.orig ./src/core/ngx_core.h 91 | --- ./src/core/ngx_core.h.orig 2018-09-23 18:21:15.052749222 +0000 92 | +++ ./src/core/ngx_core.h 2018-09-23 18:21:28.609781071 +0000 93 | @@ -39,6 +39,7 @@ 94 | #define NGX_DONE -4 95 | #define NGX_DECLINED -5 96 | #define NGX_ABORT -6 97 | +#define NGX_YIELD -7 98 | 99 | 100 | #include 101 | -------------------------------------------------------------------------------- /ngx_http_upstream_dynamic_module.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) 2010-2015 Alibaba Group Holding Limited 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | 12 | #define NGX_HTTP_UPSTREAM_DR_INIT 0 13 | #define NGX_HTTP_UPSTREAM_DR_OK 1 14 | #define NGX_HTTP_UPSTREAM_DR_FAILED 2 15 | 16 | #define NGX_HTTP_UPSTREAM_DYN_RESOLVE_NEXT 0 17 | #define NGX_HTTP_UPSTREAM_DYN_RESOLVE_STALE 1 18 | #define NGX_HTTP_UPSTREAM_DYN_RESOLVE_SHUTDOWN 2 19 | 20 | 21 | typedef struct { 22 | ngx_int_t enabled; 23 | ngx_int_t fallback; 24 | time_t fail_timeout; 25 | time_t fail_check; 26 | 27 | ngx_http_upstream_init_pt original_init_upstream; 28 | ngx_http_upstream_init_peer_pt original_init_peer; 29 | 30 | } ngx_http_upstream_dynamic_srv_conf_t; 31 | 32 | 33 | typedef struct { 34 | ngx_http_upstream_dynamic_srv_conf_t *conf; 35 | 36 | ngx_http_upstream_t *upstream; 37 | 38 | void *data; 39 | 40 | ngx_http_request_t *request; 41 | 42 | ngx_event_get_peer_pt original_get_peer; 43 | ngx_event_free_peer_pt original_free_peer; 44 | 45 | #if (NGX_HTTP_SSL) 46 | ngx_event_set_peer_session_pt original_set_session; 47 | ngx_event_save_peer_session_pt original_save_session; 48 | #endif 49 | 50 | } ngx_http_upstream_dynamic_peer_data_t; 51 | 52 | 53 | static ngx_int_t ngx_http_upstream_init_dynamic_peer(ngx_http_request_t *r, 54 | ngx_http_upstream_srv_conf_t *us); 55 | static ngx_int_t ngx_http_upstream_get_dynamic_peer(ngx_peer_connection_t *pc, 56 | void *data); 57 | static void ngx_http_upstream_free_dynamic_peer(ngx_peer_connection_t *pc, 58 | void *data, ngx_uint_t state); 59 | 60 | 61 | #if (NGX_HTTP_SSL) 62 | static ngx_int_t ngx_http_upstream_dynamic_set_session( 63 | ngx_peer_connection_t *pc, void *data); 64 | static void ngx_http_upstream_dynamic_save_session(ngx_peer_connection_t *pc, 65 | void *data); 66 | #endif 67 | 68 | static void *ngx_http_upstream_dynamic_create_conf(ngx_conf_t *cf); 69 | static char *ngx_http_upstream_dynamic(ngx_conf_t *cf, ngx_command_t *cmd, 70 | void *conf); 71 | 72 | extern void ngx_http_upstream_finalize_request(ngx_http_request_t *r, 73 | ngx_http_upstream_t *u, ngx_int_t rc); 74 | extern void ngx_http_upstream_connect(ngx_http_request_t *r, 75 | ngx_http_upstream_t *u); 76 | 77 | 78 | 79 | static ngx_command_t ngx_http_upstream_dynamic_commands[] = { 80 | 81 | { ngx_string("dynamic_resolve"), 82 | NGX_HTTP_UPS_CONF|NGX_CONF_TAKE12|NGX_CONF_NOARGS, 83 | ngx_http_upstream_dynamic, 84 | 0, 85 | 0, 86 | NULL }, 87 | 88 | ngx_null_command 89 | }; 90 | 91 | 92 | static ngx_http_module_t ngx_http_upstream_dynamic_module_ctx = { 93 | NULL, /* preconfiguration */ 94 | NULL, /* postconfiguration */ 95 | 96 | NULL, /* create main configuration */ 97 | NULL, /* init main configuration */ 98 | 99 | ngx_http_upstream_dynamic_create_conf, /* create server configuration */ 100 | NULL, /* merge server configuration */ 101 | 102 | NULL, /* create location configuration */ 103 | NULL /* merge location configuration */ 104 | }; 105 | 106 | 107 | ngx_module_t ngx_http_upstream_dynamic_module = { 108 | NGX_MODULE_V1, 109 | &ngx_http_upstream_dynamic_module_ctx, /* module context */ 110 | ngx_http_upstream_dynamic_commands, /* module directives */ 111 | NGX_HTTP_MODULE, /* module type */ 112 | NULL, /* init master */ 113 | NULL, /* init module */ 114 | NULL, /* init process */ 115 | NULL, /* init thread */ 116 | NULL, /* exit thread */ 117 | NULL, /* exit process */ 118 | NULL, /* exit master */ 119 | NGX_MODULE_V1_PADDING 120 | }; 121 | 122 | 123 | static ngx_int_t 124 | ngx_http_upstream_init_dynamic(ngx_conf_t *cf, 125 | ngx_http_upstream_srv_conf_t *us) 126 | { 127 | ngx_uint_t i; 128 | ngx_http_upstream_dynamic_srv_conf_t *dcf; 129 | ngx_http_upstream_server_t *server; 130 | ngx_str_t host; 131 | 132 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, 133 | "init dynamic resolve"); 134 | 135 | dcf = ngx_http_conf_upstream_srv_conf(us, 136 | ngx_http_upstream_dynamic_module); 137 | 138 | if (dcf->original_init_upstream(cf, us) != NGX_OK) { 139 | return NGX_ERROR; 140 | } 141 | 142 | if (us->servers) { 143 | server = us->servers->elts; 144 | 145 | for (i = 0; i < us->servers->nelts; i++) { 146 | host = server[i].host; 147 | if (ngx_inet_addr(host.data, host.len) == INADDR_NONE) { 148 | break; 149 | } 150 | } 151 | 152 | if (i == us->servers->nelts) { 153 | dcf->enabled = 0; 154 | 155 | return NGX_OK; 156 | } 157 | } 158 | 159 | dcf->original_init_peer = us->peer.init; 160 | 161 | us->peer.init = ngx_http_upstream_init_dynamic_peer; 162 | 163 | dcf->enabled = 1; 164 | 165 | return NGX_OK; 166 | } 167 | 168 | 169 | static ngx_int_t 170 | ngx_http_upstream_init_dynamic_peer(ngx_http_request_t *r, 171 | ngx_http_upstream_srv_conf_t *us) 172 | { 173 | ngx_http_upstream_dynamic_peer_data_t *dp; 174 | ngx_http_upstream_dynamic_srv_conf_t *dcf; 175 | 176 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 177 | "init dynamic peer"); 178 | 179 | dcf = ngx_http_conf_upstream_srv_conf(us, 180 | ngx_http_upstream_dynamic_module); 181 | 182 | dp = ngx_palloc(r->pool, sizeof(ngx_http_upstream_dynamic_peer_data_t)); 183 | if (dp == NULL) { 184 | return NGX_ERROR; 185 | } 186 | 187 | if (dcf->original_init_peer(r, us) != NGX_OK) { 188 | return NGX_ERROR; 189 | } 190 | 191 | dp->conf = dcf; 192 | dp->upstream = r->upstream; 193 | dp->data = r->upstream->peer.data; 194 | dp->original_get_peer = r->upstream->peer.get; 195 | dp->original_free_peer = r->upstream->peer.free; 196 | dp->request = r; 197 | 198 | r->upstream->peer.data = dp; 199 | r->upstream->peer.get = ngx_http_upstream_get_dynamic_peer; 200 | r->upstream->peer.free = ngx_http_upstream_free_dynamic_peer; 201 | 202 | #if (NGX_HTTP_SSL) 203 | dp->original_set_session = r->upstream->peer.set_session; 204 | dp->original_save_session = r->upstream->peer.save_session; 205 | r->upstream->peer.set_session = ngx_http_upstream_dynamic_set_session; 206 | r->upstream->peer.save_session = ngx_http_upstream_dynamic_save_session; 207 | #endif 208 | 209 | return NGX_OK; 210 | } 211 | 212 | 213 | static void 214 | ngx_http_upstream_dynamic_handler(ngx_resolver_ctx_t *ctx) 215 | { 216 | ngx_http_request_t *r; 217 | ngx_http_upstream_t *u; 218 | ngx_peer_connection_t *pc; 219 | #if defined(nginx_version) && nginx_version >= 1005008 220 | socklen_t socklen; 221 | struct sockaddr *sockaddr, *csockaddr; 222 | #else 223 | struct sockaddr_in *sin, *csin; 224 | #endif 225 | in_port_t port; 226 | ngx_str_t *addr; 227 | u_char *p; 228 | 229 | size_t len; 230 | ngx_http_upstream_dynamic_srv_conf_t *dscf; 231 | ngx_http_upstream_dynamic_peer_data_t *bp; 232 | 233 | bp = ctx->data; 234 | r = bp->request; 235 | u = r->upstream; 236 | pc = &u->peer; 237 | dscf = bp->conf; 238 | 239 | if (ctx->state) { 240 | 241 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 242 | "%V could not be resolved (%i: %s)", 243 | &ctx->name, ctx->state, 244 | ngx_resolver_strerror(ctx->state)); 245 | 246 | dscf->fail_check = ngx_time(); 247 | 248 | pc->resolved = NGX_HTTP_UPSTREAM_DR_FAILED; 249 | 250 | } else { 251 | /* dns query ok */ 252 | #if (NGX_DEBUG) 253 | { 254 | u_char text[NGX_SOCKADDR_STRLEN]; 255 | ngx_str_t addr; 256 | ngx_uint_t i; 257 | 258 | addr.data = text; 259 | 260 | for (i = 0; i < ctx->naddrs; i++) { 261 | addr.len = ngx_sock_ntop(ctx->addrs[i].sockaddr, ctx->addrs[i].socklen, 262 | text, NGX_SOCKADDR_STRLEN, 0); 263 | 264 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 265 | "name was resolved to %V", &addr); 266 | } 267 | } 268 | #endif 269 | dscf->fail_check = 0; 270 | #if defined(nginx_version) && nginx_version >= 1005008 271 | csockaddr = ctx->addrs[0].sockaddr; 272 | socklen = ctx->addrs[0].socklen; 273 | 274 | if (ngx_cmp_sockaddr(pc->sockaddr, pc->socklen, csockaddr, socklen, 0) 275 | == NGX_OK) 276 | { 277 | pc->resolved = NGX_HTTP_UPSTREAM_DR_OK; 278 | goto out; 279 | } 280 | 281 | sockaddr = ngx_pcalloc(r->pool, socklen); 282 | if (sockaddr == NULL) { 283 | ngx_http_upstream_finalize_request(r, u, 284 | NGX_HTTP_INTERNAL_SERVER_ERROR); 285 | return; 286 | } 287 | 288 | ngx_memcpy(sockaddr, csockaddr, socklen); 289 | port = ngx_inet_get_port(pc->sockaddr); 290 | 291 | switch (sockaddr->sa_family) { 292 | #if (NGX_HAVE_INET6) 293 | case AF_INET6: 294 | ((struct sockaddr_in6 *) sockaddr)->sin6_port = htons(port); 295 | break; 296 | #endif 297 | default: /* AF_INET */ 298 | ((struct sockaddr_in *) sockaddr)->sin_port = htons(port); 299 | } 300 | 301 | p = ngx_pnalloc(r->pool, NGX_SOCKADDR_STRLEN); 302 | if (p == NULL) { 303 | ngx_http_upstream_finalize_request(r, u, 304 | NGX_HTTP_INTERNAL_SERVER_ERROR); 305 | return; 306 | } 307 | 308 | len = ngx_sock_ntop(sockaddr, socklen, p, NGX_SOCKADDR_STRLEN, 1); 309 | 310 | addr = ngx_palloc(r->pool, sizeof(ngx_str_t)); 311 | if (addr == NULL) { 312 | ngx_http_upstream_finalize_request(r, u, 313 | NGX_HTTP_INTERNAL_SERVER_ERROR); 314 | return; 315 | } 316 | 317 | addr->data = p; 318 | addr->len = len; 319 | pc->sockaddr = sockaddr; 320 | pc->socklen = socklen; 321 | pc->name = addr; 322 | 323 | #else 324 | /* for nginx older than 1.5.8 */ 325 | 326 | sin = ngx_pcalloc(r->pool, sizeof(struct sockaddr_in)); 327 | if (sin == NULL) { 328 | ngx_http_upstream_finalize_request(r, u, 329 | NGX_HTTP_INTERNAL_SERVER_ERROR); 330 | return; 331 | } 332 | 333 | ngx_memcpy(sin, pc->sockaddr, pc->socklen); 334 | 335 | /* only the first IP addr is used in version 1 */ 336 | 337 | csin = (struct sockaddr_in *) ctx->addrs[0].sockaddr; 338 | if (sin->sin_addr.s_addr == csin->sin_addr.s_addr) { 339 | 340 | pc->resolved = NGX_HTTP_UPSTREAM_DR_OK; 341 | 342 | goto out; 343 | } 344 | 345 | sin->sin_addr.s_addr = csin->sin_addr.s_addr; 346 | 347 | len = NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1; 348 | 349 | p = ngx_pnalloc(r->pool, len); 350 | if (p == NULL) { 351 | ngx_http_upstream_finalize_request(r, u, 352 | NGX_HTTP_INTERNAL_SERVER_ERROR); 353 | return; 354 | } 355 | 356 | port = ntohs(sin->sin_port); 357 | len = ngx_inet_ntop(AF_INET, &sin->sin_addr.s_addr, 358 | p, NGX_INET_ADDRSTRLEN); 359 | len = ngx_sprintf(&p[len], ":%d", port) - p; 360 | 361 | addr = ngx_palloc(r->pool, sizeof(ngx_str_t)); 362 | if (addr == NULL) { 363 | ngx_http_upstream_finalize_request(r, u, 364 | NGX_HTTP_INTERNAL_SERVER_ERROR); 365 | return; 366 | } 367 | 368 | addr->data = p; 369 | addr->len = len; 370 | 371 | pc->sockaddr = (struct sockaddr *) sin; 372 | pc->socklen = sizeof(struct sockaddr_in); 373 | pc->name = addr; 374 | #endif 375 | 376 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 377 | "name was resolved to %V", pc->name); 378 | 379 | pc->resolved = NGX_HTTP_UPSTREAM_DR_OK; 380 | } 381 | 382 | out: 383 | ngx_resolve_name_done(ctx); 384 | u->dyn_resolve_ctx = NULL; 385 | 386 | ngx_http_upstream_connect(r, u); 387 | } 388 | 389 | 390 | static ngx_int_t 391 | ngx_http_upstream_get_dynamic_peer(ngx_peer_connection_t *pc, void *data) 392 | { 393 | ngx_http_upstream_dynamic_peer_data_t *bp = data; 394 | ngx_http_request_t *r; 395 | ngx_http_core_loc_conf_t *clcf; 396 | ngx_resolver_ctx_t *ctx, temp; 397 | ngx_http_upstream_t *u; 398 | ngx_int_t rc; 399 | ngx_http_upstream_dynamic_srv_conf_t *dscf; 400 | 401 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, 402 | "get dynamic peer"); 403 | 404 | /* The "get" function will be called twice if 405 | * one host is resolved into an IP address. 406 | * (via 'ngx_http_upstream_connect' if resolved successfully) 407 | * 408 | * So here we need to determine if it is the first 409 | * time call or the second time call. 410 | */ 411 | if (pc->resolved == NGX_HTTP_UPSTREAM_DR_OK) { 412 | return NGX_OK; 413 | } 414 | 415 | dscf = bp->conf; 416 | r = bp->request; 417 | u = r->upstream; 418 | 419 | if (pc->resolved == NGX_HTTP_UPSTREAM_DR_FAILED) { 420 | 421 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, 422 | "resolve failed! fallback: %ui", dscf->fallback); 423 | 424 | switch (dscf->fallback) { 425 | 426 | case NGX_HTTP_UPSTREAM_DYN_RESOLVE_STALE: 427 | return NGX_OK; 428 | 429 | case NGX_HTTP_UPSTREAM_DYN_RESOLVE_SHUTDOWN: 430 | ngx_http_upstream_finalize_request(r, u, NGX_HTTP_BAD_GATEWAY); 431 | return NGX_YIELD; 432 | 433 | default: 434 | /* default fallback action: check next upstream */ 435 | return NGX_DECLINED; 436 | } 437 | 438 | return NGX_DECLINED; 439 | } 440 | 441 | if (dscf->fail_check 442 | && (ngx_time() - dscf->fail_check < dscf->fail_timeout)) 443 | { 444 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, 445 | "in fail timeout period, fallback: %ui", dscf->fallback); 446 | 447 | switch (dscf->fallback) { 448 | 449 | case NGX_HTTP_UPSTREAM_DYN_RESOLVE_STALE: 450 | return bp->original_get_peer(pc, bp->data); 451 | 452 | case NGX_HTTP_UPSTREAM_DYN_RESOLVE_SHUTDOWN: 453 | ngx_http_upstream_finalize_request(r, u, NGX_HTTP_BAD_GATEWAY); 454 | return NGX_YIELD; 455 | 456 | default: 457 | /* default fallback action: check next upstream, still need 458 | * to get peer in fail timeout period 459 | */ 460 | return bp->original_get_peer(pc, bp->data); 461 | } 462 | 463 | return NGX_DECLINED; 464 | } 465 | 466 | /* NGX_HTTP_UPSTREAM_DYN_RESOLVE_INIT, ask balancer */ 467 | 468 | rc = bp->original_get_peer(pc, bp->data); 469 | 470 | if (rc != NGX_OK) { 471 | return rc; 472 | } 473 | 474 | /* resolve name */ 475 | 476 | if (pc->host == NULL) { 477 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, 478 | "load balancer doesn't support dyn resolve!"); 479 | return NGX_OK; 480 | } 481 | 482 | if (ngx_inet_addr(pc->host->data, pc->host->len) != INADDR_NONE) { 483 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, 484 | "host is an IP address, connect directly!"); 485 | return NGX_OK; 486 | } 487 | 488 | clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); 489 | if (clcf->resolver == NULL) { 490 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 491 | "resolver has not been configured!"); 492 | return NGX_OK; 493 | } 494 | 495 | temp.name = *pc->host; 496 | 497 | ctx = ngx_resolve_start(clcf->resolver, &temp); 498 | if (ctx == NULL) { 499 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 500 | "resolver start failed!"); 501 | return NGX_OK; 502 | } 503 | 504 | if (ctx == NGX_NO_RESOLVER) { 505 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 506 | "resolver started but no resolver!"); 507 | return NGX_OK; 508 | } 509 | 510 | ctx->name = *pc->host; 511 | /* TODO remove */ 512 | // ctx->type = NGX_RESOLVE_A; 513 | /* END */ 514 | ctx->handler = ngx_http_upstream_dynamic_handler; 515 | ctx->data = bp; 516 | ctx->timeout = clcf->resolver_timeout; 517 | 518 | u->dyn_resolve_ctx = ctx; 519 | 520 | if (ngx_resolve_name(ctx) != NGX_OK) { 521 | ngx_log_error(NGX_LOG_ERR, pc->log, 0, 522 | "resolver name failed!\n"); 523 | 524 | u->dyn_resolve_ctx = NULL; 525 | 526 | return NGX_OK; 527 | } 528 | 529 | return NGX_YIELD; 530 | } 531 | 532 | 533 | static void 534 | ngx_http_upstream_free_dynamic_peer(ngx_peer_connection_t *pc, void *data, 535 | ngx_uint_t state) 536 | { 537 | ngx_http_upstream_dynamic_peer_data_t *bp = data; 538 | 539 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, 540 | "free dynamic peer"); 541 | 542 | bp->original_free_peer(pc, bp->data, state); 543 | } 544 | 545 | 546 | #if (NGX_HTTP_SSL) 547 | 548 | static ngx_int_t 549 | ngx_http_upstream_dynamic_set_session(ngx_peer_connection_t *pc, void *data) 550 | { 551 | ngx_http_upstream_dynamic_peer_data_t *dp = data; 552 | 553 | return dp->original_set_session(pc, dp->data); 554 | } 555 | 556 | 557 | static void 558 | ngx_http_upstream_dynamic_save_session(ngx_peer_connection_t *pc, void *data) 559 | { 560 | ngx_http_upstream_dynamic_peer_data_t *dp = data; 561 | 562 | dp->original_save_session(pc, dp->data); 563 | 564 | return; 565 | } 566 | 567 | #endif 568 | 569 | 570 | static void * 571 | ngx_http_upstream_dynamic_create_conf(ngx_conf_t *cf) 572 | { 573 | ngx_http_upstream_dynamic_srv_conf_t *conf; 574 | 575 | conf = ngx_pcalloc(cf->pool, 576 | sizeof(ngx_http_upstream_dynamic_srv_conf_t)); 577 | if (conf == NULL) { 578 | return NULL; 579 | } 580 | 581 | /* 582 | * set by ngx_pcalloc(): 583 | * 584 | * conf->original_init_upstream = NULL; 585 | * conf->original_init_peer = NULL; 586 | */ 587 | 588 | return conf; 589 | } 590 | 591 | 592 | static char * 593 | ngx_http_upstream_dynamic(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 594 | { 595 | ngx_http_upstream_srv_conf_t *uscf; 596 | ngx_http_upstream_dynamic_srv_conf_t *dcf; 597 | ngx_str_t *value, s; 598 | ngx_uint_t i; 599 | time_t fail_timeout; 600 | ngx_int_t fallback; 601 | 602 | uscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module); 603 | 604 | dcf = ngx_http_conf_upstream_srv_conf(uscf, 605 | ngx_http_upstream_dynamic_module); 606 | 607 | if (dcf->original_init_upstream) { 608 | return "is duplicate"; 609 | } 610 | 611 | dcf->original_init_upstream = uscf->peer.init_upstream 612 | ? uscf->peer.init_upstream 613 | : ngx_http_upstream_init_round_robin; 614 | 615 | uscf->peer.init_upstream = ngx_http_upstream_init_dynamic; 616 | 617 | /* read options */ 618 | 619 | value = cf->args->elts; 620 | 621 | for (i = 1; i < cf->args->nelts; i++) { 622 | 623 | if (ngx_strncmp(value[i].data, "fail_timeout=", 13) == 0) { 624 | 625 | s.len = value[i].len - 13; 626 | s.data = &value[i].data[13]; 627 | 628 | fail_timeout = ngx_parse_time(&s, 1); 629 | 630 | if (fail_timeout == (time_t) NGX_ERROR) { 631 | return "invalid fail_timeout"; 632 | } 633 | 634 | dcf->fail_timeout = fail_timeout; 635 | 636 | continue; 637 | } 638 | 639 | if (ngx_strncmp(value[i].data, "fallback=", 9) == 0) { 640 | 641 | s.len = value[i].len - 9; 642 | s.data = &value[i].data[9]; 643 | 644 | if (ngx_strncmp(s.data, "next", 4) == 0) { 645 | fallback = NGX_HTTP_UPSTREAM_DYN_RESOLVE_NEXT; 646 | } else if (ngx_strncmp(s.data, "stale", 5) == 0) { 647 | fallback = NGX_HTTP_UPSTREAM_DYN_RESOLVE_STALE; 648 | } else if (ngx_strncmp(s.data, "shutdown", 8) == 0) { 649 | fallback = NGX_HTTP_UPSTREAM_DYN_RESOLVE_SHUTDOWN; 650 | } else { 651 | return "invalid fallback action"; 652 | } 653 | 654 | dcf->fallback = fallback; 655 | 656 | continue; 657 | } 658 | } 659 | 660 | return NGX_CONF_OK; 661 | } 662 | --------------------------------------------------------------------------------