diff options
author | Zhidao HONG <z.hong@f5.com> | 2022-06-20 13:22:13 +0800 |
---|---|---|
committer | Zhidao HONG <z.hong@f5.com> | 2022-06-20 13:22:13 +0800 |
commit | 9d2672a701e3dcaee45bef9251ab55620d42fa42 (patch) | |
tree | 60c07c277c5ae2120c346718b976a3bd09dbf6a1 | |
parent | 14dfa439eed1983693d7d128cc51c5e738a487d7 (diff) | |
download | unit-9d2672a701e3dcaee45bef9251ab55620d42fa42.tar.gz unit-9d2672a701e3dcaee45bef9251ab55620d42fa42.tar.bz2 |
Router: forwared header replacement.
Diffstat (limited to '')
-rw-r--r-- | docs/changes.xml | 6 | ||||
-rw-r--r-- | src/nxt_conf_validation.c | 50 | ||||
-rw-r--r-- | src/nxt_h1proto.c | 2 | ||||
-rw-r--r-- | src/nxt_http.h | 3 | ||||
-rw-r--r-- | src/nxt_http_request.c | 151 | ||||
-rw-r--r-- | src/nxt_http_route.c | 5 | ||||
-rw-r--r-- | src/nxt_router.c | 107 | ||||
-rw-r--r-- | src/nxt_router.h | 1 |
8 files changed, 250 insertions, 75 deletions
diff --git a/docs/changes.xml b/docs/changes.xml index 9f2e299f..24c3f9db 100644 --- a/docs/changes.xml +++ b/docs/changes.xml @@ -31,6 +31,12 @@ NGINX Unit updated to 1.28.0. date="" time="" packager="Konstantin Pavlov <thresh@nginx.com>"> +<change type="feature"> +<para> +forwarded header to replace client address and protocol. +</para> +</change> + </changes> diff --git a/src/nxt_conf_validation.c b/src/nxt_conf_validation.c index ee7ebe44..a5958788 100644 --- a/src/nxt_conf_validation.c +++ b/src/nxt_conf_validation.c @@ -166,6 +166,8 @@ static nxt_int_t nxt_conf_vldt_match_addr(nxt_conf_validation_t *vldt, nxt_conf_value_t *value); static nxt_int_t nxt_conf_vldt_app_name(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, void *data); +static nxt_int_t nxt_conf_vldt_forwarded(nxt_conf_validation_t *vldt, + nxt_conf_value_t *value, void *data); static nxt_int_t nxt_conf_vldt_app(nxt_conf_validation_t *vldt, nxt_str_t *name, nxt_conf_value_t *value); static nxt_int_t nxt_conf_vldt_object(nxt_conf_validation_t *vldt, @@ -220,6 +222,7 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_setting_members[]; static nxt_conf_vldt_object_t nxt_conf_vldt_http_members[]; static nxt_conf_vldt_object_t nxt_conf_vldt_websocket_members[]; static nxt_conf_vldt_object_t nxt_conf_vldt_static_members[]; +static nxt_conf_vldt_object_t nxt_conf_vldt_forwarded_members[]; static nxt_conf_vldt_object_t nxt_conf_vldt_client_ip_members[]; #if (NXT_TLS) static nxt_conf_vldt_object_t nxt_conf_vldt_tls_members[]; @@ -366,6 +369,10 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_listener_members[] = { .type = NXT_CONF_VLDT_STRING, .validator = nxt_conf_vldt_app_name, }, { + .name = nxt_string("forwarded"), + .type = NXT_CONF_VLDT_OBJECT, + .validator = nxt_conf_vldt_forwarded, + }, { .name = nxt_string("client_ip"), .type = NXT_CONF_VLDT_OBJECT, .validator = nxt_conf_vldt_object, @@ -385,6 +392,27 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_listener_members[] = { }; +static nxt_conf_vldt_object_t nxt_conf_vldt_forwarded_members[] = { + { + .name = nxt_string("client_ip"), + .type = NXT_CONF_VLDT_STRING, + }, { + .name = nxt_string("protocol"), + .type = NXT_CONF_VLDT_STRING, + }, { + .name = nxt_string("source"), + .type = NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY, + .validator = nxt_conf_vldt_match_addrs, + .flags = NXT_CONF_VLDT_REQUIRED + }, { + .name = nxt_string("recursive"), + .type = NXT_CONF_VLDT_BOOLEAN, + }, + + NXT_CONF_VLDT_END +}; + + static nxt_conf_vldt_object_t nxt_conf_vldt_client_ip_members[] = { { .name = nxt_string("source"), @@ -2318,6 +2346,28 @@ error: static nxt_int_t +nxt_conf_vldt_forwarded(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, + void *data) +{ + nxt_conf_value_t *client_ip, *protocol; + + static nxt_str_t client_ip_str = nxt_string("client_ip"); + static nxt_str_t protocol_str = nxt_string("protocol"); + + client_ip = nxt_conf_get_object_member(value, &client_ip_str, NULL); + protocol = nxt_conf_get_object_member(value, &protocol_str, NULL); + + if (client_ip == NULL && protocol == NULL) { + return nxt_conf_vldt_error(vldt, "The \"forwarded\" object must have " + "either \"client_ip\" or \"protocol\" " + "option set."); + } + + return nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_forwarded_members); +} + + +static nxt_int_t nxt_conf_vldt_app(nxt_conf_validation_t *vldt, nxt_str_t *name, nxt_conf_value_t *value) { diff --git a/src/nxt_h1proto.c b/src/nxt_h1proto.c index d3340774..1473aaa0 100644 --- a/src/nxt_h1proto.c +++ b/src/nxt_h1proto.c @@ -490,7 +490,7 @@ nxt_h1p_conn_request_init(nxt_task_t *task, void *obj, void *data) r->remote = c->remote; #if (NXT_TLS) - r->tls = c->u.tls; + r->tls = (c->u.tls != NULL); #endif r->task = c->task; diff --git a/src/nxt_http.h b/src/nxt_http.h index 665ccdbf..8fa0caad 100644 --- a/src/nxt_http.h +++ b/src/nxt_http.h @@ -162,7 +162,6 @@ struct nxt_http_request_s { nxt_sockaddr_t *remote; nxt_sockaddr_t *local; - void *tls; nxt_task_t task; nxt_timer_t timer; @@ -190,6 +189,7 @@ struct nxt_http_request_s { uint8_t pass_count; /* 8 bits */ uint8_t app_target; nxt_http_protocol_t protocol:8; /* 2 bits */ + uint8_t tls; /* 1 bit */ uint8_t logged; /* 1 bit */ uint8_t header_sent; /* 1 bit */ uint8_t inconsistent; /* 1 bit */ @@ -281,6 +281,7 @@ typedef struct { struct nxt_http_forward_s { nxt_http_forward_header_t client_ip; + nxt_http_forward_header_t protocol; nxt_http_route_addr_rule_t *source; uint8_t recursive; /* 1 bit */ }; diff --git a/src/nxt_http_request.c b/src/nxt_http_request.c index 3f926796..7fb86cc4 100644 --- a/src/nxt_http_request.c +++ b/src/nxt_http_request.c @@ -10,10 +10,14 @@ static nxt_int_t nxt_http_validate_host(nxt_str_t *host, nxt_mp_t *mp); static void nxt_http_request_start(nxt_task_t *task, void *obj, void *data); -static nxt_int_t nxt_http_request_client_ip(nxt_task_t *task, - nxt_http_request_t *r); +static nxt_int_t nxt_http_request_forward(nxt_task_t *task, + nxt_http_request_t *r, nxt_http_forward_t *forward); +static void nxt_http_request_forward_client_ip(nxt_http_request_t *r, + nxt_http_forward_t *forward, nxt_array_t *fields); static nxt_sockaddr_t *nxt_http_request_client_ip_sockaddr( nxt_http_request_t *r, u_char *start, size_t len); +static void nxt_http_request_forward_protocol(nxt_http_request_t *r, + nxt_http_field_t *field); static void nxt_http_request_ready(nxt_task_t *task, void *obj, void *data); static void nxt_http_request_proto_info(nxt_task_t *task, nxt_http_request_t *r); @@ -296,38 +300,46 @@ static void nxt_http_request_start(nxt_task_t *task, void *obj, void *data) { nxt_int_t ret; + nxt_socket_conf_t *skcf; nxt_http_request_t *r; r = obj; r->state = &nxt_http_request_body_state; - ret = nxt_http_request_client_ip(task, r); - if (nxt_slow_path(ret != NXT_OK)) { - nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); + skcf = r->conf->socket_conf; + + if (skcf->forwarded != NULL) { + ret = nxt_http_request_forward(task, r, skcf->forwarded); + if (nxt_slow_path(ret != NXT_OK)) { + goto fail; + } + } + + if (skcf->client_ip != NULL) { + ret = nxt_http_request_forward(task, r, skcf->client_ip); + if (nxt_slow_path(ret != NXT_OK)) { + goto fail; + } } nxt_http_request_read_body(task, r); + + return; + +fail: + nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); } static nxt_int_t -nxt_http_request_client_ip(nxt_task_t *task, nxt_http_request_t *r) +nxt_http_request_forward(nxt_task_t *task, nxt_http_request_t *r, + nxt_http_forward_t *forward) { - u_char *start, *p; - nxt_int_t ret, i, len; - nxt_str_t *header; - nxt_array_t *fields_arr; /* of nxt_http_field_t * */ - nxt_sockaddr_t *sa, *prev_sa; - nxt_http_field_t *f, **fields; - nxt_http_forward_t *forward; - nxt_http_forward_header_t *client_ip; - - forward = r->conf->socket_conf->client_ip; - - if (forward == NULL) { - return NXT_OK; - } + nxt_int_t ret; + nxt_array_t *client_ip_fields; + nxt_http_field_t *f, **fields, *protocol_field; + nxt_http_forward_header_t *client_ip, *protocol; ret = nxt_http_route_addr_rule(r, forward->source, r->remote); if (ret <= 0) { @@ -335,37 +347,78 @@ nxt_http_request_client_ip(nxt_task_t *task, nxt_http_request_t *r) } client_ip = &forward->client_ip; - header = client_ip->header; + protocol = &forward->protocol; - fields_arr = nxt_array_create(r->mem_pool, 2, sizeof(nxt_http_field_t *)); - if (nxt_slow_path(fields_arr == NULL)) { - return NXT_ERROR; + if (client_ip->header != NULL) { + client_ip_fields = nxt_array_create(r->mem_pool, 1, + sizeof(nxt_http_field_t *)); + if (nxt_slow_path(client_ip_fields == NULL)) { + return NXT_ERROR; + } + + } else { + client_ip_fields = NULL; } + protocol_field = NULL; + nxt_list_each(f, r->fields) { - if (f->hash == client_ip->header_hash - && f->name_length == client_ip->header->length + if (client_ip_fields != NULL + && f->hash == client_ip->header_hash && f->value_length > 0 - && nxt_memcasecmp(f->name, header->start, header->length) == 0) + && f->name_length == client_ip->header->length + && nxt_memcasecmp(f->name, client_ip->header->start, + client_ip->header->length) == 0) { - fields = nxt_array_add(fields_arr); + fields = nxt_array_add(client_ip_fields); if (nxt_slow_path(fields == NULL)) { return NXT_ERROR; } *fields = f; } + + if (protocol->header != NULL + && protocol_field == NULL + && f->hash == protocol->header_hash + && f->value_length > 0 + && f->name_length == protocol->header->length + && nxt_memcasecmp(f->name, protocol->header->start, + protocol->header->length) == 0) + { + protocol_field = f; + } } nxt_list_loop; + if (client_ip_fields != NULL) { + nxt_http_request_forward_client_ip(r, forward, client_ip_fields); + } + + if (protocol_field != NULL) { + nxt_http_request_forward_protocol(r, protocol_field); + } + + return NXT_OK; +} + + +static void +nxt_http_request_forward_client_ip(nxt_http_request_t *r, + nxt_http_forward_t *forward, nxt_array_t *fields) +{ + u_char *start, *p; + nxt_int_t ret, i, len; + nxt_sockaddr_t *sa, *prev_sa; + nxt_http_field_t **f; + prev_sa = r->remote; - fields = (nxt_http_field_t **) fields_arr->elts; + f = (nxt_http_field_t **) fields->elts; - i = fields_arr->nelts; + i = fields->nelts; while (i-- > 0) { - f = fields[i]; - start = f->value; - len = f->value_length; + start = f[i]->value; + len = f[i]->value_length; do { for (p = start + len - 1; p > start; p--, len--) { @@ -387,20 +440,18 @@ nxt_http_request_client_ip(nxt_task_t *task, nxt_http_request_t *r) r->remote = prev_sa; } - return NXT_OK; + return; } if (!forward->recursive) { r->remote = sa; - - return NXT_OK; + return; } ret = nxt_http_route_addr_rule(r, forward->source, sa); if (ret <= 0 || (i == 0 && p == start)) { r->remote = sa; - - return NXT_OK; + return; } prev_sa = sa; @@ -408,8 +459,6 @@ nxt_http_request_client_ip(nxt_task_t *task, nxt_http_request_t *r) } while (len > 0); } - - return NXT_OK; } @@ -453,6 +502,28 @@ nxt_http_request_client_ip_sockaddr(nxt_http_request_t *r, u_char *start, } +static void +nxt_http_request_forward_protocol(nxt_http_request_t *r, + nxt_http_field_t *field) +{ + if (field->value_length == 4) { + if (nxt_memcasecmp(field->value, "http", 4) == 0) { + r->tls = 0; + } + + } else if (field->value_length == 5) { + if (nxt_memcasecmp(field->value, "https", 5) == 0) { + r->tls = 1; + } + + } else if (field->value_length == 2) { + if (nxt_memcasecmp(field->value, "on", 2) == 0) { + r->tls = 1; + } + } +} + + static const nxt_http_request_state_t nxt_http_request_body_state nxt_aligned(64) = { diff --git a/src/nxt_http_route.c b/src/nxt_http_route.c index f7023997..5a4f349e 100644 --- a/src/nxt_http_route.c +++ b/src/nxt_http_route.c @@ -1949,14 +1949,13 @@ nxt_http_route_test_argument(nxt_http_request_t *r, static nxt_int_t nxt_http_route_scheme(nxt_http_request_t *r, nxt_http_route_rule_t *rule) { - nxt_bool_t tls, https; + nxt_bool_t https; nxt_http_route_pattern_slice_t *pattern_slice; pattern_slice = rule->pattern[0].u.pattern_slices->elts; https = (pattern_slice->length == nxt_length("https")); - tls = (r->tls != NULL); - return (tls == https); + return (r->tls == https); } diff --git a/src/nxt_router.c b/src/nxt_router.c index 8487d239..a3cc0a8d 100644 --- a/src/nxt_router.c +++ b/src/nxt_router.c @@ -108,8 +108,10 @@ static nxt_int_t nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end); static nxt_int_t nxt_router_conf_process_static(nxt_task_t *task, nxt_router_conf_t *rtcf, nxt_conf_value_t *conf); -static nxt_int_t nxt_router_conf_process_client_ip(nxt_task_t *task, - nxt_mp_t *mp, nxt_socket_conf_t *skcf, nxt_conf_value_t *conf); +static nxt_http_forward_t *nxt_router_conf_forward(nxt_task_t *task, + nxt_mp_t *mp, nxt_conf_value_t *conf); +static nxt_int_t nxt_router_conf_forward_header(nxt_mp_t *mp, + nxt_conf_value_t *conf, nxt_http_forward_header_t *fh); static nxt_app_t *nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name); static nxt_int_t nxt_router_apps_hash_test(nxt_lvlhsh_query_t *lhq, void *data); @@ -1513,6 +1515,7 @@ nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, #endif static nxt_str_t static_path = nxt_string("/settings/http/static"); static nxt_str_t websocket_path = nxt_string("/settings/http/websocket"); + static nxt_str_t forwarded_path = nxt_string("/forwarded"); static nxt_str_t client_ip_path = nxt_string("/client_ip"); root = nxt_conf_json_parse(tmcf->mem_pool, start, end, NULL); @@ -1883,11 +1886,20 @@ nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, t->length = nxt_strlen(t->start); } + conf = nxt_conf_get_path(listener, &forwarded_path); + + if (conf != NULL) { + skcf->forwarded = nxt_router_conf_forward(task, mp, conf); + if (nxt_slow_path(skcf->forwarded == NULL)) { + return NXT_ERROR; + } + } + conf = nxt_conf_get_path(listener, &client_ip_path); if (conf != NULL) { - ret = nxt_router_conf_process_client_ip(task, mp, skcf, conf); - if (nxt_slow_path(ret != NXT_OK)) { + skcf->client_ip = nxt_router_conf_forward(task, mp, conf); + if (nxt_slow_path(skcf->client_ip == NULL)) { return NXT_ERROR; } } @@ -2124,68 +2136,103 @@ nxt_router_conf_process_static(nxt_task_t *task, nxt_router_conf_t *rtcf, } -static nxt_int_t -nxt_router_conf_process_client_ip(nxt_task_t *task, nxt_mp_t *mp, - nxt_socket_conf_t *skcf, nxt_conf_value_t *conf) +static nxt_http_forward_t * +nxt_router_conf_forward(nxt_task_t *task, nxt_mp_t *mp, nxt_conf_value_t *conf) { - char c; - size_t i; - uint32_t hash; - nxt_str_t header; - nxt_conf_value_t *source_conf, *header_conf, *recursive_conf; + nxt_int_t ret; + nxt_conf_value_t *header_conf, *client_ip_conf, *protocol_conf; + nxt_conf_value_t *source_conf, *recursive_conf; nxt_http_forward_t *forward; - nxt_http_forward_header_t *client_ip; nxt_http_route_addr_rule_t *source; static nxt_str_t header_path = nxt_string("/header"); + static nxt_str_t client_ip_path = nxt_string("/client_ip"); + static nxt_str_t protocol_path = nxt_string("/protocol"); static nxt_str_t source_path = nxt_string("/source"); static nxt_str_t recursive_path = nxt_string("/recursive"); - source_conf = nxt_conf_get_path(conf, &source_path); header_conf = nxt_conf_get_path(conf, &header_path); + + if (header_conf != NULL) { + client_ip_conf = nxt_conf_get_path(conf, &header_path); + protocol_conf = NULL; + + } else { + client_ip_conf = nxt_conf_get_path(conf, &client_ip_path); + protocol_conf = nxt_conf_get_path(conf, &protocol_path); + } + + source_conf = nxt_conf_get_path(conf, &source_path); recursive_conf = nxt_conf_get_path(conf, &recursive_path); - if (source_conf == NULL || header_conf == NULL) { - return NXT_ERROR; + if (source_conf == NULL + || (protocol_conf == NULL && client_ip_conf == NULL)) + { + return NULL; } forward = nxt_mp_zget(mp, sizeof(nxt_http_forward_t)); if (nxt_slow_path(forward == NULL)) { - return NXT_ERROR; + return NULL; } source = nxt_http_route_addr_rule_create(task, mp, source_conf); if (nxt_slow_path(source == NULL)) { - return NXT_ERROR; + return NULL; } forward->source = source; - client_ip = &forward->client_ip; - - nxt_conf_get_string(header_conf, &header); - if (recursive_conf != NULL) { forward->recursive = nxt_conf_get_boolean(recursive_conf); } - client_ip->header = nxt_str_dup(mp, NULL, &header); - if (nxt_slow_path(client_ip->header == NULL)) { + if (client_ip_conf != NULL) { + ret = nxt_router_conf_forward_header(mp, client_ip_conf, + &forward->client_ip); + if (nxt_slow_path(ret != NXT_OK)) { + return NULL; + } + } + + if (protocol_conf != NULL) { + ret = nxt_router_conf_forward_header(mp, protocol_conf, + &forward->protocol); + if (nxt_slow_path(ret != NXT_OK)) { + return NULL; + } + } + + return forward; +} + + +static nxt_int_t +nxt_router_conf_forward_header(nxt_mp_t *mp, nxt_conf_value_t *conf, + nxt_http_forward_header_t *fh) +{ + char c; + size_t i; + uint32_t hash; + nxt_str_t header; + + nxt_conf_get_string(conf, &header); + + fh->header = nxt_str_dup(mp, NULL, &header); + if (nxt_slow_path(fh->header == NULL)) { return NXT_ERROR; } hash = NXT_HTTP_FIELD_HASH_INIT; - for (i = 0; i < client_ip->header->length; i++) { - c = client_ip->header->start[i]; + for (i = 0; i < fh->header->length; i++) { + c = fh->header->start[i]; hash = nxt_http_field_hash_char(hash, nxt_lowcase(c)); } hash = nxt_http_field_hash_end(hash) & 0xFFFF; - client_ip->header_hash = hash; - - skcf->client_ip = forward; + fh->header_hash = hash; return NXT_OK; } @@ -5547,7 +5594,7 @@ nxt_router_prepare_msg(nxt_task_t *task, nxt_http_request_t *r, p = nxt_cpymem(p, nxt_sockaddr_address(r->local), r->local->address_length); *p++ = '\0'; - req->tls = (r->tls != NULL); + req->tls = r->tls; req->websocket_handshake = r->websocket_handshake; req->server_name_length = r->server_name.length; diff --git a/src/nxt_router.h b/src/nxt_router.h index b97d5c20..37008f9d 100644 --- a/src/nxt_router.h +++ b/src/nxt_router.h @@ -197,6 +197,7 @@ typedef struct { uint8_t discard_unsafe_fields; /* 1 bit */ + nxt_http_forward_t *forwarded; nxt_http_forward_t *client_ip; #if (NXT_TLS) |