IPv6 & IPv4 backend with proxy_bind

SplitIce mat999 at gmail.com
Mon Dec 9 11:33:29 UTC 2013


Im not sure that patch would suit my needs, simply because most of the time
I am matching on the upstream address only and need it to work regardless
of the port (i.e a regex match on just the IP component).

Perhaps your patch could be extended to support -

map $upstream_peer_addr $bind_addr {
    127.0.0.1:8001 127.0.0.1;
    127.0.0.2 <http://127.0.0.1:8002/> 127.0.0.1;
    [::1]:8003     ::1;
}

Where 127.0.0.2 would match 127.0.0.2:*

I certainly like that it doesn't require a conversion to string.

I have also attached V2 of my patch (changes to the patch to remove windows
path style).


On Mon, Dec 9, 2013 at 8:59 PM, Ruslan Ermilov <ru at nginx.com> wrote:

> 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;
>
>
>
> _______________________________________________
> nginx-devel mailing list
> nginx-devel at nginx.org
> http://mailman.nginx.org/mailman/listinfo/nginx-devel
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.nginx.org/pipermail/nginx-devel/attachments/20131209/acff16c1/attachment-0001.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: patch-upstream.patch
Type: application/octet-stream
Size: 3196 bytes
Desc: not available
URL: <http://mailman.nginx.org/pipermail/nginx-devel/attachments/20131209/acff16c1/attachment-0001.obj>


More information about the nginx-devel mailing list