Merge pull request #1575 from opnsense/ngx_busy_buffers

[www/nginx] #1561 advanced buffering
This commit is contained in:
Fabian Franz BSc 2019-11-10 19:14:34 +01:00 committed by GitHub
commit 10727e3102
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 205 additions and 32 deletions

View File

@ -1,5 +1,5 @@
PLUGIN_NAME= nginx
PLUGIN_VERSION= 1.15
PLUGIN_VERSION= 1.16
PLUGIN_COMMENT= Nginx HTTP server and reverse proxy
PLUGIN_DEPENDS= nginx
PLUGIN_MAINTAINER= franz.fabian.94@gmail.com

View File

@ -8,6 +8,10 @@ reuse, SSL offload and HTTP media streaming.
Plugin Changelog
================
1.16
* advanced buffering configuration in location (#1575)
1.15
* add OCSP stapling and verify

View File

@ -242,6 +242,34 @@
<advanced>true</advanced>
<help>Enter a custom timout between data received from the client after which the connection is closed.</help>
</field>
<field>
<id>location.proxy_buffer_size</id>
<label>Proxy Buffer Size (kB)</label>
<type>text</type>
<help>By default this is the size of one page (4 or 8 Kilobytes). It can be changed.</help>
<advanced>true</advanced>
</field>
<field>
<id>location.proxy_buffers_count</id>
<label>Proxy Buffers: Count</label>
<type>text</type>
<advanced>true</advanced>
<help>Count of buffers for a single connection.</help>
</field>
<field>
<id>location.proxy_buffers_size</id>
<label>Proxy Buffers: Size (kB)</label>
<type>text</type>
<advanced>true</advanced>
<help>Size of buffers of a single connection</help>
</field>
<field>
<id>location.proxy_busy_buffers_size</id>
<label>Proxy Busy Buffers Size (kB)</label>
<type>text</type>
<advanced>true</advanced>
<help>When this buffer size is reached, nginx will send a part of the response to the client.</help>
</field>
<field>
<id>location.proxy_send_timeout</id>
<label>Proxy Send Timeout</label>

View File

@ -0,0 +1,96 @@
<?php
/*
* Copyright (C) 2019 Fabian Franz
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
namespace OPNsense\Base\Constraints;
use \Phalcon\Validation\Message;
/**
* a very specific nginx check - not reusable
*
* Class NgxBusyBufferConstraint
* @package OPNsense\Nginx\Constraints
*/
class NgxBusyBufferConstraint extends BaseConstraint
{
public function validate(\Phalcon\Validation $validator, $attribute)
{
$node = $this->getOption('node');
if ($node) {
$parentNode = $node->getParentNode();
if (!$this->isEmpty($node)) {
$proxy_buffer_size_node = $parentNode->proxy_buffer_size;
$proxy_buffers_count_node = $parentNode->proxy_buffers_count;
$proxy_buffers_size_node = $parentNode->proxy_buffers_size;
$proxy_busy_buffers_size_node = $parentNode->proxy_busy_buffers_size;
if(!$this->isEmpty($proxy_buffers_count_node) && !$this->isEmpty($proxy_buffers_size_node)) {
$proxy_buffers_count_int = intval((string) $proxy_buffers_count_node);
$proxy_buffers_size_int = intval((string) $proxy_buffers_size_node);
$proxy_buffers_total_minus1_size = ($proxy_buffers_count_int - 1) * $proxy_buffers_size_int;
}
if (!$this->isEmpty($proxy_busy_buffers_size_node)) {
$proxy_busy_buffers_size = intval((string) $proxy_busy_buffers_size_node);
}
if (!$this->isEmpty($proxy_buffer_size_node)) {
$proxy_buffer_size_int = intval((string) $proxy_buffer_size_node);
}
if (isset($proxy_buffers_total_minus1_size) && isset($proxy_busy_buffers_size) &&
$proxy_buffers_total_minus1_size < $proxy_busy_buffers_size) {
$validator->appendMessage(new Message(
gettext("Proxy Buffer Size must be less than the size of all Proxy Buffers minus one buffer."),
$attribute,
$this->getOption('name')));
}
// nginx: [emerg] "proxy_busy_buffers_size" must be equal to or greater than the maximum of the value of "proxy_buffer_size" and one of the "proxy_buffers"
if (isset($proxy_busy_buffers_size) && isset($proxy_buffers_size_int) &&
$proxy_busy_buffers_size < $proxy_buffers_size_int) {
$validator->appendMessage(new Message(
gettext("Proxy Busy Buffers Size must be equal to or greater than the maximum of one of the Proxy Buffers."),
$attribute,
$this->getOption('name')));
}
// nginx: [emerg] "proxy_busy_buffers_size" must be equal to or greater than the maximum of the value of "proxy_buffer_size" and one of the "proxy_buffers"
if (isset($proxy_busy_buffers_size) && isset($proxy_buffer_size_int) &&
$proxy_busy_buffers_size < $proxy_buffer_size_int) {
$validator->appendMessage(new Message(
gettext("Proxy Busy Buffers Size must be equal to or greater than the maximum of the value of Proxy Buffer Size."),
$attribute,
$this->getOption('name')));
}
}
}
return true;
}
}

View File

@ -367,6 +367,42 @@
<Required>Y</Required>
<default>0</default>
</websocket>
<proxy_buffer_size type="IntegerField">
<Required>N</Required>
<minValue>1</minValue>
<Constraints>
<check001>
<type>NgxBusyBufferConstraint</type>
</check001>
</Constraints>
</proxy_buffer_size>
<proxy_buffers_count type="IntegerField">
<Required>N</Required>
<minValue>1</minValue>
<Constraints>
<check001>
<type>NgxBusyBufferConstraint</type>
</check001>
</Constraints>
</proxy_buffers_count>
<proxy_buffers_size type="IntegerField">
<Required>N</Required>
<minValue>1</minValue>
<Constraints>
<check001>
<type>NgxBusyBufferConstraint</type>
</check001>
</Constraints>
</proxy_buffers_size>
<proxy_busy_buffers_size type="IntegerField">
<Required>N</Required>
<minValue>1</minValue>
<Constraints>
<check001>
<type>NgxBusyBufferConstraint</type>
</check001>
</Constraints>
</proxy_busy_buffers_size>
<proxy_ignore_client_abort type="BooleanField">
<Required>Y</Required>
<default>0</default>

View File

@ -87,36 +87,45 @@ location {{ location.matchtype }} {{ location.urlpattern }} {
fastcgi_param TLS-Protocol $ssl_protocol;
fastcgi_param TLS-SNI-Host $ssl_server_name;
fastcgi_param TLS-Client-Intercepted $tls_intercepted;
{% if server.zero_rtt == '1' %}
{% if server.zero_rtt == '1' %}
fastcgi_param Early-Data $ssl_early_data;
{% endif %}
fastcgi_intercept_errors off;
{% if location.upstream is not defined %}
fastcgi_pass unix:/var/run/php-www.socket;
{% if location.php_override_scriptname is defined and location.php_override_scriptname != '' %}
fastcgi_param SCRIPT_FILENAME $document_root/{{ location.php_override_scriptname }};
{% else %}
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
{% endif %}
{% else %}
fastcgi_intercept_errors off;
{% if location.upstream is not defined %}
fastcgi_pass unix:/var/run/php-www.socket;
{% if location.php_override_scriptname is defined and location.php_override_scriptname != '' %}
fastcgi_param SCRIPT_FILENAME $document_root/{{ location.php_override_scriptname }};
{% else %}
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
{% endif %}
{% else %}
fastcgi_pass upstream{{ location.upstream.replace('-','') }};
fastcgi_connect_timeout 10s;
{% if location.php_override_scriptname is defined and location.php_override_scriptname != '' %}
{% if location.php_override_scriptname is defined and location.php_override_scriptname != '' %}
fastcgi_param SCRIPT_FILENAME {{ location.php_override_scriptname }};
{% else %}
{% else %}
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
{% endif %}
{% endif %}
{% endif %}
{% endif%}
{% if location.upstream is defined and (location.php_enable is not defined or location.php_enable != '1') %}
{% set upstream = helpers.getUUID(location.upstream) %}
{% set upstream = helpers.getUUID(location.upstream) %}
proxy_set_header Host $host;
{% if location.websocket is defined and location.websocket == '1' %}
{% if location.websocket is defined and location.websocket == '1' %}
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
{% endif %}
{% if location.cache_path is defined and location.cache_path != '' %}
{% endif %}
{% if location.proxy_buffer_size is defined and location.proxy_buffer_size != '' %}
proxy_buffer_size {{ location.proxy_buffer_size }}k;
{% endif %}
{% if location.proxy_buffers_count is defined and location.proxy_buffers_count != '' and location.proxy_buffers_size is defined and location.proxy_buffers_size != '' %}
proxy_buffers {{ location.proxy_buffers_count }} {{ location.proxy_buffers_size }}k;
{% endif %}
{% if location.proxy_busy_buffers_size is defined and location.proxy_busy_buffers_size != '' %}
proxy_busy_buffers_size {{ location.proxy_busy_buffers_size }}k;
{% endif %}
{% if location.cache_path is defined and location.cache_path != '' %}
proxy_cache {{ location.cache_path.replace('-', '') }};
{% if location.cache_use_stale is defined and location.cache_use_stale != '' %}
proxy_cache_use_stale {{ location.cache_use_stale.replace(',', ' ') }};
@ -131,35 +140,35 @@ location {{ location.matchtype }} {{ location.urlpattern }} {
proxy_set_header X-TLS-Protocol $ssl_protocol;
proxy_set_header X-TLS-SNI-Host $ssl_server_name;
# proxy headers for backend server
{% if server.verify_client != 'off' %}
{% if server.verify_client != 'off' %}
proxy_set_header X-Client-Dn $ssl_client_s_dn;
proxy_set_header X-Client-Verify $ssl_client_verify;
{% endif %}
{% if server.verify_client == 'optional_no_ca' %}
{% endif %}
{% if server.verify_client == 'optional_no_ca' %}
proxy_set_header X-Client-Certificate $ssl_client_escaped_cert;
{% endif %}
{% if server.zero_rtt == '1' %}
{% endif %}
{% if server.zero_rtt == '1' %}
proxy_set_header Early-Data $ssl_early_data;
{% endif %}
{% endif %}
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-TLS-Client-Intercepted $tls_intercepted;
{% if location.proxy_read_timeout is defined and location.proxy_read_timeout != '' %}
{% if location.proxy_read_timeout is defined and location.proxy_read_timeout != '' %}
proxy_read_timeout {{ location.proxy_read_timeout }}s;
{% endif %}
{% if location.proxy_send_timeout is defined and location.proxy_send_timeout != '' %}
{% endif %}
{% if location.proxy_send_timeout is defined and location.proxy_send_timeout != '' %}
proxy_send_timeout {{ location.proxy_send_timeout }}s;
{% endif %}
{% endif %}
proxy_ignore_client_abort {% if location.proxy_ignore_client_abort == '1' %}on{% else %}off{% endif %};
proxy_request_buffering {% if location.proxy_request_buffering == '1' %}on{% else %}off{% endif %};
proxy_max_temp_file_size {% if location.proxy_max_temp_file_size is defined %}{{ location.proxy_max_temp_file_size }}{% else %}1024{% endif %}m;
proxy_buffering {% if location.proxy_buffering == '1' %}on{% else %}off{% endif %};
{% if location.path_prefix is defined and location.path_prefix != '' %}
{% if location.path_prefix is defined and location.path_prefix != '' %}
proxy_pass http{% if upstream.tls_enable == '1' %}s{% endif %}://upstream{{ location.upstream.replace('-','') }}{{ location.path_prefix }};
{% else %}
{% else %}
proxy_pass http{% if upstream.tls_enable == '1' %}s{% endif %}://upstream{{ location.upstream.replace('-','') }};
{% endif %}
{% endif %}
{% if upstream.tls_enable == '1' %}
{% if upstream.tls_client_certificate is defined and upstream.tls_client_certificate != '' %}
proxy_ssl_certificate_key /usr/local/etc/nginx/key/{{ upstream.tls_client_certificate }}.key;
@ -190,6 +199,6 @@ location {{ location.matchtype }} {{ location.urlpattern }} {
proxy_hide_header {{ our_header }};
{% endfor %}
{% endif %}
{% endif %}
{% endif %}{# honeypot #}
}