[PATCH] HTTP upstream: added possibility to specify variables for the ip_hash directive

Alexey K. alexeyk45 at gmail.com
Thu May 22 07:32:48 UTC 2014


# HG changeset patch
# User Alexey K. <alexeyk45 at gmail.com>
# Date 1400743228 -21600
#      Thu May 22 13:20:28 2014 +0600
# Node ID cbfb9bc7dc93c10baaa80571665ca1231afdafe9
# Parent  d5b8ee9f2201e1d9fa7ac41da9a4a8d939cd42b1
HTTP upstream: added possibility to specify variables for the ip_hash 
directive.

Example: ip_hash $http_x_forwarded_for;
By default, without any parameters, client's IP address is used.

A use case:
A group of load balancers is put behind another group. Thus client's IP 
address for the former is always one of the latter's.
With this patch ip_hash can use any variable with a valid address, 
including the one in X-Forwarded-For header.

diff -r d5b8ee9f2201 -r cbfb9bc7dc93 
src/http/modules/ngx_http_upstream_ip_hash_module.c
--- a/src/http/modules/ngx_http_upstream_ip_hash_module.c       Thu May 
22 00:16:17 2014 +0400
+++ b/src/http/modules/ngx_http_upstream_ip_hash_module.c       Thu May 
22 13:20:28 2014 +0600
@@ -36,7 +36,7 @@
  static ngx_command_t  ngx_http_upstream_ip_hash_commands[] = {

      { ngx_string("ip_hash"),
-      NGX_HTTP_UPS_CONF|NGX_CONF_NOARGS,
+      NGX_HTTP_UPS_CONF|NGX_CONF_NOARGS|NGX_CONF_TAKE1,
        ngx_http_upstream_ip_hash,
        0,
        0,
@@ -116,17 +116,41 @@

      r->upstream->peer.get = ngx_http_upstream_get_ip_hash_peer;

-    switch (r->connection->sockaddr->sa_family) {
+    struct sockaddr *addr=r->connection->sockaddr;
+
+    if(us->ip_hash_var != -1) {
+
+        ngx_http_variable_value_t 
*v=ngx_http_get_flushed_variable(r,us->ip_hash_var);
+
+        if (v == NULL || v->not_found) {
+            ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                    "http upstream ip_hash variable not found");
+        } else {
+
+            ngx_addr_t ngx_addr;
+
+            if (ngx_parse_addr(r->pool, &ngx_addr, v->data, v->len) == 
NGX_OK) {
+                addr=ngx_addr.sockaddr;
+            } else {
+                ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                        "http upstream ip_hash address is invalid");
+            }
+
+        }
+
+    }
+
+    switch (addr->sa_family) {

      case AF_INET:
-        sin = (struct sockaddr_in *) r->connection->sockaddr;
+        sin = (struct sockaddr_in *) addr;
          iphp->addr = (u_char *) &sin->sin_addr.s_addr;
          iphp->addrlen = 3;
          break;

  #if (NGX_HAVE_INET6)
      case AF_INET6:
-        sin6 = (struct sockaddr_in6 *) r->connection->sockaddr;
+        sin6 = (struct sockaddr_in6 *) addr;
          iphp->addr = (u_char *) &sin6->sin6_addr.s6_addr;
          iphp->addrlen = 16;
          break;
@@ -267,6 +291,31 @@
                             "load balancing method redefined");
      }

+    if (cf->args->nelts == 2) {
+
+        ngx_str_t   name;
+
+        name=((ngx_str_t *)cf->args->elts)[1];
+
+        if (name.data[0] != '$') {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                    "invalid variable name \"%V\"", &name);
+            return NGX_CONF_ERROR;
+        }
+
+        name.len--;
+        name.data++;
+
+        uscf->ip_hash_var = ngx_http_get_variable_index(cf, &name);
+
+        if (uscf->ip_hash_var == NGX_ERROR) {
+            return NGX_CONF_ERROR;
+        }
+
+    } else {
+        uscf->ip_hash_var = -1;
+    }
+
      uscf->peer.init_upstream = ngx_http_upstream_init_ip_hash;

      uscf->flags = NGX_HTTP_UPSTREAM_CREATE
diff -r d5b8ee9f2201 -r cbfb9bc7dc93 src/http/ngx_http_upstream.h
--- a/src/http/ngx_http_upstream.h      Thu May 22 00:16:17 2014 +0400
+++ b/src/http/ngx_http_upstream.h      Thu May 22 13:20:28 2014 +0600
@@ -119,6 +119,7 @@
      in_port_t                        port;
      in_port_t                        default_port;
      ngx_uint_t                       no_port;  /* unsigned no_port:1 */
+    ngx_int_t                        ip_hash_var;
  };



More information about the nginx-devel mailing list