├── .gitignore
├── Jenkinsfile
├── LICENSE
├── README.md
├── ci
├── nginx-deploy.yml
├── nginx-inventory
└── nginx_configs
│ ├── nginx-noise-backend-int.conf
│ └── nginx-noise-lb-int.conf
├── config
├── example
├── client_key_25519
├── nginx.conf
├── nginx_configure.sh
└── server_key_25519
├── ngx_noise_protocol.c
├── ngx_noise_protocol.h
├── ngx_nsoc.c
├── ngx_nsoc.h
├── ngx_nsoc_core_module.c
├── ngx_nsoc_handler.c
├── ngx_nsoc_handler.h
├── ngx_nsoc_noiseserver_module.c
├── ngx_nsoc_noiseserver_module.h
├── ngx_nsoc_proxy_module.c
├── ngx_nsoc_script.c
├── ngx_nsoc_script.h
├── ngx_nsoc_upstream.c
├── ngx_nsoc_upstream.h
├── ngx_nsoc_upstream_round_robin.c
├── ngx_nsoc_upstream_round_robin.h
├── ngx_nsoc_variables.c
├── ngx_nsoc_variables.h
└── ngx_nsoc_write_filter_module.c
/.gitignore:
--------------------------------------------------------------------------------
1 | # Prerequisites
2 | *.d
3 |
4 | # Compiled Object files
5 | *.slo
6 | *.lo
7 | *.o
8 | *.obj
9 |
10 | # Precompiled Headers
11 | *.gch
12 | *.pch
13 |
14 | # Compiled Dynamic libraries
15 | *.so
16 | *.dylib
17 | *.dll
18 |
19 | # Fortran module files
20 | *.mod
21 | *.smod
22 |
23 | # Compiled Static libraries
24 | *.lai
25 | *.la
26 | *.a
27 | *.lib
28 |
29 | # Executables
30 | *.exe
31 | *.out
32 | *.app
33 | /.project
34 |
--------------------------------------------------------------------------------
/Jenkinsfile:
--------------------------------------------------------------------------------
1 | stage('Get nginx sources'){
2 | node('master'){
3 | clearContentUnix()
4 | sh "wget https://nginx.org/download/nginx-1.12.0.tar.gz"
5 | sh "tar xfz nginx-1.12.0.tar.gz"
6 | sh "mkdir virgil-nginx-noise-socket"
7 | dir("nginx-1.12.0/virgil-nginx-noise-socket"){
8 | checkout scm
9 | }
10 | stash excludes: "*.tar.gz", includes: '**', name: 'nginx-source'
11 | }
12 | }
13 |
14 | stage('Build'){
15 | node("build-docker"){
16 | docker.image('centos:7').inside("--user root"){
17 | clearContentUnix()
18 | }
19 | unstash "nginx-source"
20 | docker.image('centos:7').inside("--user root"){
21 | sh "yum install -y gcc make pcre pcre-devel pcre2 pcre2-devel openssl-devel autoconf automake flex bison git ruby ruby-devel curl libyaml-devel rpm-build wget"
22 | sh "gem install fpm"
23 | // build libsodium
24 | // sh "git clone https://github.com/jedisct1/libsodium.git -b stable"
25 | // sh "wget https://download.libsodium.org/libsodium/releases/libsodium-1.0.13.tar.gz"
26 | // sh "tar xzf libsodium-1.0.13.tar.gz"
27 | // sh "cd libsodium-1.0.13 && ./configure"
28 | // sh "cd libsodium-1.0.13 && make && make check"
29 | // sh "cd libsodium-1.0.13 && make install"
30 | // sh "echo '/usr/local/lib' >> /etc/ld.so.conf.d/libsodium.conf"
31 | // sh "cat /etc/ld.so.conf.d/libsodium.conf"
32 | // sh "ls -la libsodium"
33 | // sh "ls -la libsodium/src/"
34 | // sh "ls -la libsodium/src/libsodium"
35 | // sh "ls -la libsodium/src/libsodium/.libs"
36 | // sh "cp libsodium/src/libsodium/.libs/libsodium.so.18.3.0 /lib/libsodium.so.18.3.0"
37 | // sh "ln -s /lib/x86_64-linux-gnu/libsodium.so.18.3.0 /lib/libsodium.so.18"
38 | // sh "ln -s /lib/x86_64-linux-gnu/libsodium.so.18.3.0 /lib/libsodium.so"
39 | // sh "cp libsodium/src/libsodium/.libs/libsodium.a /lib/libsodium.a"
40 | // build noise
41 | sh "git clone https://github.com/rweather/noise-c.git"
42 | sh "cd noise-c && autoreconf -i"
43 | sh "cd noise-c && ./configure"
44 | sh "cd noise-c && make"
45 | sh "cd noise-c && make install"
46 | sh "cd noise-c && mkdir noise-artifact"
47 | sh "cd noise-c && export DESTDIR='noise-artifact' && make install"
48 | sh "ls -la noise-c/include/noise/noise-artifact"
49 | sh "cd nginx-1.12.0 && ./configure --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --pid-path=/var/run/nginx.pid --lock-path=/var/lock/nginx.lock --http-log-path=/var/log/nginx/access.log --http-client-body-temp-path=/var/lib/nginx/body --http-proxy-temp-path=/var/lib/nginx/proxy --without-http_fastcgi_module --without-http_uwsgi_module --with-http_stub_status_module --with-http_gzip_static_module --with-http_ssl_module --with-debug --add-module=./virgil-nginx-noise-socket"
50 | // build nginx
51 | sh "cd nginx-1.12.0 && make"
52 | sh "cd nginx-1.12.0 && mkdir nginx-artifact"
53 | sh "cd nginx-1.12.0 && export DESTDIR='nginx-artifact' && make install"
54 | sh "cp -r noise-c/include/noise/noise-artifact/* nginx-1.12.0/nginx-artifact/"
55 | sh "ls -l nginx-1.12.0/nginx-artifact"
56 | sh "fpm -s dir -t rpm -p ./ -m 'sk@virgilsecurity.com' --description 'Virgil Security Noise Socket nginx with plugin' \
57 | --rpm-use-file-permissions \
58 | -n 'virgil-nginx-noise-socket' -v 1.0.${BUILD_NUMBER} -C nginx-1.12.0/nginx-artifact ./"
59 | }
60 | stash includes: "*.rpm", name: "nginx-rpm"
61 | }
62 | }
63 |
64 | stage('Deploy artifacts'){
65 | node('master'){
66 | dir('nginx-1.12.0/virgil-nginx-noise-socket'){
67 | dir('ci'){
68 | unstash 'nginx-rpm'
69 | }
70 | sh "ansible-playbook -i ci/nginx-inventory ci/nginx-deploy.yml --extra-vars 'rpm_name=virgil-nginx-noise-socket-1.0.${BUILD_NUMBER}-1.x86_64.rpm'"
71 | dir('ci'){
72 | archiveArtifacts("*.rpm")
73 | }
74 | }
75 | }
76 | }
77 |
78 | // Utility Functions
79 |
80 | def clearContentUnix() {
81 | sh "rm -fr -- *"
82 | }
83 |
84 | def archiveArtifacts(pattern) {
85 | step([$class: 'ArtifactArchiver', artifacts: pattern, fingerprint: true, onlyIfSuccessful: true])
86 | }
87 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2017, Virgil Security, Inc.
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | * Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | * Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | * Neither the name of the copyright holder nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # virgil-nginx-noise-socket
2 | Nginx module that implements Noise Socket Protocol by using Virgil Security infrastructure.
3 |
4 | ## Features ##
5 |
6 | - Own context in the Nginx server providing a functionality of TCP of a proxy.
7 | - Protection of traffic by means of [Noise Protocol](http://noiseprotocol.org/).
8 | - At the moment only `Noise_XX_25519_AESGCM_BLAKE2b` noise protocol pattern is implemented.
9 |
10 | ## Building of Nginx with the virgil-nginx-noise-socket module:
11 |
12 | #### list of dependences
13 |
14 | * Autoconf
15 | * Automake
16 | * pcre
17 | * pcre-devel
18 | * pcre2
19 | * pcre2-devel
20 | * openssl-devel
21 | * flex
22 | * bison
23 |
24 | #### Building
25 |
26 | 1. The virgil-nginx-noise-socket module is tested with nginx-1.12.1.
27 | 2. Module is tested in an OS Linux Mint 17.1 Rebecca 64-bit, Linux Mint 18.1 Serena 64-bit, Centos 7.
28 | 3. Set [Noise-C](https://github.com/rweather/noise-c) library is necessary for building of the server.
29 | * How to build `Noise-C` it is described in [Noise-C Documentation](http://rweather.github.io/noise-c/index.html).
30 | * Installation of library `Noise-C` in system:
31 | ```bash
32 | $ make install
33 | ```
34 | ###### For option of use as a crypto backend of libsodium:
35 | * To take stable release of libsodium and to build it:
36 | ```bash
37 | $ git clone https://github.com/jedisct1/libsodium.git -b stable
38 | $ ./configure
39 | $ make && make check
40 | $ sudo make install
41 | ```
42 | * To build the ´Noise-C´ library with option:
43 | ```bash
44 | $ autoreconf -i
45 | $ ./configure --with-openssl --with-libsodium
46 | $ make
47 | $ make check
48 | ```
49 | * Make sure that the list of the required libraries contains libsodium in the `virgil-nginx-noise-socket/config` file (a line 37, ngx_module_libs="... - lsodium"
50 |
51 | 4. Source code of the nginx server can be taken form [nginx.org](http://nginx.org/download/nginx-1.12.1.tar.gz). You must download and unpack source code of server in home directory
52 | ```bash
53 | $ mkdir ~/workspace
54 | $ tar -xvf path/to/nginx-1.12.1.tar.gz -C ~/workspace
55 | ```
56 | 5. To clone repository of virgil-nginx-noise-socket module into ~/workspace/nginx-1.12.1/virgil-nginx-noise-socket
57 | ```bash
58 | $ git clone https://github.com/VirgilSecurity/virgil-nginx-noise-socket ~/workspace/nginx-1.12.1/virgil-nginx-noise-socket
59 | ```
60 | 6. The example of a script for build of the nginx server with the module is located in `virgil-nginx-noise-socket/example/nginx_configure.sh`. You must copy this script to root directory of source code of nginx and run this
61 | ```bash
62 | $ cp ~/workspace/nginx-1.12.1/virgil-nginx-noise-socket/example/nginx_configure.sh ~/workspace/nginx-1.12.1/
63 | $ sudo ~/workspace/nginx-1.12.1/nginx_configure.sh
64 | ```
65 |
66 | 7. The example of a test configuration of the server is located in `virgil-nginx-noise-socket/example/nginx.conf`. The configuration realizes a functionality of reverse proxy and a backend server working in one copy of nginx launched by the local machine. The configuration works as follows:
67 |
68 |
69 |
70 | https://localhost/ | -> |
71 | internal redirect to `noise_socket` context | -> |
72 | proxy to backend over noise socket | ---> |
73 |
74 |
75 | ---> |
76 | `noise_socket` context on the backend server | -> |
77 | internal redirect to http context | -> |
78 | access to the static page index.html "Welcome to nginx!" |
79 |
80 |
81 |
82 |
83 |
84 | 8. For operation of the `Noise Protocol` files of private keys are necessary for noise initiator(client) and noise responder (server). Keys are generated by means of the test utility of `echo-keygen` from library`Noise-C` (`noise-c/examples/echo/echo-keygen`). Use of the utility is described in [noise-c example echo](http://rweather.github.io/noise-c/example_echo.html). Examples of files of the generated keys `virgil-nginx-noise-socket/example/server_key_25519` and `virgil-nginx-noise-socket/example/client_key_25519`.
85 |
86 | 9. It is necessary for start of a test configuration:
87 | * To copy files of the generated keys from the folder `virgil-nginx-noise-socket/example/` into /etc/noise directory
88 | * To copy file `nginx.conf` from the folder `virgil-nginx-noise-socket/example/` into /etc/nginx directory
89 | * To create self-signed ssl sertificate
90 | ```bash
91 | $ sudo openssl genrsa -out /etc/ssl/nginx-selfsigned.key 2048
92 | $ sudo openssl req -x509 -new -key /etc/ssl/nginx-selfsigned.key -days 10000 -out /etc/ssl/nginx-selfsigned.crt
93 | ```
94 | * To run nginx server
95 | ```bash
96 | $ sudo ~/workspace/nginx-1.12.1/objs/nginx
97 | ```
98 | * For testing open the browser and write `https://localhost`. You shall to see "Welcome to nginx!"
99 | * For nginx stop
100 | ```bash
101 | $ sudo ~/workspace/nginx-1.12.1/objs/nginx -s stop
102 | ```
103 |
104 | ## Basic directives ##
105 |
106 | ```nginx
107 | Syntax: noise_socket { ... }
108 | Default: —
109 | Context: main
110 | ```
111 |
112 | Provides the configuration file context in which the noise socket server directives are specified.
113 |
114 | ```nginx
115 | Syntax: server { ... }
116 | Default: —
117 | Context: noise_socket
118 | ```
119 | Sets the configuration for a server.
120 |
121 | ```nginx
122 | Syntax: listen address:port [noise] [udp] [backlog=number] [ipv6only=on|off] [reuseport] [so_keepalive=on|off|[keepidle]:[keepintvl]:[keepcnt]];
123 | Default: —
124 | Context: server
125 | ```
126 |
127 | The `[noise]` parameter allows specifying that all connections accepted on this port should work in noise socket mode. Defines that this socket is used as noise responder (server). Remaining parameters are similar to the parameters described for the directive of [listen](http://nginx.org/en/docs/stream/ngx_stream_core_module.html#listen) of the ngx_stream_core_module module.
128 |
129 | ```nginx
130 | Syntax: preread_buffer_size size;
131 | Default: preread_buffer_size 65517;
132 | Context: noise_socket, server
133 | ```
134 | Specifies a size of the preread buffer for server.
135 |
136 | ```nginx
137 | Syntax: server_private_key_file file;
138 | Default: —
139 | Context: noise_socket, server
140 | ```
141 |
142 | Specifies a file with the secret key in the format of the simple sequence of bytes for the given noise responder (server).
143 |
144 | ```nginx
145 | Syntax: client_private_key_file file;
146 | Default: —
147 | Context: noise_socket, server
148 | ```
149 |
150 | Specifies a file with the secret key in the format of the simple sequence of bytes for the given noise initiator(client).
151 |
152 | ```nginx
153 | Syntax: proxy_noise on | off;
154 | Default: proxy_noise off;
155 | Context: noise_socket, server
156 | ```
157 | Enables the noise socket protocol for connections to a proxied server.
158 |
159 | ```nginx
160 | Syntax: block_buffer_size size;
161 | Default: block_buffer_size 65517;
162 | Context: noise_socket, server
163 | ```
164 |
165 | Sets the size of the buffer used for reading data from the proxied server. Also sets the size of the buffer used for reading data from the client. Value by default is the maximum size of the payload determined in the specification [The Noise Protocol Framework](http://noiseprotocol.org/noise.html). This parameter determines the buffer size for noise initiator(client) and noise responder (server).
166 |
167 | ```nginx
168 | Syntax: noise_handshake_timeout time;
169 | Default: noise_handshake_timeout 60s;
170 | Context: noise_socket, server
171 | ```
172 | Specifies a timeout for the `Noise Protocol` handshake to complete.
173 |
174 | #### The module supports also following directives:
175 |
176 | `proxy_pass`, `proxy_bind`, `proxy_connect_timeout`, `proxy_timeout`, `proxy_upload_rate`, `proxy_download_rate`, `proxy_responses`, `proxy_next_upstream`, `proxy_next_upstream_tries`, `proxy_next_upstream_timeout`.
177 | The description of directives same, as for the [ngx_stream_proxy_module module](http://nginx.org/en/docs/stream/ngx_stream_proxy_module.html) only in `noise_socket` context.
178 | `resolver`, `resolver_timeout`, `preread_timeout`, `tcp_nodelay`
179 | The description of directives same, as for the [ngx_stream_core_module module](http://nginx.org/en/docs/stream/ngx_stream_core_module.html) only in `noise_socket` context.
180 |
181 | ## Keepalive connection configuring
182 |
183 | For setup of saving a noise socket session it is possible to use the following directives of nginx for frontend server http:
184 | ```nginx
185 | http {
186 | ...
187 | proxy_http_version 1.1;
188 | keepalive_requests 10;
189 | keepalive_timeout 50s;
190 | ...
191 | server {
192 | ...
193 | location {
194 | ...
195 | proxy_set_header Connection keep-alive;
196 | ...
197 | }
198 | }
199 | ustream name {
200 | ....
201 | keepalive 1;
202 | ....
203 | }
204 | }
205 |
206 | ```
207 | Directives are designated by comments "###For the noise socket connection keepalive setup...###" in the file of a test configuration `virgil-nginx-noise-socket/example/nginx.conf`
208 |
--------------------------------------------------------------------------------
/ci/nginx-deploy.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - hosts: nginx-noise
3 | user: root
4 | become: yes
5 |
6 | tasks:
7 | - name: "Check artifact dir exist"
8 | file:
9 | path: /opt/rpms
10 | state: directory
11 |
12 | - name: "Clean rpm dir from failed build"
13 | file:
14 | path: /opt/rpms/
15 | state: absent
16 |
17 | - name: "Copy artifacts"
18 | copy:
19 | src: "{{ item }}"
20 | dest: /opt/rpms/
21 | with_items:
22 | - "{{ nginx_rpm_name }}"
23 |
24 | - name: "Stop nginx"
25 | service:
26 | name: nginx
27 | state: stopped
28 |
29 | - name: "Delete previous version of nginx package"
30 | yum:
31 | name: "virgil-nginx-noise-socket"
32 | state: absent
33 |
34 | - name: "Install new version of nginx artifacts"
35 | yum:
36 | name: "/opt/rpms/{{ nginx_rpm_name }}"
37 | state: present
38 |
39 | - name: "Deploy config file"
40 | copy:
41 | src: "nginx_configs/{{ansible_hostname}}.conf"
42 | dest: /etc/nginx/nginx.conf
43 |
44 | - name: "Deploy identity html file"
45 | copy:
46 | content: "{{ ansible_hostname }}"
47 | dest: /usr/local/nginx/html/index.html
48 |
49 | - name: "Restart nginx"
50 | service:
51 | name: nginx
52 | state: restarted
53 |
54 | - name: "Clean artifacts"
55 | file:
56 | path: "/opt/rpms/{{ item }}"
57 | state: absent
58 | with_items:
59 | - "{{ nginx_rpm_name }}"
60 |
--------------------------------------------------------------------------------
/ci/nginx-inventory:
--------------------------------------------------------------------------------
1 | [nginx-noise]
2 | nginx-noise-lb-int.vrgl.net
3 | nginx-noise-backend-int.vrgl.net
4 |
5 | [nginx-noise:vars]
6 | ansible_ssh_private_key_file = ~/.ssh/nginx-noise
7 |
--------------------------------------------------------------------------------
/ci/nginx_configs/nginx-noise-backend-int.conf:
--------------------------------------------------------------------------------
1 | #user nobody;
2 |
3 | worker_processes auto;
4 |
5 | error_log /var/log/nginx/error.log debug;
6 |
7 | pid /run/nginx.pid;
8 |
9 | events {
10 | worker_connections 1024;
11 | }
12 |
13 | noise_socket {
14 | # Noise socket backend server
15 | server {
16 | error_log /var/log/nginx/errorNoiseBackend.log debug;
17 | listen 2017 noise;
18 |
19 | server_private_key_file /etc/noise/server_key_25519;
20 |
21 | proxy_pass local_http;
22 | }
23 |
24 | # Backend HTTP over Noise socket
25 | upstream local_http {
26 | server localhost:2019;
27 | }
28 | }
29 |
30 | http {
31 | include mime.types;
32 | default_type application/octet-stream;
33 |
34 | ###For the noise socket connection keepalive setup
35 | proxy_http_version 1.1;
36 | keepalive_requests 100;
37 | keepalive_timeout 50s;
38 |
39 | # Backend HTTP over Noise socket
40 | server {
41 | error_log /var/log/nginx/errorHTTPBackend.log debug;
42 | listen 2019;
43 | server_name localhost;
44 |
45 | location / {
46 | add_header Content-Type text/plain;
47 | return 200 "noise backend";
48 | }
49 | }
50 |
51 | server {
52 | error_log /var/log/nginx/tls_errors.log debug;
53 | listen 443 ssl;
54 | server_name nginx-noise-backend-int.vrgl.net;
55 |
56 | ssl_certificate /etc/ssl/certs/nginx-selfsigned.crt;
57 | ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key;
58 |
59 | ssl_session_cache shared:SSL:1m;
60 | ssl_session_timeout 5m;
61 |
62 | ssl_ciphers HIGH:!aNULL:!MD5;
63 | ssl_prefer_server_ciphers on;
64 |
65 | location / {
66 | add_header Content-Type text/plain;
67 | return 200 "ssl/tls backend";
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/ci/nginx_configs/nginx-noise-lb-int.conf:
--------------------------------------------------------------------------------
1 | #user nobody;
2 |
3 | worker_processes auto;
4 |
5 | error_log /var/log/nginx/error.log debug;
6 |
7 | pid /run/nginx.pid;
8 |
9 | events {
10 | worker_connections 1024;
11 | }
12 |
13 | noise_socket {
14 | # config stream context for the proxy server
15 | # Frontend local TCP server for proxy to Noise socket
16 | server {
17 | error_log /var/log/nginx/errorNoiseFrontend.log debug;
18 | listen 2018;
19 | proxy_noise on;
20 |
21 | client_private_key_file /etc/noise/client_key_25519;
22 |
23 | proxy_pass backend;
24 | }
25 |
26 | # Proxy to backend TCP over Noise socket
27 | upstream backend {
28 | server nginx-noise-backend-int.vrgl.net:2017;
29 | }
30 | }
31 |
32 | http {
33 | include mime.types;
34 | default_type application/octet-stream;
35 |
36 | ###For the noise socket connection keepalive setup
37 | proxy_http_version 1.1;
38 | keepalive_requests 10;
39 | keepalive_timeout 50s;
40 |
41 | # Frontend HTTP proxy to Noise socket
42 | upstream http_noise_proxy {
43 | server localhost:2018;
44 | ###For the noise socket connection keepalive setup
45 | keepalive 1;
46 | ###
47 | }
48 |
49 | upstream https_backend {
50 | server nginx-noise-backend-int.vrgl.net:443;
51 | }
52 |
53 | # HTTP server
54 | server {
55 | error_log /var/log/nginx/errorHTTPFrontend.log debug;
56 | listen 80;
57 | server_name nginx-noise-lb.vrgl.net;
58 |
59 | location / {
60 | add_header Cache-Control "no-store, no-cache, must-revalidate, post-check=0, pre-check=0";
61 | proxy_pass http://http_noise_proxy;
62 | proxy_set_header Host $host;
63 | proxy_set_header X-Real-IP $remote_addr;
64 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
65 | ###For the noise socket connection keepalive setup
66 | proxy_set_header Connection keep-alive;
67 | ###
68 | }
69 | location /tls {
70 | add_header Cache-Control "no-store, no-cache, must-revalidate, post-check=0, pre-check=0";
71 | proxy_pass https://https_backend;
72 | proxy_set_header Host $host;
73 | proxy_set_header X-Real-IP $remote_addr;
74 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/config:
--------------------------------------------------------------------------------
1 |
2 | ngx_module_type=CORE
3 | ngx_module_name=ngx_nsoc_module
4 | ngx_module_srcs="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_noise_protocol.c $ngx_addon_dir/ngx_nsoc.c $ngx_addon_dir/ngx_nsoc_script.c \
5 | $ngx_addon_dir/ngx_nsoc_variables.c $ngx_addon_dir/ngx_nsoc_handler.c "
6 |
7 | . auto/module
8 |
9 | ngx_module_type=NGX_NSOC
10 | ngx_module_name=ngx_nsoc_core_module
11 | ngx_module_srcs="$ngx_addon_dir/ngx_nsoc_core_module.c"
12 |
13 | . auto/module
14 |
15 | ngx_module_type=NGX_NSOC
16 | ngx_module_name=ngx_nsoc_proxy_module
17 | ngx_module_srcs="$ngx_addon_dir/ngx_nsoc_proxy_module.c $ngx_addon_dir/ngx_nsoc_upstream_round_robin.c"
18 |
19 | . auto/module
20 |
21 | ngx_module_type=NGX_NSOC
22 | ngx_module_name=ngx_nsoc_upstream_module
23 | ngx_module_srcs="$ngx_addon_dir/ngx_nsoc_upstream.c"
24 |
25 | . auto/module
26 |
27 | ngx_module_type=NGX_NSOC
28 | ngx_module_name=ngx_nsoc_noiseserver_module
29 | ngx_module_srcs="$ngx_addon_dir/ngx_nsoc_noiseserver_module.c"
30 |
31 | . auto/module
32 |
33 | ngx_module_type=NGX_NSOC
34 | ngx_module_name=ngx_nsoc_write_filter_module
35 | ngx_module_srcs="$ngx_addon_dir/ngx_nsoc_write_filter_module.c"
36 | ngx_module_incs="$ngx_addon_dir"
37 | ngx_module_libs="-lnoisekeys -lnoiseprotocol"
38 |
39 | . auto/module
40 |
41 | EVENT_MODULES="$EVENT_MODULES $NGX_NSOC_MODULES"
42 |
--------------------------------------------------------------------------------
/example/client_key_25519:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VirgilSecurity/virgil-nginx-noise-socket/3789587427c9d06f1e69c9ddd3358449ad9e6149/example/client_key_25519
--------------------------------------------------------------------------------
/example/nginx.conf:
--------------------------------------------------------------------------------
1 |
2 | #user nobody;
3 |
4 | worker_processes auto;
5 |
6 | error_log /var/log/nginx/error.log debug;
7 |
8 | pid logs/nginx.pid;
9 |
10 | events {
11 | worker_connections 1024;
12 | }
13 |
14 | noise_socket {
15 |
16 | # config stream context for the proxy server
17 | #
18 |
19 | # Frontend local TCP server for proxy to Noise socket
20 | server {
21 | error_log /var/log/nginx/errorNoiseFrontend.log debug;
22 | listen 2018;
23 | proxy_noise on;
24 |
25 | client_private_key_file /etc/noise/client_key_25519;
26 |
27 | proxy_pass backend;
28 | }
29 |
30 | # Proxy to backend TCP over Noise socket
31 | upstream backend {
32 | server localhost:2017;
33 | }
34 |
35 | # end сonfig stream context for the proxy server
36 | #
37 | # config stream context for the backend server
38 | #
39 | # Noise socket backend server
40 | server {
41 | error_log /var/log/nginx/errorNoiseBackend.log debug;
42 | listen 2017 noise;
43 |
44 | server_private_key_file /etc/noise/server_key_25519;
45 |
46 | proxy_pass local_http;
47 | }
48 |
49 | # Backend HTTP over Noise socket
50 | upstream local_http {
51 | server localhost:2019;
52 | }
53 |
54 | # end config stream context for the backend server
55 | #
56 | }
57 |
58 | http {
59 | include mime.types;
60 | default_type application/octet-stream;
61 |
62 | ###For the noise socket connection keepalive setup
63 | proxy_http_version 1.1;
64 | keepalive_requests 10;
65 | keepalive_timeout 50s;
66 | ###
67 | # config HTTP context for the frontend proxy server
68 | #
69 |
70 | # Frontend HTTP proxy to Noise socket
71 | upstream http_noise_proxy {
72 | server localhost:2018;
73 | ###For the noise socket connection keepalive setup
74 | keepalive 1;
75 | ###
76 | }
77 |
78 | # HTTPS server
79 | server {
80 | error_log /var/log/nginx/errorHTTPFrontend.log debug;
81 | listen 443 ssl;
82 | server_name localhost;
83 |
84 | ssl_certificate /etc/ssl/nginx-selfsigned.crt;
85 | ssl_certificate_key /etc/ssl/nginx-selfsigned.key;
86 |
87 | ssl_session_cache shared:SSL:1m;
88 | ssl_session_timeout 5m;
89 |
90 | ssl_ciphers HIGH:!aNULL:!MD5;
91 | ssl_prefer_server_ciphers on;
92 |
93 | location / {
94 | add_header Cache-Control "no-store, no-cache, must-revalidate, post-check=0, pre-check=0";
95 | proxy_pass http://http_noise_proxy;
96 | proxy_set_header Host $host;
97 | proxy_set_header X-Real-IP $remote_addr;
98 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
99 | ###For the noise socket connection keepalive setup
100 | proxy_set_header Connection keep-alive;
101 | ###
102 | }
103 | }
104 |
105 | # end сonfig HTTP context for the frontend proxy server
106 | #
107 | # config http context for the backend server
108 | #
109 | # Backend HTTP over Noise socket
110 | server {
111 | error_log /var/log/nginx/errorHTTPBackend.log debug;
112 | listen 2019;
113 | server_name localhost;
114 |
115 | location / {
116 | root html;
117 | index index.html index.htm;
118 | }
119 | }
120 |
121 | # end config http context for the backend server
122 | #
123 | }
124 |
--------------------------------------------------------------------------------
/example/nginx_configure.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #configure options
3 | #make clean
4 | ./configure \
5 | --conf-path=/etc/nginx/nginx.conf \
6 | --error-log-path=/var/log/nginx/error.log \
7 | --pid-path=/var/run/nginx.pid \
8 | --lock-path=/var/lock/nginx.lock \
9 | --http-log-path=/var/log/nginx/access.log \
10 | --http-client-body-temp-path=/var/lib/nginx/body \
11 | --http-proxy-temp-path=/var/lib/nginx/proxy \
12 | --without-http_fastcgi_module \
13 | --without-http_uwsgi_module \
14 | --with-http_stub_status_module \
15 | --with-http_gzip_static_module \
16 | --with-http_ssl_module \
17 | --with-debug \
18 | --add-module=./virgil-nginx-noise-socket \
19 |
20 | make
21 | make install
22 |
--------------------------------------------------------------------------------
/example/server_key_25519:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VirgilSecurity/virgil-nginx-noise-socket/3789587427c9d06f1e69c9ddd3358449ad9e6149/example/server_key_25519
--------------------------------------------------------------------------------
/ngx_noise_protocol.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Maxim Grigoryev
3 | * Copyright (C) Virgil Security, Inc.
4 | */
5 |
6 | #include "ngx_noise_protocol.h"
7 |
8 | ngx_int_t ngx_noise_protocol_init_handshake(NOISE_CTX *noise_ctx,
9 | noise_protocol_conn_t *noise_conn, noise_prologue_data_t *prologue_data, ngx_noise_role_e noise_role)
10 | {
11 | ngx_int_t err;
12 | NoiseDHState *dh;
13 | size_t key_len = 0;
14 | ngx_int_t role;
15 |
16 | if ((noise_role != NGX_NSOC_CLIENT_ROLE)
17 | && (noise_role != NGX_NSOC_SERVER_ROLE))
18 | return NGX_ERROR;
19 | if (noise_init() != NOISE_ERROR_NONE)
20 | return NGX_ERROR;
21 |
22 | noise_conn->protocol_id.cipher_id = NOISE_ID('C',(uint16_t)(prologue_data->header.cipher_id))&0xFFFF;
23 | noise_conn->protocol_id.dh_id = NOISE_ID('D',(uint16_t)(prologue_data->header.dh_id))&0xFFFF;
24 | noise_conn->protocol_id.hash_id = NOISE_ID('H',(uint16_t)(prologue_data->header.hash_id))&0xFFFF;
25 | noise_conn->protocol_id.hybrid_id = 0;
26 | noise_conn->protocol_id.pattern_id = NOISE_ID('P',(uint16_t)(prologue_data->header.pattern_id))&0xFFFF;
27 | noise_conn->protocol_id.prefix_id = NOISE_PREFIX_STANDARD;
28 |
29 | noise_conn->NoisePrologue = (void *) prologue_data;
30 | noise_conn->NoisePrologueLen = sizeof(noise_prologue_data_t);
31 |
32 | if (noise_role == NGX_NSOC_CLIENT_ROLE) {
33 | role = NOISE_ROLE_INITIATOR;
34 | } else {
35 | role = NOISE_ROLE_RESPONDER;
36 | }
37 |
38 | err = noise_handshakestate_new_by_id(&noise_conn->NoiseHandshakeObj,
39 | &noise_conn->protocol_id, role);
40 |
41 | if (err != NOISE_ERROR_NONE)
42 | return NGX_ERROR;
43 |
44 | err = noise_handshakestate_set_prologue(
45 | noise_conn->NoiseHandshakeObj, noise_conn->NoisePrologue,
46 | noise_conn->NoisePrologueLen);
47 | if (err != NOISE_ERROR_NONE)
48 | return NGX_ERROR;
49 |
50 | if (noise_handshakestate_needs_local_keypair(
51 | noise_conn->NoiseHandshakeObj)) {
52 | dh = noise_handshakestate_get_local_keypair_dh(
53 | noise_conn->NoiseHandshakeObj);
54 | key_len = noise_dhstate_get_private_key_length(dh);
55 | err = noise_dhstate_set_keypair_private(
56 | dh, noise_ctx->private_keys->elts, key_len);
57 | if (err != NOISE_ERROR_NONE)
58 | return NGX_ERROR;
59 | }
60 |
61 | if (noise_handshakestate_needs_remote_public_key(
62 | noise_conn->NoiseHandshakeObj)) {
63 | dh = noise_handshakestate_get_remote_public_key_dh(
64 | noise_conn->NoiseHandshakeObj);
65 | key_len = noise_dhstate_get_public_key_length(dh);
66 | err = noise_dhstate_set_public_key(
67 | dh, noise_ctx->public_keys->elts, key_len);
68 | if (err != NOISE_ERROR_NONE)
69 | return NGX_ERROR;
70 | }
71 |
72 | return NGX_OK;
73 | }
74 |
75 | ngx_int_t ngx_noise_protocol_load_private_key(const unsigned char *filename,
76 | uint8_t *key, size_t len)
77 | {
78 | FILE *file = fopen((const char *) filename, "rb");
79 | size_t posn = 0;
80 | int ch;
81 | if (len > NOISE_PROTOCOL_MAX_DH_KEY_LEN) {
82 | return NGX_ERROR;
83 | }
84 | if (!file) {
85 | return NGX_ERROR;
86 | }
87 | while ((ch = getc(file)) != EOF) {
88 | if (posn >= len) {
89 | fclose(file);
90 | return NGX_ERROR;
91 | }
92 | key[posn++] = (uint8_t) ch;
93 | }
94 | if (posn < len) {
95 | fclose(file);
96 | return NGX_ERROR;
97 | }
98 | fclose(file);
99 | return NGX_OK;
100 | }
101 |
102 | ngx_int_t ngx_noise_protocol_load_public_key(const unsigned char *filename,
103 | uint8_t *key, size_t len)
104 | {
105 | FILE *file = fopen((const char *) filename, "rb");
106 | uint32_t group = 0;
107 | size_t group_size = 0;
108 | uint32_t digit = 0;
109 | size_t posn = 0;
110 | int ch;
111 | if (len > NOISE_PROTOCOL_MAX_DH_KEY_LEN) {
112 | return NGX_ERROR;
113 | }
114 | if (!file) {
115 | return NGX_ERROR;
116 | }
117 | while ((ch = getc(file)) != EOF) {
118 | if (ch >= 'A' && ch <= 'Z') {
119 | digit = ch - 'A';
120 | } else if (ch >= 'a' && ch <= 'z') {
121 | digit = ch - 'a' + 26;
122 | } else if (ch >= '0' && ch <= '9') {
123 | digit = ch - '0' + 52;
124 | } else if (ch == '+') {
125 | digit = 62;
126 | } else if (ch == '/') {
127 | digit = 63;
128 | } else if (ch == '=') {
129 | break;
130 | } else if (ch != ' ' && ch != '\t' && ch != '\r' && ch != '\n') {
131 | fclose(file);
132 | return NGX_ERROR;
133 | }
134 | group = (group << 6) | digit;
135 | if (++group_size >= 4) {
136 | if ((len - posn) < 3) {
137 | fclose(file);
138 | return NGX_ERROR;
139 | }
140 | group_size = 0;
141 | key[posn++] = (uint8_t) (group >> 16);
142 | key[posn++] = (uint8_t) (group >> 8);
143 | key[posn++] = (uint8_t) group;
144 | }
145 | }
146 | if (group_size == 3) {
147 | if ((len - posn) < 2) {
148 | fclose(file);
149 | return NGX_ERROR;
150 | }
151 | key[posn++] = (uint8_t) (group >> 10);
152 | key[posn++] = (uint8_t) (group >> 2);
153 | } else if (group_size == 2) {
154 | if ((len - posn) < 1) {
155 | fclose(file);
156 | return NGX_ERROR;
157 | }
158 | key[posn++] = (uint8_t) (group >> 4);
159 | }
160 | if (posn < len) {
161 | fclose(file);
162 | return NGX_ERROR;
163 | }
164 | fclose(file);
165 | return NGX_OK;
166 | }
167 |
168 | void ngx_noise_protocol_log_error(ngx_int_t err, char* strObjError,
169 | ngx_log_t *log, ngx_uint_t log_level)
170 | {
171 | ngx_int_t result;
172 | char strerr[30];
173 |
174 | result = noise_strerror(err, strerr, sizeof(strerr));
175 |
176 | if (!result) {
177 | ngx_log_debug2(
178 | log_level, log, 0, "NOISE_PROTOCOL %s error: %s", strObjError,
179 | strerr);
180 | } else {
181 | ngx_log_debug0(log_level, log, 0, "NOISE_PROTOCOL error log");
182 | }
183 |
184 | }
185 |
--------------------------------------------------------------------------------
/ngx_noise_protocol.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Maxim Grigoryev
3 | * Copyright (C) Virgil Security, Inc.
4 | */
5 |
6 | #ifndef _NGX_NOISE_PROTOCOL_H_INCLUDED_
7 | #define _NGX_NOISE_PROTOCOL_H_INCLUDED_
8 |
9 | #include
10 | #include
11 |
12 | #define NOISE_PROTOCOL_CURVE25519_KEY_LEN 32
13 | #define NOISE_PROTOCOL_CURVE448_KEY_LEN 56
14 |
15 | #define NOISE_PROTOCOL_MAX_DH_KEY_LEN 2048
16 | #define NOISE_PROTOCOL_PAYLOAD_SIZE 65517
17 | #define NOISE_PROTOCOL_MAC_DATA_SIZE 16
18 | #define NOISE_PROTOCOL_MAX_HANDSHAKE_LEN NOISE_PROTOCOL_CURVE25519_KEY_LEN*2+NOISE_PROTOCOL_MAC_DATA_SIZE*2
19 |
20 | #define swapw(x)((((uint16_t)x & 0xFF00)>>8)| (((uint16_t)x & 0x00FF)<<8))
21 |
22 | typedef struct noise_ctx_st {
23 | ngx_array_t *private_keys;
24 | ngx_array_t *public_keys;
25 | } NOISE_CTX;
26 |
27 | typedef enum {
28 | NGX_NSOC_UNSET_ROLE = -1,
29 | NGX_NSOC_CLIENT_ROLE,
30 | NGX_NSOC_SERVER_ROLE
31 | } ngx_noise_role_e;
32 |
33 | #pragma pack(push, 1)
34 | typedef struct noise_handshake_first_hdr_s {
35 | uint16_t version_id;
36 | uint8_t dh_id;
37 | uint8_t cipher_id;
38 | uint8_t hash_id;
39 | uint8_t pattern_id;
40 | }noise_handshake_first_hdr_t;
41 |
42 | typedef struct noise_handshake_second_hdr_s {
43 | uint16_t version_id;
44 | uint8_t status;
45 | }noise_handshake_second_hdr_t;
46 |
47 | typedef struct noise_handshake_third_hdr_s {
48 | uint16_t version_id;
49 | }noise_handshake_third_hdr_t;
50 |
51 | typedef struct noise_prologue_data_s {
52 | uint8_t strPrologue[16];
53 | uint16_t header_len;
54 | noise_handshake_first_hdr_t header;
55 | }noise_prologue_data_t;
56 |
57 | typedef struct noise_prologue_fallback_data_t {
58 | uint8_t strPrologue[15];
59 | noise_prologue_data_t first_msg;
60 | uint16_t header_len;
61 | noise_handshake_first_hdr_t header;
62 | }noise_prologue_fallback_data_t;
63 | #pragma pack (pop)
64 |
65 | typedef struct noise_protocol_conn_s {
66 | NoiseHandshakeState *NoiseHandshakeObj;
67 | NoiseCipherState *NoiseSendCipherObj;
68 | NoiseCipherState *NoiseRecvCipherObj;
69 | NoiseRandState *NoiseRandObj;
70 | void *NoisePrologue;
71 | ngx_int_t NoisePrologueLen;
72 | NoiseProtocolId protocol_id;
73 | } noise_protocol_conn_t;
74 |
75 | ngx_int_t ngx_noise_protocol_init_handshake(NOISE_CTX *noise_ctx,
76 | noise_protocol_conn_t *noise_conn, noise_prologue_data_t *prologue_data, ngx_noise_role_e noise_role);
77 | ngx_int_t ngx_noise_protocol_load_private_key(const unsigned char *filename,
78 | uint8_t *key, size_t len);
79 | ngx_int_t ngx_noise_protocol_load_public_key(const unsigned char *filename, uint8_t *key,
80 | size_t len);
81 | void ngx_noise_protocol_log_error(ngx_int_t err, char* strError, ngx_log_t *log,
82 | ngx_uint_t log_level);
83 | #endif
84 |
--------------------------------------------------------------------------------
/ngx_nsoc.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Roman Arutyunyan
3 | * Copyright (C) Nginx, Inc.
4 | */
5 |
6 | #include "ngx_nsoc.h"
7 |
8 | #include
9 | #include
10 | #include
11 |
12 | static char *ngx_nsoc_block(ngx_conf_t *cf, ngx_command_t *cmd,
13 | void *conf);
14 | static ngx_int_t ngx_nsoc_init_phases(ngx_conf_t *cf,
15 | ngx_nsoc_core_main_conf_t *cmcf);
16 | static ngx_int_t ngx_nsoc_init_phase_handlers(ngx_conf_t *cf,
17 | ngx_nsoc_core_main_conf_t *cmcf);
18 | static ngx_int_t ngx_nsoc_add_ports(ngx_conf_t *cf, ngx_array_t *ports,
19 | ngx_nsoc_listen_t *listen);
20 | static char *ngx_nsoc_optimize_servers(ngx_conf_t *cf,
21 | ngx_array_t *ports);
22 | static ngx_int_t ngx_nsoc_add_addrs(ngx_conf_t *cf,
23 | ngx_nsoc_port_t *stport, ngx_nsoc_conf_addr_t *addr);
24 | #if (NGX_HAVE_INET6)
25 | static ngx_int_t ngx_nsoc_add_addrs6(ngx_conf_t *cf,
26 | ngx_nsoc_port_t *stport, ngx_nsoc_conf_addr_t *addr);
27 | #endif
28 | static ngx_int_t ngx_nsoc_cmp_conf_addrs(const void *one,
29 | const void *two);
30 |
31 | ngx_uint_t ngx_nsoc_max_module;
32 |
33 | ngx_nsoc_filter_pt ngx_nsoc_top_filter;
34 |
35 | static ngx_command_t ngx_nsoc_commands[] =
36 | {
37 |
38 | { ngx_string("noise_socket"),
39 | NGX_MAIN_CONF | NGX_CONF_BLOCK | NGX_CONF_NOARGS,
40 | ngx_nsoc_block,
41 | 0,
42 | 0,
43 | NULL },
44 |
45 | ngx_null_command
46 | };
47 |
48 | static ngx_core_module_t ngx_nsoc_module_ctx =
49 | {
50 | ngx_string("noisesock"),
51 | NULL,
52 | NULL };
53 |
54 | ngx_module_t ngx_nsoc_module =
55 | {
56 | NGX_MODULE_V1,
57 | &ngx_nsoc_module_ctx, /* module context */
58 | ngx_nsoc_commands, /* module directives */
59 | NGX_CORE_MODULE, /* module type */
60 | NULL, /* init master */
61 | NULL, /* init module */
62 | NULL, /* init process */
63 | NULL, /* init thread */
64 | NULL, /* exit thread */
65 | NULL, /* exit process */
66 | NULL, /* exit master */
67 | NGX_MODULE_V1_PADDING
68 | };
69 |
70 | static char *
71 | ngx_nsoc_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
72 | {
73 | char *rv;
74 | ngx_uint_t i, m, mi, s;
75 | ngx_conf_t pcf;
76 | ngx_array_t ports;
77 | ngx_nsoc_listen_t *listen;
78 | ngx_nsoc_module_t *module;
79 | ngx_nsoc_conf_ctx_t *ctx;
80 | ngx_nsoc_core_srv_conf_t **cscfp;
81 | ngx_nsoc_core_main_conf_t *cmcf;
82 |
83 | if (*(ngx_nsoc_conf_ctx_t **) conf) {
84 | return "is duplicate";
85 | }
86 |
87 | /* the main noiselink context */
88 |
89 | ctx = ngx_pcalloc(cf->pool, sizeof(ngx_nsoc_conf_ctx_t));
90 | if (ctx == NULL) {
91 | return NGX_CONF_ERROR ;
92 | }
93 |
94 | *(ngx_nsoc_conf_ctx_t **) conf = ctx;
95 |
96 | /* count the number of the noiselink modules and set up their indices */
97 |
98 | ngx_nsoc_max_module = ngx_count_modules(cf->cycle, NGX_NSOC_MODULE);
99 |
100 | /* the noiselink main_conf context, it's the same in the all noiselink contexts */
101 |
102 | ctx->main_conf = ngx_pcalloc(
103 | cf->pool, sizeof(void *) * ngx_nsoc_max_module);
104 | if (ctx->main_conf == NULL) {
105 | return NGX_CONF_ERROR ;
106 | }
107 |
108 | /*
109 | * the noiselink null srv_conf context, it is used to merge
110 | * the server{}s' srv_conf's
111 | */
112 |
113 | ctx->srv_conf = ngx_pcalloc(
114 | cf->pool, sizeof(void *) * ngx_nsoc_max_module);
115 | if (ctx->srv_conf == NULL) {
116 | return NGX_CONF_ERROR ;
117 | }
118 |
119 | /*
120 | * create the main_conf's and the null srv_conf's of the all noiselink modules
121 | */
122 |
123 | for (m = 0; cf->cycle->modules[m]; m++) {
124 | if (cf->cycle->modules[m]->type != NGX_NSOC_MODULE) {
125 | continue;
126 | }
127 |
128 | module = cf->cycle->modules[m]->ctx;
129 | mi = cf->cycle->modules[m]->ctx_index;
130 |
131 | if (module->create_main_conf) {
132 | ctx->main_conf[mi] = module->create_main_conf(cf);
133 | if (ctx->main_conf[mi] == NULL) {
134 | return NGX_CONF_ERROR ;
135 | }
136 | }
137 |
138 | if (module->create_srv_conf) {
139 | ctx->srv_conf[mi] = module->create_srv_conf(cf);
140 | if (ctx->srv_conf[mi] == NULL) {
141 | return NGX_CONF_ERROR ;
142 | }
143 | }
144 | }
145 |
146 | pcf = *cf;
147 | cf->ctx = ctx;
148 |
149 | for (m = 0; cf->cycle->modules[m]; m++) {
150 | if (cf->cycle->modules[m]->type != NGX_NSOC_MODULE) {
151 | continue;
152 | }
153 |
154 | module = cf->cycle->modules[m]->ctx;
155 |
156 | if (module->preconfiguration) {
157 | if (module->preconfiguration(cf) != NGX_OK) {
158 | return NGX_CONF_ERROR ;
159 | }
160 | }
161 | }
162 |
163 | /* parse inside the noiselink{} block */
164 |
165 | cf->module_type = NGX_NSOC_MODULE;
166 | cf->cmd_type = NGX_NSOC_MAIN_CONF;
167 | rv = ngx_conf_parse(cf, NULL);
168 |
169 | if (rv != NGX_CONF_OK) {
170 | *cf = pcf;
171 | return rv;
172 | }
173 |
174 | /* init noiselink{} main_conf's, merge the server{}s' srv_conf's */
175 |
176 | cmcf = ctx->main_conf[ngx_nsoc_core_module.ctx_index];
177 | cscfp = cmcf->servers.elts;
178 |
179 | for (m = 0; cf->cycle->modules[m]; m++) {
180 | if (cf->cycle->modules[m]->type != NGX_NSOC_MODULE) {
181 | continue;
182 | }
183 |
184 | module = cf->cycle->modules[m]->ctx;
185 | mi = cf->cycle->modules[m]->ctx_index;
186 |
187 | /* init noiselink{} main_conf's */
188 |
189 | cf->ctx = ctx;
190 |
191 | if (module->init_main_conf) {
192 | rv = module->init_main_conf(cf, ctx->main_conf[mi]);
193 | if (rv != NGX_CONF_OK) {
194 | *cf = pcf;
195 | return rv;
196 | }
197 | }
198 |
199 | for (s = 0; s < cmcf->servers.nelts; s++) {
200 |
201 | /* merge the server{}s' srv_conf's */
202 |
203 | cf->ctx = cscfp[s]->ctx;
204 |
205 | if (module->merge_srv_conf) {
206 | rv = module->merge_srv_conf(
207 | cf, ctx->srv_conf[mi], cscfp[s]->ctx->srv_conf[mi]);
208 | if (rv != NGX_CONF_OK) {
209 | *cf = pcf;
210 | return rv;
211 | }
212 | }
213 | }
214 | }
215 |
216 | if (ngx_nsoc_init_phases(cf, cmcf) != NGX_OK) {
217 | return NGX_CONF_ERROR ;
218 | }
219 |
220 | for (m = 0; cf->cycle->modules[m]; m++) {
221 | if (cf->cycle->modules[m]->type != NGX_NSOC_MODULE) {
222 | continue;
223 | }
224 |
225 | module = cf->cycle->modules[m]->ctx;
226 |
227 | if (module->postconfiguration) {
228 | if (module->postconfiguration(cf) != NGX_OK) {
229 | return NGX_CONF_ERROR ;
230 | }
231 | }
232 | }
233 |
234 | if (ngx_nsoc_variables_init_vars(cf) != NGX_OK) {
235 | return NGX_CONF_ERROR ;
236 | }
237 |
238 | *cf = pcf;
239 |
240 | if (ngx_nsoc_init_phase_handlers(cf, cmcf) != NGX_OK) {
241 | return NGX_CONF_ERROR ;
242 | }
243 |
244 | if (ngx_array_init(
245 | &ports, cf->temp_pool, 4,
246 | sizeof(ngx_nsoc_conf_port_t)) != NGX_OK) {
247 | return NGX_CONF_ERROR ;
248 | }
249 |
250 | listen = cmcf->listen.elts;
251 |
252 | for (i = 0; i < cmcf->listen.nelts; i++) {
253 | if (ngx_nsoc_add_ports(cf, &ports, &listen[i]) != NGX_OK) {
254 | return NGX_CONF_ERROR ;
255 | }
256 | }
257 |
258 | return ngx_nsoc_optimize_servers(cf, &ports);
259 | }
260 |
261 | static ngx_int_t ngx_nsoc_init_phases(ngx_conf_t *cf,
262 | ngx_nsoc_core_main_conf_t *cmcf)
263 | {
264 | if (ngx_array_init(
265 | &cmcf->phases[NGX_NSOC_POST_ACCEPT_PHASE].handlers, cf->pool, 1,
266 | sizeof(ngx_nsoc_handler_pt)) != NGX_OK) {
267 | return NGX_ERROR;
268 | }
269 |
270 | if (ngx_array_init(
271 | &cmcf->phases[NGX_NSOC_PREACCESS_PHASE].handlers, cf->pool, 1,
272 | sizeof(ngx_nsoc_handler_pt)) != NGX_OK) {
273 | return NGX_ERROR;
274 | }
275 |
276 | if (ngx_array_init(
277 | &cmcf->phases[NGX_NSOC_ACCESS_PHASE].handlers, cf->pool, 1,
278 | sizeof(ngx_nsoc_handler_pt)) != NGX_OK) {
279 | return NGX_ERROR;
280 | }
281 |
282 | if (ngx_array_init(
283 | &cmcf->phases[NGX_NSOC_PROTECT_PHASE].handlers, cf->pool, 1,
284 | sizeof(ngx_nsoc_handler_pt)) != NGX_OK) {
285 | return NGX_ERROR;
286 | }
287 |
288 | if (ngx_array_init(
289 | &cmcf->phases[NGX_NSOC_PREREAD_PHASE].handlers, cf->pool, 1,
290 | sizeof(ngx_nsoc_handler_pt)) != NGX_OK) {
291 | return NGX_ERROR;
292 | }
293 |
294 | if (ngx_array_init(
295 | &cmcf->phases[NGX_NSOC_LOG_PHASE].handlers, cf->pool, 1,
296 | sizeof(ngx_nsoc_handler_pt)) != NGX_OK) {
297 | return NGX_ERROR;
298 | }
299 |
300 | return NGX_OK;
301 | }
302 |
303 | static ngx_int_t ngx_nsoc_init_phase_handlers(ngx_conf_t *cf,
304 | ngx_nsoc_core_main_conf_t *cmcf)
305 | {
306 | ngx_int_t j;
307 | ngx_uint_t i, n;
308 | ngx_nsoc_handler_pt *h;
309 | ngx_nsoc_phase_handler_t *ph;
310 | ngx_nsoc_phase_handler_pt checker;
311 |
312 | n = 1 /* content phase */;
313 |
314 | for (i = 0; i < NGX_NSOC_LOG_PHASE; i++) {
315 | n += cmcf->phases[i].handlers.nelts;
316 | }
317 |
318 | ph = ngx_pcalloc(
319 | cf->pool,
320 | n * sizeof(ngx_nsoc_phase_handler_t) + sizeof(void *));
321 | if (ph == NULL) {
322 | return NGX_ERROR;
323 | }
324 |
325 | cmcf->phase_engine.handlers = ph;
326 | n = 0;
327 |
328 | for (i = 0; i < NGX_NSOC_LOG_PHASE; i++) {
329 | h = cmcf->phases[i].handlers.elts;
330 |
331 | switch (i) {
332 |
333 | case NGX_NSOC_PREREAD_PHASE:
334 | checker = ngx_nsoc_core_preread_phase;
335 | break;
336 |
337 | case NGX_NSOC_CONTENT_PHASE:
338 | ph->checker = ngx_nsoc_core_content_phase;
339 | n++;
340 | ph++;
341 |
342 | continue;
343 |
344 | default:
345 | checker = ngx_nsoc_core_generic_phase;
346 | }
347 |
348 | n += cmcf->phases[i].handlers.nelts;
349 |
350 | for (j = cmcf->phases[i].handlers.nelts - 1; j >= 0; j--) {
351 | ph->checker = checker;
352 | ph->handler = h[j];
353 | ph->next = n;
354 | ph++;
355 | }
356 | }
357 |
358 | return NGX_OK;
359 | }
360 |
361 | static ngx_int_t ngx_nsoc_add_ports(ngx_conf_t *cf, ngx_array_t *ports,
362 | ngx_nsoc_listen_t *listen)
363 | {
364 | in_port_t p;
365 | ngx_uint_t i;
366 | struct sockaddr *sa;
367 | ngx_nsoc_conf_port_t *port;
368 | ngx_nsoc_conf_addr_t *addr;
369 |
370 | sa = &listen->sockaddr.sockaddr;
371 | p = ngx_inet_get_port(sa);
372 |
373 | port = ports->elts;
374 | for (i = 0; i < ports->nelts; i++) {
375 |
376 | if (p == port[i].port && listen->type == port[i].type
377 | && sa->sa_family == port[i].family) {
378 | /* a port is already in the port list */
379 |
380 | port = &port[i];
381 | goto found;
382 | }
383 | }
384 |
385 | /* add a port to the port list */
386 |
387 | port = ngx_array_push(ports);
388 | if (port == NULL) {
389 | return NGX_ERROR;
390 | }
391 |
392 | port->family = sa->sa_family;
393 | port->type = listen->type;
394 | port->port = p;
395 |
396 | if (ngx_array_init(
397 | &port->addrs, cf->temp_pool, 2,
398 | sizeof(ngx_nsoc_conf_addr_t)) != NGX_OK) {
399 | return NGX_ERROR;
400 | }
401 |
402 | found:
403 |
404 | addr = ngx_array_push(&port->addrs);
405 | if (addr == NULL) {
406 | return NGX_ERROR;
407 | }
408 |
409 | addr->opt = *listen;
410 |
411 | return NGX_OK;
412 | }
413 |
414 | static char *
415 | ngx_nsoc_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports)
416 | {
417 | ngx_uint_t i, p, last, bind_wildcard;
418 | ngx_listening_t *ls;
419 | ngx_nsoc_port_t *stport;
420 | ngx_nsoc_conf_port_t *port;
421 | ngx_nsoc_conf_addr_t *addr;
422 | ngx_nsoc_core_srv_conf_t *cscf;
423 |
424 | port = ports->elts;
425 | for (p = 0; p < ports->nelts; p++) {
426 |
427 | ngx_sort(
428 | port[p].addrs.elts, (size_t) port[p].addrs.nelts,
429 | sizeof(ngx_nsoc_conf_addr_t),
430 | ngx_nsoc_cmp_conf_addrs);
431 |
432 | addr = port[p].addrs.elts;
433 | last = port[p].addrs.nelts;
434 |
435 | /*
436 | * if there is the binding to the "*:port" then we need to bind()
437 | * to the "*:port" only and ignore the other bindings
438 | */
439 |
440 | if (addr[last - 1].opt.wildcard) {
441 | addr[last - 1].opt.bind = 1;
442 | bind_wildcard = 1;
443 |
444 | } else {
445 | bind_wildcard = 0;
446 | }
447 |
448 | i = 0;
449 |
450 | while (i < last) {
451 |
452 | if (bind_wildcard && !addr[i].opt.bind) {
453 | i++;
454 | continue;
455 | }
456 |
457 | ls = ngx_create_listening(
458 | cf, &addr[i].opt.sockaddr.sockaddr, addr[i].opt.socklen);
459 | if (ls == NULL) {
460 | return NGX_CONF_ERROR ;
461 | }
462 |
463 | ls->addr_ntop = 1;
464 | ls->handler = ngx_nsoc_init_connection;
465 | ls->pool_size = 256;
466 | ls->type = addr[i].opt.type;
467 |
468 | cscf =
469 | addr->opt.ctx->srv_conf[ngx_nsoc_core_module.ctx_index];
470 |
471 | ls->logp = cscf->error_log;
472 | ls->log.data = &ls->addr_text;
473 | ls->log.handler = ngx_accept_log_error;
474 |
475 | ls->backlog = addr[i].opt.backlog;
476 |
477 | ls->wildcard = addr[i].opt.wildcard;
478 |
479 | ls->keepalive = addr[i].opt.so_keepalive;
480 | #if (NGX_HAVE_KEEPALIVE_TUNABLE)
481 | ls->keepidle = addr[i].opt.tcp_keepidle;
482 | ls->keepintvl = addr[i].opt.tcp_keepintvl;
483 | ls->keepcnt = addr[i].opt.tcp_keepcnt;
484 | #endif
485 |
486 | #if (NGX_HAVE_INET6)
487 | ls->ipv6only = addr[i].opt.ipv6only;
488 | #endif
489 |
490 | #if (NGX_HAVE_REUSEPORT)
491 | ls->reuseport = addr[i].opt.reuseport;
492 | #endif
493 |
494 | stport = ngx_palloc(cf->pool, sizeof(ngx_nsoc_port_t));
495 | if (stport == NULL) {
496 | return NGX_CONF_ERROR ;
497 | }
498 |
499 | ls->servers = stport;
500 |
501 | stport->naddrs = i + 1;
502 |
503 | switch (ls->sockaddr->sa_family) {
504 | #if (NGX_HAVE_INET6)
505 | case AF_INET6:
506 | if (ngx_nsoc_add_addrs6(cf, stport, addr) != NGX_OK) {
507 | return NGX_CONF_ERROR ;
508 | }
509 | break;
510 | #endif
511 | default: /* AF_INET */
512 | if (ngx_nsoc_add_addrs(cf, stport, addr) != NGX_OK) {
513 | return NGX_CONF_ERROR ;
514 | }
515 | break;
516 | }
517 |
518 | if (ngx_clone_listening(cf, ls) != NGX_OK) {
519 | return NGX_CONF_ERROR ;
520 | }
521 |
522 | addr++;
523 | last--;
524 | }
525 | }
526 |
527 | return NGX_CONF_OK;
528 | }
529 |
530 | static ngx_int_t ngx_nsoc_add_addrs(ngx_conf_t *cf,
531 | ngx_nsoc_port_t *stport, ngx_nsoc_conf_addr_t *addr)
532 | {
533 | u_char *p;
534 | size_t len;
535 | ngx_uint_t i;
536 | struct sockaddr_in *sin;
537 | ngx_nsoc_in_addr_t *addrs;
538 | u_char buf[NGX_SOCKADDR_STRLEN];
539 |
540 | stport->addrs = ngx_pcalloc(
541 | cf->pool, stport->naddrs * sizeof(ngx_nsoc_in_addr_t));
542 | if (stport->addrs == NULL) {
543 | return NGX_ERROR;
544 | }
545 |
546 | addrs = stport->addrs;
547 |
548 | for (i = 0; i < stport->naddrs; i++) {
549 |
550 | sin = &addr[i].opt.sockaddr.sockaddr_in;
551 | addrs[i].addr = sin->sin_addr.s_addr;
552 |
553 | addrs[i].conf.ctx = addr[i].opt.ctx;
554 | /*noise*/
555 | addrs[i].conf.noise_on = addr[i].opt.noise_on;
556 | /*end noise*/
557 |
558 | len = ngx_sock_ntop(
559 | &addr[i].opt.sockaddr.sockaddr, addr[i].opt.socklen, buf,
560 | NGX_SOCKADDR_STRLEN, 1);
561 |
562 | p = ngx_pnalloc(cf->pool, len);
563 | if (p == NULL) {
564 | return NGX_ERROR;
565 | }
566 |
567 | ngx_memcpy(p, buf, len);
568 |
569 | addrs[i].conf.addr_text.len = len;
570 | addrs[i].conf.addr_text.data = p;
571 | }
572 |
573 | return NGX_OK;
574 | }
575 |
576 | #if (NGX_HAVE_INET6)
577 |
578 | static ngx_int_t ngx_nsoc_add_addrs6(ngx_conf_t *cf,
579 | ngx_nsoc_port_t *stport, ngx_nsoc_conf_addr_t *addr)
580 | {
581 | u_char *p;
582 | size_t len;
583 | ngx_uint_t i;
584 | struct sockaddr_in6 *sin6;
585 | ngx_nsoc_in6_addr_t *addrs6;
586 | u_char buf[NGX_SOCKADDR_STRLEN];
587 |
588 | stport->addrs = ngx_pcalloc(
589 | cf->pool, stport->naddrs * sizeof(ngx_nsoc_in6_addr_t));
590 | if (stport->addrs == NULL) {
591 | return NGX_ERROR;
592 | }
593 |
594 | addrs6 = stport->addrs;
595 |
596 | for (i = 0; i < stport->naddrs; i++) {
597 |
598 | sin6 = &addr[i].opt.sockaddr.sockaddr_in6;
599 | addrs6[i].addr6 = sin6->sin6_addr;
600 |
601 | addrs6[i].conf.ctx = addr[i].opt.ctx;
602 | /*noise*/
603 | addrs6[i].conf.noise_on = addr[i].opt.noise_on;
604 | /*end noise*/
605 |
606 | len = ngx_sock_ntop(
607 | &addr[i].opt.sockaddr.sockaddr, addr[i].opt.socklen, buf,
608 | NGX_SOCKADDR_STRLEN, 1);
609 |
610 | p = ngx_pnalloc(cf->pool, len);
611 | if (p == NULL) {
612 | return NGX_ERROR;
613 | }
614 |
615 | ngx_memcpy(p, buf, len);
616 |
617 | addrs6[i].conf.addr_text.len = len;
618 | addrs6[i].conf.addr_text.data = p;
619 | }
620 |
621 | return NGX_OK;
622 | }
623 |
624 | #endif
625 |
626 | static ngx_int_t ngx_nsoc_cmp_conf_addrs(const void *one,
627 | const void *two)
628 | {
629 | ngx_nsoc_conf_addr_t *first, *second;
630 |
631 | first = (ngx_nsoc_conf_addr_t *) one;
632 | second = (ngx_nsoc_conf_addr_t *) two;
633 |
634 | if (first->opt.wildcard) {
635 | /* a wildcard must be the last resort, shift it to the end */
636 | return 1;
637 | }
638 |
639 | if (second->opt.wildcard) {
640 | /* a wildcard must be the last resort, shift it to the end */
641 | return -1;
642 | }
643 |
644 | if (first->opt.bind && !second->opt.bind) {
645 | /* shift explicit bind()ed addresses to the start */
646 | return -1;
647 | }
648 |
649 | if (!first->opt.bind && second->opt.bind) {
650 | /* shift explicit bind()ed addresses to the start */
651 | return 1;
652 | }
653 |
654 | /* do not sort by default */
655 |
656 | return 0;
657 | }
658 |
--------------------------------------------------------------------------------
/ngx_nsoc.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Roman Arutyunyan
3 | * Copyright (C) Nginx, Inc.
4 | */
5 |
6 | #ifndef _NGX_NSOC_H_INCLUDED_
7 | #define _NGX_NSOC_H_INCLUDED_
8 |
9 | #include
10 | #include
11 |
12 | typedef struct ngx_nsoc_session_s ngx_nsoc_session_t;
13 |
14 | #include "ngx_noise_protocol.h"
15 | #include "ngx_nsoc_handler.h"
16 | #include "ngx_nsoc_noiseserver_module.h"
17 | #include "ngx_nsoc_variables.h"
18 | #include "ngx_nsoc_script.h"
19 | #include "ngx_nsoc_upstream.h"
20 | #include "ngx_nsoc_upstream_round_robin.h"
21 |
22 | #define NGX_NSOC_OK 200
23 | #define NGX_NSOC_BAD_REQUEST 400
24 | #define NGX_NSOC_FORBIDDEN 403
25 | #define NGX_NSOC_INTERNAL_SERVER_ERROR 500
26 | #define NGX_NSOC_BAD_GATEWAY 502
27 | #define NGX_NSOC_SERVICE_UNAVAILABLE 503
28 |
29 | #define NGX_NSOC_BUFFERED 0x01
30 |
31 | typedef struct {
32 | void **main_conf;
33 | void **srv_conf;
34 | } ngx_nsoc_conf_ctx_t;
35 |
36 | typedef struct {
37 | ngx_sockaddr_t sockaddr;
38 | socklen_t socklen;
39 |
40 | /* server ctx */
41 | ngx_nsoc_conf_ctx_t *ctx;
42 |
43 | unsigned bind :1;
44 | unsigned wildcard :1;
45 |
46 | /*noise*/
47 | unsigned noise_on :1;
48 | /*end noise*/
49 | #if (NGX_HAVE_INET6)
50 | unsigned ipv6only :1;
51 | #endif
52 | unsigned reuseport :1;
53 | unsigned so_keepalive :2;
54 | unsigned proxy_protocol :1;
55 | #if (NGX_HAVE_KEEPALIVE_TUNABLE)
56 | int tcp_keepidle;
57 | int tcp_keepintvl;
58 | int tcp_keepcnt;
59 | #endif
60 | int backlog;
61 | int type;
62 | } ngx_nsoc_listen_t;
63 |
64 | typedef struct {
65 | ngx_nsoc_conf_ctx_t *ctx;
66 | ngx_str_t addr_text;
67 | /*noise*/
68 | unsigned noise_on :1;
69 | /*end noise*/
70 | //unsigned proxy_protocol :1;
71 | } ngx_nsoc_addr_conf_t;
72 |
73 | typedef struct {
74 | in_addr_t addr;
75 | ngx_nsoc_addr_conf_t conf;
76 | } ngx_nsoc_in_addr_t;
77 |
78 | #if (NGX_HAVE_INET6)
79 |
80 | typedef struct {
81 | struct in6_addr addr6;
82 | ngx_nsoc_addr_conf_t conf;
83 | } ngx_nsoc_in6_addr_t;
84 |
85 | #endif
86 |
87 | typedef struct {
88 | /* ngx_nsoc_in_addr_t or ngx_nsoc_in6_addr_t */
89 | void *addrs;
90 | ngx_uint_t naddrs;
91 | } ngx_nsoc_port_t;
92 |
93 | typedef struct {
94 | int family;
95 | int type;
96 | in_port_t port;
97 | ngx_array_t addrs; /* array of ngx_nsoc_conf_addr_t */
98 | } ngx_nsoc_conf_port_t;
99 |
100 | typedef struct {
101 | ngx_nsoc_listen_t opt;
102 | } ngx_nsoc_conf_addr_t;
103 |
104 | typedef enum {
105 | NGX_NSOC_POST_ACCEPT_PHASE = 0,
106 | NGX_NSOC_PREACCESS_PHASE,
107 | NGX_NSOC_ACCESS_PHASE,
108 | NGX_NSOC_PROTECT_PHASE,
109 | NGX_NSOC_PREREAD_PHASE,
110 | NGX_NSOC_CONTENT_PHASE,
111 | NGX_NSOC_LOG_PHASE
112 | } ngx_nsoc_phases;
113 |
114 | typedef struct ngx_nsoc_phase_handler_s ngx_nsoc_phase_handler_t;
115 |
116 | typedef ngx_int_t (*ngx_nsoc_phase_handler_pt)(ngx_nsoc_session_t *s,
117 | ngx_nsoc_phase_handler_t *ph);
118 | typedef ngx_int_t (*ngx_nsoc_handler_pt)(ngx_nsoc_session_t *s);
119 | typedef void (*ngx_nsoc_content_handler_pt)(ngx_nsoc_session_t *s);
120 |
121 | struct ngx_nsoc_phase_handler_s {
122 | ngx_nsoc_phase_handler_pt checker;
123 | ngx_nsoc_handler_pt handler;
124 | ngx_uint_t next;
125 | };
126 |
127 | typedef struct {
128 | ngx_nsoc_phase_handler_t *handlers;
129 | } ngx_nsoc_phase_engine_t;
130 |
131 | typedef struct {
132 | ngx_array_t handlers;
133 | } ngx_nsoc_phase_t;
134 |
135 | typedef struct {
136 | ngx_array_t servers; /* ngx_nsoc_core_srv_conf_t */
137 | ngx_array_t listen; /* ngx_nsoc_listen_t */
138 |
139 | ngx_pool_t *pool;
140 |
141 | ngx_nsoc_phase_engine_t phase_engine;
142 |
143 | ngx_hash_t variables_hash;
144 |
145 | ngx_array_t variables; /* ngx_nsoc_variable_t */
146 | ngx_array_t prefix_variables; /* ngx_nsoc_variable_t */
147 | ngx_uint_t ncaptures;
148 |
149 | ngx_uint_t variables_hash_max_size;
150 | ngx_uint_t variables_hash_bucket_size;
151 |
152 | ngx_hash_keys_arrays_t *variables_keys;
153 |
154 | ngx_nsoc_phase_t phases[NGX_NSOC_LOG_PHASE + 1];
155 | } ngx_nsoc_core_main_conf_t;
156 |
157 | typedef struct {
158 | ngx_nsoc_content_handler_pt handler;
159 |
160 | ngx_nsoc_conf_ctx_t *ctx;
161 |
162 | u_char *file_name;
163 | ngx_uint_t line;
164 |
165 | ngx_flag_t tcp_nodelay;
166 | size_t nsoc_preread_buffer_size;
167 | ngx_msec_t preread_timeout;
168 |
169 | ngx_log_t *error_log;
170 |
171 | ngx_msec_t resolver_timeout;
172 | ngx_resolver_t *resolver;
173 |
174 | //ngx_msec_t proxy_protocol_timeout;
175 |
176 | ngx_uint_t listen; /* unsigned listen:1; */
177 | } ngx_nsoc_core_srv_conf_t;
178 |
179 | struct ngx_nsoc_session_s {
180 | uint32_t signature; /* "NSOC" */
181 |
182 | ngx_connection_t *connection;
183 |
184 | off_t received;
185 | time_t start_sec;
186 | ngx_msec_t start_msec;
187 |
188 | ngx_log_handler_pt log_handler;
189 |
190 | void **ctx;
191 | void **main_conf;
192 | void **srv_conf;
193 |
194 | /*noise*/
195 | ngx_noise_connection_t *client_noise_connection;
196 | ngx_noise_connection_t *server_noise_connection;
197 | /*end noise*/
198 |
199 | ngx_nsoc_upstream_t *upstream;
200 | ngx_array_t *upstream_states;
201 | /* of ngx_nsoc_upstream_state_t */
202 | ngx_nsoc_variable_value_t *variables;
203 |
204 | #if (NGX_PCRE)
205 | ngx_uint_t ncaptures;
206 | int *captures;
207 | u_char *captures_data;
208 | #endif
209 |
210 | ngx_int_t phase_handler;
211 | ngx_uint_t status;
212 |
213 | /*noise*/
214 | unsigned noise_on :1;
215 | /*end noise*/
216 | unsigned stat_processing :1;
217 |
218 | unsigned health_check :1;
219 | };
220 |
221 | typedef struct {
222 | ngx_int_t (*preconfiguration)(ngx_conf_t *cf);
223 | ngx_int_t (*postconfiguration)(ngx_conf_t *cf);
224 |
225 | void *(*create_main_conf)(ngx_conf_t *cf);
226 | char *(*init_main_conf)(ngx_conf_t *cf, void *conf);
227 |
228 | void *(*create_srv_conf)(ngx_conf_t *cf);
229 | char *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf);
230 | } ngx_nsoc_module_t;
231 |
232 | #define NGX_NSOC_MODULE 0x434F534E /* "NSOC" */
233 |
234 | #define NGX_NSOC_MAIN_CONF 0x02000000
235 | #define NGX_NSOC_SRV_CONF 0x04000000
236 | #define NGX_NSOC_UPS_CONF 0x08000000
237 |
238 | #define NGX_NSOC_MAIN_CONF_OFFSET offsetof(ngx_nsoc_conf_ctx_t, main_conf)
239 | #define NGX_NSOC_SRV_CONF_OFFSET offsetof(ngx_nsoc_conf_ctx_t, srv_conf)
240 |
241 | #define ngx_nsoc_get_module_ctx(s, module) (s)->ctx[module.ctx_index]
242 | #define ngx_nsoc_set_ctx(s, c, module) s->ctx[module.ctx_index] = c;
243 | #define ngx_nsoc_delete_ctx(s, module) s->ctx[module.ctx_index] = NULL;
244 |
245 | #define ngx_nsoc_get_module_main_conf(s, module) \
246 | (s)->main_conf[module.ctx_index]
247 | #define ngx_nsoc_get_module_srv_conf(s, module) \
248 | (s)->srv_conf[module.ctx_index]
249 |
250 | #define ngx_nsoc_conf_get_module_main_conf(cf, module) \
251 | ((ngx_nsoc_conf_ctx_t *) cf->ctx)->main_conf[module.ctx_index]
252 | #define ngx_nsoc_conf_get_module_srv_conf(cf, module) \
253 | ((ngx_nsoc_conf_ctx_t *) cf->ctx)->srv_conf[module.ctx_index]
254 |
255 | #define ngx_nsoc_cycle_get_module_main_conf(cycle, module) \
256 | (cycle->conf_ctx[ngx_nsoc_module.index] ? \
257 | ((ngx_nsoc_conf_ctx_t *) cycle->conf_ctx[ngx_nsoc_module.index]) \
258 | ->main_conf[module.ctx_index]: \
259 | NULL)
260 |
261 | #define NGX_NSOC_WRITE_BUFFERED 0x10
262 |
263 | void ngx_nsoc_core_run_phases(ngx_nsoc_session_t *s);
264 | ngx_int_t ngx_nsoc_core_generic_phase(ngx_nsoc_session_t *s,
265 | ngx_nsoc_phase_handler_t *ph);
266 | ngx_int_t ngx_nsoc_core_preread_phase(ngx_nsoc_session_t *s,
267 | ngx_nsoc_phase_handler_t *ph);
268 | ngx_int_t ngx_nsoc_core_content_phase(ngx_nsoc_session_t *s,
269 | ngx_nsoc_phase_handler_t *ph);
270 |
271 | extern ngx_module_t ngx_nsoc_module;
272 | extern ngx_uint_t ngx_nsoc_max_module;
273 | extern ngx_module_t ngx_nsoc_core_module;
274 |
275 | typedef ngx_int_t (*ngx_nsoc_filter_pt)(ngx_nsoc_session_t *s,
276 | ngx_chain_t *chain, ngx_uint_t from_upstream);
277 |
278 | extern ngx_nsoc_filter_pt ngx_nsoc_top_filter;
279 |
280 | #endif /* _NGX_NSOC_H_INCLUDED_ */
281 |
--------------------------------------------------------------------------------
/ngx_nsoc_core_module.c:
--------------------------------------------------------------------------------
1 |
2 | /*
3 | * Copyright (C) Roman Arutyunyan
4 | * Copyright (C) Nginx, Inc.
5 | */
6 |
7 |
8 | #include
9 | #include
10 |
11 | #include "ngx_nsoc.h"
12 |
13 |
14 | static ngx_int_t ngx_nsoc_core_preconfiguration(ngx_conf_t *cf);
15 | static void *ngx_nsoc_core_create_main_conf(ngx_conf_t *cf);
16 | static char *ngx_nsoc_core_init_main_conf(ngx_conf_t *cf, void *conf);
17 | static void *ngx_nsoc_core_create_srv_conf(ngx_conf_t *cf);
18 | static char *ngx_nsoc_core_merge_srv_conf(ngx_conf_t *cf, void *parent,
19 | void *child);
20 | static char *ngx_nsoc_core_error_log(ngx_conf_t *cf, ngx_command_t *cmd,
21 | void *conf);
22 | static char *ngx_nsoc_core_server(ngx_conf_t *cf, ngx_command_t *cmd,
23 | void *conf);
24 | static char *ngx_nsoc_core_listen(ngx_conf_t *cf, ngx_command_t *cmd,
25 | void *conf);
26 | static char *ngx_nsoc_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd,
27 | void *conf);
28 |
29 |
30 | static ngx_command_t ngx_nsoc_core_commands[] = {
31 |
32 | { ngx_string("variables_hash_max_size"),
33 | NGX_NSOC_MAIN_CONF|NGX_CONF_TAKE1,
34 | ngx_conf_set_num_slot,
35 | NGX_NSOC_MAIN_CONF_OFFSET,
36 | offsetof(ngx_nsoc_core_main_conf_t, variables_hash_max_size),
37 | NULL },
38 |
39 | { ngx_string("variables_hash_bucket_size"),
40 | NGX_NSOC_MAIN_CONF|NGX_CONF_TAKE1,
41 | ngx_conf_set_num_slot,
42 | NGX_NSOC_MAIN_CONF_OFFSET,
43 | offsetof(ngx_nsoc_core_main_conf_t, variables_hash_bucket_size),
44 | NULL },
45 |
46 | { ngx_string("server"),
47 | NGX_NSOC_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
48 | ngx_nsoc_core_server,
49 | 0,
50 | 0,
51 | NULL },
52 |
53 | { ngx_string("listen"),
54 | NGX_NSOC_SRV_CONF|NGX_CONF_1MORE,
55 | ngx_nsoc_core_listen,
56 | NGX_NSOC_SRV_CONF_OFFSET,
57 | 0,
58 | NULL },
59 |
60 | { ngx_string("error_log"),
61 | NGX_NSOC_MAIN_CONF|NGX_NSOC_SRV_CONF|NGX_CONF_1MORE,
62 | ngx_nsoc_core_error_log,
63 | NGX_NSOC_SRV_CONF_OFFSET,
64 | 0,
65 | NULL },
66 |
67 | { ngx_string("resolver"),
68 | NGX_NSOC_MAIN_CONF|NGX_NSOC_SRV_CONF|NGX_CONF_1MORE,
69 | ngx_nsoc_core_resolver,
70 | NGX_NSOC_SRV_CONF_OFFSET,
71 | 0,
72 | NULL },
73 |
74 | { ngx_string("resolver_timeout"),
75 | NGX_NSOC_MAIN_CONF|NGX_NSOC_SRV_CONF|NGX_CONF_TAKE1,
76 | ngx_conf_set_msec_slot,
77 | NGX_NSOC_SRV_CONF_OFFSET,
78 | offsetof(ngx_nsoc_core_srv_conf_t, resolver_timeout),
79 | NULL },
80 |
81 |
82 | { ngx_string("tcp_nodelay"),
83 | NGX_NSOC_MAIN_CONF|NGX_NSOC_SRV_CONF|NGX_CONF_FLAG,
84 | ngx_conf_set_flag_slot,
85 | NGX_NSOC_SRV_CONF_OFFSET,
86 | offsetof(ngx_nsoc_core_srv_conf_t, tcp_nodelay),
87 | NULL },
88 |
89 | { ngx_string("preread_buffer_size"),
90 | NGX_NSOC_MAIN_CONF|NGX_NSOC_SRV_CONF|NGX_CONF_TAKE1,
91 | ngx_conf_set_size_slot,
92 | NGX_NSOC_SRV_CONF_OFFSET,
93 | offsetof(ngx_nsoc_core_srv_conf_t,nsoc_preread_buffer_size ),
94 | NULL },
95 |
96 | { ngx_string("preread_timeout"),
97 | NGX_NSOC_MAIN_CONF|NGX_NSOC_SRV_CONF|NGX_CONF_TAKE1,
98 | ngx_conf_set_msec_slot,
99 | NGX_NSOC_SRV_CONF_OFFSET,
100 | offsetof(ngx_nsoc_core_srv_conf_t, preread_timeout),
101 | NULL },
102 |
103 | ngx_null_command
104 | };
105 |
106 |
107 | static ngx_nsoc_module_t ngx_nsoc_core_module_ctx = {
108 | ngx_nsoc_core_preconfiguration, /* preconfiguration */
109 | NULL, /* postconfiguration */
110 |
111 | ngx_nsoc_core_create_main_conf, /* create main configuration */
112 | ngx_nsoc_core_init_main_conf, /* init main configuration */
113 |
114 | ngx_nsoc_core_create_srv_conf, /* create server configuration */
115 | ngx_nsoc_core_merge_srv_conf /* merge server configuration */
116 | };
117 |
118 |
119 | ngx_module_t ngx_nsoc_core_module = {
120 | NGX_MODULE_V1,
121 | &ngx_nsoc_core_module_ctx, /* module context */
122 | ngx_nsoc_core_commands, /* module directives */
123 | NGX_NSOC_MODULE, /* module type */
124 | NULL, /* init master */
125 | NULL, /* init module */
126 | NULL, /* init process */
127 | NULL, /* init thread */
128 | NULL, /* exit thread */
129 | NULL, /* exit process */
130 | NULL, /* exit master */
131 | NGX_MODULE_V1_PADDING
132 | };
133 |
134 |
135 | void
136 | ngx_nsoc_core_run_phases(ngx_nsoc_session_t *s)
137 | {
138 | ngx_int_t rc;
139 | ngx_nsoc_phase_handler_t *ph;
140 | ngx_nsoc_core_main_conf_t *cmcf;
141 |
142 | cmcf = ngx_nsoc_get_module_main_conf(s, ngx_nsoc_core_module);
143 |
144 | ph = cmcf->phase_engine.handlers;
145 |
146 | while (ph[s->phase_handler].checker) {
147 |
148 | rc = ph[s->phase_handler].checker(s, &ph[s->phase_handler]);
149 |
150 | if (rc == NGX_OK) {
151 | return;
152 | }
153 | }
154 | }
155 |
156 |
157 | ngx_int_t
158 | ngx_nsoc_core_generic_phase(ngx_nsoc_session_t *s,
159 | ngx_nsoc_phase_handler_t *ph)
160 | {
161 | ngx_int_t rc;
162 |
163 | /*
164 | * generic phase checker,
165 | * used by all phases, except for preread and content
166 | */
167 |
168 | ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
169 | "generic phase: %ui", s->phase_handler);
170 |
171 | rc = ph->handler(s);
172 |
173 | if (rc == NGX_OK) {
174 | s->phase_handler = ph->next;
175 | return NGX_AGAIN;
176 | }
177 |
178 | if (rc == NGX_DECLINED) {
179 | s->phase_handler++;
180 | return NGX_AGAIN;
181 | }
182 |
183 | if (rc == NGX_AGAIN || rc == NGX_DONE) {
184 | return NGX_OK;
185 | }
186 |
187 | if (rc == NGX_ERROR) {
188 | rc = NGX_NSOC_INTERNAL_SERVER_ERROR;
189 | }
190 |
191 | ngx_nsoc_finalize_session(s, rc);
192 |
193 | return NGX_OK;
194 | }
195 |
196 |
197 | ngx_int_t
198 | ngx_nsoc_core_preread_phase(ngx_nsoc_session_t *s,
199 | ngx_nsoc_phase_handler_t *ph)
200 | {
201 | size_t size;
202 | ssize_t n;
203 | ngx_int_t rc;
204 | ngx_connection_t *c;
205 | ngx_nsoc_core_srv_conf_t *cscf;
206 |
207 | c = s->connection;
208 |
209 | c->log->action = "prereading client data";
210 |
211 | cscf = ngx_nsoc_get_module_srv_conf(s, ngx_nsoc_core_module);
212 |
213 | if (c->read->timedout) {
214 | rc = NGX_NSOC_OK;
215 |
216 | } else if (c->read->timer_set) {
217 | rc = NGX_AGAIN;
218 |
219 | } else {
220 | rc = ph->handler(s);
221 | }
222 |
223 | while (rc == NGX_AGAIN) {
224 |
225 | if (c->buffer == NULL) {
226 | c->buffer = ngx_create_temp_buf(c->pool, cscf->nsoc_preread_buffer_size);
227 | if (c->buffer == NULL) {
228 | rc = NGX_ERROR;
229 | break;
230 | }
231 | }
232 |
233 | size = c->buffer->end - c->buffer->last;
234 |
235 | if (size == 0) {
236 | ngx_log_error(NGX_LOG_ERR, c->log, 0, "preread buffer full");
237 | rc = NGX_NSOC_BAD_REQUEST;
238 | break;
239 | }
240 |
241 | if (c->read->eof) {
242 | rc = NGX_NSOC_OK;
243 | break;
244 | }
245 |
246 | if (!c->read->ready) {
247 | if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
248 | rc = NGX_ERROR;
249 | break;
250 | }
251 |
252 | if (!c->read->timer_set) {
253 | ngx_add_timer(c->read, cscf->preread_timeout);
254 | }
255 |
256 | c->read->handler = ngx_nsoc_session_handler;
257 |
258 | return NGX_OK;
259 | }
260 |
261 | n = c->recv(c, c->buffer->last, size);
262 |
263 | if (n == NGX_ERROR) {
264 | rc = NGX_NSOC_OK;
265 | break;
266 | }
267 |
268 | if (n > 0) {
269 | c->buffer->last += n;
270 | }
271 |
272 | rc = ph->handler(s);
273 | }
274 |
275 | if (c->read->timer_set) {
276 | ngx_del_timer(c->read);
277 | }
278 |
279 | if (rc == NGX_OK) {
280 | s->phase_handler = ph->next;
281 | return NGX_AGAIN;
282 | }
283 |
284 | if (rc == NGX_DECLINED) {
285 | s->phase_handler++;
286 | return NGX_AGAIN;
287 | }
288 |
289 | if (rc == NGX_DONE) {
290 | return NGX_OK;
291 | }
292 |
293 | if (rc == NGX_ERROR) {
294 | rc = NGX_NSOC_INTERNAL_SERVER_ERROR;
295 | }
296 |
297 | ngx_nsoc_finalize_session(s, rc);
298 |
299 | return NGX_OK;
300 | }
301 |
302 |
303 | ngx_int_t
304 | ngx_nsoc_core_content_phase(ngx_nsoc_session_t *s,
305 | ngx_nsoc_phase_handler_t *ph)
306 | {
307 | int tcp_nodelay;
308 | ngx_connection_t *c;
309 | ngx_nsoc_core_srv_conf_t *cscf;
310 |
311 | c = s->connection;
312 |
313 | c->log->action = NULL;
314 |
315 | cscf = ngx_nsoc_get_module_srv_conf(s, ngx_nsoc_core_module);
316 |
317 | if (c->type == SOCK_STREAM
318 | && cscf->tcp_nodelay
319 | && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET)
320 | {
321 | ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0, "tcp_nodelay");
322 |
323 | tcp_nodelay = 1;
324 |
325 | if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY,
326 | (const void *) &tcp_nodelay, sizeof(int)) == -1)
327 | {
328 | ngx_connection_error(c, ngx_socket_errno,
329 | "setsockopt(TCP_NODELAY) failed");
330 | ngx_nsoc_finalize_session(s, NGX_NSOC_INTERNAL_SERVER_ERROR);
331 | return NGX_OK;
332 | }
333 |
334 | c->tcp_nodelay = NGX_TCP_NODELAY_SET;
335 | }
336 |
337 | cscf->handler(s);
338 |
339 | return NGX_OK;
340 | }
341 |
342 |
343 | static ngx_int_t
344 | ngx_nsoc_core_preconfiguration(ngx_conf_t *cf)
345 | {
346 | return ngx_nsoc_variables_add_core_vars(cf);
347 | }
348 |
349 |
350 | static void *
351 | ngx_nsoc_core_create_main_conf(ngx_conf_t *cf)
352 | {
353 | ngx_nsoc_core_main_conf_t *cmcf;
354 |
355 | cmcf = ngx_pcalloc(cf->pool, sizeof(ngx_nsoc_core_main_conf_t));
356 | if (cmcf == NULL) {
357 | return NULL;
358 | }
359 |
360 | if (ngx_array_init(&cmcf->servers, cf->pool, 4,
361 | sizeof(ngx_nsoc_core_srv_conf_t *))
362 | != NGX_OK)
363 | {
364 | return NULL;
365 | }
366 |
367 | if (ngx_array_init(&cmcf->listen, cf->pool, 4, sizeof(ngx_nsoc_listen_t))
368 | != NGX_OK)
369 | {
370 | return NULL;
371 | }
372 |
373 | cmcf->variables_hash_max_size = NGX_CONF_UNSET_UINT;
374 | cmcf->variables_hash_bucket_size = NGX_CONF_UNSET_UINT;
375 |
376 | return cmcf;
377 | }
378 |
379 |
380 | static char *
381 | ngx_nsoc_core_init_main_conf(ngx_conf_t *cf, void *conf)
382 | {
383 | ngx_nsoc_core_main_conf_t *cmcf = conf;
384 |
385 | ngx_conf_init_uint_value(cmcf->variables_hash_max_size, 1024);
386 | ngx_conf_init_uint_value(cmcf->variables_hash_bucket_size, 64);
387 |
388 | cmcf->variables_hash_bucket_size =
389 | ngx_align(cmcf->variables_hash_bucket_size, ngx_cacheline_size);
390 |
391 | if (cmcf->ncaptures) {
392 | cmcf->ncaptures = (cmcf->ncaptures + 1) * 3;
393 | }
394 |
395 | return NGX_CONF_OK;
396 | }
397 |
398 |
399 | static void *
400 | ngx_nsoc_core_create_srv_conf(ngx_conf_t *cf)
401 | {
402 | ngx_nsoc_core_srv_conf_t *cscf;
403 |
404 | cscf = ngx_pcalloc(cf->pool, sizeof(ngx_nsoc_core_srv_conf_t));
405 | if (cscf == NULL) {
406 | return NULL;
407 | }
408 |
409 | /*
410 | * set by ngx_pcalloc():
411 | *
412 | * cscf->handler = NULL;
413 | * cscf->error_log = NULL;
414 | */
415 |
416 | cscf->file_name = cf->conf_file->file.name.data;
417 | cscf->line = cf->conf_file->line;
418 | cscf->resolver_timeout = NGX_CONF_UNSET_MSEC;
419 | cscf->tcp_nodelay = NGX_CONF_UNSET;
420 | cscf->nsoc_preread_buffer_size = NGX_CONF_UNSET_SIZE;
421 | cscf->preread_timeout = NGX_CONF_UNSET_MSEC;
422 |
423 | return cscf;
424 | }
425 |
426 |
427 | static char *
428 | ngx_nsoc_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
429 | {
430 | ngx_nsoc_core_srv_conf_t *prev = parent;
431 | ngx_nsoc_core_srv_conf_t *conf = child;
432 |
433 | ngx_conf_merge_msec_value(conf->resolver_timeout,
434 | prev->resolver_timeout, 30000);
435 |
436 | if (conf->resolver == NULL) {
437 |
438 | if (prev->resolver == NULL) {
439 |
440 | /*
441 | * create dummy resolver in stream {} context
442 | * to inherit it in all servers
443 | */
444 |
445 | prev->resolver = ngx_resolver_create(cf, NULL, 0);
446 | if (prev->resolver == NULL) {
447 | return NGX_CONF_ERROR;
448 | }
449 | }
450 |
451 | conf->resolver = prev->resolver;
452 | }
453 |
454 | if (conf->handler == NULL) {
455 | ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
456 | "no handler for server in %s:%ui",
457 | conf->file_name, conf->line);
458 | return NGX_CONF_ERROR;
459 | }
460 |
461 | if (conf->error_log == NULL) {
462 | if (prev->error_log) {
463 | conf->error_log = prev->error_log;
464 | } else {
465 | conf->error_log = &cf->cycle->new_log;
466 | }
467 | }
468 |
469 | ngx_conf_merge_value(conf->tcp_nodelay, prev->tcp_nodelay, 1);
470 |
471 | ngx_conf_merge_size_value(conf->nsoc_preread_buffer_size,
472 | prev->nsoc_preread_buffer_size, NOISE_PROTOCOL_PAYLOAD_SIZE);
473 |
474 | if (conf->nsoc_preread_buffer_size > NOISE_PROTOCOL_PAYLOAD_SIZE) {
475 | ngx_log_error(
476 | NGX_LOG_EMERG, cf->log, 0, "noise socket responder buffer too big");
477 | return NGX_CONF_ERROR ;
478 | }
479 |
480 | ngx_conf_merge_msec_value(conf->preread_timeout,
481 | prev->preread_timeout, 30000);
482 |
483 | return NGX_CONF_OK;
484 | }
485 |
486 |
487 | static char *
488 | ngx_nsoc_core_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
489 | {
490 | ngx_nsoc_core_srv_conf_t *cscf = conf;
491 |
492 | return ngx_log_set_log(cf, &cscf->error_log);
493 | }
494 |
495 |
496 | static char *
497 | ngx_nsoc_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
498 | {
499 | char *rv;
500 | void *mconf;
501 | ngx_uint_t m;
502 | ngx_conf_t pcf;
503 | ngx_nsoc_module_t *module;
504 | ngx_nsoc_conf_ctx_t *ctx, *stream_ctx;
505 | ngx_nsoc_core_srv_conf_t *cscf, **cscfp;
506 | ngx_nsoc_core_main_conf_t *cmcf;
507 |
508 | ctx = ngx_pcalloc(cf->pool, sizeof(ngx_nsoc_conf_ctx_t));
509 | if (ctx == NULL) {
510 | return NGX_CONF_ERROR;
511 | }
512 |
513 | stream_ctx = cf->ctx;
514 | ctx->main_conf = stream_ctx->main_conf;
515 |
516 | /* the server{}'s srv_conf */
517 |
518 | ctx->srv_conf = ngx_pcalloc(cf->pool,
519 | sizeof(void *) * ngx_nsoc_max_module);
520 | if (ctx->srv_conf == NULL) {
521 | return NGX_CONF_ERROR;
522 | }
523 |
524 | for (m = 0; cf->cycle->modules[m]; m++) {
525 | if (cf->cycle->modules[m]->type != NGX_NSOC_MODULE) {
526 | continue;
527 | }
528 |
529 | module = cf->cycle->modules[m]->ctx;
530 |
531 | if (module->create_srv_conf) {
532 | mconf = module->create_srv_conf(cf);
533 | if (mconf == NULL) {
534 | return NGX_CONF_ERROR;
535 | }
536 |
537 | ctx->srv_conf[cf->cycle->modules[m]->ctx_index] = mconf;
538 | }
539 | }
540 |
541 | /* the server configuration context */
542 |
543 | cscf = ctx->srv_conf[ngx_nsoc_core_module.ctx_index];
544 | cscf->ctx = ctx;
545 |
546 | cmcf = ctx->main_conf[ngx_nsoc_core_module.ctx_index];
547 |
548 | cscfp = ngx_array_push(&cmcf->servers);
549 | if (cscfp == NULL) {
550 | return NGX_CONF_ERROR;
551 | }
552 |
553 | *cscfp = cscf;
554 |
555 |
556 | /* parse inside server{} */
557 |
558 | pcf = *cf;
559 | cf->ctx = ctx;
560 | cf->cmd_type = NGX_NSOC_SRV_CONF;
561 |
562 | rv = ngx_conf_parse(cf, NULL);
563 |
564 | *cf = pcf;
565 |
566 | if (rv == NGX_CONF_OK && !cscf->listen) {
567 | ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
568 | "no \"listen\" is defined for server in %s:%ui",
569 | cscf->file_name, cscf->line);
570 | return NGX_CONF_ERROR;
571 | }
572 |
573 | return rv;
574 | }
575 |
576 |
577 | static char *
578 | ngx_nsoc_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
579 | {
580 | ngx_nsoc_core_srv_conf_t *cscf = conf;
581 |
582 | ngx_str_t *value;
583 | ngx_url_t u;
584 | ngx_uint_t i, backlog;
585 | ngx_nsoc_listen_t *ls, *als;
586 | ngx_nsoc_core_main_conf_t *cmcf;
587 |
588 | cscf->listen = 1;
589 |
590 | value = cf->args->elts;
591 |
592 | ngx_memzero(&u, sizeof(ngx_url_t));
593 |
594 | u.url = value[1];
595 | u.listen = 1;
596 |
597 | if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
598 | if (u.err) {
599 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
600 | "%s in \"%V\" of the \"listen\" directive",
601 | u.err, &u.url);
602 | }
603 |
604 | return NGX_CONF_ERROR;
605 | }
606 |
607 | cmcf = ngx_nsoc_conf_get_module_main_conf(cf, ngx_nsoc_core_module);
608 |
609 | ls = ngx_array_push(&cmcf->listen);
610 | if (ls == NULL) {
611 | return NGX_CONF_ERROR;
612 | }
613 |
614 | ngx_memzero(ls, sizeof(ngx_nsoc_listen_t));
615 |
616 | ngx_memcpy(&ls->sockaddr.sockaddr, &u.sockaddr, u.socklen);
617 |
618 | ls->socklen = u.socklen;
619 | ls->backlog = NGX_LISTEN_BACKLOG;
620 | ls->type = SOCK_STREAM;
621 | ls->wildcard = u.wildcard;
622 | ls->ctx = cf->ctx;
623 |
624 | #if (NGX_HAVE_INET6)
625 | ls->ipv6only = 1;
626 | #endif
627 |
628 | backlog = 0;
629 |
630 | for (i = 2; i < cf->args->nelts; i++) {
631 |
632 | #if !(NGX_WIN32)
633 | if (ngx_strcmp(value[i].data, "udp") == 0) {
634 | ls->type = SOCK_DGRAM;
635 | continue;
636 | }
637 | #endif
638 |
639 | if (ngx_strcmp(value[i].data, "bind") == 0) {
640 | ls->bind = 1;
641 | continue;
642 | }
643 |
644 | if (ngx_strncmp(value[i].data, "backlog=", 8) == 0) {
645 | ls->backlog = ngx_atoi(value[i].data + 8, value[i].len - 8);
646 | ls->bind = 1;
647 |
648 | if (ls->backlog == NGX_ERROR || ls->backlog == 0) {
649 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
650 | "invalid backlog \"%V\"", &value[i]);
651 | return NGX_CONF_ERROR;
652 | }
653 |
654 | backlog = 1;
655 |
656 | continue;
657 | }
658 |
659 | if (ngx_strncmp(value[i].data, "ipv6only=o", 10) == 0) {
660 | #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
661 | size_t len;
662 | u_char buf[NGX_SOCKADDR_STRLEN];
663 |
664 | if (ls->sockaddr.sockaddr.sa_family == AF_INET6) {
665 |
666 | if (ngx_strcmp(&value[i].data[10], "n") == 0) {
667 | ls->ipv6only = 1;
668 |
669 | } else if (ngx_strcmp(&value[i].data[10], "ff") == 0) {
670 | ls->ipv6only = 0;
671 |
672 | } else {
673 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
674 | "invalid ipv6only flags \"%s\"",
675 | &value[i].data[9]);
676 | return NGX_CONF_ERROR;
677 | }
678 |
679 | ls->bind = 1;
680 |
681 | } else {
682 | len = ngx_sock_ntop(&ls->sockaddr.sockaddr, ls->socklen, buf,
683 | NGX_SOCKADDR_STRLEN, 1);
684 |
685 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
686 | "ipv6only is not supported "
687 | "on addr \"%*s\", ignored", len, buf);
688 | }
689 |
690 | continue;
691 | #else
692 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
693 | "bind ipv6only is not supported "
694 | "on this platform");
695 | return NGX_CONF_ERROR;
696 | #endif
697 | }
698 |
699 | if (ngx_strcmp(value[i].data, "reuseport") == 0) {
700 | #if (NGX_HAVE_REUSEPORT)
701 | ls->reuseport = 1;
702 | ls->bind = 1;
703 | #else
704 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
705 | "reuseport is not supported "
706 | "on this platform, ignored");
707 | #endif
708 | continue;
709 | }
710 |
711 | if (ngx_strcmp(value[i].data, "noise") == 0) {
712 | ls->noise_on = 1;
713 | continue;
714 | }
715 |
716 | if (ngx_strncmp(value[i].data, "so_keepalive=", 13) == 0) {
717 |
718 | if (ngx_strcmp(&value[i].data[13], "on") == 0) {
719 | ls->so_keepalive = 1;
720 |
721 | } else if (ngx_strcmp(&value[i].data[13], "off") == 0) {
722 | ls->so_keepalive = 2;
723 |
724 | } else {
725 |
726 | #if (NGX_HAVE_KEEPALIVE_TUNABLE)
727 | u_char *p, *end;
728 | ngx_str_t s;
729 |
730 | end = value[i].data + value[i].len;
731 | s.data = value[i].data + 13;
732 |
733 | p = ngx_strlchr(s.data, end, ':');
734 | if (p == NULL) {
735 | p = end;
736 | }
737 |
738 | if (p > s.data) {
739 | s.len = p - s.data;
740 |
741 | ls->tcp_keepidle = ngx_parse_time(&s, 1);
742 | if (ls->tcp_keepidle == (time_t) NGX_ERROR) {
743 | goto invalid_so_keepalive;
744 | }
745 | }
746 |
747 | s.data = (p < end) ? (p + 1) : end;
748 |
749 | p = ngx_strlchr(s.data, end, ':');
750 | if (p == NULL) {
751 | p = end;
752 | }
753 |
754 | if (p > s.data) {
755 | s.len = p - s.data;
756 |
757 | ls->tcp_keepintvl = ngx_parse_time(&s, 1);
758 | if (ls->tcp_keepintvl == (time_t) NGX_ERROR) {
759 | goto invalid_so_keepalive;
760 | }
761 | }
762 |
763 | s.data = (p < end) ? (p + 1) : end;
764 |
765 | if (s.data < end) {
766 | s.len = end - s.data;
767 |
768 | ls->tcp_keepcnt = ngx_atoi(s.data, s.len);
769 | if (ls->tcp_keepcnt == NGX_ERROR) {
770 | goto invalid_so_keepalive;
771 | }
772 | }
773 |
774 | if (ls->tcp_keepidle == 0 && ls->tcp_keepintvl == 0
775 | && ls->tcp_keepcnt == 0)
776 | {
777 | goto invalid_so_keepalive;
778 | }
779 |
780 | ls->so_keepalive = 1;
781 |
782 | #else
783 |
784 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
785 | "the \"so_keepalive\" parameter accepts "
786 | "only \"on\" or \"off\" on this platform");
787 | return NGX_CONF_ERROR;
788 |
789 | #endif
790 | }
791 |
792 | ls->bind = 1;
793 |
794 | continue;
795 |
796 | #if (NGX_HAVE_KEEPALIVE_TUNABLE)
797 | invalid_so_keepalive:
798 |
799 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
800 | "invalid so_keepalive value: \"%s\"",
801 | &value[i].data[13]);
802 | return NGX_CONF_ERROR;
803 | #endif
804 | }
805 |
806 | if (ngx_strcmp(value[i].data, "proxy_protocol") == 0) {
807 | ls->proxy_protocol = 1;
808 | continue;
809 | }
810 |
811 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
812 | "the invalid \"%V\" parameter", &value[i]);
813 | return NGX_CONF_ERROR;
814 | }
815 |
816 | if (ls->type == SOCK_DGRAM) {
817 | if (backlog) {
818 | return "\"backlog\" parameter is incompatible with \"udp\"";
819 | }
820 |
821 | if (ls->noise_on) {
822 | return "\"noise\" parameter is incompatible with \"udp\"";
823 | }
824 |
825 | if (ls->so_keepalive) {
826 | return "\"so_keepalive\" parameter is incompatible with \"udp\"";
827 | }
828 |
829 | if (ls->proxy_protocol) {
830 | return "\"proxy_protocol\" parameter is incompatible with \"udp\"";
831 | }
832 | }
833 |
834 | als = cmcf->listen.elts;
835 |
836 | for (i = 0; i < cmcf->listen.nelts - 1; i++) {
837 | if (ls->type != als[i].type) {
838 | continue;
839 | }
840 |
841 | if (ngx_cmp_sockaddr(&als[i].sockaddr.sockaddr, als[i].socklen,
842 | &ls->sockaddr.sockaddr, ls->socklen, 1)
843 | != NGX_OK)
844 | {
845 | continue;
846 | }
847 |
848 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
849 | "duplicate \"%V\" address and port pair", &u.url);
850 | return NGX_CONF_ERROR;
851 | }
852 |
853 | return NGX_CONF_OK;
854 | }
855 |
856 |
857 | static char *
858 | ngx_nsoc_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
859 | {
860 | ngx_nsoc_core_srv_conf_t *cscf = conf;
861 |
862 | ngx_str_t *value;
863 |
864 | if (cscf->resolver) {
865 | return "is duplicate";
866 | }
867 |
868 | value = cf->args->elts;
869 |
870 | cscf->resolver = ngx_resolver_create(cf, &value[1], cf->args->nelts - 1);
871 | if (cscf->resolver == NULL) {
872 | return NGX_CONF_ERROR;
873 | }
874 |
875 | return NGX_CONF_OK;
876 | }
877 |
--------------------------------------------------------------------------------
/ngx_nsoc_handler.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Maxim Grigoryev
3 | * Copyright (C) Virgil Security, Inc.
4 | */
5 |
6 | #ifndef _NGX_NSOC_HANDLER_H_INCLUDED_
7 | #define _NGX_NSOC_HANDLER_H_INCLUDED_
8 |
9 | #include
10 | #include
11 | #include "ngx_nsoc.h"
12 |
13 | #define NGX_NSOC_BUFFER 1
14 | #define NGX_NSOC_CLIENT 2
15 | #define NGX_NSOC_SIZE_UNSET -1
16 |
17 | #define NGX_NSOC_1MSG 0
18 | #define NGX_NSOC_2MSG_OK 1
19 | #define NGX_NSOC_2MSG_FB 2
20 | #define NGX_NSOC_2MSG_ERR 3
21 | #define NGX_NSOC_3MSG 4
22 |
23 | #define NGX_NSOC_1MSG_NEG_DATA_SIZE 6
24 |
25 | #define NGX_NSOC_2MSG_NEG_DATA_OK_SIZE 0
26 | #define NGX_NSOC_2MSG_NEG_DATA_FB_SIZE 3
27 | #define NGX_NSOC_2MSG_NEG_DATA_ERR_SIZE 3
28 |
29 | #define NGX_NSOC_3MSG_NEG_DATA_SIZE 0
30 |
31 | #define NGX_NSOC_LEN_FIELD_SIZE 2
32 |
33 | #define NGX_NSOC_VERSION_ID swapw(1)
34 |
35 | #define NGX_NSOC_BUFSIZE NOISE_PROTOCOL_PAYLOAD_SIZE + NOISE_PROTOCOL_MAC_DATA_SIZE + 2*NGX_NSOC_LEN_FIELD_SIZE
36 |
37 | typedef enum {
38 | NGX_NSOC_HANDSHAKE_NONE_PHASE = 0,
39 | NGX_NSOC_HANDSHAKE_PROCESS_PHASE,
40 | NGX_NSOC_HANDSHAKE_END_PHASE,
41 | } ngx_noise_handshake_phases_e;
42 |
43 | typedef struct ngx_noise_s {
44 | NOISE_CTX *ctx;
45 | ngx_log_t *log;
46 | noise_prologue_data_t prologue;
47 | size_t buffer_size;
48 | ngx_msec_t handshake_timeout;
49 | } ngx_noise_t;
50 |
51 | typedef struct ngx_noise_connection_s {
52 |
53 | ngx_connection_t *connection;
54 | noise_protocol_conn_t noise_connection;
55 | NOISE_CTX *noise_ctx;
56 | noise_prologue_data_t *prologue;
57 |
58 | ngx_noise_handshake_phases_e handshake_phase;
59 | ngx_noise_role_e noise_role;
60 | ngx_int_t msg_num;
61 |
62 | ngx_int_t last;
63 | ngx_buf_t *buf;
64 | size_t buffer_size;
65 |
66 | ngx_msec_t handshake_timeout;
67 |
68 | ngx_buf_t *send_buf;
69 | ngx_buf_t *recv_buf;
70 | size_t to_send;
71 | ssize_t neg_data_recv_size;
72 | ssize_t noise_msg_recv_size;
73 |
74 | ngx_connection_handler_pt handler;
75 |
76 | unsigned handshaked :1;
77 | unsigned noise_msg_size_reading :1;
78 | unsigned neg_data_size_reading :1;
79 | unsigned buffer :1;
80 |
81 | } ngx_noise_connection_t;
82 |
83 | void ngx_nsoc_init_connection(ngx_connection_t *c);
84 | void ngx_nsoc_session_handler(ngx_event_t *rev);
85 | void ngx_nsoc_finalize_session(ngx_nsoc_session_t *s, ngx_uint_t rc);
86 |
87 | void ngx_nsoc_cleanup_ctx(void *data);
88 | ngx_int_t ngx_nsoc_create(ngx_noise_t *noise, size_t buffer_size, void *data);
89 | ngx_int_t ngx_nsoc_create_connection(ngx_noise_t *noise, ngx_connection_t *c,
90 | ngx_uint_t flags);
91 | ngx_int_t ngx_nsoc_handshake(ngx_connection_t *c);
92 | ngx_int_t ngx_nsoc_shutdown(ngx_connection_t *c);
93 |
94 | ssize_t ngx_nsoc_recv_chain(ngx_connection_t *c, ngx_chain_t *cl, off_t limit);
95 | ssize_t ngx_nsoc_recv(ngx_connection_t *c, u_char *buf, size_t size);
96 | ngx_chain_t * ngx_nsoc_send_chain(ngx_connection_t *c, ngx_chain_t *in,
97 | off_t limit);
98 | ssize_t ngx_nsoc_write(ngx_connection_t *c, u_char *data, size_t size);
99 | #endif
100 |
101 |
--------------------------------------------------------------------------------
/ngx_nsoc_noiseserver_module.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Maxim Grigoryev
3 | * Copyright (C) Virgil Security, Inc.
4 | */
5 |
6 | #include
7 | #include
8 |
9 | #include "ngx_nsoc.h"
10 |
11 | typedef ngx_int_t (*ngx_noise_variable_handler_pt)(ngx_connection_t *c,
12 | ngx_pool_t *pool, ngx_str_t *s);
13 |
14 | static ngx_int_t ngx_nsoc_noiseserver_handler(ngx_nsoc_session_t *s);
15 | static ngx_int_t ngx_nsoc_noiseserver_init_connection(ngx_noise_t *noise,
16 | ngx_connection_t *c);
17 | static void ngx_nsoc_noiseserver_handshake_handler(ngx_connection_t *c);
18 | static void *ngx_nsoc_noiseserver_create_conf(ngx_conf_t *cf);
19 | static char *ngx_nsoc_noiseserver_merge_conf(ngx_conf_t *cf, void *parent,
20 | void *child);
21 |
22 | static ngx_int_t ngx_nsoc_noiseserver_init(ngx_conf_t *cf);
23 |
24 | static ngx_command_t ngx_nsoc_noiseserver_commands[] =
25 | {
26 |
27 | { ngx_string("noise_handshake_timeout"),
28 | NGX_NSOC_MAIN_CONF | NGX_NSOC_SRV_CONF | NGX_CONF_TAKE1,
29 | ngx_conf_set_msec_slot,
30 | NGX_NSOC_SRV_CONF_OFFSET,
31 | offsetof(ngx_nsoc_noiseserver_conf_t, handshake_timeout),
32 | NULL },
33 |
34 | { ngx_string("server_private_key_file"),
35 | NGX_NSOC_MAIN_CONF | NGX_NSOC_SRV_CONF | NGX_CONF_TAKE1,
36 | ngx_conf_set_str_slot,
37 | NGX_NSOC_SRV_CONF_OFFSET,
38 | offsetof(ngx_nsoc_noiseserver_conf_t, server_private_key_file),
39 | NULL },
40 |
41 | { ngx_string("client_public_key_file"),
42 | NGX_NSOC_MAIN_CONF | NGX_NSOC_SRV_CONF | NGX_CONF_TAKE1,
43 | ngx_conf_set_str_slot,
44 | NGX_NSOC_SRV_CONF_OFFSET,
45 | offsetof(ngx_nsoc_noiseserver_conf_t, client_public_key_file),
46 | NULL },
47 |
48 | ngx_null_command
49 | };
50 |
51 | static ngx_nsoc_module_t ngx_nsoc_noiseserver_module_ctx =
52 | { //ngx_nsoc_noiseserver_add_variables, /* preconfiguration */
53 | NULL,/* preconfiguration */
54 | ngx_nsoc_noiseserver_init, /* postconfiguration */
55 |
56 | NULL, /* create main configuration */
57 | NULL, /* init main configuration */
58 |
59 | ngx_nsoc_noiseserver_create_conf, /* create server configuration */
60 | ngx_nsoc_noiseserver_merge_conf /* merge server configuration */
61 | };
62 |
63 | ngx_module_t ngx_nsoc_noiseserver_module =
64 | {
65 | NGX_MODULE_V1,
66 | &ngx_nsoc_noiseserver_module_ctx, /* module context */
67 | ngx_nsoc_noiseserver_commands, /* module directives */
68 | NGX_NSOC_MODULE, /* module type */
69 | NULL, /* init master */
70 | NULL, /* init module */
71 | NULL, /* init process */
72 | NULL, /* init thread */
73 | NULL, /* exit thread */
74 | NULL, /* exit process */
75 | NULL, /* exit master */
76 | NGX_MODULE_V1_PADDING
77 | };
78 |
79 | static ngx_int_t ngx_nsoc_noiseserver_handler(ngx_nsoc_session_t *s)
80 | {
81 | ngx_int_t rv;
82 | ngx_connection_t *c;
83 | ngx_nsoc_noiseserver_conf_t *noisecf;
84 | ngx_array_t *private_key, *public_key;
85 | ngx_str_t *key;
86 | ngx_nsoc_core_main_conf_t *cmcf;
87 |
88 | if (!s->noise_on) {
89 | return NGX_OK;
90 | }
91 |
92 | c = s->connection;
93 | noisecf = ngx_nsoc_get_module_srv_conf(s, ngx_nsoc_noiseserver_module);
94 |
95 | cmcf = ngx_nsoc_get_module_main_conf(s, ngx_nsoc_core_module);
96 |
97 | if(noisecf->noise->ctx->private_keys == NULL) {
98 | if (noisecf->server_private_key_file.len == 0){
99 | ngx_log_error(NGX_LOG_EMERG, c->log, 0,
100 | "server private key file is not set");
101 |
102 | return NGX_ERROR;
103 | }
104 |
105 | private_key = ngx_array_create(cmcf->pool, 1, sizeof(ngx_str_t));
106 | key = private_key->elts;
107 | key->len = NOISE_PROTOCOL_CURVE25519_KEY_LEN;
108 | key->data = ngx_pnalloc(cmcf->pool, NOISE_PROTOCOL_CURVE25519_KEY_LEN);
109 | if (ngx_noise_protocol_load_private_key(
110 | noisecf->server_private_key_file.data, key->data,
111 | NOISE_PROTOCOL_CURVE25519_KEY_LEN) != NGX_OK) {
112 | ngx_log_error(NGX_LOG_EMERG, c->log, 0,
113 | "unable to open server private key file %s",noisecf->server_private_key_file.data);
114 |
115 | return NGX_ERROR;
116 | }
117 | private_key->nelts = 1;
118 | noisecf->noise->ctx->private_keys = private_key;
119 |
120 | }
121 |
122 | if (noisecf->noise->ctx->public_keys == NULL) {
123 | if (noisecf->client_public_key_file.len != 0) {
124 | public_key = ngx_array_create(cmcf->pool, 1, sizeof(ngx_str_t));
125 | key = public_key->elts;
126 | key->len = NOISE_PROTOCOL_CURVE25519_KEY_LEN;
127 | key->data = ngx_pnalloc(cmcf->pool,
128 | NOISE_PROTOCOL_CURVE25519_KEY_LEN);
129 | if (ngx_noise_protocol_load_public_key(
130 | noisecf->client_public_key_file.data, key->data,
131 | NOISE_PROTOCOL_CURVE25519_KEY_LEN) != NGX_OK) {
132 | ngx_log_error(NGX_LOG_EMERG, c->log, 0,
133 | "unable to open client public key file %s",noisecf->client_public_key_file.data);
134 |
135 | return NGX_ERROR;
136 | }
137 | public_key->nelts = 1;
138 | noisecf->noise->ctx->public_keys = public_key;
139 | }
140 | }
141 |
142 | if (s->server_noise_connection == NULL) {
143 | c->log->action = "NOISE handshaking";
144 | rv = ngx_nsoc_noiseserver_init_connection(noisecf->noise, c);
145 |
146 | if (rv != NGX_OK) {
147 | return rv;
148 | }
149 | }
150 |
151 | return NGX_OK;
152 | }
153 |
154 | static ngx_int_t ngx_nsoc_noiseserver_init_connection(ngx_noise_t *noise,
155 | ngx_connection_t *c)
156 | {
157 | ngx_int_t rc;
158 | ngx_nsoc_session_t *s;
159 |
160 | s = c->data;
161 |
162 | ngx_log_debug0(
163 | NGX_LOG_DEBUG_EVENT, c->log, 0,
164 | "ngx_nsoc_noiseserver_init_connection");
165 |
166 | if (ngx_nsoc_create_connection(noise, c, 0) == NGX_ERROR) {
167 | return NGX_ERROR;
168 | }
169 |
170 | rc = ngx_nsoc_handshake(c);
171 |
172 | if (rc == NGX_ERROR) {
173 | return NGX_ERROR;
174 | }
175 |
176 | if (rc == NGX_AGAIN) {
177 |
178 | s->server_noise_connection->handler =
179 | ngx_nsoc_noiseserver_handshake_handler;
180 |
181 | return NGX_AGAIN;
182 | }
183 |
184 | return NGX_OK;
185 | }
186 |
187 | static void ngx_nsoc_noiseserver_handshake_handler(ngx_connection_t *c)
188 | {
189 | ngx_nsoc_session_t *s;
190 |
191 | s = c->data;
192 |
193 | ngx_log_debug8(
194 | NGX_LOG_DEBUG_EVENT,
195 | c->log,
196 | 0,
197 | "wew status: act:%d dis:%d, rdy:%d eof:%d del:%d peof:%d pos:%d clo:%d",
198 | c->write->active, c->write->disabled, c->write->ready,
199 | c->write->eof, c->write->delayed, c->write->pending_eof,
200 | c->write->posted, c->write->closed);
201 |
202 | ngx_log_debug8(
203 | NGX_LOG_DEBUG_EVENT,
204 | c->log,
205 | 0,
206 | "rew status: act:%d dis:%d, rdy:%d eof:%d del:%d peof:%d pos:%d clo:%d",
207 | c->read->active, c->read->disabled, c->read->ready, c->read->eof,
208 | c->read->delayed, c->read->pending_eof, c->read->posted,
209 | c->read->closed);
210 | if (!s->server_noise_connection->handshaked) {
211 | ngx_nsoc_finalize_session(s, NGX_NSOC_INTERNAL_SERVER_ERROR);
212 | return;
213 | }
214 |
215 | if (c->read->timer_set) {
216 | ngx_del_timer(c->read);
217 | }
218 |
219 | if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
220 | return;
221 | }
222 |
223 | ngx_nsoc_core_run_phases(s);
224 | }
225 |
226 | static void *
227 | ngx_nsoc_noiseserver_create_conf(ngx_conf_t *cf)
228 | {
229 | ngx_nsoc_noiseserver_conf_t *noisecf;
230 |
231 | noisecf = ngx_pcalloc(cf->pool, sizeof(ngx_nsoc_noiseserver_conf_t));
232 | if (noisecf == NULL) {
233 | return NULL;
234 | }
235 |
236 | noisecf->handshake_timeout = NGX_CONF_UNSET_MSEC;
237 |
238 | return noisecf;
239 | }
240 |
241 | static char *
242 | ngx_nsoc_noiseserver_merge_conf(ngx_conf_t *cf, void *parent, void *child)
243 | {
244 | ngx_nsoc_noiseserver_conf_t *prev = parent;
245 | ngx_nsoc_noiseserver_conf_t *conf = child;
246 | ngx_nsoc_core_srv_conf_t *cscf;
247 | ngx_pool_cleanup_t *cln;
248 |
249 | ngx_conf_merge_msec_value(
250 | conf->handshake_timeout, prev->handshake_timeout, 60000);
251 |
252 | ngx_conf_merge_str_value(
253 | conf->server_private_key_file, prev->server_private_key_file, "");
254 | ngx_conf_merge_str_value(
255 | conf->client_public_key_file, prev->client_public_key_file, "");
256 |
257 | conf->noise = ngx_pcalloc(cf->pool, sizeof(ngx_noise_t));
258 | if (conf->noise == NULL) {
259 | return NGX_CONF_ERROR ;
260 | }
261 |
262 | conf->noise->log = cf->log;
263 | conf->noise->handshake_timeout = conf->handshake_timeout;
264 | memcpy( conf->noise->prologue.strPrologue,"NoiseSocketInit1",16);
265 | conf->noise->prologue.header_len = swapw(NGX_NSOC_1MSG_NEG_DATA_SIZE);
266 |
267 | cscf = ngx_nsoc_conf_get_module_srv_conf(cf, ngx_nsoc_core_module);
268 |
269 | if (ngx_nsoc_create(conf->noise, cscf->nsoc_preread_buffer_size, NULL) != NGX_OK) {
270 | ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
271 | "noise server module merge_conf error: unable to create noise ctx");
272 | return NGX_CONF_ERROR ;
273 | }
274 |
275 | cln = ngx_pool_cleanup_add(cf->pool, 0);
276 | if (cln == NULL) {
277 | return NGX_CONF_ERROR ;
278 | }
279 |
280 | cln->handler = ngx_nsoc_cleanup_ctx;
281 | cln->data = conf->noise;
282 |
283 | return NGX_CONF_OK;
284 | }
285 |
286 | static ngx_int_t ngx_nsoc_noiseserver_init(ngx_conf_t *cf)
287 | {
288 | ngx_nsoc_handler_pt *h;
289 | ngx_nsoc_core_main_conf_t *cmcf;
290 |
291 | cmcf = ngx_nsoc_conf_get_module_main_conf(cf, ngx_nsoc_core_module);
292 | cmcf->pool = cf->pool;
293 |
294 | h = ngx_array_push(&cmcf->phases[NGX_NSOC_PROTECT_PHASE].handlers);
295 | if (h == NULL) {
296 | return NGX_ERROR;
297 | }
298 |
299 | *h = ngx_nsoc_noiseserver_handler;
300 |
301 | return NGX_OK;
302 | }
303 |
--------------------------------------------------------------------------------
/ngx_nsoc_noiseserver_module.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Maxim Grigoryev
3 | * Copyright (C) Virgil Security, Inc.
4 | */
5 |
6 |
7 | #ifndef _NGX_NSOC_NOISESERVER_H_INCLUDED_
8 | #define _NGX_NSOC_NOISESERVER_H_INCLUDED_
9 |
10 | #include
11 | #include
12 | #include "ngx_nsoc.h"
13 |
14 | typedef struct {
15 | ngx_msec_t handshake_timeout;
16 |
17 | ngx_noise_t *noise;
18 |
19 | ngx_str_t server_private_key_file;
20 | ngx_str_t client_public_key_file;
21 |
22 | } ngx_nsoc_noiseserver_conf_t;
23 |
24 | extern ngx_module_t ngx_nsoc_noiseserver_module;
25 |
26 | #endif /* _NGX_NSOC_NOISESERVER_H_INCLUDED_ */
27 |
--------------------------------------------------------------------------------
/ngx_nsoc_script.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Igor Sysoev
3 | * Copyright (C) Nginx, Inc.
4 | */
5 |
6 | #include
7 | #include
8 |
9 | #include "ngx_nsoc.h"
10 |
11 | static ngx_int_t ngx_nsoc_script_init_arrays(
12 | ngx_nsoc_script_compile_t *sc);
13 | static ngx_int_t ngx_nsoc_script_done(
14 | ngx_nsoc_script_compile_t *sc);
15 | static ngx_int_t ngx_nsoc_script_add_copy_code(
16 | ngx_nsoc_script_compile_t *sc, ngx_str_t *value, ngx_uint_t last);
17 | static ngx_int_t ngx_nsoc_script_add_var_code(
18 | ngx_nsoc_script_compile_t *sc, ngx_str_t *name);
19 | #if (NGX_PCRE)
20 | static ngx_int_t ngx_nsoc_script_add_capture_code(
21 | ngx_nsoc_script_compile_t *sc, ngx_uint_t n);
22 | #endif
23 | static ngx_int_t ngx_nsoc_script_add_full_name_code(
24 | ngx_nsoc_script_compile_t *sc);
25 | static size_t ngx_nsoc_script_full_name_len_code(
26 | ngx_nsoc_script_engine_t *e);
27 | static void ngx_nsoc_script_full_name_code(
28 | ngx_nsoc_script_engine_t *e);
29 |
30 | #define ngx_nsoc_script_exit (u_char *) &ngx_nsoc_script_exit_code
31 |
32 | static uintptr_t ngx_nsoc_script_exit_code = (uintptr_t) NULL;
33 |
34 | void ngx_nsoc_script_flush_complex_value(ngx_nsoc_session_t *s,
35 | ngx_nsoc_complex_value_t *val)
36 | {
37 | ngx_uint_t *index;
38 |
39 | index = val->flushes;
40 |
41 | if (index) {
42 | while (*index != (ngx_uint_t) -1) {
43 |
44 | if (s->variables[*index].no_cacheable) {
45 | s->variables[*index].valid = 0;
46 | s->variables[*index].not_found = 0;
47 | }
48 |
49 | index++;
50 | }
51 | }
52 | }
53 |
54 | ngx_int_t ngx_nsoc_complex_value(ngx_nsoc_session_t *s,
55 | ngx_nsoc_complex_value_t *val, ngx_str_t *value)
56 | {
57 | size_t len;
58 | ngx_nsoc_script_code_pt code;
59 | ngx_nsoc_script_engine_t e;
60 | ngx_nsoc_script_len_code_pt lcode;
61 |
62 | if (val->lengths == NULL) {
63 | *value = val->value;
64 | return NGX_OK;
65 | }
66 |
67 | ngx_nsoc_script_flush_complex_value(s, val);
68 |
69 | ngx_memzero(&e, sizeof(ngx_nsoc_script_engine_t));
70 |
71 | e.ip = val->lengths;
72 | e.session = s;
73 | e.flushed = 1;
74 |
75 | len = 0;
76 |
77 | while (*(uintptr_t *) e.ip) {
78 | lcode = *(ngx_nsoc_script_len_code_pt *) e.ip;
79 | len += lcode(&e);
80 | }
81 |
82 | value->len = len;
83 | value->data = ngx_pnalloc(s->connection->pool, len);
84 | if (value->data == NULL) {
85 | return NGX_ERROR;
86 | }
87 |
88 | e.ip = val->values;
89 | e.pos = value->data;
90 | e.buf = *value;
91 |
92 | while (*(uintptr_t *) e.ip) {
93 | code = *(ngx_nsoc_script_code_pt *) e.ip;
94 | code((ngx_nsoc_script_engine_t *) &e);
95 | }
96 |
97 | *value = e.buf;
98 |
99 | return NGX_OK;
100 | }
101 |
102 | ngx_int_t ngx_nsoc_compile_complex_value(
103 | ngx_nsoc_compile_complex_value_t *ccv)
104 | {
105 | ngx_str_t *v;
106 | ngx_uint_t i, n, nv, nc;
107 | ngx_array_t flushes, lengths, values, *pf, *pl, *pv;
108 | ngx_nsoc_script_compile_t sc;
109 |
110 | v = ccv->value;
111 |
112 | nv = 0;
113 | nc = 0;
114 |
115 | for (i = 0; i < v->len; i++) {
116 | if (v->data[i] == '$') {
117 | if (v->data[i + 1] >= '1' && v->data[i + 1] <= '9') {
118 | nc++;
119 |
120 | } else {
121 | nv++;
122 | }
123 | }
124 | }
125 |
126 | if ((v->len == 0 || v->data[0] != '$')
127 | && (ccv->conf_prefix || ccv->root_prefix)) {
128 | if (ngx_conf_full_name(ccv->cf->cycle, v, ccv->conf_prefix) != NGX_OK) {
129 | return NGX_ERROR;
130 | }
131 |
132 | ccv->conf_prefix = 0;
133 | ccv->root_prefix = 0;
134 | }
135 |
136 | ccv->complex_value->value = *v;
137 | ccv->complex_value->flushes = NULL;
138 | ccv->complex_value->lengths = NULL;
139 | ccv->complex_value->values = NULL;
140 |
141 | if (nv == 0 && nc == 0) {
142 | return NGX_OK;
143 | }
144 |
145 | n = nv + 1;
146 |
147 | if (ngx_array_init(&flushes, ccv->cf->pool, n, sizeof(ngx_uint_t)) != NGX_OK) {
148 | return NGX_ERROR;
149 | }
150 |
151 | n = nv
152 | * (2 * sizeof(ngx_nsoc_script_copy_code_t)
153 | + sizeof(ngx_nsoc_script_var_code_t))
154 | + sizeof(uintptr_t);
155 |
156 | if (ngx_array_init(&lengths, ccv->cf->pool, n, 1) != NGX_OK) {
157 | return NGX_ERROR;
158 | }
159 |
160 | n = (nv
161 | * (2 * sizeof(ngx_nsoc_script_copy_code_t)
162 | + sizeof(ngx_nsoc_script_var_code_t))
163 | + sizeof(uintptr_t) + v->len + sizeof(uintptr_t) - 1)
164 | & ~(sizeof(uintptr_t) - 1);
165 |
166 | if (ngx_array_init(&values, ccv->cf->pool, n, 1) != NGX_OK) {
167 | return NGX_ERROR;
168 | }
169 |
170 | pf = &flushes;
171 | pl = &lengths;
172 | pv = &values;
173 |
174 | ngx_memzero(&sc, sizeof(ngx_nsoc_script_compile_t));
175 |
176 | sc.cf = ccv->cf;
177 | sc.source = v;
178 | sc.flushes = &pf;
179 | sc.lengths = &pl;
180 | sc.values = &pv;
181 | sc.complete_lengths = 1;
182 | sc.complete_values = 1;
183 | sc.zero = ccv->zero;
184 | sc.conf_prefix = ccv->conf_prefix;
185 | sc.root_prefix = ccv->root_prefix;
186 |
187 | if (ngx_nsoc_script_compile(&sc) != NGX_OK) {
188 | return NGX_ERROR;
189 | }
190 |
191 | if (flushes.nelts) {
192 | ccv->complex_value->flushes = flushes.elts;
193 | ccv->complex_value->flushes[flushes.nelts] = (ngx_uint_t) -1;
194 | }
195 |
196 | ccv->complex_value->lengths = lengths.elts;
197 | ccv->complex_value->values = values.elts;
198 |
199 | return NGX_OK;
200 | }
201 |
202 | char *
203 | ngx_nsoc_set_complex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd,
204 | void *conf)
205 | {
206 | char *p = conf;
207 |
208 | ngx_str_t *value;
209 | ngx_nsoc_complex_value_t **cv;
210 | ngx_nsoc_compile_complex_value_t ccv;
211 |
212 | cv = (ngx_nsoc_complex_value_t **) (p + cmd->offset);
213 |
214 | if (*cv != NULL) {
215 | return "is duplicate";
216 | }
217 |
218 | *cv = ngx_palloc(cf->pool, sizeof(ngx_nsoc_complex_value_t));
219 | if (*cv == NULL) {
220 | return NGX_CONF_ERROR ;
221 | }
222 |
223 | value = cf->args->elts;
224 |
225 | ngx_memzero(&ccv, sizeof(ngx_nsoc_compile_complex_value_t));
226 |
227 | ccv.cf = cf;
228 | ccv.value = &value[1];
229 | ccv.complex_value = *cv;
230 |
231 | if (ngx_nsoc_compile_complex_value(&ccv) != NGX_OK) {
232 | return NGX_CONF_ERROR ;
233 | }
234 |
235 | return NGX_CONF_OK;
236 | }
237 |
238 | ngx_uint_t ngx_nsoc_script_variables_count(ngx_str_t *value)
239 | {
240 | ngx_uint_t i, n;
241 |
242 | for (n = 0, i = 0; i < value->len; i++) {
243 | if (value->data[i] == '$') {
244 | n++;
245 | }
246 | }
247 |
248 | return n;
249 | }
250 |
251 | ngx_int_t ngx_nsoc_script_compile(ngx_nsoc_script_compile_t *sc)
252 | {
253 | u_char ch;
254 | ngx_str_t name;
255 | ngx_uint_t i, bracket;
256 |
257 | if (ngx_nsoc_script_init_arrays(sc) != NGX_OK) {
258 | return NGX_ERROR;
259 | }
260 |
261 | for (i = 0; i < sc->source->len; /* void */) {
262 |
263 | name.len = 0;
264 |
265 | if (sc->source->data[i] == '$') {
266 |
267 | if (++i == sc->source->len) {
268 | goto invalid_variable;
269 | }
270 |
271 | if (sc->source->data[i] >= '1' && sc->source->data[i] <= '9') {
272 | #if (NGX_PCRE)
273 | ngx_uint_t n;
274 |
275 | n = sc->source->data[i] - '0';
276 |
277 | if (ngx_nsoc_script_add_capture_code(sc, n) != NGX_OK) {
278 | return NGX_ERROR;
279 | }
280 |
281 | i++;
282 |
283 | continue;
284 | #else
285 | ngx_conf_log_error(NGX_LOG_EMERG, sc->cf, 0,
286 | "using variable \"$%c\" requires "
287 | "PCRE library", sc->source->data[i]);
288 | return NGX_ERROR;
289 | #endif
290 | }
291 |
292 | if (sc->source->data[i] == '{') {
293 | bracket = 1;
294 |
295 | if (++i == sc->source->len) {
296 | goto invalid_variable;
297 | }
298 |
299 | name.data = &sc->source->data[i];
300 |
301 | } else {
302 | bracket = 0;
303 | name.data = &sc->source->data[i];
304 | }
305 |
306 | for ( /* void */; i < sc->source->len; i++, name.len++) {
307 | ch = sc->source->data[i];
308 |
309 | if (ch == '}' && bracket) {
310 | i++;
311 | bracket = 0;
312 | break;
313 | }
314 |
315 | if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')
316 | || (ch >= '0' && ch <= '9') || ch == '_') {
317 | continue;
318 | }
319 |
320 | break;
321 | }
322 |
323 | if (bracket) {
324 | ngx_conf_log_error(
325 | NGX_LOG_EMERG, sc->cf, 0,
326 | "the closing bracket in \"%V\" "
327 | "variable is missing", &name);
328 | return NGX_ERROR;
329 | }
330 |
331 | if (name.len == 0) {
332 | goto invalid_variable;
333 | }
334 |
335 | sc->variables++;
336 |
337 | if (ngx_nsoc_script_add_var_code(sc, &name) != NGX_OK) {
338 | return NGX_ERROR;
339 | }
340 |
341 | continue;
342 | }
343 |
344 | name.data = &sc->source->data[i];
345 |
346 | while (i < sc->source->len) {
347 |
348 | if (sc->source->data[i] == '$') {
349 | break;
350 | }
351 |
352 | i++;
353 | name.len++;
354 | }
355 |
356 | sc->size += name.len;
357 |
358 | if (ngx_nsoc_script_add_copy_code(
359 | sc, &name, (i == sc->source->len)) != NGX_OK) {
360 | return NGX_ERROR;
361 | }
362 | }
363 |
364 | return ngx_nsoc_script_done(sc);
365 |
366 | invalid_variable:
367 |
368 | ngx_conf_log_error(NGX_LOG_EMERG, sc->cf, 0, "invalid variable name");
369 |
370 | return NGX_ERROR;
371 | }
372 |
373 | u_char *
374 | ngx_nsoc_script_run(ngx_nsoc_session_t *s, ngx_str_t *value,
375 | void *code_lengths, size_t len, void *code_values)
376 | {
377 | ngx_uint_t i;
378 | ngx_nsoc_script_code_pt code;
379 | ngx_nsoc_script_engine_t e;
380 | ngx_nsoc_core_main_conf_t *cmcf;
381 | ngx_nsoc_script_len_code_pt lcode;
382 |
383 | cmcf = ngx_nsoc_get_module_main_conf(s, ngx_nsoc_core_module);
384 |
385 | for (i = 0; i < cmcf->variables.nelts; i++) {
386 | if (s->variables[i].no_cacheable) {
387 | s->variables[i].valid = 0;
388 | s->variables[i].not_found = 0;
389 | }
390 | }
391 |
392 | ngx_memzero(&e, sizeof(ngx_nsoc_script_engine_t));
393 |
394 | e.ip = code_lengths;
395 | e.session = s;
396 | e.flushed = 1;
397 |
398 | while (*(uintptr_t *) e.ip) {
399 | lcode = *(ngx_nsoc_script_len_code_pt *) e.ip;
400 | len += lcode(&e);
401 | }
402 |
403 | value->len = len;
404 | value->data = ngx_pnalloc(s->connection->pool, len);
405 | if (value->data == NULL) {
406 | return NULL;
407 | }
408 |
409 | e.ip = code_values;
410 | e.pos = value->data;
411 |
412 | while (*(uintptr_t *) e.ip) {
413 | code = *(ngx_nsoc_script_code_pt *) e.ip;
414 | code((ngx_nsoc_script_engine_t *) &e);
415 | }
416 |
417 | return e.pos;
418 | }
419 |
420 | void ngx_nsoc_script_flush_no_cacheable_variables(
421 | ngx_nsoc_session_t *s, ngx_array_t *indices)
422 | {
423 | ngx_uint_t n, *index;
424 |
425 | if (indices) {
426 | index = indices->elts;
427 | for (n = 0; n < indices->nelts; n++) {
428 | if (s->variables[index[n]].no_cacheable) {
429 | s->variables[index[n]].valid = 0;
430 | s->variables[index[n]].not_found = 0;
431 | }
432 | }
433 | }
434 | }
435 |
436 | static ngx_int_t ngx_nsoc_script_init_arrays(
437 | ngx_nsoc_script_compile_t *sc)
438 | {
439 | ngx_uint_t n;
440 |
441 | if (sc->flushes && *sc->flushes == NULL) {
442 | n = sc->variables ? sc->variables : 1;
443 | *sc->flushes = ngx_array_create(sc->cf->pool, n, sizeof(ngx_uint_t));
444 | if (*sc->flushes == NULL) {
445 | return NGX_ERROR;
446 | }
447 | }
448 |
449 | if (*sc->lengths == NULL) {
450 | n = sc->variables
451 | * (2 * sizeof(ngx_nsoc_script_copy_code_t)
452 | + sizeof(ngx_nsoc_script_var_code_t))
453 | + sizeof(uintptr_t);
454 |
455 | *sc->lengths = ngx_array_create(sc->cf->pool, n, 1);
456 | if (*sc->lengths == NULL) {
457 | return NGX_ERROR;
458 | }
459 | }
460 |
461 | if (*sc->values == NULL) {
462 | n = (sc->variables
463 | * (2 * sizeof(ngx_nsoc_script_copy_code_t)
464 | + sizeof(ngx_nsoc_script_var_code_t))
465 | + sizeof(uintptr_t) + sc->source->len + sizeof(uintptr_t) - 1)
466 | & ~(sizeof(uintptr_t) - 1);
467 |
468 | *sc->values = ngx_array_create(sc->cf->pool, n, 1);
469 | if (*sc->values == NULL) {
470 | return NGX_ERROR;
471 | }
472 | }
473 |
474 | sc->variables = 0;
475 |
476 | return NGX_OK;
477 | }
478 |
479 | static ngx_int_t ngx_nsoc_script_done(
480 | ngx_nsoc_script_compile_t *sc)
481 | {
482 | ngx_str_t zero;
483 | uintptr_t *code;
484 |
485 | if (sc->zero) {
486 |
487 | zero.len = 1;
488 | zero.data = (u_char *) "\0";
489 |
490 | if (ngx_nsoc_script_add_copy_code(sc, &zero, 0) != NGX_OK) {
491 | return NGX_ERROR;
492 | }
493 | }
494 |
495 | if (sc->conf_prefix || sc->root_prefix) {
496 | if (ngx_nsoc_script_add_full_name_code(sc) != NGX_OK) {
497 | return NGX_ERROR;
498 | }
499 | }
500 |
501 | if (sc->complete_lengths) {
502 | code = ngx_nsoc_script_add_code(*sc->lengths, sizeof(uintptr_t),
503 | NULL);
504 | if (code == NULL) {
505 | return NGX_ERROR;
506 | }
507 |
508 | *code = (uintptr_t) NULL;
509 | }
510 |
511 | if (sc->complete_values) {
512 | code = ngx_nsoc_script_add_code(
513 | *sc->values, sizeof(uintptr_t), &sc->main);
514 | if (code == NULL) {
515 | return NGX_ERROR;
516 | }
517 |
518 | *code = (uintptr_t) NULL;
519 | }
520 |
521 | return NGX_OK;
522 | }
523 |
524 | void *
525 | ngx_nsoc_script_add_code(ngx_array_t *codes, size_t size, void *code)
526 | {
527 | u_char *elts, **p;
528 | void *new;
529 |
530 | elts = codes->elts;
531 |
532 | new = ngx_array_push_n(codes, size);
533 | if (new == NULL) {
534 | return NULL;
535 | }
536 |
537 | if (code) {
538 | if (elts != codes->elts) {
539 | p = code;
540 | *p += (u_char *) codes->elts - elts;
541 | }
542 | }
543 |
544 | return new;
545 | }
546 |
547 | static ngx_int_t ngx_nsoc_script_add_copy_code(
548 | ngx_nsoc_script_compile_t *sc, ngx_str_t *value, ngx_uint_t last)
549 | {
550 | u_char *p;
551 | size_t size, len, zero;
552 | ngx_nsoc_script_copy_code_t *code;
553 |
554 | zero = (sc->zero && last);
555 | len = value->len + zero;
556 |
557 | code = ngx_nsoc_script_add_code(
558 | *sc->lengths, sizeof(ngx_nsoc_script_copy_code_t),
559 | NULL);
560 | if (code == NULL) {
561 | return NGX_ERROR;
562 | }
563 |
564 | code->code =
565 | (ngx_nsoc_script_code_pt) ngx_nsoc_script_copy_len_code;
566 | code->len = len;
567 |
568 | size = (sizeof(ngx_nsoc_script_copy_code_t) + len + sizeof(uintptr_t)
569 | - 1) & ~(sizeof(uintptr_t) - 1);
570 |
571 | code = ngx_nsoc_script_add_code(*sc->values, size, &sc->main);
572 | if (code == NULL) {
573 | return NGX_ERROR;
574 | }
575 |
576 | code->code = ngx_nsoc_script_copy_code;
577 | code->len = len;
578 |
579 | p = ngx_cpymem(
580 | (u_char * ) code + sizeof(ngx_nsoc_script_copy_code_t),
581 | value->data, value->len);
582 |
583 | if (zero) {
584 | *p = '\0';
585 | sc->zero = 0;
586 | }
587 |
588 | return NGX_OK;
589 | }
590 |
591 | size_t ngx_nsoc_script_copy_len_code(ngx_nsoc_script_engine_t *e)
592 | {
593 | ngx_nsoc_script_copy_code_t *code;
594 |
595 | code = (ngx_nsoc_script_copy_code_t *) e->ip;
596 |
597 | e->ip += sizeof(ngx_nsoc_script_copy_code_t);
598 |
599 | return code->len;
600 | }
601 |
602 | void ngx_nsoc_script_copy_code(ngx_nsoc_script_engine_t *e)
603 | {
604 | u_char *p;
605 | ngx_nsoc_script_copy_code_t *code;
606 |
607 | code = (ngx_nsoc_script_copy_code_t *) e->ip;
608 |
609 | p = e->pos;
610 |
611 | if (!e->skip) {
612 | e->pos = ngx_copy(p, e->ip + sizeof(ngx_nsoc_script_copy_code_t),
613 | code->len);
614 | }
615 |
616 | e->ip += sizeof(ngx_nsoc_script_copy_code_t)
617 | + ((code->len + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1));
618 |
619 | ngx_log_debug2(
620 | NGX_LOG_DEBUG_STREAM, e->session->connection->log, 0,
621 | "stream script copy: \"%*s\"", e->pos - p, p);
622 | }
623 |
624 | static ngx_int_t ngx_nsoc_script_add_var_code(
625 | ngx_nsoc_script_compile_t *sc, ngx_str_t *name)
626 | {
627 | ngx_int_t index, *p;
628 | ngx_nsoc_script_var_code_t *code;
629 |
630 | index = ngx_nsoc_get_variable_index(sc->cf, name);
631 |
632 | if (index == NGX_ERROR) {
633 | return NGX_ERROR;
634 | }
635 |
636 | if (sc->flushes) {
637 | p = ngx_array_push(*sc->flushes);
638 | if (p == NULL) {
639 | return NGX_ERROR;
640 | }
641 |
642 | *p = index;
643 | }
644 |
645 | code = ngx_nsoc_script_add_code(
646 | *sc->lengths, sizeof(ngx_nsoc_script_var_code_t),
647 | NULL);
648 | if (code == NULL) {
649 | return NGX_ERROR;
650 | }
651 |
652 | code->code =
653 | (ngx_nsoc_script_code_pt) ngx_nsoc_script_copy_var_len_code;
654 | code->index = (uintptr_t) index;
655 |
656 | code = ngx_nsoc_script_add_code(
657 | *sc->values, sizeof(ngx_nsoc_script_var_code_t), &sc->main);
658 | if (code == NULL) {
659 | return NGX_ERROR;
660 | }
661 |
662 | code->code = ngx_nsoc_script_copy_var_code;
663 | code->index = (uintptr_t) index;
664 |
665 | return NGX_OK;
666 | }
667 |
668 | size_t ngx_nsoc_script_copy_var_len_code(
669 | ngx_nsoc_script_engine_t *e)
670 | {
671 | ngx_nsoc_variable_value_t *value;
672 | ngx_nsoc_script_var_code_t *code;
673 |
674 | code = (ngx_nsoc_script_var_code_t *) e->ip;
675 |
676 | e->ip += sizeof(ngx_nsoc_script_var_code_t);
677 |
678 | if (e->flushed) {
679 | value = ngx_nsoc_get_indexed_variable(e->session, code->index);
680 |
681 | } else {
682 | value = ngx_nsoc_get_flushed_variable(e->session, code->index);
683 | }
684 |
685 | if (value && !value->not_found) {
686 | return value->len;
687 | }
688 |
689 | return 0;
690 | }
691 |
692 | void ngx_nsoc_script_copy_var_code(ngx_nsoc_script_engine_t *e)
693 | {
694 | u_char *p;
695 | ngx_nsoc_variable_value_t *value;
696 | ngx_nsoc_script_var_code_t *code;
697 |
698 | code = (ngx_nsoc_script_var_code_t *) e->ip;
699 |
700 | e->ip += sizeof(ngx_nsoc_script_var_code_t);
701 |
702 | if (!e->skip) {
703 |
704 | if (e->flushed) {
705 | value = ngx_nsoc_get_indexed_variable(
706 | e->session, code->index);
707 |
708 | } else {
709 | value = ngx_nsoc_get_flushed_variable(
710 | e->session, code->index);
711 | }
712 |
713 | if (value && !value->not_found) {
714 | p = e->pos;
715 | e->pos = ngx_copy(p, value->data, value->len);
716 |
717 | ngx_log_debug2(
718 | NGX_LOG_DEBUG_STREAM, e->session->connection->log, 0,
719 | "stream script var: \"%*s\"", e->pos - p, p);
720 | }
721 | }
722 | }
723 |
724 | #if (NGX_PCRE)
725 |
726 | static ngx_int_t ngx_nsoc_script_add_capture_code(
727 | ngx_nsoc_script_compile_t *sc, ngx_uint_t n)
728 | {
729 | ngx_nsoc_script_copy_capture_code_t *code;
730 |
731 | code = ngx_nsoc_script_add_code(
732 | *sc->lengths, sizeof(ngx_nsoc_script_copy_capture_code_t),
733 | NULL);
734 | if (code == NULL) {
735 | return NGX_ERROR;
736 | }
737 |
738 | code->code =
739 | (ngx_nsoc_script_code_pt) ngx_nsoc_script_copy_capture_len_code;
740 | code->n = 2 * n;
741 |
742 | code = ngx_nsoc_script_add_code(
743 | *sc->values, sizeof(ngx_nsoc_script_copy_capture_code_t),
744 | &sc->main);
745 | if (code == NULL) {
746 | return NGX_ERROR;
747 | }
748 |
749 | code->code = ngx_nsoc_script_copy_capture_code;
750 | code->n = 2 * n;
751 |
752 | if (sc->ncaptures < n) {
753 | sc->ncaptures = n;
754 | }
755 |
756 | return NGX_OK;
757 | }
758 |
759 | size_t ngx_nsoc_script_copy_capture_len_code(
760 | ngx_nsoc_script_engine_t *e)
761 | {
762 | int *cap;
763 | ngx_uint_t n;
764 | ngx_nsoc_session_t *s;
765 | ngx_nsoc_script_copy_capture_code_t *code;
766 |
767 | s = e->session;
768 |
769 | code = (ngx_nsoc_script_copy_capture_code_t *) e->ip;
770 |
771 | e->ip += sizeof(ngx_nsoc_script_copy_capture_code_t);
772 |
773 | n = code->n;
774 |
775 | if (n < s->ncaptures) {
776 | cap = s->captures;
777 | return cap[n + 1] - cap[n];
778 | }
779 |
780 | return 0;
781 | }
782 |
783 | void ngx_nsoc_script_copy_capture_code(
784 | ngx_nsoc_script_engine_t *e)
785 | {
786 | int *cap;
787 | u_char *p, *pos;
788 | ngx_uint_t n;
789 | ngx_nsoc_session_t *s;
790 | ngx_nsoc_script_copy_capture_code_t *code;
791 |
792 | s = e->session;
793 |
794 | code = (ngx_nsoc_script_copy_capture_code_t *) e->ip;
795 |
796 | e->ip += sizeof(ngx_nsoc_script_copy_capture_code_t);
797 |
798 | n = code->n;
799 |
800 | pos = e->pos;
801 |
802 | if (n < s->ncaptures) {
803 | cap = s->captures;
804 | p = s->captures_data;
805 | e->pos = ngx_copy(pos, &p[cap[n]], cap[n + 1] - cap[n]);
806 | }
807 |
808 | ngx_log_debug2(
809 | NGX_LOG_DEBUG_STREAM, e->session->connection->log, 0,
810 | "stream script capture: \"%*s\"", e->pos - pos, pos);
811 | }
812 |
813 | #endif
814 |
815 | static ngx_int_t ngx_nsoc_script_add_full_name_code(
816 | ngx_nsoc_script_compile_t *sc)
817 | {
818 | ngx_nsoc_script_full_name_code_t *code;
819 |
820 | code = ngx_nsoc_script_add_code(
821 | *sc->lengths, sizeof(ngx_nsoc_script_full_name_code_t),
822 | NULL);
823 | if (code == NULL) {
824 | return NGX_ERROR;
825 | }
826 |
827 | code->code =
828 | (ngx_nsoc_script_code_pt) ngx_nsoc_script_full_name_len_code;
829 | code->conf_prefix = sc->conf_prefix;
830 |
831 | code = ngx_nsoc_script_add_code(
832 | *sc->values, sizeof(ngx_nsoc_script_full_name_code_t),
833 | &sc->main);
834 | if (code == NULL) {
835 | return NGX_ERROR;
836 | }
837 |
838 | code->code = ngx_nsoc_script_full_name_code;
839 | code->conf_prefix = sc->conf_prefix;
840 |
841 | return NGX_OK;
842 | }
843 |
844 | static size_t ngx_nsoc_script_full_name_len_code(
845 | ngx_nsoc_script_engine_t *e)
846 | {
847 | ngx_nsoc_script_full_name_code_t *code;
848 |
849 | code = (ngx_nsoc_script_full_name_code_t *) e->ip;
850 |
851 | e->ip += sizeof(ngx_nsoc_script_full_name_code_t);
852 |
853 | return code->conf_prefix ?
854 | ngx_cycle->conf_prefix.len : ngx_cycle->prefix.len;
855 | }
856 |
857 | static void ngx_nsoc_script_full_name_code(
858 | ngx_nsoc_script_engine_t *e)
859 | {
860 | ngx_nsoc_script_full_name_code_t *code;
861 |
862 | ngx_str_t value, *prefix;
863 |
864 | code = (ngx_nsoc_script_full_name_code_t *) e->ip;
865 |
866 | value.data = e->buf.data;
867 | value.len = e->pos - e->buf.data;
868 |
869 | prefix =
870 | code->conf_prefix ?
871 | (ngx_str_t *) &ngx_cycle->conf_prefix :
872 | (ngx_str_t *) &ngx_cycle->prefix;
873 |
874 | if (ngx_get_full_name(
875 | e->session->connection->pool, prefix, &value) != NGX_OK) {
876 | e->ip = ngx_nsoc_script_exit;
877 | return;
878 | }
879 |
880 | e->buf = value;
881 |
882 | ngx_log_debug1(
883 | NGX_LOG_DEBUG_STREAM, e->session->connection->log, 0,
884 | "stream script fullname: \"%V\"", &value);
885 |
886 | e->ip += sizeof(ngx_nsoc_script_full_name_code_t);
887 | }
888 |
--------------------------------------------------------------------------------
/ngx_nsoc_script.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Igor Sysoev
3 | * Copyright (C) Nginx, Inc.
4 | */
5 |
6 | #ifndef _NGX_NSOC_SCRIPT_H_INCLUDED_
7 | #define _NGX_NSOC_SCRIPT_H_INCLUDED_
8 |
9 | #include
10 | #include
11 | #include "ngx_nsoc.h"
12 |
13 | typedef struct {
14 | u_char *ip;
15 | u_char *pos;
16 | ngx_nsoc_variable_value_t *sp;
17 |
18 | ngx_str_t buf;
19 | ngx_str_t line;
20 |
21 | unsigned flushed :1;
22 | unsigned skip :1;
23 |
24 | ngx_nsoc_session_t *session;
25 | } ngx_nsoc_script_engine_t;
26 |
27 | typedef struct {
28 | ngx_conf_t *cf;
29 | ngx_str_t *source;
30 |
31 | ngx_array_t **flushes;
32 | ngx_array_t **lengths;
33 | ngx_array_t **values;
34 |
35 | ngx_uint_t variables;
36 | ngx_uint_t ncaptures;
37 | ngx_uint_t size;
38 |
39 | void *main;
40 |
41 | unsigned complete_lengths :1;
42 | unsigned complete_values :1;
43 | unsigned zero :1;
44 | unsigned conf_prefix :1;
45 | unsigned root_prefix :1;
46 | } ngx_nsoc_script_compile_t;
47 |
48 | typedef struct {
49 | ngx_str_t value;
50 | ngx_uint_t *flushes;
51 | void *lengths;
52 | void *values;
53 | } ngx_nsoc_complex_value_t;
54 |
55 | typedef struct {
56 | ngx_conf_t *cf;
57 | ngx_str_t *value;
58 | ngx_nsoc_complex_value_t *complex_value;
59 |
60 | unsigned zero :1;
61 | unsigned conf_prefix :1;
62 | unsigned root_prefix :1;
63 | } ngx_nsoc_compile_complex_value_t;
64 |
65 | typedef void (*ngx_nsoc_script_code_pt)(
66 | ngx_nsoc_script_engine_t *e);
67 | typedef size_t (*ngx_nsoc_script_len_code_pt)(
68 | ngx_nsoc_script_engine_t *e);
69 |
70 | typedef struct {
71 | ngx_nsoc_script_code_pt code;
72 | uintptr_t len;
73 | } ngx_nsoc_script_copy_code_t;
74 |
75 | typedef struct {
76 | ngx_nsoc_script_code_pt code;
77 | uintptr_t index;
78 | } ngx_nsoc_script_var_code_t;
79 |
80 | typedef struct {
81 | ngx_nsoc_script_code_pt code;
82 | uintptr_t n;
83 | } ngx_nsoc_script_copy_capture_code_t;
84 |
85 | typedef struct {
86 | ngx_nsoc_script_code_pt code;
87 | uintptr_t conf_prefix;
88 | } ngx_nsoc_script_full_name_code_t;
89 |
90 | void ngx_nsoc_script_flush_complex_value(ngx_nsoc_session_t *s,
91 | ngx_nsoc_complex_value_t *val);
92 | ngx_int_t ngx_nsoc_complex_value(ngx_nsoc_session_t *s,
93 | ngx_nsoc_complex_value_t *val, ngx_str_t *value);
94 | ngx_int_t ngx_nsoc_compile_complex_value(
95 | ngx_nsoc_compile_complex_value_t *ccv);
96 | char *ngx_nsoc_set_complex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd,
97 | void *conf);
98 |
99 | ngx_uint_t ngx_nsoc_script_variables_count(ngx_str_t *value);
100 | ngx_int_t ngx_nsoc_script_compile(ngx_nsoc_script_compile_t *sc);
101 | u_char *ngx_nsoc_script_run(ngx_nsoc_session_t *s,
102 | ngx_str_t *value, void *code_lengths, size_t reserved,
103 | void *code_values);
104 | void ngx_nsoc_script_flush_no_cacheable_variables(
105 | ngx_nsoc_session_t *s, ngx_array_t *indices);
106 |
107 | void *ngx_nsoc_script_add_code(ngx_array_t *codes, size_t size,
108 | void *code);
109 |
110 | size_t ngx_nsoc_script_copy_len_code(ngx_nsoc_script_engine_t *e);
111 | void ngx_nsoc_script_copy_code(ngx_nsoc_script_engine_t *e);
112 | size_t ngx_nsoc_script_copy_var_len_code(
113 | ngx_nsoc_script_engine_t *e);
114 | void ngx_nsoc_script_copy_var_code(ngx_nsoc_script_engine_t *e);
115 | size_t ngx_nsoc_script_copy_capture_len_code(
116 | ngx_nsoc_script_engine_t *e);
117 | void ngx_nsoc_script_copy_capture_code(
118 | ngx_nsoc_script_engine_t *e);
119 |
120 | #endif /* _NGX_NSOC_SCRIPT_H_INCLUDED_ */
121 |
--------------------------------------------------------------------------------
/ngx_nsoc_upstream.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Igor Sysoev
3 | * Copyright (C) Nginx, Inc.
4 | */
5 |
6 | #include
7 | #include
8 |
9 | #include "ngx_nsoc.h"
10 |
11 | static ngx_int_t ngx_nsoc_upstream_add_variables(ngx_conf_t *cf);
12 | static ngx_int_t ngx_nsoc_upstream_addr_variable(
13 | ngx_nsoc_session_t *s, ngx_nsoc_variable_value_t *v,
14 | uintptr_t data);
15 | static ngx_int_t ngx_nsoc_upstream_response_time_variable(
16 | ngx_nsoc_session_t *s, ngx_nsoc_variable_value_t *v,
17 | uintptr_t data);
18 | static ngx_int_t ngx_nsoc_upstream_bytes_variable(
19 | ngx_nsoc_session_t *s, ngx_nsoc_variable_value_t *v,
20 | uintptr_t data);
21 |
22 | static char *ngx_nsoc_upstream(ngx_conf_t *cf, ngx_command_t *cmd,
23 | void *dummy);
24 | static char *ngx_nsoc_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd,
25 | void *conf);
26 | static void *ngx_nsoc_upstream_create_main_conf(ngx_conf_t *cf);
27 | static char *ngx_nsoc_upstream_init_main_conf(ngx_conf_t *cf, void *conf);
28 |
29 | static ngx_command_t ngx_nsoc_upstream_commands[] =
30 | {
31 |
32 | { ngx_string("upstream"),
33 | NGX_NSOC_MAIN_CONF | NGX_CONF_BLOCK | NGX_CONF_TAKE1,
34 | ngx_nsoc_upstream,
35 | 0,
36 | 0,
37 | NULL },
38 |
39 | { ngx_string("server"),
40 | NGX_NSOC_UPS_CONF | NGX_CONF_1MORE,
41 | ngx_nsoc_upstream_server,
42 | NGX_NSOC_SRV_CONF_OFFSET,
43 | 0,
44 | NULL },
45 |
46 | ngx_null_command
47 | };
48 |
49 | static ngx_nsoc_module_t ngx_nsoc_upstream_module_ctx =
50 | { ngx_nsoc_upstream_add_variables, /* preconfiguration */
51 | NULL, /* postconfiguration */
52 |
53 | ngx_nsoc_upstream_create_main_conf, /* create main configuration */
54 | ngx_nsoc_upstream_init_main_conf, /* init main configuration */
55 |
56 | NULL, /* create server configuration */
57 | NULL /* merge server configuration */
58 | };
59 |
60 | ngx_module_t ngx_nsoc_upstream_module =
61 | {
62 | NGX_MODULE_V1,
63 | &ngx_nsoc_upstream_module_ctx, /* module context */
64 | ngx_nsoc_upstream_commands, /* module directives */
65 | NGX_NSOC_MODULE, /* module type */
66 | NULL, /* init master */
67 | NULL, /* init module */
68 | NULL, /* init process */
69 | NULL, /* init thread */
70 | NULL, /* exit thread */
71 | NULL, /* exit process */
72 | NULL, /* exit master */
73 | NGX_MODULE_V1_PADDING
74 | };
75 |
76 | static ngx_nsoc_variable_t ngx_nsoc_upstream_vars[] =
77 | {
78 |
79 | { ngx_string("upstream_addr"),
80 | NULL,
81 | ngx_nsoc_upstream_addr_variable,
82 | 0,
83 | NGX_NSOC_VAR_NOCACHEABLE,
84 | 0 },
85 |
86 | { ngx_string("upstream_bytes_sent"),
87 | NULL,
88 | ngx_nsoc_upstream_bytes_variable,
89 | 0,
90 | NGX_NSOC_VAR_NOCACHEABLE,
91 | 0 },
92 |
93 | { ngx_string("upstream_connect_time"),
94 | NULL,
95 | ngx_nsoc_upstream_response_time_variable,
96 | 2,
97 | NGX_NSOC_VAR_NOCACHEABLE,
98 | 0 },
99 |
100 | { ngx_string("upstream_first_byte_time"),
101 | NULL,
102 | ngx_nsoc_upstream_response_time_variable,
103 | 1,
104 | NGX_NSOC_VAR_NOCACHEABLE,
105 | 0 },
106 |
107 | { ngx_string("upstream_session_time"),
108 | NULL,
109 | ngx_nsoc_upstream_response_time_variable,
110 | 0,
111 | NGX_NSOC_VAR_NOCACHEABLE,
112 | 0 },
113 |
114 | { ngx_string("upstream_bytes_received"),
115 | NULL,
116 | ngx_nsoc_upstream_bytes_variable,
117 | 1,
118 | NGX_NSOC_VAR_NOCACHEABLE,
119 | 0 },
120 |
121 | { ngx_null_string,
122 | NULL,
123 | NULL,
124 | 0,
125 | 0,
126 | 0 }
127 | };
128 |
129 | static ngx_int_t ngx_nsoc_upstream_add_variables(ngx_conf_t *cf)
130 | {
131 | ngx_nsoc_variable_t *var, *v;
132 |
133 | for (v = ngx_nsoc_upstream_vars; v->name.len; v++) {
134 | var = ngx_nsoc_add_variable(cf, &v->name, v->flags);
135 | if (var == NULL) {
136 | return NGX_ERROR;
137 | }
138 |
139 | var->get_handler = v->get_handler;
140 | var->data = v->data;
141 | }
142 |
143 | return NGX_OK;
144 | }
145 |
146 | static ngx_int_t ngx_nsoc_upstream_addr_variable(
147 | ngx_nsoc_session_t *s, ngx_nsoc_variable_value_t *v,
148 | uintptr_t data)
149 | {
150 | u_char *p;
151 | size_t len;
152 | ngx_uint_t i;
153 | ngx_nsoc_upstream_state_t *state;
154 |
155 | v->valid = 1;
156 | v->no_cacheable = 0;
157 | v->not_found = 0;
158 |
159 | if (s->upstream_states == NULL || s->upstream_states->nelts == 0) {
160 | v->not_found = 1;
161 | return NGX_OK;
162 | }
163 |
164 | len = 0;
165 | state = s->upstream_states->elts;
166 |
167 | for (i = 0; i < s->upstream_states->nelts; i++) {
168 | if (state[i].peer) {
169 | len += state[i].peer->len;
170 | }
171 |
172 | len += 2;
173 | }
174 |
175 | p = ngx_pnalloc(s->connection->pool, len);
176 | if (p == NULL) {
177 | return NGX_ERROR;
178 | }
179 |
180 | v->data = p;
181 |
182 | i = 0;
183 |
184 | for (;;) {
185 | if (state[i].peer) {
186 | p = ngx_cpymem(p, state[i].peer->data, state[i].peer->len);
187 | }
188 |
189 | if (++i == s->upstream_states->nelts) {
190 | break;
191 | }
192 |
193 | *p++ = ',';
194 | *p++ = ' ';
195 | }
196 |
197 | v->len = p - v->data;
198 |
199 | return NGX_OK;
200 | }
201 |
202 | static ngx_int_t ngx_nsoc_upstream_bytes_variable(
203 | ngx_nsoc_session_t *s, ngx_nsoc_variable_value_t *v,
204 | uintptr_t data)
205 | {
206 | u_char *p;
207 | size_t len;
208 | ngx_uint_t i;
209 | ngx_nsoc_upstream_state_t *state;
210 |
211 | v->valid = 1;
212 | v->no_cacheable = 0;
213 | v->not_found = 0;
214 |
215 | if (s->upstream_states == NULL || s->upstream_states->nelts == 0) {
216 | v->not_found = 1;
217 | return NGX_OK;
218 | }
219 |
220 | len = s->upstream_states->nelts * (NGX_OFF_T_LEN + 2);
221 |
222 | p = ngx_pnalloc(s->connection->pool, len);
223 | if (p == NULL) {
224 | return NGX_ERROR;
225 | }
226 |
227 | v->data = p;
228 |
229 | i = 0;
230 | state = s->upstream_states->elts;
231 |
232 | for (;;) {
233 |
234 | if (data == 1) {
235 | p = ngx_sprintf(p, "%O", state[i].bytes_received);
236 |
237 | } else {
238 | p = ngx_sprintf(p, "%O", state[i].bytes_sent);
239 | }
240 |
241 | if (++i == s->upstream_states->nelts) {
242 | break;
243 | }
244 |
245 | *p++ = ',';
246 | *p++ = ' ';
247 | }
248 |
249 | v->len = p - v->data;
250 |
251 | return NGX_OK;
252 | }
253 |
254 | static ngx_int_t ngx_nsoc_upstream_response_time_variable(
255 | ngx_nsoc_session_t *s, ngx_nsoc_variable_value_t *v,
256 | uintptr_t data)
257 | {
258 | u_char *p;
259 | size_t len;
260 | ngx_uint_t i;
261 | ngx_msec_int_t ms;
262 | ngx_nsoc_upstream_state_t *state;
263 |
264 | v->valid = 1;
265 | v->no_cacheable = 0;
266 | v->not_found = 0;
267 |
268 | if (s->upstream_states == NULL || s->upstream_states->nelts == 0) {
269 | v->not_found = 1;
270 | return NGX_OK;
271 | }
272 |
273 | len = s->upstream_states->nelts * (NGX_TIME_T_LEN + 4 + 2);
274 |
275 | p = ngx_pnalloc(s->connection->pool, len);
276 | if (p == NULL) {
277 | return NGX_ERROR;
278 | }
279 |
280 | v->data = p;
281 |
282 | i = 0;
283 | state = s->upstream_states->elts;
284 |
285 | for (;;) {
286 |
287 | if (data == 1) {
288 | if (state[i].first_byte_time == (ngx_msec_t) -1) {
289 | *p++ = '-';
290 | goto next;
291 | }
292 |
293 | ms = state[i].first_byte_time;
294 |
295 | } else if (data == 2 && state[i].connect_time != (ngx_msec_t) -1) {
296 | ms = state[i].connect_time;
297 |
298 | } else {
299 | ms = state[i].response_time;
300 | }
301 |
302 | ms = ngx_max(ms, 0);
303 | p = ngx_sprintf(p, "%T.%03M", (time_t) ms / 1000, ms % 1000);
304 |
305 | next:
306 |
307 | if (++i == s->upstream_states->nelts) {
308 | break;
309 | }
310 |
311 | *p++ = ',';
312 | *p++ = ' ';
313 | }
314 |
315 | v->len = p - v->data;
316 |
317 | return NGX_OK;
318 | }
319 |
320 | static char *
321 | ngx_nsoc_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
322 | {
323 | char *rv;
324 | void *mconf;
325 | ngx_str_t *value;
326 | ngx_url_t u;
327 | ngx_uint_t m;
328 | ngx_conf_t pcf;
329 | ngx_nsoc_module_t *module;
330 | ngx_nsoc_conf_ctx_t *ctx, *stream_ctx;
331 | ngx_nsoc_upstream_srv_conf_t *uscf;
332 |
333 | ngx_memzero(&u, sizeof(ngx_url_t));
334 |
335 | value = cf->args->elts;
336 | u.host = value[1];
337 | u.no_resolve = 1;
338 | u.no_port = 1;
339 |
340 | uscf = ngx_nsoc_upstream_add(
341 | cf,
342 | &u,
343 | NGX_NSOC_UPSTREAM_CREATE | NGX_NSOC_UPSTREAM_WEIGHT
344 | | NGX_NSOC_UPSTREAM_MAX_CONNS
345 | | NGX_NSOC_UPSTREAM_MAX_FAILS
346 | | NGX_NSOC_UPSTREAM_FAIL_TIMEOUT | NGX_NSOC_UPSTREAM_DOWN
347 | | NGX_NSOC_UPSTREAM_BACKUP);
348 | if (uscf == NULL) {
349 | return NGX_CONF_ERROR ;
350 | }
351 |
352 | ctx = ngx_pcalloc(cf->pool, sizeof(ngx_nsoc_conf_ctx_t));
353 | if (ctx == NULL) {
354 | return NGX_CONF_ERROR ;
355 | }
356 |
357 | stream_ctx = cf->ctx;
358 | ctx->main_conf = stream_ctx->main_conf;
359 |
360 | /* the upstream{}'s srv_conf */
361 |
362 | ctx->srv_conf = ngx_pcalloc(
363 | cf->pool, sizeof(void *) * ngx_nsoc_max_module);
364 | if (ctx->srv_conf == NULL) {
365 | return NGX_CONF_ERROR ;
366 | }
367 |
368 | ctx->srv_conf[ngx_nsoc_upstream_module.ctx_index] = uscf;
369 |
370 | uscf->srv_conf = ctx->srv_conf;
371 |
372 | for (m = 0; cf->cycle->modules[m]; m++) {
373 | if (cf->cycle->modules[m]->type != NGX_NSOC_MODULE) {
374 | continue;
375 | }
376 |
377 | module = cf->cycle->modules[m]->ctx;
378 |
379 | if (module->create_srv_conf) {
380 | mconf = module->create_srv_conf(cf);
381 | if (mconf == NULL) {
382 | return NGX_CONF_ERROR ;
383 | }
384 |
385 | ctx->srv_conf[cf->cycle->modules[m]->ctx_index] = mconf;
386 | }
387 | }
388 |
389 | uscf->servers = ngx_array_create(
390 | cf->pool, 4, sizeof(ngx_nsoc_upstream_server_t));
391 | if (uscf->servers == NULL) {
392 | return NGX_CONF_ERROR ;
393 | }
394 |
395 | /* parse inside upstream{} */
396 |
397 | pcf = *cf;
398 | cf->ctx = ctx;
399 | cf->cmd_type = NGX_NSOC_UPS_CONF;
400 |
401 | rv = ngx_conf_parse(cf, NULL);
402 |
403 | *cf = pcf;
404 |
405 | if (rv != NGX_CONF_OK) {
406 | return rv;
407 | }
408 |
409 | if (uscf->servers->nelts == 0) {
410 | ngx_conf_log_error(
411 | NGX_LOG_EMERG, cf, 0, "no servers are inside upstream");
412 | return NGX_CONF_ERROR ;
413 | }
414 |
415 | return rv;
416 | }
417 |
418 | static char *
419 | ngx_nsoc_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
420 | {
421 | ngx_nsoc_upstream_srv_conf_t *uscf = conf;
422 |
423 | time_t fail_timeout;
424 | ngx_str_t *value, s;
425 | ngx_url_t u;
426 | ngx_int_t weight, max_conns, max_fails;
427 | ngx_uint_t i;
428 | ngx_nsoc_upstream_server_t *us;
429 |
430 | us = ngx_array_push(uscf->servers);
431 | if (us == NULL) {
432 | return NGX_CONF_ERROR ;
433 | }
434 |
435 | ngx_memzero(us, sizeof(ngx_nsoc_upstream_server_t));
436 |
437 | value = cf->args->elts;
438 |
439 | weight = 1;
440 | max_conns = 0;
441 | max_fails = 1;
442 | fail_timeout = 10;
443 |
444 | for (i = 2; i < cf->args->nelts; i++) {
445 |
446 | if (ngx_strncmp(value[i].data, "weight=", 7) == 0) {
447 |
448 | if (!(uscf->flags & NGX_NSOC_UPSTREAM_WEIGHT)) {
449 | goto not_supported;
450 | }
451 |
452 | weight = ngx_atoi(&value[i].data[7], value[i].len - 7);
453 |
454 | if (weight == NGX_ERROR || weight == 0) {
455 | goto invalid;
456 | }
457 |
458 | continue;
459 | }
460 |
461 | if (ngx_strncmp(value[i].data, "max_conns=", 10) == 0) {
462 |
463 | if (!(uscf->flags & NGX_NSOC_UPSTREAM_MAX_CONNS)) {
464 | goto not_supported;
465 | }
466 |
467 | max_conns = ngx_atoi(&value[i].data[10], value[i].len - 10);
468 |
469 | if (max_conns == NGX_ERROR) {
470 | goto invalid;
471 | }
472 |
473 | continue;
474 | }
475 |
476 | if (ngx_strncmp(value[i].data, "max_fails=", 10) == 0) {
477 |
478 | if (!(uscf->flags & NGX_NSOC_UPSTREAM_MAX_FAILS)) {
479 | goto not_supported;
480 | }
481 |
482 | max_fails = ngx_atoi(&value[i].data[10], value[i].len - 10);
483 |
484 | if (max_fails == NGX_ERROR) {
485 | goto invalid;
486 | }
487 |
488 | continue;
489 | }
490 |
491 | if (ngx_strncmp(value[i].data, "fail_timeout=", 13) == 0) {
492 |
493 | if (!(uscf->flags & NGX_NSOC_UPSTREAM_FAIL_TIMEOUT)) {
494 | goto not_supported;
495 | }
496 |
497 | s.len = value[i].len - 13;
498 | s.data = &value[i].data[13];
499 |
500 | fail_timeout = ngx_parse_time(&s, 1);
501 |
502 | if (fail_timeout == (time_t) NGX_ERROR) {
503 | goto invalid;
504 | }
505 |
506 | continue;
507 | }
508 |
509 | if (ngx_strcmp(value[i].data, "backup") == 0) {
510 |
511 | if (!(uscf->flags & NGX_NSOC_UPSTREAM_BACKUP)) {
512 | goto not_supported;
513 | }
514 |
515 | us->backup = 1;
516 |
517 | continue;
518 | }
519 |
520 | if (ngx_strcmp(value[i].data, "down") == 0) {
521 |
522 | if (!(uscf->flags & NGX_NSOC_UPSTREAM_DOWN)) {
523 | goto not_supported;
524 | }
525 |
526 | us->down = 1;
527 |
528 | continue;
529 | }
530 |
531 | goto invalid;
532 | }
533 |
534 | ngx_memzero(&u, sizeof(ngx_url_t));
535 |
536 | u.url = value[1];
537 |
538 | if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
539 | if (u.err) {
540 | ngx_conf_log_error(
541 | NGX_LOG_EMERG, cf, 0, "%s in upstream \"%V\"", u.err,
542 | &u.url);
543 | }
544 |
545 | return NGX_CONF_ERROR ;
546 | }
547 |
548 | if (u.no_port) {
549 | ngx_conf_log_error(
550 | NGX_LOG_EMERG, cf, 0, "no port in upstream \"%V\"", &u.url);
551 | return NGX_CONF_ERROR ;
552 | }
553 |
554 | us->name = u.url;
555 | us->addrs = u.addrs;
556 | us->naddrs = u.naddrs;
557 | us->weight = weight;
558 | us->max_conns = max_conns;
559 | us->max_fails = max_fails;
560 | us->fail_timeout = fail_timeout;
561 |
562 | return NGX_CONF_OK;
563 |
564 | invalid:
565 |
566 | ngx_conf_log_error(
567 | NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"", &value[i]);
568 |
569 | return NGX_CONF_ERROR ;
570 |
571 | not_supported:
572 |
573 | ngx_conf_log_error(
574 | NGX_LOG_EMERG, cf, 0,
575 | "balancing method does not support parameter \"%V\"", &value[i]);
576 |
577 | return NGX_CONF_ERROR ;
578 | }
579 |
580 | ngx_nsoc_upstream_srv_conf_t *
581 | ngx_nsoc_upstream_add(ngx_conf_t *cf, ngx_url_t *u, ngx_uint_t flags)
582 | {
583 | ngx_uint_t i;
584 | ngx_nsoc_upstream_server_t *us;
585 | ngx_nsoc_upstream_srv_conf_t *uscf, **uscfp;
586 | ngx_nsoc_upstream_main_conf_t *umcf;
587 |
588 | if (!(flags & NGX_NSOC_UPSTREAM_CREATE)) {
589 |
590 | if (ngx_parse_url(cf->pool, u) != NGX_OK) {
591 | if (u->err) {
592 | ngx_conf_log_error(
593 | NGX_LOG_EMERG, cf, 0, "%s in upstream \"%V\"", u->err,
594 | &u->url);
595 | }
596 |
597 | return NULL;
598 | }
599 | }
600 |
601 | umcf = ngx_nsoc_conf_get_module_main_conf(
602 | cf, ngx_nsoc_upstream_module);
603 |
604 | uscfp = umcf->upstreams.elts;
605 |
606 | for (i = 0; i < umcf->upstreams.nelts; i++) {
607 |
608 | if (uscfp[i]->host.len != u->host.len
609 | || ngx_strncasecmp(
610 | uscfp[i]->host.data, u->host.data, u->host.len) != 0) {
611 | continue;
612 | }
613 |
614 | if ((flags & NGX_NSOC_UPSTREAM_CREATE)
615 | && (uscfp[i]->flags & NGX_NSOC_UPSTREAM_CREATE)) {
616 | ngx_conf_log_error(
617 | NGX_LOG_EMERG, cf, 0, "duplicate upstream \"%V\"",
618 | &u->host);
619 | return NULL;
620 | }
621 |
622 | if ((uscfp[i]->flags & NGX_NSOC_UPSTREAM_CREATE) && !u->no_port) {
623 | ngx_conf_log_error(
624 | NGX_LOG_EMERG, cf, 0,
625 | "upstream \"%V\" may not have port %d", &u->host, u->port);
626 | return NULL;
627 | }
628 |
629 | if ((flags & NGX_NSOC_UPSTREAM_CREATE) && !uscfp[i]->no_port) {
630 | ngx_log_error(
631 | NGX_LOG_EMERG, cf->log, 0,
632 | "upstream \"%V\" may not have port %d in %s:%ui", &u->host,
633 | uscfp[i]->port, uscfp[i]->file_name, uscfp[i]->line);
634 | return NULL;
635 | }
636 |
637 | if (uscfp[i]->port != u->port) {
638 | continue;
639 | }
640 |
641 | if (flags & NGX_NSOC_UPSTREAM_CREATE) {
642 | uscfp[i]->flags = flags;
643 | }
644 |
645 | return uscfp[i];
646 | }
647 |
648 | uscf = ngx_pcalloc(cf->pool, sizeof(ngx_nsoc_upstream_srv_conf_t));
649 | if (uscf == NULL) {
650 | return NULL;
651 | }
652 |
653 | uscf->flags = flags;
654 | uscf->host = u->host;
655 | uscf->file_name = cf->conf_file->file.name.data;
656 | uscf->line = cf->conf_file->line;
657 | uscf->port = u->port;
658 | uscf->no_port = u->no_port;
659 |
660 | if (u->naddrs == 1 && (u->port || u->family == AF_UNIX)) {
661 | uscf->servers = ngx_array_create(
662 | cf->pool, 1, sizeof(ngx_nsoc_upstream_server_t));
663 | if (uscf->servers == NULL) {
664 | return NULL;
665 | }
666 |
667 | us = ngx_array_push(uscf->servers);
668 | if (us == NULL) {
669 | return NULL;
670 | }
671 |
672 | ngx_memzero(us, sizeof(ngx_nsoc_upstream_server_t));
673 |
674 | us->addrs = u->addrs;
675 | us->naddrs = 1;
676 | }
677 |
678 | uscfp = ngx_array_push(&umcf->upstreams);
679 | if (uscfp == NULL) {
680 | return NULL;
681 | }
682 |
683 | *uscfp = uscf;
684 |
685 | return uscf;
686 | }
687 |
688 | static void *
689 | ngx_nsoc_upstream_create_main_conf(ngx_conf_t *cf)
690 | {
691 | ngx_nsoc_upstream_main_conf_t *umcf;
692 |
693 | umcf = ngx_pcalloc(cf->pool, sizeof(ngx_nsoc_upstream_main_conf_t));
694 | if (umcf == NULL) {
695 | return NULL;
696 | }
697 |
698 | if (ngx_array_init(
699 | &umcf->upstreams, cf->pool, 4,
700 | sizeof(ngx_nsoc_upstream_srv_conf_t *)) != NGX_OK) {
701 | return NULL;
702 | }
703 |
704 | return umcf;
705 | }
706 |
707 | static char *
708 | ngx_nsoc_upstream_init_main_conf(ngx_conf_t *cf, void *conf)
709 | {
710 | ngx_nsoc_upstream_main_conf_t *umcf = conf;
711 |
712 | ngx_uint_t i;
713 | ngx_nsoc_upstream_init_pt init;
714 | ngx_nsoc_upstream_srv_conf_t **uscfp;
715 |
716 | uscfp = umcf->upstreams.elts;
717 |
718 | for (i = 0; i < umcf->upstreams.nelts; i++) {
719 |
720 | init = uscfp[i]->peer.init_upstream ?
721 | uscfp[i]->peer.init_upstream :
722 | ngx_nsoc_upstream_init_round_robin;
723 |
724 | if (init(cf, uscfp[i]) != NGX_OK) {
725 | return NGX_CONF_ERROR ;
726 | }
727 | }
728 |
729 | return NGX_CONF_OK;
730 | }
731 |
--------------------------------------------------------------------------------
/ngx_nsoc_upstream.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Igor Sysoev
3 | * Copyright (C) Nginx, Inc.
4 | */
5 |
6 | #ifndef _NGX_NSOC_UPSTREAM_H_INCLUDED_
7 | #define _NGX_NSOC_UPSTREAM_H_INCLUDED_
8 |
9 | #include
10 | #include
11 | #include
12 | #include "ngx_nsoc.h"
13 |
14 | #define NGX_NSOC_UPSTREAM_CREATE 0x0001
15 | #define NGX_NSOC_UPSTREAM_WEIGHT 0x0002
16 | #define NGX_NSOC_UPSTREAM_MAX_FAILS 0x0004
17 | #define NGX_NSOC_UPSTREAM_FAIL_TIMEOUT 0x0008
18 | #define NGX_NSOC_UPSTREAM_DOWN 0x0010
19 | #define NGX_NSOC_UPSTREAM_BACKUP 0x0020
20 | #define NGX_NSOC_UPSTREAM_MAX_CONNS 0x0100
21 |
22 | #define NGX_NSOC_UPSTREAM_NOTIFY_CONNECT 0x1
23 |
24 | typedef struct {
25 | ngx_array_t upstreams;
26 | /* ngx_nsoc_upstream_srv_conf_t */
27 | } ngx_nsoc_upstream_main_conf_t;
28 |
29 | typedef struct ngx_nsoc_upstream_srv_conf_s ngx_nsoc_upstream_srv_conf_t;
30 |
31 | typedef ngx_int_t (*ngx_nsoc_upstream_init_pt)(ngx_conf_t *cf,
32 | ngx_nsoc_upstream_srv_conf_t *us);
33 | typedef ngx_int_t (*ngx_nsoc_upstream_init_peer_pt)(
34 | ngx_nsoc_session_t *s, ngx_nsoc_upstream_srv_conf_t *us);
35 |
36 | typedef struct {
37 | ngx_nsoc_upstream_init_pt init_upstream;
38 | ngx_nsoc_upstream_init_peer_pt init;
39 | void *data;
40 | } ngx_nsoc_upstream_peer_t;
41 |
42 | typedef struct {
43 | ngx_str_t name;
44 | ngx_addr_t *addrs;
45 | ngx_uint_t naddrs;
46 | ngx_uint_t weight;
47 | ngx_uint_t max_conns;
48 | ngx_uint_t max_fails;
49 | time_t fail_timeout;
50 | ngx_msec_t slow_start;
51 |
52 | unsigned down :1;
53 | unsigned backup :1;
54 |
55 | NGX_COMPAT_BEGIN(4)
56 | NGX_COMPAT_END
57 | } ngx_nsoc_upstream_server_t;
58 |
59 | struct ngx_nsoc_upstream_srv_conf_s {
60 | ngx_nsoc_upstream_peer_t peer;
61 | void **srv_conf;
62 |
63 | ngx_array_t *servers;
64 | /* ngx_nsoc_upstream_server_t */
65 |
66 | ngx_uint_t flags;
67 | ngx_str_t host;
68 | u_char *file_name;
69 | ngx_uint_t line;
70 | in_port_t port;
71 | ngx_uint_t no_port; /* unsigned no_port:1 */
72 |
73 | #if (NGX_NSOC_UPSTREAM_ZONE)
74 | ngx_shm_zone_t *shm_zone;
75 | #endif
76 | };
77 |
78 | typedef struct {
79 | ngx_msec_t response_time;
80 | ngx_msec_t connect_time;
81 | ngx_msec_t first_byte_time;
82 | off_t bytes_sent;
83 | off_t bytes_received;
84 |
85 | ngx_str_t *peer;
86 | } ngx_nsoc_upstream_state_t;
87 |
88 | typedef struct {
89 | ngx_str_t host;
90 | in_port_t port;
91 | ngx_uint_t no_port; /* unsigned no_port:1 */
92 |
93 | ngx_uint_t naddrs;
94 | ngx_resolver_addr_t *addrs;
95 |
96 | struct sockaddr *sockaddr;
97 | socklen_t socklen;
98 | ngx_str_t name;
99 |
100 | ngx_resolver_ctx_t *ctx;
101 | } ngx_nsoc_upstream_resolved_t;
102 |
103 | typedef struct {
104 | ngx_peer_connection_t peer;
105 |
106 | ngx_buf_t downstream_buf;
107 | ngx_buf_t upstream_buf;
108 |
109 | ngx_chain_t *free;
110 | ngx_chain_t *upstream_out;
111 | ngx_chain_t *upstream_busy;
112 | ngx_chain_t *downstream_out;
113 | ngx_chain_t *downstream_busy;
114 |
115 | off_t received;
116 | time_t start_sec;
117 | ngx_uint_t responses;
118 |
119 | ngx_nsoc_upstream_srv_conf_t *upstream;
120 | ngx_nsoc_upstream_resolved_t *resolved;
121 | ngx_nsoc_upstream_state_t *state;
122 | unsigned connected :1;
123 | //unsigned proxy_protocol :1;
124 | } ngx_nsoc_upstream_t;
125 |
126 | ngx_nsoc_upstream_srv_conf_t *ngx_nsoc_upstream_add(
127 | ngx_conf_t *cf, ngx_url_t *u, ngx_uint_t flags);
128 |
129 | #define ngx_nsoc_conf_upstream_srv_conf(uscf, module) \
130 | uscf->srv_conf[module.ctx_index]
131 |
132 | extern ngx_module_t ngx_nsoc_upstream_module;
133 |
134 | #endif /* _NGX_NSOC_UPSTREAM_H_INCLUDED_ */
135 |
--------------------------------------------------------------------------------
/ngx_nsoc_upstream_round_robin.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Igor Sysoev
3 | * Copyright (C) Nginx, Inc.
4 | */
5 |
6 | #include
7 | #include
8 |
9 | #include "ngx_nsoc.h"
10 |
11 | #define ngx_nsoc_upstream_tries(p) ((p)->number \
12 | + ((p)->next ? (p)->next->number : 0))
13 |
14 | static ngx_nsoc_upstream_rr_peer_t *ngx_nsoc_upstream_get_peer(
15 | ngx_nsoc_upstream_rr_peer_data_t *rrp);
16 | static void ngx_nsoc_upstream_notify_round_robin_peer(
17 | ngx_peer_connection_t *pc, void *data, ngx_uint_t state);
18 |
19 | ngx_int_t ngx_nsoc_upstream_init_round_robin(ngx_conf_t *cf,
20 | ngx_nsoc_upstream_srv_conf_t *us)
21 | {
22 | ngx_url_t u;
23 | ngx_uint_t i, j, n, w;
24 | ngx_nsoc_upstream_server_t *server;
25 | ngx_nsoc_upstream_rr_peer_t *peer, **peerp;
26 | ngx_nsoc_upstream_rr_peers_t *peers, *backup;
27 |
28 | us->peer.init = ngx_nsoc_upstream_init_round_robin_peer;
29 |
30 | if (us->servers) {
31 | server = us->servers->elts;
32 |
33 | n = 0;
34 | w = 0;
35 |
36 | for (i = 0; i < us->servers->nelts; i++) {
37 | if (server[i].backup) {
38 | continue;
39 | }
40 |
41 | n += server[i].naddrs;
42 | w += server[i].naddrs * server[i].weight;
43 | }
44 |
45 | if (n == 0) {
46 | ngx_log_error(
47 | NGX_LOG_EMERG, cf->log, 0,
48 | "no servers in upstream \"%V\" in %s:%ui", &us->host,
49 | us->file_name, us->line);
50 | return NGX_ERROR;
51 | }
52 |
53 | peers = ngx_pcalloc(
54 | cf->pool, sizeof(ngx_nsoc_upstream_rr_peers_t));
55 | if (peers == NULL) {
56 | return NGX_ERROR;
57 | }
58 |
59 | peer = ngx_pcalloc(
60 | cf->pool, sizeof(ngx_nsoc_upstream_rr_peer_t) * n);
61 | if (peer == NULL) {
62 | return NGX_ERROR;
63 | }
64 |
65 | peers->single = (n == 1);
66 | peers->number = n;
67 | peers->weighted = (w != n);
68 | peers->total_weight = w;
69 | peers->name = &us->host;
70 |
71 | n = 0;
72 | peerp = &peers->peer;
73 |
74 | for (i = 0; i < us->servers->nelts; i++) {
75 | if (server[i].backup) {
76 | continue;
77 | }
78 |
79 | for (j = 0; j < server[i].naddrs; j++) {
80 | peer[n].sockaddr = server[i].addrs[j].sockaddr;
81 | peer[n].socklen = server[i].addrs[j].socklen;
82 | peer[n].name = server[i].addrs[j].name;
83 | peer[n].weight = server[i].weight;
84 | peer[n].effective_weight = server[i].weight;
85 | peer[n].current_weight = 0;
86 | peer[n].max_conns = server[i].max_conns;
87 | peer[n].max_fails = server[i].max_fails;
88 | peer[n].fail_timeout = server[i].fail_timeout;
89 | peer[n].down = server[i].down;
90 | peer[n].server = server[i].name;
91 |
92 | *peerp = &peer[n];
93 | peerp = &peer[n].next;
94 | n++;
95 | }
96 | }
97 |
98 | us->peer.data = peers;
99 |
100 | /* backup servers */
101 |
102 | n = 0;
103 | w = 0;
104 |
105 | for (i = 0; i < us->servers->nelts; i++) {
106 | if (!server[i].backup) {
107 | continue;
108 | }
109 |
110 | n += server[i].naddrs;
111 | w += server[i].naddrs * server[i].weight;
112 | }
113 |
114 | if (n == 0) {
115 | return NGX_OK;
116 | }
117 |
118 | backup = ngx_pcalloc(
119 | cf->pool, sizeof(ngx_nsoc_upstream_rr_peers_t));
120 | if (backup == NULL) {
121 | return NGX_ERROR;
122 | }
123 |
124 | peer = ngx_pcalloc(
125 | cf->pool, sizeof(ngx_nsoc_upstream_rr_peer_t) * n);
126 | if (peer == NULL) {
127 | return NGX_ERROR;
128 | }
129 |
130 | peers->single = 0;
131 | backup->single = 0;
132 | backup->number = n;
133 | backup->weighted = (w != n);
134 | backup->total_weight = w;
135 | backup->name = &us->host;
136 |
137 | n = 0;
138 | peerp = &backup->peer;
139 |
140 | for (i = 0; i < us->servers->nelts; i++) {
141 | if (!server[i].backup) {
142 | continue;
143 | }
144 |
145 | for (j = 0; j < server[i].naddrs; j++) {
146 | peer[n].sockaddr = server[i].addrs[j].sockaddr;
147 | peer[n].socklen = server[i].addrs[j].socklen;
148 | peer[n].name = server[i].addrs[j].name;
149 | peer[n].weight = server[i].weight;
150 | peer[n].effective_weight = server[i].weight;
151 | peer[n].current_weight = 0;
152 | peer[n].max_conns = server[i].max_conns;
153 | peer[n].max_fails = server[i].max_fails;
154 | peer[n].fail_timeout = server[i].fail_timeout;
155 | peer[n].down = server[i].down;
156 | peer[n].server = server[i].name;
157 |
158 | *peerp = &peer[n];
159 | peerp = &peer[n].next;
160 | n++;
161 | }
162 | }
163 |
164 | peers->next = backup;
165 |
166 | return NGX_OK;
167 | }
168 |
169 | /* an upstream implicitly defined by proxy_pass, etc. */
170 |
171 | if (us->port == 0) {
172 | ngx_log_error(
173 | NGX_LOG_EMERG, cf->log, 0,
174 | "no port in upstream \"%V\" in %s:%ui", &us->host,
175 | us->file_name, us->line);
176 | return NGX_ERROR;
177 | }
178 |
179 | ngx_memzero(&u, sizeof(ngx_url_t));
180 |
181 | u.host = us->host;
182 | u.port = us->port;
183 |
184 | if (ngx_inet_resolve_host(cf->pool, &u) != NGX_OK) {
185 | if (u.err) {
186 | ngx_log_error(
187 | NGX_LOG_EMERG, cf->log, 0,
188 | "%s in upstream \"%V\" in %s:%ui", u.err, &us->host,
189 | us->file_name, us->line);
190 | }
191 |
192 | return NGX_ERROR;
193 | }
194 |
195 | n = u.naddrs;
196 |
197 | peers = ngx_pcalloc(cf->pool, sizeof(ngx_nsoc_upstream_rr_peers_t));
198 | if (peers == NULL) {
199 | return NGX_ERROR;
200 | }
201 |
202 | peer = ngx_pcalloc(
203 | cf->pool, sizeof(ngx_nsoc_upstream_rr_peer_t) * n);
204 | if (peer == NULL) {
205 | return NGX_ERROR;
206 | }
207 |
208 | peers->single = (n == 1);
209 | peers->number = n;
210 | peers->weighted = 0;
211 | peers->total_weight = n;
212 | peers->name = &us->host;
213 |
214 | peerp = &peers->peer;
215 |
216 | for (i = 0; i < u.naddrs; i++) {
217 | peer[i].sockaddr = u.addrs[i].sockaddr;
218 | peer[i].socklen = u.addrs[i].socklen;
219 | peer[i].name = u.addrs[i].name;
220 | peer[i].weight = 1;
221 | peer[i].effective_weight = 1;
222 | peer[i].current_weight = 0;
223 | peer[i].max_conns = 0;
224 | peer[i].max_fails = 1;
225 | peer[i].fail_timeout = 10;
226 | *peerp = &peer[i];
227 | peerp = &peer[i].next;
228 | }
229 |
230 | us->peer.data = peers;
231 |
232 | /* implicitly defined upstream has no backup servers */
233 |
234 | return NGX_OK;
235 | }
236 |
237 | ngx_int_t ngx_nsoc_upstream_init_round_robin_peer(
238 | ngx_nsoc_session_t *s, ngx_nsoc_upstream_srv_conf_t *us)
239 | {
240 | ngx_uint_t n;
241 | ngx_nsoc_upstream_rr_peer_data_t *rrp;
242 |
243 | rrp = s->upstream->peer.data;
244 |
245 | if (rrp == NULL) {
246 | rrp = ngx_palloc(
247 | s->connection->pool,
248 | sizeof(ngx_nsoc_upstream_rr_peer_data_t));
249 | if (rrp == NULL) {
250 | return NGX_ERROR;
251 | }
252 |
253 | s->upstream->peer.data = rrp;
254 | }
255 |
256 | rrp->peers = us->peer.data;
257 | rrp->current = NULL;
258 | rrp->config = 0;
259 |
260 | n = rrp->peers->number;
261 |
262 | if (rrp->peers->next && rrp->peers->next->number > n) {
263 | n = rrp->peers->next->number;
264 | }
265 |
266 | if (n <= 8 * sizeof(uintptr_t)) {
267 | rrp->tried = &rrp->data;
268 | rrp->data = 0;
269 |
270 | } else {
271 | n = (n + (8 * sizeof(uintptr_t) - 1)) / (8 * sizeof(uintptr_t));
272 |
273 | rrp->tried = ngx_pcalloc(s->connection->pool, n * sizeof(uintptr_t));
274 | if (rrp->tried == NULL) {
275 | return NGX_ERROR;
276 | }
277 | }
278 |
279 | s->upstream->peer.get = ngx_nsoc_upstream_get_round_robin_peer;
280 | s->upstream->peer.free = ngx_nsoc_upstream_free_round_robin_peer;
281 | s->upstream->peer.notify = ngx_nsoc_upstream_notify_round_robin_peer;
282 | s->upstream->peer.tries = ngx_nsoc_upstream_tries(rrp->peers);
283 |
284 | return NGX_OK;
285 | }
286 |
287 | ngx_int_t ngx_nsoc_upstream_create_round_robin_peer(
288 | ngx_nsoc_session_t *s, ngx_nsoc_upstream_resolved_t *ur)
289 | {
290 | u_char *p;
291 | size_t len;
292 | socklen_t socklen;
293 | ngx_uint_t i, n;
294 | struct sockaddr *sockaddr;
295 | ngx_nsoc_upstream_rr_peer_t *peer, **peerp;
296 | ngx_nsoc_upstream_rr_peers_t *peers;
297 | ngx_nsoc_upstream_rr_peer_data_t *rrp;
298 |
299 | rrp = s->upstream->peer.data;
300 |
301 | if (rrp == NULL) {
302 | rrp = ngx_palloc(
303 | s->connection->pool,
304 | sizeof(ngx_nsoc_upstream_rr_peer_data_t));
305 | if (rrp == NULL) {
306 | return NGX_ERROR;
307 | }
308 |
309 | s->upstream->peer.data = rrp;
310 | }
311 |
312 | peers = ngx_pcalloc(
313 | s->connection->pool, sizeof(ngx_nsoc_upstream_rr_peers_t));
314 | if (peers == NULL) {
315 | return NGX_ERROR;
316 | }
317 |
318 | peer = ngx_pcalloc(
319 | s->connection->pool,
320 | sizeof(ngx_nsoc_upstream_rr_peer_t) * ur->naddrs);
321 | if (peer == NULL) {
322 | return NGX_ERROR;
323 | }
324 |
325 | peers->single = (ur->naddrs == 1);
326 | peers->number = ur->naddrs;
327 | peers->name = &ur->host;
328 |
329 | if (ur->sockaddr) {
330 | peer[0].sockaddr = ur->sockaddr;
331 | peer[0].socklen = ur->socklen;
332 | peer[0].name = ur->name;
333 | peer[0].weight = 1;
334 | peer[0].effective_weight = 1;
335 | peer[0].current_weight = 0;
336 | peer[0].max_conns = 0;
337 | peer[0].max_fails = 1;
338 | peer[0].fail_timeout = 10;
339 | peers->peer = peer;
340 |
341 | } else {
342 | peerp = &peers->peer;
343 |
344 | for (i = 0; i < ur->naddrs; i++) {
345 |
346 | socklen = ur->addrs[i].socklen;
347 |
348 | sockaddr = ngx_palloc(s->connection->pool, socklen);
349 | if (sockaddr == NULL) {
350 | return NGX_ERROR;
351 | }
352 |
353 | ngx_memcpy(sockaddr, ur->addrs[i].sockaddr, socklen);
354 | ngx_inet_set_port(sockaddr, ur->port);
355 |
356 | p = ngx_pnalloc(s->connection->pool, NGX_SOCKADDR_STRLEN);
357 | if (p == NULL) {
358 | return NGX_ERROR;
359 | }
360 |
361 | len = ngx_sock_ntop(sockaddr, socklen, p, NGX_SOCKADDR_STRLEN, 1);
362 |
363 | peer[i].sockaddr = sockaddr;
364 | peer[i].socklen = socklen;
365 | peer[i].name.len = len;
366 | peer[i].name.data = p;
367 | peer[i].weight = 1;
368 | peer[i].effective_weight = 1;
369 | peer[i].current_weight = 0;
370 | peer[i].max_conns = 0;
371 | peer[i].max_fails = 1;
372 | peer[i].fail_timeout = 10;
373 | *peerp = &peer[i];
374 | peerp = &peer[i].next;
375 | }
376 | }
377 |
378 | rrp->peers = peers;
379 | rrp->current = NULL;
380 | rrp->config = 0;
381 |
382 | if (rrp->peers->number <= 8 * sizeof(uintptr_t)) {
383 | rrp->tried = &rrp->data;
384 | rrp->data = 0;
385 |
386 | } else {
387 | n = (rrp->peers->number + (8 * sizeof(uintptr_t) - 1))
388 | / (8 * sizeof(uintptr_t));
389 |
390 | rrp->tried = ngx_pcalloc(s->connection->pool, n * sizeof(uintptr_t));
391 | if (rrp->tried == NULL) {
392 | return NGX_ERROR;
393 | }
394 | }
395 |
396 | s->upstream->peer.get = ngx_nsoc_upstream_get_round_robin_peer;
397 | s->upstream->peer.free = ngx_nsoc_upstream_free_round_robin_peer;
398 | s->upstream->peer.tries = ngx_nsoc_upstream_tries(rrp->peers);
399 |
400 | return NGX_OK;
401 | }
402 |
403 | ngx_int_t ngx_nsoc_upstream_get_round_robin_peer(
404 | ngx_peer_connection_t *pc, void *data)
405 | {
406 | ngx_nsoc_upstream_rr_peer_data_t *rrp = data;
407 |
408 | ngx_int_t rc;
409 | ngx_uint_t i, n;
410 | ngx_nsoc_upstream_rr_peer_t *peer;
411 | ngx_nsoc_upstream_rr_peers_t *peers;
412 |
413 | ngx_log_debug1(
414 | NGX_LOG_DEBUG_STREAM, pc->log, 0, "get rr peer, try: %ui",
415 | pc->tries);
416 |
417 | pc->connection = NULL;
418 |
419 | peers = rrp->peers;
420 | ngx_nsoc_upstream_rr_peers_wlock(peers);
421 |
422 | if (peers->single) {
423 | peer = peers->peer;
424 |
425 | if (peer->down) {
426 | goto failed;
427 | }
428 |
429 | if (peer->max_conns && peer->conns >= peer->max_conns) {
430 | goto failed;
431 | }
432 |
433 | rrp->current = peer;
434 |
435 | } else {
436 |
437 | /* there are several peers */
438 |
439 | peer = ngx_nsoc_upstream_get_peer(rrp);
440 |
441 | if (peer == NULL) {
442 | goto failed;
443 | }
444 |
445 | ngx_log_debug2(
446 | NGX_LOG_DEBUG_STREAM, pc->log, 0, "get rr peer, current: %p %i",
447 | peer, peer->current_weight);
448 | }
449 |
450 | pc->sockaddr = peer->sockaddr;
451 | pc->socklen = peer->socklen;
452 | pc->name = &peer->name;
453 |
454 | peer->conns++;
455 |
456 | ngx_nsoc_upstream_rr_peers_unlock(peers);
457 |
458 | return NGX_OK;
459 |
460 | failed:
461 |
462 | if (peers->next) {
463 |
464 | ngx_log_debug0(NGX_LOG_DEBUG_STREAM, pc->log, 0, "backup servers");
465 |
466 | rrp->peers = peers->next;
467 |
468 | n = (rrp->peers->number + (8 * sizeof(uintptr_t) - 1))
469 | / (8 * sizeof(uintptr_t));
470 |
471 | for (i = 0; i < n; i++) {
472 | rrp->tried[i] = 0;
473 | }
474 |
475 | ngx_nsoc_upstream_rr_peers_unlock(peers);
476 |
477 | rc = ngx_nsoc_upstream_get_round_robin_peer(pc, rrp);
478 |
479 | if (rc != NGX_BUSY) {
480 | return rc;
481 | }
482 |
483 | ngx_nsoc_upstream_rr_peers_wlock(peers);
484 | }
485 |
486 | ngx_nsoc_upstream_rr_peers_unlock(peers);
487 |
488 | pc->name = peers->name;
489 |
490 | return NGX_BUSY;
491 | }
492 |
493 | static ngx_nsoc_upstream_rr_peer_t *
494 | ngx_nsoc_upstream_get_peer(ngx_nsoc_upstream_rr_peer_data_t *rrp)
495 | {
496 | time_t now;
497 | uintptr_t m;
498 | ngx_int_t total;
499 | ngx_uint_t i, n, p;
500 | ngx_nsoc_upstream_rr_peer_t *peer, *best;
501 |
502 | now = ngx_time();
503 |
504 | best = NULL;
505 | total = 0;
506 |
507 | #if (NGX_SUPPRESS_WARN)
508 | p = 0;
509 | #endif
510 |
511 | for (peer = rrp->peers->peer, i = 0; peer; peer = peer->next, i++) {
512 | n = i / (8 * sizeof(uintptr_t));
513 | m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t));
514 |
515 | if (rrp->tried[n] & m) {
516 | continue;
517 | }
518 |
519 | if (peer->down) {
520 | continue;
521 | }
522 |
523 | if (peer->max_fails && peer->fails >= peer->max_fails
524 | && now - peer->checked <= peer->fail_timeout) {
525 | continue;
526 | }
527 |
528 | if (peer->max_conns && peer->conns >= peer->max_conns) {
529 | continue;
530 | }
531 |
532 | peer->current_weight += peer->effective_weight;
533 | total += peer->effective_weight;
534 |
535 | if (peer->effective_weight < peer->weight) {
536 | peer->effective_weight++;
537 | }
538 |
539 | if (best == NULL || peer->current_weight > best->current_weight) {
540 | best = peer;
541 | p = i;
542 | }
543 | }
544 |
545 | if (best == NULL) {
546 | return NULL;
547 | }
548 |
549 | rrp->current = best;
550 |
551 | n = p / (8 * sizeof(uintptr_t));
552 | m = (uintptr_t) 1 << p % (8 * sizeof(uintptr_t));
553 |
554 | rrp->tried[n] |= m;
555 |
556 | best->current_weight -= total;
557 |
558 | if (now - best->checked > best->fail_timeout) {
559 | best->checked = now;
560 | }
561 |
562 | return best;
563 | }
564 |
565 | void ngx_nsoc_upstream_free_round_robin_peer(ngx_peer_connection_t *pc,
566 | void *data, ngx_uint_t state)
567 | {
568 | ngx_nsoc_upstream_rr_peer_data_t *rrp = data;
569 |
570 | time_t now;
571 | ngx_nsoc_upstream_rr_peer_t *peer;
572 |
573 | ngx_log_debug2(
574 | NGX_LOG_DEBUG_STREAM, pc->log, 0, "free rr peer %ui %ui", pc->tries,
575 | state);
576 |
577 | peer = rrp->current;
578 |
579 | ngx_nsoc_upstream_rr_peers_rlock(rrp->peers); ngx_nsoc_upstream_rr_peer_lock(rrp->peers, peer);
580 |
581 | if (rrp->peers->single) {
582 | peer->conns--;
583 |
584 | ngx_nsoc_upstream_rr_peer_unlock(rrp->peers, peer); ngx_nsoc_upstream_rr_peers_unlock(rrp->peers);
585 |
586 | pc->tries = 0;
587 | return;
588 | }
589 |
590 | if (state & NGX_PEER_FAILED) {
591 | now = ngx_time();
592 |
593 | peer->fails++;
594 | peer->accessed = now;
595 | peer->checked = now;
596 |
597 | if (peer->max_fails) {
598 | peer->effective_weight -= peer->weight / peer->max_fails;
599 |
600 | if (peer->fails >= peer->max_fails) {
601 | ngx_log_error(
602 | NGX_LOG_WARN, pc->log, 0,
603 | "upstream server temporarily disabled");
604 | }
605 | }
606 |
607 | ngx_log_debug2(
608 | NGX_LOG_DEBUG_STREAM, pc->log, 0, "free rr peer failed: %p %i",
609 | peer, peer->effective_weight);
610 |
611 | if (peer->effective_weight < 0) {
612 | peer->effective_weight = 0;
613 | }
614 |
615 | } else {
616 |
617 | /* mark peer live if check passed */
618 |
619 | if (peer->accessed < peer->checked) {
620 | peer->fails = 0;
621 | }
622 | }
623 |
624 | peer->conns--;
625 |
626 | ngx_nsoc_upstream_rr_peer_unlock(rrp->peers, peer); ngx_nsoc_upstream_rr_peers_unlock(rrp->peers);
627 |
628 | if (pc->tries) {
629 | pc->tries--;
630 | }
631 | }
632 |
633 | static void ngx_nsoc_upstream_notify_round_robin_peer(
634 | ngx_peer_connection_t *pc, void *data, ngx_uint_t type)
635 | {
636 | ngx_nsoc_upstream_rr_peer_data_t *rrp = data;
637 |
638 | ngx_nsoc_upstream_rr_peer_t *peer;
639 |
640 | peer = rrp->current;
641 |
642 | if (type == NGX_NSOC_UPSTREAM_NOTIFY_CONNECT
643 | && pc->connection->type == SOCK_STREAM) {
644 | ngx_nsoc_upstream_rr_peers_rlock(rrp->peers); ngx_nsoc_upstream_rr_peer_lock(rrp->peers, peer);
645 |
646 | if (peer->accessed < peer->checked) {
647 | peer->fails = 0;
648 | }
649 |
650 | ngx_nsoc_upstream_rr_peer_unlock(rrp->peers, peer); ngx_nsoc_upstream_rr_peers_unlock(rrp->peers);
651 | }
652 | }
653 |
654 |
--------------------------------------------------------------------------------
/ngx_nsoc_upstream_round_robin.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Igor Sysoev
3 | * Copyright (C) Nginx, Inc.
4 | */
5 |
6 | #ifndef _NGX_NSOC_UPSTREAM_ROUND_ROBIN_H_INCLUDED_
7 | #define _NGX_NSOC_UPSTREAM_ROUND_ROBIN_H_INCLUDED_
8 |
9 | #include
10 | #include
11 | #include "ngx_nsoc.h"
12 |
13 | typedef struct ngx_nsoc_upstream_rr_peer_s ngx_nsoc_upstream_rr_peer_t;
14 |
15 | struct ngx_nsoc_upstream_rr_peer_s {
16 | struct sockaddr *sockaddr;
17 | socklen_t socklen;
18 | ngx_str_t name;
19 | ngx_str_t server;
20 |
21 | ngx_int_t current_weight;
22 | ngx_int_t effective_weight;
23 | ngx_int_t weight;
24 |
25 | ngx_uint_t conns;
26 | ngx_uint_t max_conns;
27 |
28 | ngx_uint_t fails;
29 | time_t accessed;
30 | time_t checked;
31 |
32 | ngx_uint_t max_fails;
33 | time_t fail_timeout;
34 | ngx_msec_t slow_start;
35 | ngx_msec_t start_time;
36 |
37 | ngx_uint_t down;
38 |
39 | void *ssl_session;
40 | int ssl_session_len;
41 |
42 | #if (NGX_NSOC_UPSTREAM_ZONE)
43 | ngx_atomic_t lock;
44 | #endif
45 |
46 | ngx_nsoc_upstream_rr_peer_t *next;
47 |
48 | NGX_COMPAT_BEGIN(25)
49 | NGX_COMPAT_END
50 | };
51 |
52 | typedef struct ngx_nsoc_upstream_rr_peers_s ngx_nsoc_upstream_rr_peers_t;
53 |
54 | struct ngx_nsoc_upstream_rr_peers_s {
55 | ngx_uint_t number;
56 |
57 | #if (NGX_NSOC_UPSTREAM_ZONE)
58 | ngx_slab_pool_t *shpool;
59 | ngx_atomic_t rwlock;
60 | ngx_nsoc_upstream_rr_peers_t *zone_next;
61 | #endif
62 |
63 | ngx_uint_t total_weight;
64 |
65 | unsigned single :1;
66 | unsigned weighted :1;
67 |
68 | ngx_str_t *name;
69 |
70 | ngx_nsoc_upstream_rr_peers_t *next;
71 |
72 | ngx_nsoc_upstream_rr_peer_t *peer;
73 | };
74 |
75 | #if (NGX_NSOC_UPSTREAM_ZONE)
76 |
77 | #define ngx_nsoc_upstream_rr_peers_rlock(peers) \
78 | \
79 | if (peers->shpool) { \
80 | ngx_rwlock_rlock(&peers->rwlock); \
81 | }
82 |
83 | #define ngx_nsoc_upstream_rr_peers_wlock(peers) \
84 | \
85 | if (peers->shpool) { \
86 | ngx_rwlock_wlock(&peers->rwlock); \
87 | }
88 |
89 | #define ngx_nsoc_upstream_rr_peers_unlock(peers) \
90 | \
91 | if (peers->shpool) { \
92 | ngx_rwlock_unlock(&peers->rwlock); \
93 | }
94 |
95 | #define ngx_nsoc_upstream_rr_peer_lock(peers, peer) \
96 | \
97 | if (peers->shpool) { \
98 | ngx_rwlock_wlock(&peer->lock); \
99 | }
100 |
101 | #define ngx_nsoc_upstream_rr_peer_unlock(peers, peer) \
102 | \
103 | if (peers->shpool) { \
104 | ngx_rwlock_unlock(&peer->lock); \
105 | }
106 |
107 | #else
108 |
109 | #define ngx_nsoc_upstream_rr_peers_rlock(peers)
110 | #define ngx_nsoc_upstream_rr_peers_wlock(peers)
111 | #define ngx_nsoc_upstream_rr_peers_unlock(peers)
112 | #define ngx_nsoc_upstream_rr_peer_lock(peers, peer)
113 | #define ngx_nsoc_upstream_rr_peer_unlock(peers, peer)
114 |
115 | #endif
116 |
117 | typedef struct {
118 | ngx_uint_t config;
119 | ngx_nsoc_upstream_rr_peers_t *peers;
120 | ngx_nsoc_upstream_rr_peer_t *current;
121 | uintptr_t *tried;
122 | uintptr_t data;
123 | } ngx_nsoc_upstream_rr_peer_data_t;
124 |
125 | ngx_int_t ngx_nsoc_upstream_init_round_robin(ngx_conf_t *cf,
126 | ngx_nsoc_upstream_srv_conf_t *us);
127 | ngx_int_t ngx_nsoc_upstream_init_round_robin_peer(
128 | ngx_nsoc_session_t *s, ngx_nsoc_upstream_srv_conf_t *us);
129 | ngx_int_t ngx_nsoc_upstream_create_round_robin_peer(
130 | ngx_nsoc_session_t *s, ngx_nsoc_upstream_resolved_t *ur);
131 | ngx_int_t ngx_nsoc_upstream_get_round_robin_peer(
132 | ngx_peer_connection_t *pc, void *data);
133 | void ngx_nsoc_upstream_free_round_robin_peer(ngx_peer_connection_t *pc,
134 | void *data, ngx_uint_t state);
135 |
136 | #endif /* _NGX_NSOC_UPSTREAM_ROUND_ROBIN_H_INCLUDED_ */
137 |
--------------------------------------------------------------------------------
/ngx_nsoc_variables.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Igor Sysoev
3 | * Copyright (C) Nginx, Inc.
4 | */
5 |
6 | #include
7 | #include
8 | #include
9 | #include "ngx_nsoc.h"
10 |
11 | static ngx_nsoc_variable_t *ngx_nsoc_add_prefix_variable(
12 | ngx_conf_t *cf, ngx_str_t *name, ngx_uint_t flags);
13 |
14 | static ngx_int_t ngx_nsoc_variable_binary_remote_addr(
15 | ngx_nsoc_session_t *s, ngx_nsoc_variable_value_t *v,
16 | uintptr_t data);
17 | static ngx_int_t ngx_nsoc_variable_remote_addr(
18 | ngx_nsoc_session_t *s, ngx_nsoc_variable_value_t *v,
19 | uintptr_t data);
20 | static ngx_int_t ngx_nsoc_variable_remote_port(
21 | ngx_nsoc_session_t *s, ngx_nsoc_variable_value_t *v,
22 | uintptr_t data);
23 | static ngx_int_t ngx_nsoc_variable_proxy_protocol_addr(
24 | ngx_nsoc_session_t *s, ngx_nsoc_variable_value_t *v,
25 | uintptr_t data);
26 | static ngx_int_t ngx_nsoc_variable_proxy_protocol_port(
27 | ngx_nsoc_session_t *s, ngx_nsoc_variable_value_t *v,
28 | uintptr_t data);
29 | static ngx_int_t ngx_nsoc_variable_server_addr(
30 | ngx_nsoc_session_t *s, ngx_nsoc_variable_value_t *v,
31 | uintptr_t data);
32 | static ngx_int_t ngx_nsoc_variable_server_port(
33 | ngx_nsoc_session_t *s, ngx_nsoc_variable_value_t *v,
34 | uintptr_t data);
35 | static ngx_int_t ngx_nsoc_variable_bytes(ngx_nsoc_session_t *s,
36 | ngx_nsoc_variable_value_t *v, uintptr_t data);
37 | static ngx_int_t ngx_nsoc_variable_session_time(
38 | ngx_nsoc_session_t *s, ngx_nsoc_variable_value_t *v,
39 | uintptr_t data);
40 | static ngx_int_t ngx_nsoc_variable_status(ngx_nsoc_session_t *s,
41 | ngx_nsoc_variable_value_t *v, uintptr_t data);
42 | static ngx_int_t ngx_nsoc_variable_connection(
43 | ngx_nsoc_session_t *s, ngx_nsoc_variable_value_t *v,
44 | uintptr_t data);
45 |
46 | static ngx_int_t ngx_nsoc_variable_nginx_version(
47 | ngx_nsoc_session_t *s, ngx_nsoc_variable_value_t *v,
48 | uintptr_t data);
49 | static ngx_int_t ngx_nsoc_variable_hostname(ngx_nsoc_session_t *s,
50 | ngx_nsoc_variable_value_t *v, uintptr_t data);
51 | static ngx_int_t ngx_nsoc_variable_pid(ngx_nsoc_session_t *s,
52 | ngx_nsoc_variable_value_t *v, uintptr_t data);
53 | static ngx_int_t ngx_nsoc_variable_msec(ngx_nsoc_session_t *s,
54 | ngx_nsoc_variable_value_t *v, uintptr_t data);
55 | static ngx_int_t ngx_nsoc_variable_time_iso8601(
56 | ngx_nsoc_session_t *s, ngx_nsoc_variable_value_t *v,
57 | uintptr_t data);
58 | static ngx_int_t ngx_nsoc_variable_time_local(
59 | ngx_nsoc_session_t *s, ngx_nsoc_variable_value_t *v,
60 | uintptr_t data);
61 | static ngx_int_t ngx_nsoc_variable_protocol(ngx_nsoc_session_t *s,
62 | ngx_nsoc_variable_value_t *v, uintptr_t data);
63 |
64 | static ngx_nsoc_variable_t ngx_nsoc_core_variables[] =
65 | {
66 |
67 | { ngx_string("binary_remote_addr"),
68 | NULL,
69 | ngx_nsoc_variable_binary_remote_addr,
70 | 0,
71 | 0,
72 | 0 },
73 |
74 | { ngx_string("remote_addr"),
75 | NULL,
76 | ngx_nsoc_variable_remote_addr,
77 | 0,
78 | 0,
79 | 0 },
80 |
81 | { ngx_string("remote_port"),
82 | NULL,
83 | ngx_nsoc_variable_remote_port,
84 | 0,
85 | 0,
86 | 0 },
87 |
88 | { ngx_string("proxy_protocol_addr"),
89 | NULL,
90 | ngx_nsoc_variable_proxy_protocol_addr,
91 | 0,
92 | 0,
93 | 0 },
94 |
95 | { ngx_string("proxy_protocol_port"),
96 | NULL,
97 | ngx_nsoc_variable_proxy_protocol_port,
98 | 0,
99 | 0,
100 | 0 },
101 |
102 | { ngx_string("server_addr"),
103 | NULL,
104 | ngx_nsoc_variable_server_addr,
105 | 0,
106 | 0,
107 | 0 },
108 |
109 | { ngx_string("server_port"),
110 | NULL,
111 | ngx_nsoc_variable_server_port,
112 | 0,
113 | 0,
114 | 0 },
115 |
116 | { ngx_string("bytes_sent"),
117 | NULL,
118 | ngx_nsoc_variable_bytes,
119 | 0,
120 | 0,
121 | 0 },
122 |
123 | { ngx_string("bytes_received"),
124 | NULL,
125 | ngx_nsoc_variable_bytes,
126 | 1,
127 | 0,
128 | 0 },
129 |
130 | { ngx_string("session_time"),
131 | NULL,
132 | ngx_nsoc_variable_session_time,
133 | 0,
134 | NGX_NSOC_VAR_NOCACHEABLE,
135 | 0 },
136 |
137 | { ngx_string("status"),
138 | NULL,
139 | ngx_nsoc_variable_status,
140 | 0,
141 | NGX_NSOC_VAR_NOCACHEABLE,
142 | 0 },
143 |
144 | { ngx_string("connection"),
145 | NULL,
146 | ngx_nsoc_variable_connection,
147 | 0,
148 | 0,
149 | 0 },
150 |
151 | { ngx_string("nginx_version"),
152 | NULL,
153 | ngx_nsoc_variable_nginx_version,
154 | 0,
155 | 0,
156 | 0 },
157 |
158 | { ngx_string("hostname"),
159 | NULL,
160 | ngx_nsoc_variable_hostname,
161 | 0,
162 | 0,
163 | 0 },
164 |
165 | { ngx_string("pid"),
166 | NULL,
167 | ngx_nsoc_variable_pid,
168 | 0,
169 | 0,
170 | 0 },
171 |
172 | { ngx_string("msec"),
173 | NULL,
174 | ngx_nsoc_variable_msec,
175 | 0,
176 | NGX_NSOC_VAR_NOCACHEABLE,
177 | 0 },
178 |
179 | { ngx_string("time_iso8601"),
180 | NULL,
181 | ngx_nsoc_variable_time_iso8601,
182 | 0,
183 | NGX_NSOC_VAR_NOCACHEABLE,
184 | 0 },
185 |
186 | { ngx_string("time_local"),
187 | NULL,
188 | ngx_nsoc_variable_time_local,
189 | 0,
190 | NGX_NSOC_VAR_NOCACHEABLE,
191 | 0 },
192 |
193 | { ngx_string("protocol"),
194 | NULL,
195 | ngx_nsoc_variable_protocol,
196 | 0,
197 | 0,
198 | 0 },
199 |
200 | { ngx_null_string,
201 | NULL,
202 | NULL,
203 | 0,
204 | 0,
205 | 0 }
206 | };
207 |
208 | ngx_nsoc_variable_value_t ngx_nsoc_variable_null_value =
209 | ngx_nsoc_variable("")
210 | ;
211 | ngx_nsoc_variable_value_t ngx_nsoc_variable_true_value =
212 | ngx_nsoc_variable("1")
213 | ;
214 |
215 | static ngx_uint_t ngx_nsoc_variable_depth = 100;
216 |
217 | ngx_nsoc_variable_t *
218 | ngx_nsoc_add_variable(ngx_conf_t *cf, ngx_str_t *name, ngx_uint_t flags)
219 | {
220 | ngx_int_t rc;
221 | ngx_uint_t i;
222 | ngx_hash_key_t *key;
223 | ngx_nsoc_variable_t *v;
224 | ngx_nsoc_core_main_conf_t *cmcf;
225 |
226 | if (name->len == 0) {
227 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid variable name \"$\"");
228 | return NULL;
229 | }
230 |
231 | if (flags & NGX_NSOC_VAR_PREFIX) {
232 | return ngx_nsoc_add_prefix_variable(cf, name, flags);
233 | }
234 |
235 | cmcf = ngx_nsoc_conf_get_module_main_conf(
236 | cf, ngx_nsoc_core_module);
237 |
238 | key = cmcf->variables_keys->keys.elts;
239 | for (i = 0; i < cmcf->variables_keys->keys.nelts; i++) {
240 | if (name->len != key[i].key.len
241 | || ngx_strncasecmp(name->data, key[i].key.data, name->len)
242 | != 0) {
243 | continue;
244 | }
245 |
246 | v = key[i].value;
247 |
248 | if (!(v->flags & NGX_NSOC_VAR_CHANGEABLE)) {
249 | ngx_conf_log_error(
250 | NGX_LOG_EMERG, cf, 0, "the duplicate \"%V\" variable",
251 | name);
252 | return NULL;
253 | }
254 |
255 | v->flags &= flags | ~NGX_NSOC_VAR_WEAK;
256 |
257 | return v;
258 | }
259 |
260 | v = ngx_palloc(cf->pool, sizeof(ngx_nsoc_variable_t));
261 | if (v == NULL) {
262 | return NULL;
263 | }
264 |
265 | v->name.len = name->len;
266 | v->name.data = ngx_pnalloc(cf->pool, name->len);
267 | if (v->name.data == NULL) {
268 | return NULL;
269 | }
270 |
271 | ngx_strlow(v->name.data, name->data, name->len);
272 |
273 | v->set_handler = NULL;
274 | v->get_handler = NULL;
275 | v->data = 0;
276 | v->flags = flags;
277 | v->index = 0;
278 |
279 | rc = ngx_hash_add_key(cmcf->variables_keys, &v->name, v, 0);
280 |
281 | if (rc == NGX_ERROR) {
282 | return NULL;
283 | }
284 |
285 | if (rc == NGX_BUSY) {
286 | ngx_conf_log_error(
287 | NGX_LOG_EMERG, cf, 0, "conflicting variable name \"%V\"", name);
288 | return NULL;
289 | }
290 |
291 | return v;
292 | }
293 |
294 | static ngx_nsoc_variable_t *
295 | ngx_nsoc_add_prefix_variable(ngx_conf_t *cf, ngx_str_t *name,
296 | ngx_uint_t flags)
297 | {
298 | ngx_uint_t i;
299 | ngx_nsoc_variable_t *v;
300 | ngx_nsoc_core_main_conf_t *cmcf;
301 |
302 | cmcf = ngx_nsoc_conf_get_module_main_conf(
303 | cf, ngx_nsoc_core_module);
304 |
305 | v = cmcf->prefix_variables.elts;
306 | for (i = 0; i < cmcf->prefix_variables.nelts; i++) {
307 | if (name->len != v[i].name.len
308 | || ngx_strncasecmp(name->data, v[i].name.data, name->len)
309 | != 0) {
310 | continue;
311 | }
312 |
313 | v = &v[i];
314 |
315 | if (!(v->flags & NGX_NSOC_VAR_CHANGEABLE)) {
316 | ngx_conf_log_error(
317 | NGX_LOG_EMERG, cf, 0, "the duplicate \"%V\" variable",
318 | name);
319 | return NULL;
320 | }
321 |
322 | v->flags &= flags | ~NGX_NSOC_VAR_WEAK;
323 |
324 | return v;
325 | }
326 |
327 | v = ngx_array_push(&cmcf->prefix_variables);
328 | if (v == NULL) {
329 | return NULL;
330 | }
331 |
332 | v->name.len = name->len;
333 | v->name.data = ngx_pnalloc(cf->pool, name->len);
334 | if (v->name.data == NULL) {
335 | return NULL;
336 | }
337 |
338 | ngx_strlow(v->name.data, name->data, name->len);
339 |
340 | v->set_handler = NULL;
341 | v->get_handler = NULL;
342 | v->data = 0;
343 | v->flags = flags;
344 | v->index = 0;
345 |
346 | return v;
347 | }
348 |
349 | ngx_int_t ngx_nsoc_get_variable_index(ngx_conf_t *cf, ngx_str_t *name)
350 | {
351 | ngx_uint_t i;
352 | ngx_nsoc_variable_t *v;
353 | ngx_nsoc_core_main_conf_t *cmcf;
354 |
355 | if (name->len == 0) {
356 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid variable name \"$\"");
357 | return NGX_ERROR;
358 | }
359 |
360 | cmcf = ngx_nsoc_conf_get_module_main_conf(
361 | cf, ngx_nsoc_core_module);
362 |
363 | v = cmcf->variables.elts;
364 |
365 | if (v == NULL) {
366 | if (ngx_array_init(
367 | &cmcf->variables, cf->pool, 4,
368 | sizeof(ngx_nsoc_variable_t)) != NGX_OK) {
369 | return NGX_ERROR;
370 | }
371 |
372 | } else {
373 | for (i = 0; i < cmcf->variables.nelts; i++) {
374 | if (name->len != v[i].name.len
375 | || ngx_strncasecmp(name->data, v[i].name.data, name->len)
376 | != 0) {
377 | continue;
378 | }
379 |
380 | return i;
381 | }
382 | }
383 |
384 | v = ngx_array_push(&cmcf->variables);
385 | if (v == NULL) {
386 | return NGX_ERROR;
387 | }
388 |
389 | v->name.len = name->len;
390 | v->name.data = ngx_pnalloc(cf->pool, name->len);
391 | if (v->name.data == NULL) {
392 | return NGX_ERROR;
393 | }
394 |
395 | ngx_strlow(v->name.data, name->data, name->len);
396 |
397 | v->set_handler = NULL;
398 | v->get_handler = NULL;
399 | v->data = 0;
400 | v->flags = 0;
401 | v->index = cmcf->variables.nelts - 1;
402 |
403 | return v->index;
404 | }
405 |
406 | ngx_nsoc_variable_value_t *
407 | ngx_nsoc_get_indexed_variable(ngx_nsoc_session_t *s,
408 | ngx_uint_t index)
409 | {
410 | ngx_nsoc_variable_t *v;
411 | ngx_nsoc_core_main_conf_t *cmcf;
412 |
413 | cmcf = ngx_nsoc_get_module_main_conf(s, ngx_nsoc_core_module);
414 |
415 | if (cmcf->variables.nelts <= index) {
416 | ngx_log_error(
417 | NGX_LOG_ALERT, s->connection->log, 0,
418 | "unknown variable index: %ui", index);
419 | return NULL;
420 | }
421 |
422 | if (s->variables[index].not_found || s->variables[index].valid) {
423 | return &s->variables[index];
424 | }
425 |
426 | v = cmcf->variables.elts;
427 |
428 | if (ngx_nsoc_variable_depth == 0) {
429 | ngx_log_error(
430 | NGX_LOG_ERR, s->connection->log, 0,
431 | "cycle while evaluating variable \"%V\"", &v[index].name);
432 | return NULL;
433 | }
434 |
435 | ngx_nsoc_variable_depth--;
436 |
437 | if (v[index].get_handler(s, &s->variables[index], v[index].data) == NGX_OK) {
438 | ngx_nsoc_variable_depth++;
439 |
440 | if (v[index].flags & NGX_NSOC_VAR_NOCACHEABLE) {
441 | s->variables[index].no_cacheable = 1;
442 | }
443 |
444 | return &s->variables[index];
445 | }
446 |
447 | ngx_nsoc_variable_depth++;
448 |
449 | s->variables[index].valid = 0;
450 | s->variables[index].not_found = 1;
451 |
452 | return NULL;
453 | }
454 |
455 | ngx_nsoc_variable_value_t *
456 | ngx_nsoc_get_flushed_variable(ngx_nsoc_session_t *s,
457 | ngx_uint_t index)
458 | {
459 | ngx_nsoc_variable_value_t *v;
460 |
461 | v = &s->variables[index];
462 |
463 | if (v->valid || v->not_found) {
464 | if (!v->no_cacheable) {
465 | return v;
466 | }
467 |
468 | v->valid = 0;
469 | v->not_found = 0;
470 | }
471 |
472 | return ngx_nsoc_get_indexed_variable(s, index);
473 | }
474 |
475 | ngx_nsoc_variable_value_t *
476 | ngx_nsoc_get_variable(ngx_nsoc_session_t *s, ngx_str_t *name,
477 | ngx_uint_t key)
478 | {
479 | size_t len;
480 | ngx_uint_t i, n;
481 | ngx_nsoc_variable_t *v;
482 | ngx_nsoc_variable_value_t *vv;
483 | ngx_nsoc_core_main_conf_t *cmcf;
484 |
485 | cmcf = ngx_nsoc_get_module_main_conf(s, ngx_nsoc_core_module);
486 |
487 | v = ngx_hash_find(&cmcf->variables_hash, key, name->data, name->len);
488 |
489 | if (v) {
490 | if (v->flags & NGX_NSOC_VAR_INDEXED) {
491 | return ngx_nsoc_get_flushed_variable(s, v->index);
492 | }
493 |
494 | if (ngx_nsoc_variable_depth == 0) {
495 | ngx_log_error(
496 | NGX_LOG_ERR, s->connection->log, 0,
497 | "cycle while evaluating variable \"%V\"", name);
498 | return NULL;
499 | }
500 |
501 | ngx_nsoc_variable_depth--;
502 |
503 | vv = ngx_palloc(
504 | s->connection->pool, sizeof(ngx_nsoc_variable_value_t));
505 |
506 | if (vv && v->get_handler(s, vv, v->data) == NGX_OK) {
507 | ngx_nsoc_variable_depth++;
508 | return vv;
509 | }
510 |
511 | ngx_nsoc_variable_depth++;
512 | return NULL;
513 | }
514 |
515 | vv = ngx_palloc(
516 | s->connection->pool, sizeof(ngx_nsoc_variable_value_t));
517 | if (vv == NULL) {
518 | return NULL;
519 | }
520 |
521 | len = 0;
522 |
523 | v = cmcf->prefix_variables.elts;
524 | n = cmcf->prefix_variables.nelts;
525 |
526 | for (i = 0; i < cmcf->prefix_variables.nelts; i++) {
527 | if (name->len >= v[i].name.len && name->len > len
528 | && ngx_strncmp(name->data, v[i].name.data, v[i].name.len)
529 | == 0) {
530 | len = v[i].name.len;
531 | n = i;
532 | }
533 | }
534 |
535 | if (n != cmcf->prefix_variables.nelts) {
536 | if (v[n].get_handler(s, vv, (uintptr_t) name) == NGX_OK) {
537 | return vv;
538 | }
539 |
540 | return NULL;
541 | }
542 |
543 | vv->not_found = 1;
544 |
545 | return vv;
546 | }
547 |
548 | static ngx_int_t ngx_nsoc_variable_binary_remote_addr(
549 | ngx_nsoc_session_t *s, ngx_nsoc_variable_value_t *v,
550 | uintptr_t data)
551 | {
552 | struct sockaddr_in *sin;
553 | #if (NGX_HAVE_INET6)
554 | struct sockaddr_in6 *sin6;
555 | #endif
556 |
557 | switch (s->connection->sockaddr->sa_family) {
558 |
559 | #if (NGX_HAVE_INET6)
560 | case AF_INET6:
561 | sin6 = (struct sockaddr_in6 *) s->connection->sockaddr;
562 |
563 | v->len = sizeof(struct in6_addr);
564 | v->valid = 1;
565 | v->no_cacheable = 0;
566 | v->not_found = 0;
567 | v->data = sin6->sin6_addr.s6_addr;
568 |
569 | break;
570 | #endif
571 |
572 | default: /* AF_INET */
573 | sin = (struct sockaddr_in *) s->connection->sockaddr;
574 |
575 | v->len = sizeof(in_addr_t);
576 | v->valid = 1;
577 | v->no_cacheable = 0;
578 | v->not_found = 0;
579 | v->data = (u_char *) &sin->sin_addr;
580 |
581 | break;
582 | }
583 |
584 | return NGX_OK;
585 | }
586 |
587 | static ngx_int_t ngx_nsoc_variable_remote_addr(
588 | ngx_nsoc_session_t *s, ngx_nsoc_variable_value_t *v,
589 | uintptr_t data)
590 | {
591 | v->len = s->connection->addr_text.len;
592 | v->valid = 1;
593 | v->no_cacheable = 0;
594 | v->not_found = 0;
595 | v->data = s->connection->addr_text.data;
596 |
597 | return NGX_OK;
598 | }
599 |
600 | static ngx_int_t ngx_nsoc_variable_remote_port(
601 | ngx_nsoc_session_t *s, ngx_nsoc_variable_value_t *v,
602 | uintptr_t data)
603 | {
604 | ngx_uint_t port;
605 |
606 | v->len = 0;
607 | v->valid = 1;
608 | v->no_cacheable = 0;
609 | v->not_found = 0;
610 |
611 | v->data = ngx_pnalloc(s->connection->pool, sizeof("65535") - 1);
612 | if (v->data == NULL) {
613 | return NGX_ERROR;
614 | }
615 |
616 | port = ngx_inet_get_port(s->connection->sockaddr);
617 |
618 | if (port > 0 && port < 65536) {
619 | v->len = ngx_sprintf(v->data, "%ui", port) - v->data;
620 | }
621 |
622 | return NGX_OK;
623 | }
624 |
625 | static ngx_int_t ngx_nsoc_variable_proxy_protocol_addr(
626 | ngx_nsoc_session_t *s, ngx_nsoc_variable_value_t *v,
627 | uintptr_t data)
628 | {
629 | v->len = s->connection->proxy_protocol_addr.len;
630 | v->valid = 1;
631 | v->no_cacheable = 0;
632 | v->not_found = 0;
633 | v->data = s->connection->proxy_protocol_addr.data;
634 |
635 | return NGX_OK;
636 | }
637 |
638 | static ngx_int_t ngx_nsoc_variable_proxy_protocol_port(
639 | ngx_nsoc_session_t *s, ngx_nsoc_variable_value_t *v,
640 | uintptr_t data)
641 | {
642 | ngx_uint_t port;
643 |
644 | v->len = 0;
645 | v->valid = 1;
646 | v->no_cacheable = 0;
647 | v->not_found = 0;
648 |
649 | v->data = ngx_pnalloc(s->connection->pool, sizeof("65535") - 1);
650 | if (v->data == NULL) {
651 | return NGX_ERROR;
652 | }
653 |
654 | port = s->connection->proxy_protocol_port;
655 |
656 | if (port > 0 && port < 65536) {
657 | v->len = ngx_sprintf(v->data, "%ui", port) - v->data;
658 | }
659 |
660 | return NGX_OK;
661 | }
662 |
663 | static ngx_int_t ngx_nsoc_variable_server_addr(
664 | ngx_nsoc_session_t *s, ngx_nsoc_variable_value_t *v,
665 | uintptr_t data)
666 | {
667 | ngx_str_t str;
668 | u_char addr[NGX_SOCKADDR_STRLEN];
669 |
670 | str.len = NGX_SOCKADDR_STRLEN;
671 | str.data = addr;
672 |
673 | if (ngx_connection_local_sockaddr(s->connection, &str, 0) != NGX_OK) {
674 | return NGX_ERROR;
675 | }
676 |
677 | str.data = ngx_pnalloc(s->connection->pool, str.len);
678 | if (str.data == NULL) {
679 | return NGX_ERROR;
680 | }
681 |
682 | ngx_memcpy(str.data, addr, str.len);
683 |
684 | v->len = str.len;
685 | v->valid = 1;
686 | v->no_cacheable = 0;
687 | v->not_found = 0;
688 | v->data = str.data;
689 |
690 | return NGX_OK;
691 | }
692 |
693 | static ngx_int_t ngx_nsoc_variable_server_port(
694 | ngx_nsoc_session_t *s, ngx_nsoc_variable_value_t *v,
695 | uintptr_t data)
696 | {
697 | ngx_uint_t port;
698 |
699 | v->len = 0;
700 | v->valid = 1;
701 | v->no_cacheable = 0;
702 | v->not_found = 0;
703 |
704 | if (ngx_connection_local_sockaddr(s->connection, NULL, 0) != NGX_OK) {
705 | return NGX_ERROR;
706 | }
707 |
708 | v->data = ngx_pnalloc(s->connection->pool, sizeof("65535") - 1);
709 | if (v->data == NULL) {
710 | return NGX_ERROR;
711 | }
712 |
713 | port = ngx_inet_get_port(s->connection->local_sockaddr);
714 |
715 | if (port > 0 && port < 65536) {
716 | v->len = ngx_sprintf(v->data, "%ui", port) - v->data;
717 | }
718 |
719 | return NGX_OK;
720 | }
721 |
722 | static ngx_int_t ngx_nsoc_variable_bytes(ngx_nsoc_session_t *s,
723 | ngx_nsoc_variable_value_t *v, uintptr_t data)
724 | {
725 | u_char *p;
726 |
727 | p = ngx_pnalloc(s->connection->pool, NGX_OFF_T_LEN);
728 | if (p == NULL) {
729 | return NGX_ERROR;
730 | }
731 |
732 | if (data == 1) {
733 | v->len = ngx_sprintf(p, "%O", s->received) - p;
734 |
735 | } else {
736 | v->len = ngx_sprintf(p, "%O", s->connection->sent) - p;
737 | }
738 |
739 | v->valid = 1;
740 | v->no_cacheable = 0;
741 | v->not_found = 0;
742 | v->data = p;
743 |
744 | return NGX_OK;
745 | }
746 |
747 | static ngx_int_t ngx_nsoc_variable_session_time(
748 | ngx_nsoc_session_t *s, ngx_nsoc_variable_value_t *v,
749 | uintptr_t data)
750 | {
751 | u_char *p;
752 | ngx_time_t *tp;
753 | ngx_msec_int_t ms;
754 |
755 | p = ngx_pnalloc(s->connection->pool, NGX_TIME_T_LEN + 4);
756 | if (p == NULL) {
757 | return NGX_ERROR;
758 | }
759 |
760 | tp = ngx_timeofday();
761 |
762 | ms = (ngx_msec_int_t) ((tp->sec - s->start_sec) * 1000
763 | + (tp->msec - s->start_msec));
764 | ms = ngx_max(ms, 0);
765 |
766 | v->len = ngx_sprintf(p, "%T.%03M", (time_t) ms / 1000, ms % 1000) - p;
767 | v->valid = 1;
768 | v->no_cacheable = 0;
769 | v->not_found = 0;
770 | v->data = p;
771 |
772 | return NGX_OK;
773 | }
774 |
775 | static ngx_int_t ngx_nsoc_variable_status(ngx_nsoc_session_t *s,
776 | ngx_nsoc_variable_value_t *v, uintptr_t data)
777 | {
778 | v->data = ngx_pnalloc(s->connection->pool, NGX_INT_T_LEN);
779 | if (v->data == NULL) {
780 | return NGX_ERROR;
781 | }
782 |
783 | v->len = ngx_sprintf(v->data, "%03ui", s->status) - v->data;
784 | v->valid = 1;
785 | v->no_cacheable = 0;
786 | v->not_found = 0;
787 |
788 | return NGX_OK;
789 | }
790 |
791 | static ngx_int_t ngx_nsoc_variable_connection(
792 | ngx_nsoc_session_t *s, ngx_nsoc_variable_value_t *v,
793 | uintptr_t data)
794 | {
795 | u_char *p;
796 |
797 | p = ngx_pnalloc(s->connection->pool, NGX_ATOMIC_T_LEN);
798 | if (p == NULL) {
799 | return NGX_ERROR;
800 | }
801 |
802 | v->len = ngx_sprintf(p, "%uA", s->connection->number) - p;
803 | v->valid = 1;
804 | v->no_cacheable = 0;
805 | v->not_found = 0;
806 | v->data = p;
807 |
808 | return NGX_OK;
809 | }
810 |
811 | static ngx_int_t ngx_nsoc_variable_nginx_version(
812 | ngx_nsoc_session_t *s, ngx_nsoc_variable_value_t *v,
813 | uintptr_t data)
814 | {
815 | v->len = sizeof(NGINX_VERSION) - 1;
816 | v->valid = 1;
817 | v->no_cacheable = 0;
818 | v->not_found = 0;
819 | v->data = (u_char *) NGINX_VERSION;
820 |
821 | return NGX_OK;
822 | }
823 |
824 | static ngx_int_t ngx_nsoc_variable_hostname(ngx_nsoc_session_t *s,
825 | ngx_nsoc_variable_value_t *v, uintptr_t data)
826 | {
827 | v->len = ngx_cycle->hostname.len;
828 | v->valid = 1;
829 | v->no_cacheable = 0;
830 | v->not_found = 0;
831 | v->data = ngx_cycle->hostname.data;
832 |
833 | return NGX_OK;
834 | }
835 |
836 | static ngx_int_t ngx_nsoc_variable_pid(ngx_nsoc_session_t *s,
837 | ngx_nsoc_variable_value_t *v, uintptr_t data)
838 | {
839 | u_char *p;
840 |
841 | p = ngx_pnalloc(s->connection->pool, NGX_INT64_LEN);
842 | if (p == NULL) {
843 | return NGX_ERROR;
844 | }
845 |
846 | v->len = ngx_sprintf(p, "%P", ngx_pid) - p;
847 | v->valid = 1;
848 | v->no_cacheable = 0;
849 | v->not_found = 0;
850 | v->data = p;
851 |
852 | return NGX_OK;
853 | }
854 |
855 | static ngx_int_t ngx_nsoc_variable_msec(ngx_nsoc_session_t *s,
856 | ngx_nsoc_variable_value_t *v, uintptr_t data)
857 | {
858 | u_char *p;
859 | ngx_time_t *tp;
860 |
861 | p = ngx_pnalloc(s->connection->pool, NGX_TIME_T_LEN + 4);
862 | if (p == NULL) {
863 | return NGX_ERROR;
864 | }
865 |
866 | tp = ngx_timeofday();
867 |
868 | v->len = ngx_sprintf(p, "%T.%03M", tp->sec, tp->msec) - p;
869 | v->valid = 1;
870 | v->no_cacheable = 0;
871 | v->not_found = 0;
872 | v->data = p;
873 |
874 | return NGX_OK;
875 | }
876 |
877 | static ngx_int_t ngx_nsoc_variable_time_iso8601(
878 | ngx_nsoc_session_t *s, ngx_nsoc_variable_value_t *v,
879 | uintptr_t data)
880 | {
881 | u_char *p;
882 |
883 | p = ngx_pnalloc(s->connection->pool, ngx_cached_http_log_iso8601.len);
884 | if (p == NULL) {
885 | return NGX_ERROR;
886 | }
887 |
888 | ngx_memcpy(
889 | p, ngx_cached_http_log_iso8601.data,
890 | ngx_cached_http_log_iso8601.len);
891 |
892 | v->len = ngx_cached_http_log_iso8601.len;
893 | v->valid = 1;
894 | v->no_cacheable = 0;
895 | v->not_found = 0;
896 | v->data = p;
897 |
898 | return NGX_OK;
899 | }
900 |
901 | static ngx_int_t ngx_nsoc_variable_time_local(
902 | ngx_nsoc_session_t *s, ngx_nsoc_variable_value_t *v,
903 | uintptr_t data)
904 | {
905 | u_char *p;
906 |
907 | p = ngx_pnalloc(s->connection->pool, ngx_cached_http_log_time.len);
908 | if (p == NULL) {
909 | return NGX_ERROR;
910 | }
911 |
912 | ngx_memcpy(p, ngx_cached_http_log_time.data, ngx_cached_http_log_time.len);
913 |
914 | v->len = ngx_cached_http_log_time.len;
915 | v->valid = 1;
916 | v->no_cacheable = 0;
917 | v->not_found = 0;
918 | v->data = p;
919 |
920 | return NGX_OK;
921 | }
922 |
923 | static ngx_int_t ngx_nsoc_variable_protocol(ngx_nsoc_session_t *s,
924 | ngx_nsoc_variable_value_t *v, uintptr_t data)
925 | {
926 | v->len = 3;
927 | v->valid = 1;
928 | v->no_cacheable = 0;
929 | v->not_found = 0;
930 | v->data = (u_char *) (s->connection->type == SOCK_DGRAM ? "UDP" : "TCP");
931 |
932 | return NGX_OK;
933 | }
934 |
935 | void *
936 | ngx_nsoc_map_find(ngx_nsoc_session_t *s,
937 | ngx_nsoc_map_t *map, ngx_str_t *match)
938 | {
939 | void *value;
940 | u_char *low;
941 | size_t len;
942 | ngx_uint_t key;
943 |
944 | len = match->len;
945 |
946 | if (len) {
947 | low = ngx_pnalloc(s->connection->pool, len);
948 | if (low == NULL) {
949 | return NULL;
950 | }
951 |
952 | } else {
953 | low = NULL;
954 | }
955 |
956 | key = ngx_hash_strlow(low, match->data, len);
957 |
958 | value = ngx_hash_find_combined(&map->hash, key, low, len);
959 | if (value) {
960 | return value;
961 | }
962 |
963 | #if (NGX_PCRE)
964 |
965 | if (len && map->nregex) {
966 | ngx_int_t n;
967 | ngx_uint_t i;
968 | ngx_nsoc_map_regex_t *reg;
969 |
970 | reg = map->regex;
971 |
972 | for (i = 0; i < map->nregex; i++) {
973 |
974 | n = ngx_nsoc_regex_exec(s, reg[i].regex, match);
975 |
976 | if (n == NGX_OK) {
977 | return reg[i].value;
978 | }
979 |
980 | if (n == NGX_DECLINED) {
981 | continue;
982 | }
983 |
984 | /* NGX_ERROR */
985 |
986 | return NULL;
987 | }
988 | }
989 |
990 | #endif
991 |
992 | return NULL;
993 | }
994 |
995 | #if (NGX_PCRE)
996 |
997 | static ngx_int_t ngx_nsoc_variable_not_found(
998 | ngx_nsoc_session_t *s, ngx_nsoc_variable_value_t *v,
999 | uintptr_t data)
1000 | {
1001 | v->not_found = 1;
1002 | return NGX_OK;
1003 | }
1004 |
1005 | ngx_nsoc_regex_t *
1006 | ngx_nsoc_regex_compile(ngx_conf_t *cf, ngx_regex_compile_t *rc)
1007 | {
1008 | u_char *p;
1009 | size_t size;
1010 | ngx_str_t name;
1011 | ngx_uint_t i, n;
1012 | ngx_nsoc_variable_t *v;
1013 | ngx_nsoc_regex_t *re;
1014 | ngx_nsoc_regex_variable_t *rv;
1015 | ngx_nsoc_core_main_conf_t *cmcf;
1016 |
1017 | rc->pool = cf->pool;
1018 |
1019 | if (ngx_regex_compile(rc) != NGX_OK) {
1020 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V", &rc->err);
1021 | return NULL;
1022 | }
1023 |
1024 | re = ngx_pcalloc(cf->pool, sizeof(ngx_nsoc_regex_t));
1025 | if (re == NULL) {
1026 | return NULL;
1027 | }
1028 |
1029 | re->regex = rc->regex;
1030 | re->ncaptures = rc->captures;
1031 | re->name = rc->pattern;
1032 |
1033 | cmcf = ngx_nsoc_conf_get_module_main_conf(
1034 | cf, ngx_nsoc_core_module);
1035 | cmcf->ncaptures = ngx_max(cmcf->ncaptures, re->ncaptures);
1036 |
1037 | n = (ngx_uint_t) rc->named_captures;
1038 |
1039 | if (n == 0) {
1040 | return re;
1041 | }
1042 |
1043 | rv = ngx_palloc(rc->pool, n * sizeof(ngx_nsoc_regex_variable_t));
1044 | if (rv == NULL) {
1045 | return NULL;
1046 | }
1047 |
1048 | re->variables = rv;
1049 | re->nvariables = n;
1050 |
1051 | size = rc->name_size;
1052 | p = rc->names;
1053 |
1054 | for (i = 0; i < n; i++) {
1055 | rv[i].capture = 2 * ((p[0] << 8) + p[1]);
1056 |
1057 | name.data = &p[2];
1058 | name.len = ngx_strlen(name.data);
1059 |
1060 | v = ngx_nsoc_add_variable(cf, &name, NGX_NSOC_VAR_CHANGEABLE);
1061 | if (v == NULL) {
1062 | return NULL;
1063 | }
1064 |
1065 | rv[i].index = ngx_nsoc_get_variable_index(cf, &name);
1066 | if (rv[i].index == NGX_ERROR) {
1067 | return NULL;
1068 | }
1069 |
1070 | v->get_handler = ngx_nsoc_variable_not_found;
1071 |
1072 | p += size;
1073 | }
1074 |
1075 | return re;
1076 | }
1077 |
1078 | ngx_int_t ngx_nsoc_regex_exec(ngx_nsoc_session_t *s,
1079 | ngx_nsoc_regex_t *re, ngx_str_t *str)
1080 | {
1081 | ngx_int_t rc, index;
1082 | ngx_uint_t i, n, len;
1083 | ngx_nsoc_variable_value_t *vv;
1084 | ngx_nsoc_core_main_conf_t *cmcf;
1085 |
1086 | cmcf = ngx_nsoc_get_module_main_conf(s, ngx_nsoc_core_module);
1087 |
1088 | if (re->ncaptures) {
1089 | len = cmcf->ncaptures;
1090 |
1091 | if (s->captures == NULL) {
1092 | s->captures = ngx_palloc(s->connection->pool, len * sizeof(int));
1093 | if (s->captures == NULL) {
1094 | return NGX_ERROR;
1095 | }
1096 | }
1097 |
1098 | } else {
1099 | len = 0;
1100 | }
1101 |
1102 | rc = ngx_regex_exec(re->regex, str, s->captures, len);
1103 |
1104 | if (rc == NGX_REGEX_NO_MATCHED) {
1105 | return NGX_DECLINED;
1106 | }
1107 |
1108 | if (rc < 0) {
1109 | ngx_log_error(
1110 | NGX_LOG_ALERT, s->connection->log, 0,
1111 | ngx_regex_exec_n " failed: %i on \"%V\" using \"%V\"", rc, str,
1112 | &re->name);
1113 | return NGX_ERROR;
1114 | }
1115 |
1116 | for (i = 0; i < re->nvariables; i++) {
1117 |
1118 | n = re->variables[i].capture;
1119 | index = re->variables[i].index;
1120 | vv = &s->variables[index];
1121 |
1122 | vv->len = s->captures[n + 1] - s->captures[n];
1123 | vv->valid = 1;
1124 | vv->no_cacheable = 0;
1125 | vv->not_found = 0;
1126 | vv->data = &str->data[s->captures[n]];
1127 |
1128 | #if (NGX_DEBUG)
1129 | {
1130 | ngx_nsoc_variable_t *v;
1131 |
1132 | v = cmcf->variables.elts;
1133 |
1134 | ngx_log_debug2(
1135 | NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
1136 | "stream regex set $%V to \"%v\"", &v[index].name, vv);
1137 | }
1138 | #endif
1139 | }
1140 |
1141 | s->ncaptures = rc * 2;
1142 | s->captures_data = str->data;
1143 |
1144 | return NGX_OK;
1145 | }
1146 |
1147 | #endif
1148 |
1149 | ngx_int_t ngx_nsoc_variables_add_core_vars(ngx_conf_t *cf)
1150 | {
1151 | ngx_nsoc_variable_t *cv, *v;
1152 | ngx_nsoc_core_main_conf_t *cmcf;
1153 |
1154 | cmcf = ngx_nsoc_conf_get_module_main_conf(
1155 | cf, ngx_nsoc_core_module);
1156 |
1157 | cmcf->variables_keys = ngx_pcalloc(
1158 | cf->temp_pool, sizeof(ngx_hash_keys_arrays_t));
1159 | if (cmcf->variables_keys == NULL) {
1160 | return NGX_ERROR;
1161 | }
1162 |
1163 | cmcf->variables_keys->pool = cf->pool;
1164 | cmcf->variables_keys->temp_pool = cf->pool;
1165 |
1166 | if (ngx_hash_keys_array_init(cmcf->variables_keys, NGX_HASH_SMALL) != NGX_OK) {
1167 | return NGX_ERROR;
1168 | }
1169 |
1170 | if (ngx_array_init(
1171 | &cmcf->prefix_variables, cf->pool, 8,
1172 | sizeof(ngx_nsoc_variable_t)) != NGX_OK) {
1173 | return NGX_ERROR;
1174 | }
1175 |
1176 | for (cv = ngx_nsoc_core_variables; cv->name.len; cv++) {
1177 | v = ngx_nsoc_add_variable(cf, &cv->name, cv->flags);
1178 | if (v == NULL) {
1179 | return NGX_ERROR;
1180 | }
1181 |
1182 | *v = *cv;
1183 | }
1184 |
1185 | return NGX_OK;
1186 | }
1187 |
1188 | ngx_int_t ngx_nsoc_variables_init_vars(ngx_conf_t *cf)
1189 | {
1190 | size_t len;
1191 | ngx_uint_t i, n;
1192 | ngx_hash_key_t *key;
1193 | ngx_hash_init_t hash;
1194 | ngx_nsoc_variable_t *v, *av, *pv;
1195 | ngx_nsoc_core_main_conf_t *cmcf;
1196 |
1197 | /* set the handlers for the indexed stream variables */
1198 |
1199 | cmcf = ngx_nsoc_conf_get_module_main_conf(
1200 | cf, ngx_nsoc_core_module);
1201 |
1202 | v = cmcf->variables.elts;
1203 | pv = cmcf->prefix_variables.elts;
1204 | key = cmcf->variables_keys->keys.elts;
1205 |
1206 | for (i = 0; i < cmcf->variables.nelts; i++) {
1207 |
1208 | for (n = 0; n < cmcf->variables_keys->keys.nelts; n++) {
1209 |
1210 | av = key[n].value;
1211 |
1212 | if (v[i].name.len == key[n].key.len
1213 | && ngx_strncmp(
1214 | v[i].name.data, key[n].key.data, v[i].name.len)
1215 | == 0) {
1216 | v[i].get_handler = av->get_handler;
1217 | v[i].data = av->data;
1218 |
1219 | av->flags |= NGX_NSOC_VAR_INDEXED;
1220 | v[i].flags = av->flags;
1221 |
1222 | av->index = i;
1223 |
1224 | if (av->get_handler == NULL
1225 | || (av->flags & NGX_NSOC_VAR_WEAK)) {
1226 | break;
1227 | }
1228 |
1229 | goto next;
1230 | }
1231 | }
1232 |
1233 | len = 0;
1234 | av = NULL;
1235 |
1236 | for (n = 0; n < cmcf->prefix_variables.nelts; n++) {
1237 | if (v[i].name.len >= pv[n].name.len && v[i].name.len > len
1238 | && ngx_strncmp(
1239 | v[i].name.data, pv[n].name.data, pv[n].name.len)
1240 | == 0) {
1241 | av = &pv[n];
1242 | len = pv[n].name.len;
1243 | }
1244 | }
1245 |
1246 | if (av) {
1247 | v[i].get_handler = av->get_handler;
1248 | v[i].data = (uintptr_t) &v[i].name;
1249 | v[i].flags = av->flags;
1250 |
1251 | goto next;
1252 | }
1253 |
1254 | if (v[i].get_handler == NULL) {
1255 | ngx_log_error(
1256 | NGX_LOG_EMERG, cf->log, 0, "unknown \"%V\" variable",
1257 | &v[i].name);
1258 | return NGX_ERROR;
1259 | }
1260 |
1261 | next: continue;
1262 | }
1263 |
1264 | for (n = 0; n < cmcf->variables_keys->keys.nelts; n++) {
1265 | av = key[n].value;
1266 |
1267 | if (av->flags & NGX_NSOC_VAR_NOHASH) {
1268 | key[n].key.data = NULL;
1269 | }
1270 | }
1271 |
1272 | hash.hash = &cmcf->variables_hash;
1273 | hash.key = ngx_hash_key;
1274 | hash.max_size = cmcf->variables_hash_max_size;
1275 | hash.bucket_size = cmcf->variables_hash_bucket_size;
1276 | hash.name = "variables_hash";
1277 | hash.pool = cf->pool;
1278 | hash.temp_pool = NULL;
1279 |
1280 | if (ngx_hash_init(
1281 | &hash, cmcf->variables_keys->keys.elts,
1282 | cmcf->variables_keys->keys.nelts) != NGX_OK) {
1283 | return NGX_ERROR;
1284 | }
1285 |
1286 | cmcf->variables_keys = NULL;
1287 |
1288 | return NGX_OK;
1289 | }
1290 |
--------------------------------------------------------------------------------
/ngx_nsoc_variables.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Igor Sysoev
3 | * Copyright (C) Nginx, Inc.
4 | */
5 |
6 | #ifndef _NGX_NSOC_VARIABLES_H_INCLUDED_
7 | #define _NGX_NSOC_VARIABLES_H_INCLUDED_
8 |
9 | #include
10 | #include
11 | #include "ngx_nsoc.h"
12 |
13 | typedef ngx_variable_value_t ngx_nsoc_variable_value_t;
14 |
15 | #define ngx_nsoc_variable(v) { sizeof(v) - 1, 1, 0, 0, 0, (u_char *) v }
16 |
17 | typedef struct ngx_nsoc_variable_s ngx_nsoc_variable_t;
18 |
19 | typedef void (*ngx_nsoc_set_variable_pt)(ngx_nsoc_session_t *s,
20 | ngx_nsoc_variable_value_t *v, uintptr_t data);
21 | typedef ngx_int_t (*ngx_nsoc_get_variable_pt)(
22 | ngx_nsoc_session_t *s, ngx_nsoc_variable_value_t *v,
23 | uintptr_t data);
24 |
25 | #define NGX_NSOC_VAR_CHANGEABLE 1
26 | #define NGX_NSOC_VAR_NOCACHEABLE 2
27 | #define NGX_NSOC_VAR_INDEXED 4
28 | #define NGX_NSOC_VAR_NOHASH 8
29 | #define NGX_NSOC_VAR_WEAK 16
30 | #define NGX_NSOC_VAR_PREFIX 32
31 |
32 | struct ngx_nsoc_variable_s {
33 | ngx_str_t name; /* must be first to build the hash */
34 | ngx_nsoc_set_variable_pt set_handler;
35 | ngx_nsoc_get_variable_pt get_handler;
36 | uintptr_t data;
37 | ngx_uint_t flags;
38 | ngx_uint_t index;
39 | };
40 |
41 | ngx_nsoc_variable_t *ngx_nsoc_add_variable(ngx_conf_t *cf,
42 | ngx_str_t *name, ngx_uint_t flags);
43 | ngx_int_t ngx_nsoc_get_variable_index(ngx_conf_t *cf, ngx_str_t *name);
44 | ngx_nsoc_variable_value_t *ngx_nsoc_get_indexed_variable(
45 | ngx_nsoc_session_t *s, ngx_uint_t index);
46 | ngx_nsoc_variable_value_t *ngx_nsoc_get_flushed_variable(
47 | ngx_nsoc_session_t *s, ngx_uint_t index);
48 |
49 | ngx_nsoc_variable_value_t *ngx_nsoc_get_variable(
50 | ngx_nsoc_session_t *s, ngx_str_t *name, ngx_uint_t key);
51 |
52 | #if (NGX_PCRE)
53 |
54 | typedef struct {
55 | ngx_uint_t capture;
56 | ngx_int_t index;
57 | } ngx_nsoc_regex_variable_t;
58 |
59 | typedef struct {
60 | ngx_regex_t *regex;
61 | ngx_uint_t ncaptures;
62 | ngx_nsoc_regex_variable_t *variables;
63 | ngx_uint_t nvariables;
64 | ngx_str_t name;
65 | } ngx_nsoc_regex_t;
66 |
67 | typedef struct {
68 | ngx_nsoc_regex_t *regex;
69 | void *value;
70 | } ngx_nsoc_map_regex_t;
71 |
72 | ngx_nsoc_regex_t *ngx_nsoc_regex_compile(ngx_conf_t *cf,
73 | ngx_regex_compile_t *rc);
74 | ngx_int_t ngx_nsoc_regex_exec(ngx_nsoc_session_t *s,
75 | ngx_nsoc_regex_t *re, ngx_str_t *str);
76 |
77 | #endif
78 |
79 | typedef struct {
80 | ngx_hash_combined_t hash;
81 | #if (NGX_PCRE)
82 | ngx_nsoc_map_regex_t *regex;
83 | ngx_uint_t nregex;
84 | #endif
85 | } ngx_nsoc_map_t;
86 |
87 | void *ngx_nsoc_map_find(ngx_nsoc_session_t *s,
88 | ngx_nsoc_map_t *map, ngx_str_t *match);
89 |
90 | ngx_int_t ngx_nsoc_variables_add_core_vars(ngx_conf_t *cf);
91 | ngx_int_t ngx_nsoc_variables_init_vars(ngx_conf_t *cf);
92 |
93 | extern ngx_nsoc_variable_value_t ngx_nsoc_variable_null_value;
94 | extern ngx_nsoc_variable_value_t ngx_nsoc_variable_true_value;
95 |
96 | #endif /* _NGX_NSOC_VARIABLES_H_INCLUDED_ */
97 |
--------------------------------------------------------------------------------
/ngx_nsoc_write_filter_module.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Igor Sysoev
3 | * Copyright (C) Nginx, Inc.
4 | */
5 |
6 | #include
7 | #include
8 |
9 | #include "ngx_nsoc.h"
10 |
11 | typedef struct {
12 | ngx_chain_t *from_upstream;
13 | ngx_chain_t *from_downstream;
14 | } ngx_nsoc_write_filter_ctx_t;
15 |
16 | static ngx_int_t ngx_nsoc_write_filter(ngx_nsoc_session_t *s,
17 | ngx_chain_t *in, ngx_uint_t from_upstream);
18 | static ngx_int_t ngx_nsoc_write_filter_init(ngx_conf_t *cf);
19 |
20 | static ngx_nsoc_module_t ngx_nsoc_write_filter_module_ctx =
21 | {
22 | NULL, /* preconfiguration */
23 | ngx_nsoc_write_filter_init, /* postconfiguration */
24 |
25 | NULL, /* create main configuration */
26 | NULL, /* init main configuration */
27 |
28 | NULL, /* create server configuration */
29 | NULL /* merge server configuration */
30 | };
31 |
32 | ngx_module_t ngx_nsoc_write_filter_module =
33 | {
34 | NGX_MODULE_V1,
35 | &ngx_nsoc_write_filter_module_ctx, /* module context */
36 | NULL, /* module directives */
37 | NGX_NSOC_MODULE, /* module type */
38 | NULL, /* init master */
39 | NULL, /* init module */
40 | NULL, /* init process */
41 | NULL, /* init thread */
42 | NULL, /* exit thread */
43 | NULL, /* exit process */
44 | NULL, /* exit master */
45 | NGX_MODULE_V1_PADDING
46 | };
47 |
48 | static ngx_int_t ngx_nsoc_write_filter(ngx_nsoc_session_t *s,
49 | ngx_chain_t *in, ngx_uint_t from_upstream)
50 | {
51 | off_t size;
52 | ngx_uint_t last, flush, sync;
53 | ngx_chain_t *cl, *ln, **ll, **out, *chain;
54 | ngx_connection_t *c;
55 | ngx_nsoc_write_filter_ctx_t *ctx;
56 |
57 | ctx = ngx_nsoc_get_module_ctx(
58 | s, ngx_nsoc_write_filter_module);
59 |
60 | if (ctx == NULL) {
61 | ctx = ngx_pcalloc(
62 | s->connection->pool,
63 | sizeof(ngx_nsoc_write_filter_ctx_t));
64 | if (ctx == NULL) {
65 | return NGX_ERROR;
66 | }
67 |
68 | ngx_nsoc_set_ctx(s, ctx, ngx_nsoc_write_filter_module);
69 | }
70 |
71 | if (from_upstream) {
72 | c = s->connection;
73 | out = &ctx->from_upstream;
74 | } else {
75 | c = s->upstream->peer.connection;
76 | out = &ctx->from_downstream;
77 | }
78 |
79 | if (c->error) {
80 | return NGX_ERROR;
81 | }
82 |
83 | size = 0;
84 | flush = 0;
85 | sync = 0;
86 | last = 0;
87 | ll = out;
88 |
89 | /* find the size, the flush point and the last link of the saved chain */
90 |
91 | for (cl = *out; cl; cl = cl->next) {
92 | ll = &cl->next;
93 |
94 | ngx_log_debug7(
95 | NGX_LOG_DEBUG_EVENT, c->log, 0,
96 | "write old buf t:%d f:%d %p, pos %p, size: %z "
97 | "file: %O, size: %O", cl->buf->temporary,
98 | cl->buf->in_file, cl->buf->start, cl->buf->pos,
99 | cl->buf->last - cl->buf->pos, cl->buf->file_pos,
100 | cl->buf->file_last - cl->buf->file_pos);
101 |
102 | #if 1
103 | if (ngx_buf_size(cl->buf) == 0 && !ngx_buf_special(cl->buf)) {
104 | ngx_log_error(
105 | NGX_LOG_ALERT, c->log, 0, "zero size buf in writer "
106 | "t:%d r:%d f:%d %p %p-%p %p %O-%O",
107 | cl->buf->temporary, cl->buf->recycled, cl->buf->in_file,
108 | cl->buf->start, cl->buf->pos, cl->buf->last, cl->buf->file,
109 | cl->buf->file_pos, cl->buf->file_last);
110 |
111 | ngx_debug_point();
112 | return NGX_ERROR;
113 | }
114 | #endif
115 |
116 | size += ngx_buf_size(cl->buf);
117 |
118 | if (cl->buf->flush || cl->buf->recycled) {
119 | flush = 1;
120 | }
121 |
122 | if (cl->buf->sync) {
123 | sync = 1;
124 | }
125 |
126 | if (cl->buf->last_buf) {
127 | last = 1;
128 | }
129 | }
130 |
131 | /* add the new chain to the existent one */
132 |
133 | for (ln = in; ln; ln = ln->next) {
134 | cl = ngx_alloc_chain_link(c->pool);
135 | if (cl == NULL) {
136 | return NGX_ERROR;
137 | }
138 |
139 | cl->buf = ln->buf;
140 | *ll = cl;
141 | ll = &cl->next;
142 |
143 | ngx_log_debug7(
144 | NGX_LOG_DEBUG_EVENT, c->log, 0,
145 | "write new buf t:%d f:%d %p, pos %p, size: %z "
146 | "file: %O, size: %O", cl->buf->temporary,
147 | cl->buf->in_file, cl->buf->start, cl->buf->pos,
148 | cl->buf->last - cl->buf->pos, cl->buf->file_pos,
149 | cl->buf->file_last - cl->buf->file_pos);
150 |
151 | #if 1
152 | if (ngx_buf_size(cl->buf) == 0 && !ngx_buf_special(cl->buf)) {
153 | ngx_log_error(
154 | NGX_LOG_ALERT, c->log, 0, "zero size buf in writer "
155 | "t:%d r:%d f:%d %p %p-%p %p %O-%O",
156 | cl->buf->temporary, cl->buf->recycled, cl->buf->in_file,
157 | cl->buf->start, cl->buf->pos, cl->buf->last, cl->buf->file,
158 | cl->buf->file_pos, cl->buf->file_last);
159 |
160 | ngx_debug_point();
161 | return NGX_ERROR;
162 | }
163 | #endif
164 |
165 | size += ngx_buf_size(cl->buf);
166 |
167 | if (cl->buf->flush || cl->buf->recycled) {
168 | flush = 1;
169 | }
170 |
171 | if (cl->buf->sync) {
172 | sync = 1;
173 | }
174 |
175 | if (cl->buf->last_buf) {
176 | last = 1;
177 | }
178 | }
179 |
180 | *ll = NULL;
181 |
182 | ngx_log_debug3(
183 | NGX_LOG_DEBUG_STREAM, c->log, 0,
184 | "NOISE write filter: l:%ui f:%ui s:%O", last, flush, size);
185 |
186 | if (size == 0 && !(c->buffered & NGX_LOWLEVEL_BUFFERED)
187 | && !(last && c->need_last_buf)) {
188 | if (last || flush || sync) {
189 | for (cl = *out; cl; /* void */) {
190 | ln = cl;
191 | cl = cl->next;
192 | ngx_free_chain(c->pool, ln);
193 | }
194 |
195 | *out = NULL;
196 | c->buffered &= ~NGX_NSOC_WRITE_BUFFERED;
197 |
198 | return NGX_OK;
199 | }
200 |
201 | ngx_log_error(
202 | NGX_LOG_ALERT, c->log, 0, "the nsoc output chain is empty");
203 |
204 | ngx_debug_point();
205 |
206 | return NGX_ERROR;
207 | }
208 |
209 | chain = c->send_chain(c, *out, 0);
210 |
211 | ngx_log_debug1(
212 | NGX_LOG_DEBUG_EVENT, c->log, 0, "nsoc write filter %p", chain);
213 |
214 | if (chain == NGX_CHAIN_ERROR) {
215 | c->error = 1;
216 | return NGX_ERROR;
217 | }
218 |
219 | for (cl = *out; cl && cl != chain; /* void */) {
220 | ln = cl;
221 | cl = cl->next;
222 | ngx_free_chain(c->pool, ln);
223 | }
224 |
225 | *out = chain;
226 |
227 | if (chain) {
228 | if (c->shared) {
229 | ngx_log_error(
230 | NGX_LOG_ALERT, c->log, 0, "shared connection is busy");
231 | return NGX_ERROR;
232 | }
233 |
234 | c->buffered |= NGX_NSOC_WRITE_BUFFERED;
235 | return NGX_AGAIN;
236 | }
237 |
238 | c->buffered &= ~NGX_NSOC_WRITE_BUFFERED;
239 |
240 | if (c->buffered & NGX_LOWLEVEL_BUFFERED) {
241 | return NGX_AGAIN;
242 | }
243 |
244 | return NGX_OK;
245 | }
246 |
247 | static ngx_int_t ngx_nsoc_write_filter_init(ngx_conf_t *cf)
248 | {
249 | ngx_nsoc_top_filter = ngx_nsoc_write_filter;
250 |
251 | return NGX_OK;
252 | }
253 |
--------------------------------------------------------------------------------