Welcome! Log In Create A New Profile

Advanced

Re: [PATCH 3 of 3] Stream: ngx_stream_pass_module

This forum is currently read only. You can not log in or make any changes. This is a temporary situation.
Sergey Kandaurov
February 13, 2024 05:48AM
> On 10 Nov 2023, at 14:07, Roman Arutyunyan <arut@nginx.com> wrote:
>
> # HG changeset patch
> # User Roman Arutyunyan <arut@nginx.com>
> # Date 1699543504 -14400
> # Thu Nov 09 19:25:04 2023 +0400
> # Node ID 3cab85fe55272835674b7f1c296796955256d019
> # Parent 1d3464283405a4d8ac54caae9bf1815c723f04c5
> Stream: ngx_stream_pass_module.
>
> The module allows to pass connections from Stream to other modules such as HTTP
> or Mail, as well as back to Stream. Previously, this was only possible with
> proxying. Connections with preread buffer read out from socket cannot be
> passed.
>
> The module allows to terminate SSL selectively based on SNI.
>
> stream {
> server {
> listen 8000 default_server;
> ssl_preread on;
> ...
> }
>
> server {
> listen 8000;
> server_name foo.example.com;
> pass 8001; # to HTTP
> }
>
> server {
> listen 8000;
> server_name bar.example.com;
> ...
> }
> }
>
> http {
> server {
> listen 8001 ssl;
> ...
>
> location / {
> root html;
> }
> }
> }
>
> diff --git a/auto/modules b/auto/modules
> --- a/auto/modules
> +++ b/auto/modules
> @@ -1166,6 +1166,16 @@ if [ $STREAM != NO ]; then
> . auto/module
> fi
>
> + if [ $STREAM_PASS = YES ]; then
> + ngx_module_name=ngx_stream_pass_module
> + ngx_module_deps=
> + ngx_module_srcs=src/stream/ngx_stream_pass_module.c
> + ngx_module_libs=
> + ngx_module_link=$STREAM_PASS
> +
> + . auto/module
> + fi
> +
> if [ $STREAM_SET = YES ]; then
> ngx_module_name=ngx_stream_set_module
> ngx_module_deps=
> diff --git a/auto/options b/auto/options
> --- a/auto/options
> +++ b/auto/options
> @@ -127,6 +127,7 @@ STREAM_GEOIP=NO
> STREAM_MAP=YES
> STREAM_SPLIT_CLIENTS=YES
> STREAM_RETURN=YES
> +STREAM_PASS=YES
> STREAM_SET=YES
> STREAM_UPSTREAM_HASH=YES
> STREAM_UPSTREAM_LEAST_CONN=YES
> @@ -337,6 +338,7 @@ use the \"--with-mail_ssl_module\" optio
> --without-stream_split_clients_module)
> STREAM_SPLIT_CLIENTS=NO ;;
> --without-stream_return_module) STREAM_RETURN=NO ;;
> + --without-stream_pass_module) STREAM_PASS=NO ;;
> --without-stream_set_module) STREAM_SET=NO ;;
> --without-stream_upstream_hash_module)
> STREAM_UPSTREAM_HASH=NO ;;
> @@ -556,6 +558,7 @@ cat << END
> --without-stream_split_clients_module
> disable ngx_stream_split_clients_module
> --without-stream_return_module disable ngx_stream_return_module
> + --without-stream_pass_module disable ngx_stream_pass_module
> --without-stream_set_module disable ngx_stream_set_module
> --without-stream_upstream_hash_module
> disable ngx_stream_upstream_hash_module
> diff --git a/src/stream/ngx_stream_pass_module.c b/src/stream/ngx_stream_pass_module.c
> new file mode 100644
> --- /dev/null
> +++ b/src/stream/ngx_stream_pass_module.c
> @@ -0,0 +1,245 @@
> +
> +/*
> + * Copyright (C) Roman Arutyunyan
> + * Copyright (C) Nginx, Inc.
> + */
> +
> +
> +#include <ngx_config.h>
> +#include <ngx_core.h>
> +#include <ngx_stream.h>
> +
> +
> +typedef struct {
> + ngx_addr_t *addr;
> + ngx_stream_complex_value_t *addr_value;
> +} ngx_stream_pass_srv_conf_t;
> +
> +
> +static void ngx_stream_pass_handler(ngx_stream_session_t *s);
> +static void *ngx_stream_pass_create_srv_conf(ngx_conf_t *cf);
> +static char *ngx_stream_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
> +
> +
> +static ngx_command_t ngx_stream_pass_commands[] = {
> +
> + { ngx_string("pass"),
> + NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1,
> + ngx_stream_pass,
> + NGX_STREAM_SRV_CONF_OFFSET,
> + 0,
> + NULL },
> +
> + ngx_null_command
> +};
> +
> +
> +static ngx_stream_module_t ngx_stream_pass_module_ctx = {
> + NULL, /* preconfiguration */
> + NULL, /* postconfiguration */
> +
> + NULL, /* create main configuration */
> + NULL, /* init main configuration */
> +
> + ngx_stream_pass_create_srv_conf, /* create server configuration */
> + NULL /* merge server configuration */
> +};
> +
> +
> +ngx_module_t ngx_stream_pass_module = {
> + NGX_MODULE_V1,
> + &ngx_stream_pass_module_ctx, /* module conaddr */
> + ngx_stream_pass_commands, /* module directives */
> + NGX_STREAM_MODULE, /* module type */
> + NULL, /* init master */
> + NULL, /* init module */
> + NULL, /* init process */
> + NULL, /* init thread */
> + NULL, /* exit thread */
> + NULL, /* exit process */
> + NULL, /* exit master */
> + NGX_MODULE_V1_PADDING
> +};
> +
> +
> +static void
> +ngx_stream_pass_handler(ngx_stream_session_t *s)
> +{
> + ngx_url_t u;
> + ngx_str_t url;
> + ngx_addr_t *addr;
> + ngx_uint_t i;
> + ngx_listening_t *ls;
> + ngx_connection_t *c;
> + ngx_stream_pass_srv_conf_t *pscf;
> +
> + c = s->connection;
> +
> + c->log->action = "passing connection to another module";
> +
> + if (c->buffer && c->buffer->pos != c->buffer->last) {
> + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
> + "cannot pass connection with preread data");
> + goto failed;
> + }
> +
> + pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_pass_module);
> +
> + addr = pscf->addr;
> +
> + if (addr == NULL) {
> + if (ngx_stream_complex_value(s, pscf->addr_value, &url) != NGX_OK) {
> + goto failed;
> + }
> +
> + ngx_memzero(&u, sizeof(ngx_url_t));
> +
> + u.url = url;
> + u.listen = 1;
> + u.no_resolve = 1;
> +
> + if (ngx_parse_url(s->connection->pool, &u) != NGX_OK) {
> + if (u.err) {
> + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
> + "%s in pass \"%V\"", u.err, &u.url);
> + }
> +
> + goto failed;
> + }
> +
> + if (u.naddrs == 0) {
> + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
> + "no addresses in pass \"%V\"", &u.url);
> + goto failed;
> + }
> +
> + addr = &u.addrs[0];
> + }
> +
> + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0,
> + "stream pass addr: \"%V\"", &addr->name);
> +
> + ls = ngx_cycle->listening.elts;
> +
> + for (i = 0; i < ngx_cycle->listening.nelts; i++) {
> + if (ngx_cmp_sockaddr(ls[i].sockaddr, ls[i].socklen,
> + addr->sockaddr, addr->socklen, 1)
> + == NGX_OK)
> + {
> + c->listening = &ls[i];

The address configuration (addr_conf) is stored depending on the
protocol family of the listening socket, it's different for AF_INET6.
So, if the protocol family is switched when passing a connection,
it may happen that c->local_sockaddr->sa_family will keep a wrong
value, the listen handler will dereference addr_conf incorrectly.

Consider the following example:

server {
listen 127.0.0.1:8081;
pass [::1]:8091;
}

server {
listen [::1]:8091;
...
}

When ls->handler is invoked, c->local_sockaddr is kept inherited
from the originally accepted connection, which is of AF_INET.
To fix this, c->local_sockaddr and c->local_socklen should be
updated according to the new listen socket configuration.

OTOH, c->sockaddr / c->socklen should be kept intact.
Note that this makes possible cross protocol family
configurations in e.g. realip and access modules;
from now on this will have to be taken into account.

> +
> + c->data = NULL;
> + c->buffer = NULL;
> +
> + *c->log = c->listening->log;
> + c->log->handler = NULL;
> + c->log->data = NULL;
> +
> + c->listening->handler(c);
> +
> + return;
> + }
> + }
> +
> + ngx_log_error(NGX_LOG_ERR, c->log, 0,
> + "listen not found for \"%V\"", &addr->name);
> +
> + ngx_stream_finalize_session(s, NGX_STREAM_OK);
> +
> + return;
> +
> +failed:
> +
> + ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR);
> +}
> +
> +
> +static void *
> +ngx_stream_pass_create_srv_conf(ngx_conf_t *cf)
> +{
> + ngx_stream_pass_srv_conf_t *conf;
> +
> + conf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_pass_srv_conf_t));
> + if (conf == NULL) {
> + return NULL;
> + }
> +
> + /*
> + * set by ngx_pcalloc():
> + *
> + * conf->addr = NULL;
> + * conf->addr_value = NULL;
> + */
> +
> + return conf;
> +}
> +
> +
> +static char *
> +ngx_stream_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
> +{
> + ngx_stream_pass_srv_conf_t *pscf = conf;
> +
> + ngx_url_t u;
> + ngx_str_t *value, *url;
> + ngx_stream_complex_value_t cv;
> + ngx_stream_core_srv_conf_t *cscf;
> + ngx_stream_compile_complex_value_t ccv;
> +
> + if (pscf->addr || pscf->addr_value) {
> + return "is duplicate";
> + }
> +
> + cscf = ngx_stream_conf_get_module_srv_conf(cf, ngx_stream_core_module);
> +
> + cscf->handler = ngx_stream_pass_handler;
> +
> + value = cf->args->elts;
> +
> + url = &value[1];
> +
> + ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t));
> +
> + ccv.cf = cf;
> + ccv.value = url;
> + ccv.complex_value = &cv;
> +
> + if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) {
> + return NGX_CONF_ERROR;
> + }
> +
> + if (cv.lengths) {
> + pscf->addr_value = ngx_palloc(cf->pool,
> + sizeof(ngx_stream_complex_value_t));
> + if (pscf->addr_value == NULL) {
> + return NGX_CONF_ERROR;
> + }
> +
> + *pscf->addr_value = cv;
> +
> + return NGX_CONF_OK;
> + }
> +
> + ngx_memzero(&u, sizeof(ngx_url_t));
> +
> + u.url = *url;
> + u.listen = 1;
> +
> + if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
> + if (u.err) {
> + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
> + "%s in \"%V\" of the \"pass\" directive",
> + u.err, &u.url);
> + }
> +
> + return NGX_CONF_ERROR;
> + }
> +
> + if (u.naddrs == 0) {
> + return "has no addresses";
> + }
> +
> + pscf->addr = &u.addrs[0];
> +
> + return NGX_CONF_OK;
> +}

--
Sergey Kandaurov
_______________________________________________
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel
Subject Author Views Posted

[PATCH 0 of 3] Stream connection handling updates

Roman Arutyunyan 806 November 10, 2023 05:08AM

[PATCH 1 of 3] Stream: socket peek in preread phase

Roman Arutyunyan 144 November 10, 2023 05:08AM

Re: [PATCH 1 of 3] Stream: socket peek in preread phase

Sergey Kandaurov 124 December 12, 2023 08:18AM

Re: [PATCH 1 of 3] Stream: socket peek in preread phase

Roman Arutyunyan 139 December 13, 2023 09:08AM

Re: [PATCH 1 of 3] Stream: socket peek in preread phase

Sergey Kandaurov 139 December 13, 2023 10:52AM

Re: [PATCH 1 of 3] Stream: socket peek in preread phase

Sergey Kandaurov 125 December 27, 2023 09:36AM

Re: [PATCH 1 of 3] Stream: socket peek in preread phase

Roman Arutyunyan 127 January 04, 2024 11:04AM

Re: [PATCH 1 of 3] Stream: socket peek in preread phase

Sergey Kandaurov 134 January 18, 2024 08:44AM

Re: [PATCH 1 of 3] Stream: socket peek in preread phase

Roman Arutyunyan 117 January 18, 2024 10:08AM

Re: [PATCH 1 of 3] Stream: socket peek in preread phase

Sergey Kandaurov 106 January 18, 2024 11:16AM

Re: [PATCH 1 of 3] Stream: socket peek in preread phase

Maxim Dounin 136 January 18, 2024 02:46PM

Re: [PATCH 1 of 3] Stream: socket peek in preread phase

Sergey Kandaurov 111 January 19, 2024 06:44AM

Re: [PATCH 1 of 3] Stream: socket peek in preread phase

Maxim Dounin 131 January 19, 2024 03:28PM

[PATCH 2 of 3] Stream: virtual servers

Roman Arutyunyan 194 November 10, 2023 05:08AM

Re: [PATCH 2 of 3] Stream: virtual servers

Sergey Kandaurov 162 December 13, 2023 08:42AM

Re: [PATCH 2 of 3] Stream: virtual servers

Sergey Kandaurov 144 December 14, 2023 12:36PM

[PATCH 0 of 6] Re: [PATCH 2 of 3] Stream: virtual servers

Sergey Kandaurov 142 December 15, 2023 10:40AM

[PATCH 1 of 6] Stream: using ngx_stream_ssl_srv_conf_t *sscf naming convention

Sergey Kandaurov 160 December 15, 2023 10:40AM

Re: [PATCH 1 of 6] Stream: using ngx_stream_ssl_srv_conf_t *sscf naming convention

Roman Arutyunyan 136 January 08, 2024 08:32AM

[PATCH 2 of 6] Overhauled some diagnostic messages missed in 1b05b9bbcebf

Sergey Kandaurov 127 December 15, 2023 10:40AM

Re: [PATCH 2 of 6] Overhauled some diagnostic messages missed in 1b05b9bbcebf

Roman Arutyunyan 121 January 09, 2024 08:16AM

[PATCH 3 of 6] Stream: reshuffled ngx_stream_listen_opt_t fields

Sergey Kandaurov 148 December 15, 2023 10:40AM

Re: [PATCH 3 of 6] Stream: reshuffled ngx_stream_listen_opt_t fields

Roman Arutyunyan 123 January 09, 2024 08:18AM

[PATCH 4 of 6] Stream: the "deferred" parameter of the "listen" directive

Sergey Kandaurov 131 December 15, 2023 10:40AM

Re: [PATCH 4 of 6] Stream: the "deferred" parameter of the "listen" directive

Roman Arutyunyan 119 January 09, 2024 10:40AM

Re: [PATCH 4 of 6] Stream: the "deferred" parameter of the "listen" directive

Sergey Kandaurov 112 January 18, 2024 09:52AM

Re: [PATCH 4 of 6] Stream: the "deferred" parameter of the "listen" directive

Roman Arutyunyan 115 January 18, 2024 10:26AM

Re: [PATCH 4 of 6] Stream: the "deferred" parameter of the "listen" directive

Sergey Kandaurov 124 January 18, 2024 11:22AM

[PATCH 5 of 6] Stream: the "accept_filter" parameter of the "listen" directive

Sergey Kandaurov 142 December 15, 2023 10:40AM

Re: [PATCH 5 of 6] Stream: the "accept_filter" parameter of the "listen" directive

Roman Arutyunyan 127 January 11, 2024 07:42AM

[PATCH 6 of 6] Stream: the "setfib" parameter of the "listen" directive

Sergey Kandaurov 135 December 15, 2023 10:42AM

Re: [PATCH 6 of 6] Stream: the "setfib" parameter of the "listen" directive

Roman Arutyunyan 146 January 11, 2024 07:46AM

[PATCH 3 of 3] Stream: ngx_stream_pass_module

Roman Arutyunyan 159 November 10, 2023 05:08AM

Re: [PATCH 3 of 3] Stream: ngx_stream_pass_module

Sergey Kandaurov 122 December 13, 2023 10:46AM

Re: [PATCH 3 of 3] Stream: ngx_stream_pass_module

Sergey Kandaurov 154 December 15, 2023 10:48AM

Re: [PATCH 3 of 3] Stream: ngx_stream_pass_module

Sergey Kandaurov 116 February 13, 2024 05:48AM

Re: [PATCH 3 of 3] Stream: ngx_stream_pass_module

Roman Arutyunyan 156 February 21, 2024 08:38AM

Re: [PATCH 3 of 3] Stream: ngx_stream_pass_module

Sergey Kandaurov 116 February 28, 2024 05:18AM

Re: [PATCH 3 of 3] Stream: ngx_stream_pass_module

Roman Arutyunyan 139 February 28, 2024 09:24AM

Re: [PATCH 3 of 3] Stream: ngx_stream_pass_module

Sergey Kandaurov 219 February 29, 2024 06:40AM



Online Users

Guests: 77
Record Number of Users: 8 on April 13, 2023
Record Number of Guests: 500 on July 15, 2024
Powered by nginx      Powered by FreeBSD      PHP Powered      Powered by MariaDB      ipv6 ready