├── .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 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 |
https://localhost/->internal redirect to `noise_socket` context->proxy to backend over noise socket--->
--->`noise_socket` context on the backend server->internal redirect to http context->access to the static page index.html "Welcome to nginx!"
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 | --------------------------------------------------------------------------------