IPv6 & IPv4 backend with proxy_bind
Ruslan Ermilov
ru at nginx.com
Mon Dec 9 10:29:29 UTC 2013
On Sat, Nov 23, 2013 at 12:15:28PM +1030, SplitIce wrote:
> Attached is the patch,
>
> This is the first time I have created a variable or really done anything
> inside the http request processing flow so feel free to let me know if
> there is a better way to do something or if I have any edge cases.
>
> This patch provides a $upstream_connecting variable which contains the IP
> address and port of the upstream being connected. If there is no upstream,
> it will return "-" my understanding is this may happen if the upstream is
> DNS resolved (untested). There may be a better way of doing this?
>
> This should be used in a config like the following -
> map $upstream_connecting $test {
> ~^93\.184\.216\.119\: 192.168.2.40;
> ~^192\.168\.2\.([0-9]+)\: 192.168.2.40;
> }
>
> proxy_bind $test;
I took a different approach. I've made "local" a peer's method,
so the computation of the local address is delayed until it's
actually needed. By that time, the peer address is already known.
I've also patched "map" so it creates non-cacheable variables.
This way, $upstream_peer_addr can be mapped into the local address:
map $upstream_peer_addr $bind_addr {
127.0.0.1:8001 127.0.0.1;
127.0.0.1:8002 127.0.0.1;
[::1]:8003 ::1;
}
server {
...
location / {
proxy_pass ...;
proxy_bind $bind_addr;
...
}
}
diff --git a/src/event/ngx_event_connect.c b/src/event/ngx_event_connect.c
--- a/src/event/ngx_event_connect.c
+++ b/src/event/ngx_event_connect.c
@@ -17,6 +17,7 @@ ngx_event_connect_peer(ngx_peer_connecti
int rc;
ngx_int_t event;
ngx_err_t err;
+ ngx_addr_t *local;
ngx_uint_t level;
ngx_socket_t s;
ngx_event_t *rev, *wev;
@@ -67,9 +68,13 @@ ngx_event_connect_peer(ngx_peer_connecti
}
if (pc->local) {
- if (bind(s, pc->local->sockaddr, pc->local->socklen) == -1) {
+ local = pc->local(pc, pc->data);
+
+ if (local != NULL
+ && bind(s, local->sockaddr, local->socklen) == -1)
+ {
ngx_log_error(NGX_LOG_CRIT, pc->log, ngx_socket_errno,
- "bind(%V) failed", &pc->local->name);
+ "bind(%V) failed", &local->name);
goto failed;
}
diff --git a/src/event/ngx_event_connect.h b/src/event/ngx_event_connect.h
--- a/src/event/ngx_event_connect.h
+++ b/src/event/ngx_event_connect.h
@@ -25,6 +25,8 @@ typedef ngx_int_t (*ngx_event_get_peer_p
void *data);
typedef void (*ngx_event_free_peer_pt)(ngx_peer_connection_t *pc, void *data,
ngx_uint_t state);
+typedef ngx_addr_t *(*ngx_event_get_local_pt)(ngx_peer_connection_t *pc,
+ void *data);
#if (NGX_SSL)
typedef ngx_int_t (*ngx_event_set_peer_session_pt)(ngx_peer_connection_t *pc,
@@ -45,6 +47,7 @@ struct ngx_peer_connection_s {
ngx_event_get_peer_pt get;
ngx_event_free_peer_pt free;
+ ngx_event_get_local_pt local;
void *data;
#if (NGX_SSL)
@@ -56,8 +59,6 @@ struct ngx_peer_connection_s {
ngx_atomic_t *lock;
#endif
- ngx_addr_t *local;
-
int rcvbuf;
ngx_log_t *log;
diff --git a/src/http/modules/ngx_http_map_module.c b/src/http/modules/ngx_http_map_module.c
--- a/src/http/modules/ngx_http_map_module.c
+++ b/src/http/modules/ngx_http_map_module.c
@@ -477,7 +477,7 @@ ngx_http_map(ngx_conf_t *cf, ngx_command
}
var->valid = 1;
- var->no_cacheable = 0;
+ var->no_cacheable = 1;
var->not_found = 0;
vp = ngx_array_push(&ctx->values_hash[key]);
diff --git a/src/http/modules/ngx_http_upstream_keepalive_module.c b/src/http/modules/ngx_http_upstream_keepalive_module.c
--- a/src/http/modules/ngx_http_upstream_keepalive_module.c
+++ b/src/http/modules/ngx_http_upstream_keepalive_module.c
@@ -31,6 +31,7 @@ typedef struct {
ngx_event_get_peer_pt original_get_peer;
ngx_event_free_peer_pt original_free_peer;
+ ngx_event_get_local_pt original_get_local;
#if (NGX_HTTP_SSL)
ngx_event_set_peer_session_pt original_set_session;
@@ -63,6 +64,9 @@ static void ngx_http_upstream_keepalive_
static void ngx_http_upstream_keepalive_close_handler(ngx_event_t *ev);
static void ngx_http_upstream_keepalive_close(ngx_connection_t *c);
+static ngx_addr_t *ngx_http_upstream_get_keepalive_local(
+ ngx_peer_connection_t *pc, void *data);
+
#if (NGX_HTTP_SSL)
static ngx_int_t ngx_http_upstream_keepalive_set_session(
@@ -189,10 +193,12 @@ ngx_http_upstream_init_keepalive_peer(ng
kp->data = r->upstream->peer.data;
kp->original_get_peer = r->upstream->peer.get;
kp->original_free_peer = r->upstream->peer.free;
+ kp->original_get_local = r->upstream->peer.local;
r->upstream->peer.data = kp;
r->upstream->peer.get = ngx_http_upstream_get_keepalive_peer;
r->upstream->peer.free = ngx_http_upstream_free_keepalive_peer;
+ r->upstream->peer.local = ngx_http_upstream_get_keepalive_local;
#if (NGX_HTTP_SSL)
kp->original_set_session = r->upstream->peer.set_session;
@@ -430,6 +436,16 @@ ngx_http_upstream_keepalive_close(ngx_co
}
+static ngx_addr_t *
+ngx_http_upstream_get_keepalive_local(ngx_peer_connection_t *pc,
+ void *data)
+{
+ ngx_http_upstream_keepalive_peer_data_t *kp = data;
+
+ return kp->original_get_local(pc, kp->data);
+}
+
+
#if (NGX_HTTP_SSL)
static ngx_int_t
diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -141,14 +141,13 @@ static ngx_int_t ngx_http_upstream_respo
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_upstream_response_length_variable(
ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data);
+static ngx_int_t ngx_http_upstream_peer_addr_variable(ngx_http_request_t *r,
+ ngx_http_variable_value_t *v, uintptr_t data);
static char *ngx_http_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy);
static char *ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
-static ngx_addr_t *ngx_http_upstream_get_local(ngx_http_request_t *r,
- ngx_http_upstream_local_t *local);
-
static void *ngx_http_upstream_create_main_conf(ngx_conf_t *cf);
static char *ngx_http_upstream_init_main_conf(ngx_conf_t *cf, void *conf);
@@ -366,6 +365,10 @@ static ngx_http_variable_t ngx_http_ups
#endif
+ { ngx_string("upstream_peer_addr"), NULL,
+ ngx_http_upstream_peer_addr_variable, 0,
+ NGX_HTTP_VAR_NOCACHEABLE, 0 },
+
{ ngx_null_string, NULL, NULL, 0, 0, 0 }
};
@@ -534,8 +537,6 @@ ngx_http_upstream_init_request(ngx_http_
return;
}
- u->peer.local = ngx_http_upstream_get_local(r, u->conf->local);
-
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
u->output.alignment = clcf->directio_alignment;
@@ -4509,6 +4510,25 @@ ngx_http_upstream_response_length_variab
}
+static ngx_int_t
+ngx_http_upstream_peer_addr_variable(ngx_http_request_t *r,
+ ngx_http_variable_value_t *v, uintptr_t data)
+{
+ if (r->upstream == NULL || r->upstream->peer.name == NULL) {
+ v->not_found = 1;
+ return NGX_OK;
+ }
+
+ v->len = r->upstream->peer.name->len;
+ v->data = r->upstream->peer.name->data;
+ v->valid = 1;
+ v->no_cacheable = 0;
+ v->not_found = 0;
+
+ return NGX_OK;
+}
+
+
ngx_int_t
ngx_http_upstream_header_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
@@ -5022,53 +5042,6 @@ ngx_http_upstream_bind_set_slot(ngx_conf
}
-static ngx_addr_t *
-ngx_http_upstream_get_local(ngx_http_request_t *r,
- ngx_http_upstream_local_t *local)
-{
- ngx_int_t rc;
- ngx_str_t val;
- ngx_addr_t *addr;
-
- if (local == NULL) {
- return NULL;
- }
-
- if (local->value == NULL) {
- return local->addr;
- }
-
- if (ngx_http_complex_value(r, local->value, &val) != NGX_OK) {
- return NULL;
- }
-
- if (val.len == 0) {
- return NULL;
- }
-
- addr = ngx_palloc(r->pool, sizeof(ngx_addr_t));
- if (addr == NULL) {
- return NULL;
- }
-
- rc = ngx_parse_addr(r->pool, addr, val.data, val.len);
-
- switch (rc) {
- case NGX_OK:
- addr->name = val;
- return addr;
-
- case NGX_DECLINED:
- ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
- "invalid local address \"%V\"", &val);
- /* fall through */
-
- default:
- return NULL;
- }
-}
-
-
char *
ngx_http_upstream_param_set_slot(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf)
diff --git a/src/http/ngx_http_upstream_round_robin.c b/src/http/ngx_http_upstream_round_robin.c
--- a/src/http/ngx_http_upstream_round_robin.c
+++ b/src/http/ngx_http_upstream_round_robin.c
@@ -22,6 +22,9 @@ static void ngx_http_upstream_empty_save
#endif
+static ngx_addr_t *ngx_http_upstream_get_local(ngx_peer_connection_t *pc,
+ void *data);
+
ngx_int_t
ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
@@ -246,6 +249,8 @@ ngx_http_upstream_init_round_robin_peer(
}
}
+ rrp->request = r;
+
r->upstream->peer.get = ngx_http_upstream_get_round_robin_peer;
r->upstream->peer.free = ngx_http_upstream_free_round_robin_peer;
r->upstream->peer.tries = rrp->peers->number;
@@ -255,6 +260,7 @@ ngx_http_upstream_init_round_robin_peer(
r->upstream->peer.save_session =
ngx_http_upstream_save_round_robin_peer_session;
#endif
+ r->upstream->peer.local = ngx_http_upstream_get_local;
return NGX_OK;
}
@@ -679,3 +685,56 @@ ngx_http_upstream_empty_save_session(ngx
}
#endif
+
+
+static ngx_addr_t *
+ngx_http_upstream_get_local(ngx_peer_connection_t *pc, void *data)
+{
+ ngx_http_upstream_rr_peer_data_t *rrp = data;
+
+ ngx_int_t rc;
+ ngx_str_t val;
+ ngx_addr_t *addr;
+ ngx_http_request_t *r;
+ ngx_http_upstream_local_t *local;
+
+ r = rrp->request;
+ local = r->upstream->conf->local;
+
+ if (local == NULL) {
+ return NULL;
+ }
+
+ if (local->value == NULL) {
+ return local->addr;
+ }
+
+ if (ngx_http_complex_value(r, local->value, &val) != NGX_OK) {
+ return NULL;
+ }
+
+ if (val.len == 0) {
+ return NULL;
+ }
+
+ addr = ngx_palloc(r->pool, sizeof(ngx_addr_t));
+ if (addr == NULL) {
+ return NULL;
+ }
+
+ rc = ngx_parse_addr(r->pool, addr, val.data, val.len);
+
+ switch (rc) {
+ case NGX_OK:
+ addr->name = val;
+ return addr;
+
+ case NGX_DECLINED:
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "invalid local address \"%V\"", &val);
+ /* fall through */
+
+ default:
+ return NULL;
+ }
+}
diff --git a/src/http/ngx_http_upstream_round_robin.h b/src/http/ngx_http_upstream_round_robin.h
--- a/src/http/ngx_http_upstream_round_robin.h
+++ b/src/http/ngx_http_upstream_round_robin.h
@@ -63,6 +63,7 @@ typedef struct {
ngx_uint_t current;
uintptr_t *tried;
uintptr_t data;
+ ngx_http_request_t *request;
} ngx_http_upstream_rr_peer_data_t;
More information about the nginx-devel
mailing list