From 6dbb36a53793b920e073fc633a4e3c6bd3922b10 Mon Sep 17 00:00:00 2001 From: Konstantin Pavlov Date: Fri, 5 Feb 2021 14:48:52 +0300 Subject: Docker: added curl run-time dependency. It is needed for docker-entrypoint scripts to work. --- pkg/docker/template.Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/docker/template.Dockerfile b/pkg/docker/template.Dockerfile index d96d7982..55feecc6 100644 --- a/pkg/docker/template.Dockerfile +++ b/pkg/docker/template.Dockerfile @@ -61,7 +61,7 @@ RUN set -x \ --shell /bin/false \ unit \ && apt update \ - && apt --no-install-recommends --no-install-suggests -y install $(cat /requirements.apt) \ + && apt --no-install-recommends --no-install-suggests -y install curl $(cat /requirements.apt) \ && apt-get clean && rm -rf /var/lib/apt/lists/* \ && rm -f /requirements.apt \ && ln -sf /dev/stdout /var/log/unit.log -- cgit From 958bc90caafeaa4cd6b4d6894d0a67284ba13900 Mon Sep 17 00:00:00 2001 From: Konstantin Pavlov Date: Fri, 5 Feb 2021 15:54:51 +0300 Subject: Regenerated Dockerfiles. --- pkg/docker/Dockerfile.go1.15 | 2 +- pkg/docker/Dockerfile.jsc11 | 2 +- pkg/docker/Dockerfile.minimal | 2 +- pkg/docker/Dockerfile.node15 | 2 +- pkg/docker/Dockerfile.perl5.32 | 2 +- pkg/docker/Dockerfile.php8.0 | 2 +- pkg/docker/Dockerfile.python3.9 | 2 +- pkg/docker/Dockerfile.ruby2.7 | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pkg/docker/Dockerfile.go1.15 b/pkg/docker/Dockerfile.go1.15 index 270dc428..ea83d2df 100644 --- a/pkg/docker/Dockerfile.go1.15 +++ b/pkg/docker/Dockerfile.go1.15 @@ -63,7 +63,7 @@ RUN set -x \ --shell /bin/false \ unit \ && apt update \ - && apt --no-install-recommends --no-install-suggests -y install $(cat /requirements.apt) \ + && apt --no-install-recommends --no-install-suggests -y install curl $(cat /requirements.apt) \ && apt-get clean && rm -rf /var/lib/apt/lists/* \ && rm -f /requirements.apt \ && ln -sf /dev/stdout /var/log/unit.log diff --git a/pkg/docker/Dockerfile.jsc11 b/pkg/docker/Dockerfile.jsc11 index cde7c590..abb21023 100644 --- a/pkg/docker/Dockerfile.jsc11 +++ b/pkg/docker/Dockerfile.jsc11 @@ -61,7 +61,7 @@ RUN set -x \ --shell /bin/false \ unit \ && apt update \ - && apt --no-install-recommends --no-install-suggests -y install $(cat /requirements.apt) \ + && apt --no-install-recommends --no-install-suggests -y install curl $(cat /requirements.apt) \ && apt-get clean && rm -rf /var/lib/apt/lists/* \ && rm -f /requirements.apt \ && ln -sf /dev/stdout /var/log/unit.log diff --git a/pkg/docker/Dockerfile.minimal b/pkg/docker/Dockerfile.minimal index 91fd79d0..7ff5057a 100644 --- a/pkg/docker/Dockerfile.minimal +++ b/pkg/docker/Dockerfile.minimal @@ -61,7 +61,7 @@ RUN set -x \ --shell /bin/false \ unit \ && apt update \ - && apt --no-install-recommends --no-install-suggests -y install $(cat /requirements.apt) \ + && apt --no-install-recommends --no-install-suggests -y install curl $(cat /requirements.apt) \ && apt-get clean && rm -rf /var/lib/apt/lists/* \ && rm -f /requirements.apt \ && ln -sf /dev/stdout /var/log/unit.log diff --git a/pkg/docker/Dockerfile.node15 b/pkg/docker/Dockerfile.node15 index 59b12012..a392045f 100644 --- a/pkg/docker/Dockerfile.node15 +++ b/pkg/docker/Dockerfile.node15 @@ -63,7 +63,7 @@ RUN set -x \ --shell /bin/false \ unit \ && apt update \ - && apt --no-install-recommends --no-install-suggests -y install $(cat /requirements.apt) \ + && apt --no-install-recommends --no-install-suggests -y install curl $(cat /requirements.apt) \ && apt-get clean && rm -rf /var/lib/apt/lists/* \ && rm -f /requirements.apt \ && ln -sf /dev/stdout /var/log/unit.log diff --git a/pkg/docker/Dockerfile.perl5.32 b/pkg/docker/Dockerfile.perl5.32 index 589eb989..a9813f47 100644 --- a/pkg/docker/Dockerfile.perl5.32 +++ b/pkg/docker/Dockerfile.perl5.32 @@ -61,7 +61,7 @@ RUN set -x \ --shell /bin/false \ unit \ && apt update \ - && apt --no-install-recommends --no-install-suggests -y install $(cat /requirements.apt) \ + && apt --no-install-recommends --no-install-suggests -y install curl $(cat /requirements.apt) \ && apt-get clean && rm -rf /var/lib/apt/lists/* \ && rm -f /requirements.apt \ && ln -sf /dev/stdout /var/log/unit.log diff --git a/pkg/docker/Dockerfile.php8.0 b/pkg/docker/Dockerfile.php8.0 index c31513d4..d4b02940 100644 --- a/pkg/docker/Dockerfile.php8.0 +++ b/pkg/docker/Dockerfile.php8.0 @@ -61,7 +61,7 @@ RUN set -x \ --shell /bin/false \ unit \ && apt update \ - && apt --no-install-recommends --no-install-suggests -y install $(cat /requirements.apt) \ + && apt --no-install-recommends --no-install-suggests -y install curl $(cat /requirements.apt) \ && apt-get clean && rm -rf /var/lib/apt/lists/* \ && rm -f /requirements.apt \ && ln -sf /dev/stdout /var/log/unit.log diff --git a/pkg/docker/Dockerfile.python3.9 b/pkg/docker/Dockerfile.python3.9 index 76f50733..29ce7f3b 100644 --- a/pkg/docker/Dockerfile.python3.9 +++ b/pkg/docker/Dockerfile.python3.9 @@ -61,7 +61,7 @@ RUN set -x \ --shell /bin/false \ unit \ && apt update \ - && apt --no-install-recommends --no-install-suggests -y install $(cat /requirements.apt) \ + && apt --no-install-recommends --no-install-suggests -y install curl $(cat /requirements.apt) \ && apt-get clean && rm -rf /var/lib/apt/lists/* \ && rm -f /requirements.apt \ && ln -sf /dev/stdout /var/log/unit.log diff --git a/pkg/docker/Dockerfile.ruby2.7 b/pkg/docker/Dockerfile.ruby2.7 index aa823756..a2fb0b26 100644 --- a/pkg/docker/Dockerfile.ruby2.7 +++ b/pkg/docker/Dockerfile.ruby2.7 @@ -61,7 +61,7 @@ RUN set -x \ --shell /bin/false \ unit \ && apt update \ - && apt --no-install-recommends --no-install-suggests -y install $(cat /requirements.apt) \ + && apt --no-install-recommends --no-install-suggests -y install curl $(cat /requirements.apt) \ && apt-get clean && rm -rf /var/lib/apt/lists/* \ && rm -f /requirements.apt \ && ln -sf /dev/stdout /var/log/unit.log -- cgit From 4404097e05dc71b7ee78ef49c8ba4d0eaf234f85 Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Mon, 8 Feb 2021 23:32:27 +0000 Subject: Tests: added "--restart" option. Now Unit do not restart after each test by default. --- test/conftest.py | 113 ++++++++++++++++++++++++++++++++++++-------- test/test_proxy.py | 1 + test/test_share_fallback.py | 7 ++- test/test_tls.py | 2 +- test/unit/utils.py | 2 +- 5 files changed, 103 insertions(+), 22 deletions(-) diff --git a/test/conftest.py b/test/conftest.py index b36aabad..35249a1f 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -1,9 +1,12 @@ import fcntl +import inspect +import json import os import platform import re import shutil import signal +import socket import stat import subprocess import sys @@ -16,6 +19,7 @@ from unit.check.go import check_go from unit.check.isolation import check_isolation from unit.check.node import check_node from unit.check.tls import check_openssl +from unit.http import TestHTTP from unit.option import option from unit.utils import public_dir from unit.utils import waitforfiles @@ -51,10 +55,18 @@ def pytest_addoption(parser): type=str, help="Default user for non-privileged processes of unitd", ) + parser.addoption( + "--restart", + default=False, + action="store_true", + help="Force Unit to restart after every test", + ) unit_instance = {} +unit_log_copy = "unit.log.copy" _processes = [] +http = TestHTTP() def pytest_configure(config): option.config = config.option @@ -64,6 +76,7 @@ def pytest_configure(config): option.save_log = config.option.save_log option.unsafe = config.option.unsafe option.user = config.option.user + option.restart = config.option.restart option.generated_tests = {} option.current_dir = os.path.abspath( @@ -172,12 +185,17 @@ def pytest_sessionstart(session): check_isolation() + assert 'success' in _clear_conf(unit['temp_dir'] + '/control.unit.sock') + unit_stop() _check_alerts() - shutil.rmtree(unit_instance['temp_dir']) + if option.restart: + shutil.rmtree(unit_instance['temp_dir']) + elif option.save_log: + open(unit_instance['temp_dir'] + '/' + unit_log_copy, 'w').close() @pytest.hookimpl(tryfirst=True, hookwrapper=True) def pytest_runtest_makereport(item, call): @@ -241,38 +259,74 @@ def run(request): # stop unit - error = unit_stop() + error_stop_unit = unit_stop() + error_stop_processes = stop_processes() - if error: - _print_log() + # prepare log - assert error is None, 'stop unit' + with open( + unit_instance['log'], 'r', encoding='utf-8', errors='ignore' + ) as f: + log = f.read() - # stop all processes + if not option.restart and option.save_log: + with open(unit_instance['temp_dir'] + '/' + unit_log_copy, 'a') as f: + f.write(log) - error = stop_processes() + # remove unit.log - if error: - _print_log() + if not option.save_log and option.restart: + shutil.rmtree(unit['temp_dir']) - assert error is None, 'stop unit' + # clean temp_dir before the next test - # check unit.log for alerts + if not option.restart: + conf_resp = _clear_conf(unit['temp_dir'] + '/control.unit.sock') - _check_alerts() + if 'success' not in conf_resp: + _print_log(log) + assert 'success' in conf_resp + + open(unit['log'], 'w').close() + + for item in os.listdir(unit['temp_dir']): + if item not in [ + 'control.unit.sock', + 'state', + 'unit.pid', + 'unit.log', + unit_log_copy, + ]: + path = os.path.join(unit['temp_dir'], item) + + public_dir(path) + + if os.path.isfile(path) or stat.S_ISSOCK(os.stat(path).st_mode): + os.remove(path) + else: + shutil.rmtree(path) # print unit.log in case of error if hasattr(request.node, 'rep_call') and request.node.rep_call.failed: - _print_log() + _print_log(log) - # remove unit.log + if error_stop_unit or error_stop_processes: + _print_log(log) - if not option.save_log: - shutil.rmtree(unit['temp_dir']) + # check unit.log for errors + + assert error_stop_unit is None, 'stop unit' + assert error_stop_processes is None, 'stop processes' + + _check_alerts(log=log) def unit_run(): global unit_instance + + if not option.restart and 'unitd' in unit_instance: + return unit_instance + build_dir = option.current_dir + '/build' unitd = build_dir + '/unitd' @@ -323,6 +377,12 @@ def unit_run(): def unit_stop(): + if not option.restart: + if inspect.stack()[1].function.startswith('test_'): + pytest.skip('no restart mode') + + return + p = unit_instance['process'] if p.poll() is not None: @@ -345,12 +405,13 @@ def unit_stop(): -def _check_alerts(path=None): +def _check_alerts(path=None, log=None): if path is None: path = unit_instance['log'] - with open(path, 'r', encoding='utf-8', errors='ignore') as f: - log = f.read() + if log is None: + with open(path, 'r', encoding='utf-8', errors='ignore') as f: + log = f.read() found = False @@ -396,6 +457,15 @@ def _print_log(data=None): sys.stdout.write(data) +def _clear_conf(sock): + return http.put( + url='/config', + sock_type='unix', + addr=sock, + body=json.dumps({"listeners": {}, "applications": {}}), + )['body'] + + def run_process(target, *args): global _processes @@ -446,5 +516,10 @@ def unit_pid(request): return unit_instance['process'].pid def pytest_sessionfinish(session): + if not option.restart and option.save_log: + print('Path to unit.log:\n' + unit_instance['log'] + '\n') + + option.restart = True + unit_stop() shutil.rmtree(option.cache_dir) diff --git a/test/test_proxy.py b/test/test_proxy.py index 2d305e98..7e7c7246 100644 --- a/test/test_proxy.py +++ b/test/test_proxy.py @@ -482,6 +482,7 @@ Content-Length: 10 check_proxy('http://[:]:7080') check_proxy('http://[::7080') + @pytest.mark.skip('not yet') def test_proxy_loop(self, skip_alert): skip_alert( r'socket.*failed', diff --git a/test/test_share_fallback.py b/test/test_share_fallback.py index a02cb1a3..46464670 100644 --- a/test/test_share_fallback.py +++ b/test/test_share_fallback.py @@ -1,5 +1,6 @@ import os +import pytest from unit.applications.proto import TestApplicationProto from unit.option import option @@ -27,7 +28,10 @@ class TestStatic(TestApplicationProto): ) def teardown_method(self): - os.chmod(option.temp_dir + '/assets/403', 0o777) + try: + os.chmod(option.temp_dir + '/assets/403', 0o777) + except FileNotFoundError: + pass def action_update(self, conf): assert 'success' in self.conf(conf, 'routes/0/action') @@ -116,6 +120,7 @@ class TestStatic(TestApplicationProto): assert resp['status'] == 200, 'fallback proxy status' assert resp['body'] == '', 'fallback proxy' + @pytest.mark.skip('not yet') def test_fallback_proxy_loop(self, skip_alert): skip_alert( r'open.*/blah/index.html.*failed', diff --git a/test/test_tls.py b/test/test_tls.py index 89c57d07..206ea828 100644 --- a/test/test_tls.py +++ b/test/test_tls.py @@ -199,7 +199,7 @@ class TestTLS(TestApplicationTLS): self.sec_epoch() - self.openssl_date_to_sec_epoch(cert['validity']['since']) ) - < 5 + < 60 ), 'certificate validity since' assert ( self.openssl_date_to_sec_epoch(cert['validity']['until']) diff --git a/test/unit/utils.py b/test/unit/utils.py index 7a0a3fe5..e80fc469 100644 --- a/test/unit/utils.py +++ b/test/unit/utils.py @@ -47,7 +47,7 @@ def waitforsocket(port): except KeyboardInterrupt: raise - pytest.fail('Can\'t connect to the 127.0.0.1:' + port) + pytest.fail('Can\'t connect to the 127.0.0.1:' + str(port)) def findmnt(): -- cgit From 11f7d833a9bad1fb3f066cee815fe9772bed4875 Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Wed, 10 Feb 2021 16:34:37 +0000 Subject: Tests: increased timeout in wait_for_record(). --- test/test_asgi_application.py | 2 +- test/test_python_application.py | 2 +- test/unit/applications/proto.py | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/test_asgi_application.py b/test/test_asgi_application.py index 5770265d..886a160b 100644 --- a/test/test_asgi_application.py +++ b/test/test_asgi_application.py @@ -377,7 +377,7 @@ Connection: close self.get(no_recv=True) assert ( - self.wait_for_record(r'\(5\) Thread: 100') is not None + self.wait_for_record(r'\(5\) Thread: 100', wait=50) is not None ), 'last thread finished' def test_asgi_application_threads(self): diff --git a/test/test_python_application.py b/test/test_python_application.py index 709df3ff..41f6f538 100644 --- a/test/test_python_application.py +++ b/test/test_python_application.py @@ -569,7 +569,7 @@ last line: 987654321 self.get(no_recv=True) assert ( - self.wait_for_record(r'\(5\) Thread: 100') is not None + self.wait_for_record(r'\(5\) Thread: 100', wait=50) is not None ), 'last thread finished' def test_python_application_iter_exception(self): diff --git a/test/unit/applications/proto.py b/test/unit/applications/proto.py index af05d071..5c400621 100644 --- a/test/unit/applications/proto.py +++ b/test/unit/applications/proto.py @@ -19,8 +19,8 @@ class TestApplicationProto(TestControl): with open(option.temp_dir + '/' + name, 'r', errors='ignore') as f: return re.search(pattern, f.read()) - def wait_for_record(self, pattern, name='unit.log'): - for i in range(50): + def wait_for_record(self, pattern, name='unit.log', wait=150): + for i in range(wait): found = self.search_in_log(pattern, name) if found is not None: -- cgit From cf530e19bc5cc0de67bd57a650a0adf3d58e0881 Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Mon, 15 Feb 2021 03:11:26 +0000 Subject: Tests: clear certificates after each test. --- test/conftest.py | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/test/conftest.py b/test/conftest.py index 35249a1f..b49fb377 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -185,7 +185,7 @@ def pytest_sessionstart(session): check_isolation() - assert 'success' in _clear_conf(unit['temp_dir'] + '/control.unit.sock') + _clear_conf(unit['temp_dir'] + '/control.unit.sock') unit_stop() @@ -281,11 +281,7 @@ def run(request): # clean temp_dir before the next test if not option.restart: - conf_resp = _clear_conf(unit['temp_dir'] + '/control.unit.sock') - - if 'success' not in conf_resp: - _print_log(log) - assert 'success' in conf_resp + _clear_conf(unit['temp_dir'] + '/control.unit.sock', log) open(unit['log'], 'w').close() @@ -457,14 +453,39 @@ def _print_log(data=None): sys.stdout.write(data) -def _clear_conf(sock): - return http.put( +def _clear_conf(sock, log=None): + def check_success(resp): + if 'success' not in resp: + _print_log(log) + assert 'success' in resp + + resp = http.put( url='/config', sock_type='unix', addr=sock, body=json.dumps({"listeners": {}, "applications": {}}), )['body'] + check_success(resp) + + try: + certs = json.loads(http.get( + url='/certificates', + sock_type='unix', + addr=sock, + )['body']).keys() + + except json.JSONDecodeError: + pytest.fail('Can\'t parse certificates list.') + + for cert in certs: + resp = http.delete( + url='/certificates/' + cert, + sock_type='unix', + addr=sock, + )['body'] + + check_success(resp) def run_process(target, *args): global _processes -- cgit From ecd0fc5d81541e1263a7cc35c632242e33c4082e Mon Sep 17 00:00:00 2001 From: Valentin Bartenev Date: Tue, 16 Feb 2021 18:54:00 +0300 Subject: Version bump. --- docs/changes.xml | 8 ++++++++ version | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/docs/changes.xml b/docs/changes.xml index 6cf8e849..02a8653f 100644 --- a/docs/changes.xml +++ b/docs/changes.xml @@ -5,6 +5,14 @@ + + + + + + diff --git a/version b/version index 55e5da42..6d66d5f1 100644 --- a/version +++ b/version @@ -1,5 +1,5 @@ # Copyright (C) NGINX, Inc. -NXT_VERSION=1.22.0 -NXT_VERNUM=12200 +NXT_VERSION=1.23.0 +NXT_VERNUM=12300 -- cgit From af3b6ef37d0d8d4d9e27d77a750419d96e0119bc Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Thu, 18 Feb 2021 21:21:55 +0000 Subject: Tests: added regex check. --- test/conftest.py | 2 ++ test/test_routing.py | 12 ++++++++++++ test/unit/check/regex.py | 13 +++++++++++++ 3 files changed, 27 insertions(+) create mode 100644 test/unit/check/regex.py diff --git a/test/conftest.py b/test/conftest.py index b49fb377..e75f9208 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -19,6 +19,7 @@ from unit.check.go import check_go from unit.check.isolation import check_isolation from unit.check.node import check_node from unit.check.tls import check_openssl +from unit.check.regex import check_regex from unit.http import TestHTTP from unit.option import option from unit.utils import public_dir @@ -176,6 +177,7 @@ def pytest_sessionstart(session): option.current_dir, unit['temp_dir'], option.test_dir ) option.available['modules']['node'] = check_node(option.current_dir) + option.available['modules']['regex'] = check_regex(unit['unitd']) # remove None values diff --git a/test/test_routing.py b/test/test_routing.py index 4d27cb61..be9a1faf 100644 --- a/test/test_routing.py +++ b/test/test_routing.py @@ -229,6 +229,9 @@ class TestRouting(TestApplicationProto): assert self.get(url='/ABc')['status'] == 404 def test_routes_empty_regex(self): + if not option.available['modules']['regex']: + pytest.skip('requires regex') + self.route_match({"uri":"~"}) assert self.get(url='/')['status'] == 200, 'empty regexp' assert self.get(url='/anything')['status'] == 200, '/anything' @@ -238,6 +241,9 @@ class TestRouting(TestApplicationProto): assert self.get(url='/nothing')['status'] == 404, '/nothing' def test_routes_bad_regex(self): + if not option.available['modules']['regex']: + pytest.skip('requires regex') + assert 'error' in self.route( {"match": {"uri": "~/bl[ah"}, "action": {"return": 200}} ), 'bad regex' @@ -255,6 +261,9 @@ class TestRouting(TestApplicationProto): assert self.get(url='/nothing_z')['status'] == 500, '/nothing_z' def test_routes_match_regex_case_sensitive(self): + if not option.available['modules']['regex']: + pytest.skip('requires regex') + self.route_match({"uri": "~/bl[ah]"}) assert self.get(url='/rlah')['status'] == 404, '/rlah' @@ -263,6 +272,9 @@ class TestRouting(TestApplicationProto): assert self.get(url='/BLAH')['status'] == 404, '/BLAH' def test_routes_match_regex_negative_case_sensitive(self): + if not option.available['modules']['regex']: + pytest.skip('requires regex') + self.route_match({"uri": "!~/bl[ah]"}) assert self.get(url='/rlah')['status'] == 200, '/rlah' diff --git a/test/unit/check/regex.py b/test/unit/check/regex.py new file mode 100644 index 00000000..734c0150 --- /dev/null +++ b/test/unit/check/regex.py @@ -0,0 +1,13 @@ +import re +import subprocess + + +def check_regex(unitd): + output = subprocess.check_output( + [unitd, '--version'], stderr=subprocess.STDOUT + ) + + if re.search('--no-regex', output.decode()): + return False + + return True -- cgit From d0591f07d7681a66197ee9ea4104177f13ccf8df Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Tue, 23 Feb 2021 22:25:47 +0000 Subject: Tests: fixed tests to work without openssl support. --- test/conftest.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/conftest.py b/test/conftest.py index e75f9208..20ac6e81 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -470,6 +470,9 @@ def _clear_conf(sock, log=None): check_success(resp) + if 'openssl' not in option.available['modules']: + return + try: certs = json.loads(http.get( url='/certificates', -- cgit From fddde539c9cde818857f46c24eaa7d4e57eb9b44 Mon Sep 17 00:00:00 2001 From: Max Romanov Date: Tue, 2 Mar 2021 18:30:34 +0300 Subject: Fixing NetBSD compatibility. Instead of PTHREAD_STACK_MIN define, NetBSD requires to get minimum stack size using sysctl(_SC_THREAD_STACK_MIN). This change originally proposed by Juraj Lutter . --- src/nxt_conf_validation.c | 4 ++-- src/nxt_thread.h | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/nxt_conf_validation.c b/src/nxt_conf_validation.c index 67fa3095..0e6fc135 100644 --- a/src/nxt_conf_validation.c +++ b/src/nxt_conf_validation.c @@ -1459,10 +1459,10 @@ nxt_conf_vldt_thread_stack_size(nxt_conf_validation_t *vldt, size = nxt_conf_get_number(value); - if (size < PTHREAD_STACK_MIN) { + if (size < NXT_THREAD_STACK_MIN) { return nxt_conf_vldt_error(vldt, "The \"thread_stack_size\" number " "must be equal to or greater than %d.", - PTHREAD_STACK_MIN); + NXT_THREAD_STACK_MIN); } if ((size % nxt_pagesize) != 0) { diff --git a/src/nxt_thread.h b/src/nxt_thread.h index 2ebc331d..d7800cc6 100644 --- a/src/nxt_thread.h +++ b/src/nxt_thread.h @@ -142,6 +142,14 @@ nxt_thread_yield() \ #endif +#if (PTHREAD_STACK_MIN) +#define NXT_THREAD_STACK_MIN PTHREAD_STACK_MIN + +#else +#define NXT_THREAD_STACK_MIN sysconf(_SC_THREAD_STACK_MIN) +#endif + + struct nxt_thread_s { nxt_log_t *log; nxt_log_t main_log; -- cgit From 73ac0496feb38ef2098163847206d304cf2c9a73 Mon Sep 17 00:00:00 2001 From: Max Romanov Date: Tue, 2 Mar 2021 18:31:03 +0300 Subject: Fixing warnings on Solaris. pthread_t on Solaris is an integer type with size not equal to pointer size. To avoid warnings, type casts to and from pointer needs to be done via uintptr_t type. This change originally proposed by Juraj Lutter . --- src/nxt_router.c | 2 +- src/nxt_unit.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/nxt_router.c b/src/nxt_router.c index 03fe2a6c..4be4197a 100644 --- a/src/nxt_router.c +++ b/src/nxt_router.c @@ -3726,7 +3726,7 @@ nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, void *data) nxt_event_engine_t *engine; nxt_thread_handle_t handle; - handle = (nxt_thread_handle_t) obj; + handle = (nxt_thread_handle_t) (uintptr_t) obj; link = data; nxt_thread_wait(handle); diff --git a/src/nxt_unit.c b/src/nxt_unit.c index 2fef17c5..ae4499d8 100644 --- a/src/nxt_unit.c +++ b/src/nxt_unit.c @@ -3785,7 +3785,7 @@ nxt_unit_shm_open(nxt_unit_ctx_t *ctx, size_t size) char name[64]; snprintf(name, sizeof(name), NXT_SHM_PREFIX "unit.%d.%p", - lib->pid, (void *) pthread_self()); + lib->pid, (void *) (uintptr_t) pthread_self()); #endif #if (NXT_HAVE_MEMFD_CREATE) -- cgit From 1950d0aee2bc95f1cb6a07349f11eb5e5f6edf5c Mon Sep 17 00:00:00 2001 From: Max Romanov Date: Tue, 2 Mar 2021 19:33:37 +0300 Subject: Closing app outgoing shared memory file descriptor. This fixes file descriptor leakage in router. Shared memory file used to send data from router to application. These files are shared among all processes of same application and router keeps the opened file descriptor since 06017e6e3a5f commit. --- docs/changes.xml | 6 ++++++ src/nxt_port_memory.c | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/docs/changes.xml b/docs/changes.xml index 02a8653f..b8c76089 100644 --- a/docs/changes.xml +++ b/docs/changes.xml @@ -9,6 +9,12 @@ date="" time="" packager="Andrei Belov <defan@nginx.com>"> + + +a descriptor leak occurring in the router process when removing or +reconfiguring an application; the bug had appeared in 1.19.0. + + diff --git a/src/nxt_port_memory.c b/src/nxt_port_memory.c index ae9f079c..bffae8a1 100644 --- a/src/nxt_port_memory.c +++ b/src/nxt_port_memory.c @@ -34,6 +34,10 @@ nxt_port_mmap_handler_use(nxt_port_mmap_handler_t *mmap_handler, int i) mmap_handler->hdr = NULL; } + if (mmap_handler->fd != -1) { + nxt_fd_close(mmap_handler->fd); + } + nxt_free(mmap_handler); } } @@ -238,6 +242,7 @@ nxt_port_incoming_port_mmap(nxt_task_t *task, nxt_process_t *process, } mmap_handler->hdr = hdr; + mmap_handler->fd = -1; if (nxt_slow_path(hdr->src_pid != process->pid || hdr->dst_pid != nxt_pid)) -- cgit From a1107e859b5f401261d378fc251667bcf2272536 Mon Sep 17 00:00:00 2001 From: Valentin Bartenev Date: Mon, 15 Mar 2021 14:57:01 +0300 Subject: Fixed TLS connection shutdown on errors. An immediate return statement on connection errors was mistakenly added to the beginning of nxt_openssl_conn_io_shutdown() in ecd3c5bbf7d8, breaking the TLS connection finalization procedure. As a result, a TLS connection was left unfinalized if it had been closed prematurely or a fatal protocol error had occurred, which caused memory and socket descriptor leakage. Moreover, in some cases (notably, on handshake errors in tests with kqueue on macOS) the read event was triggered later and nxt_h1p_conn_error() was called the second time; after the change in af93c866b4f0, the latter call crashed the router process in an attempt to remove a connection from the idle queue twice. --- docs/changes.xml | 14 ++++++++++++++ src/nxt_openssl.c | 4 ---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/docs/changes.xml b/docs/changes.xml index b8c76089..d9d25e5c 100644 --- a/docs/changes.xml +++ b/docs/changes.xml @@ -9,6 +9,20 @@ date="" time="" packager="Andrei Belov <defan@nginx.com>"> + + +the router process could crash on premature TLS connection close; the bug had +appeared in 1.17.0. + + + + + +a connection leak occurring on premature TLS connection close; the bug had +appeared in 1.6. + + + a descriptor leak occurring in the router process when removing or diff --git a/src/nxt_openssl.c b/src/nxt_openssl.c index 832d1f0d..3c0212f7 100644 --- a/src/nxt_openssl.c +++ b/src/nxt_openssl.c @@ -720,10 +720,6 @@ nxt_openssl_conn_io_shutdown(nxt_task_t *task, void *obj, void *data) nxt_debug(task, "openssl conn shutdown fd:%d", c->socket.fd); - if (c->socket.error != 0) { - return; - } - c->read_state = NULL; tls = c->u.tls; -- cgit From b0a1266835386590c65ec433759c5cc1063bd472 Mon Sep 17 00:00:00 2001 From: Valentin Bartenev Date: Mon, 15 Mar 2021 14:57:31 +0300 Subject: Fixed certificates loading on startup with some filesystems. It appears that readdir() on Linux detects file types unreliably, always setting the "d_type" field to DT_UNKNOWN for some less common filesystems. As a result, all files were skipped and no certificate bundles were found when the state directory was located on such filesystems. Skipping "." and ".." instead of any non-regular files should be enough, as no other non-regular files normally appear in this directory. This closes #368 issue on GitHub. --- docs/changes.xml | 7 +++++++ src/nxt_cert.c | 10 ++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/docs/changes.xml b/docs/changes.xml index d9d25e5c..07decb2a 100644 --- a/docs/changes.xml +++ b/docs/changes.xml @@ -30,6 +30,13 @@ reconfiguring an application; the bug had appeared in 1.19.0. + + +persistent storage of certificates might've not worked with some filesystems in +Linux, and all uploaded certificate bundles were forgotten after restart. + + + diff --git a/src/nxt_cert.c b/src/nxt_cert.c index 9e825d80..357a9211 100644 --- a/src/nxt_cert.c +++ b/src/nxt_cert.c @@ -838,7 +838,12 @@ nxt_cert_store_load(nxt_task_t *task, nxt_mp_t *mp) break; } - if (de->d_type != DT_REG) { + nxt_debug(task, "readdir(\"%s\"): \"%s\"", rt->certs.start, de->d_name); + + name.length = nxt_strlen(de->d_name); + name.start = (u_char *) de->d_name; + + if (nxt_str_eq(&name, ".", 1) || nxt_str_eq(&name, "..", 2)) { continue; } @@ -849,9 +854,6 @@ nxt_cert_store_load(nxt_task_t *task, nxt_mp_t *mp) item->fd = -1; - name.length = nxt_strlen(de->d_name); - name.start = (u_char *) de->d_name; - size = rt->certs.length + name.length + 1; if (size > alloc) { -- cgit From 4c261a7ff8f2b2af08cc2cdee6828af4a1cf7794 Mon Sep 17 00:00:00 2001 From: Valentin Bartenev Date: Mon, 15 Mar 2021 15:03:32 +0300 Subject: Ruby: fixed encodings initialization. The Ruby interpreter expects an explicit setlocale() call before initialization to pick up character encodings in the "Encoding" class from the environment. This closes #531 issue on GitHub. --- docs/changes.xml | 6 ++++++ src/ruby/nxt_ruby.c | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/docs/changes.xml b/docs/changes.xml index 07decb2a..2f68083d 100644 --- a/docs/changes.xml +++ b/docs/changes.xml @@ -37,6 +37,12 @@ Linux, and all uploaded certificate bundles were forgotten after restart. + + +the Ruby module didn't respect user locale for defaults in the Encoding class. + + + diff --git a/src/ruby/nxt_ruby.c b/src/ruby/nxt_ruby.c index 0aad887d..ca14af5b 100644 --- a/src/ruby/nxt_ruby.c +++ b/src/ruby/nxt_ruby.c @@ -12,6 +12,8 @@ #include NXT_RUBY_MOUNTS_H +#include + #define NXT_RUBY_RACK_API_VERSION_MAJOR 1 #define NXT_RUBY_RACK_API_VERSION_MINOR 3 @@ -200,6 +202,8 @@ nxt_ruby_start(nxt_task_t *task, nxt_process_data_t *data) nxt_ruby_threads = c->threads; + setlocale(LC_CTYPE, ""); + RUBY_INIT_STACK ruby_init(); ruby_options(2, argv); -- cgit From 99337728edbc38ac979b0f23805dbe74920a6bc2 Mon Sep 17 00:00:00 2001 From: Valentin Bartenev Date: Mon, 15 Mar 2021 15:03:32 +0300 Subject: Fixed building the PHP 5 module with ZTS, broken by dab8544b5440. This closes #525 issue on GitHub. --- docs/changes.xml | 7 +++++++ src/nxt_php_sapi.c | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/docs/changes.xml b/docs/changes.xml index 2f68083d..22adc2dd 100644 --- a/docs/changes.xml +++ b/docs/changes.xml @@ -43,6 +43,13 @@ the Ruby module didn't respect user locale for defaults in the Encoding class. + + +the PHP 5 module failed to build with thread safety enabled; the bug had +appeared in 1.22.0. + + + diff --git a/src/nxt_php_sapi.c b/src/nxt_php_sapi.c index 369e7f32..8fbe7f65 100644 --- a/src/nxt_php_sapi.c +++ b/src/nxt_php_sapi.c @@ -1041,7 +1041,11 @@ nxt_php_execute(nxt_php_run_ctx_t *ctx, nxt_unit_request_t *r) if (r->authorization_field != NXT_UNIT_NONE_FIELD) { f = r->fields + r->authorization_field; +#ifdef NXT_PHP7 php_handle_auth_data(nxt_unit_sptr_get(&f->value)); +#else + php_handle_auth_data(nxt_unit_sptr_get(&f->value) TSRMLS_CC); +#endif } else { SG(request_info).auth_digest = NULL; -- cgit From 175ef1c1dbe5a8fb65b1fbb4adb8a56a16b08569 Mon Sep 17 00:00:00 2001 From: "Sergey A. Osokin" Date: Mon, 22 Mar 2021 17:15:12 +0300 Subject: Java: upgrading third-party components. --- auto/modules/java | 8 ++++---- auto/modules/java_jar.sha512 | 28 ++++++++++++++-------------- test/unit/applications/lang/java.py | 2 +- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/auto/modules/java b/auto/modules/java index 60415c35..05b3100c 100644 --- a/auto/modules/java +++ b/auto/modules/java @@ -238,7 +238,7 @@ cat << END > $NXT_JAVA_JARS static const char *nxt_java_system_jars[] = { END -NXT_TOMCAT_VERSION=9.0.39 +NXT_TOMCAT_VERSION=9.0.44 NXT_JAR_VERSION=$NXT_TOMCAT_VERSION @@ -271,7 +271,7 @@ NXT_JAR_NAME=tomcat-util . auto/modules/java_get_jar NXT_JAR_NAME=ecj -NXT_JAR_VERSION=3.23.0 +NXT_JAR_VERSION=3.25.0 NXT_JAR_NAMESPACE=org/eclipse/jdt/ . auto/modules/java_get_jar @@ -284,7 +284,7 @@ static const char *nxt_java_unit_jars[] = { "$NXT_UNIT_JAR", END -NXT_JAR_VERSION=9.4.33.v20201020 +NXT_JAR_VERSION=9.4.38.v20210224 NXT_JAR_NAMESPACE=org/eclipse/jetty/ NXT_JAR_NAME=jetty-util @@ -297,7 +297,7 @@ NXT_JAR_NAME=jetty-http . auto/modules/java_get_jar NXT_JAR_NAME=classgraph -NXT_JAR_VERSION=4.8.90 +NXT_JAR_VERSION=4.8.102 NXT_JAR_NAMESPACE=io/github/classgraph/ . auto/modules/java_get_jar diff --git a/auto/modules/java_jar.sha512 b/auto/modules/java_jar.sha512 index 214cff33..98d27149 100644 --- a/auto/modules/java_jar.sha512 +++ b/auto/modules/java_jar.sha512 @@ -1,14 +1,14 @@ -083f2102a50f2c3a4fc3993d328ddee17707b0529fdcee4868bd3b6901ff20a3d97e9733f83b2e46828469ecc273a1a3a5da26e4ba3d63f725a81b0b9e3e49e6 classgraph-4.8.90.jar -5e63e06eccd76a61249c7c6bd97e5b77dc37335bfdf316d941b00a16bae4f152d4306bac4e45c8422976187b0d77fe30cf7e6f6d4425f7732a3cb0cfa954385b ecj-3.23.0.jar -9abb4ba6802c39526b755429e3f41d641408f91f1c48844cd56cda116fb1479f05f1a3d90c18f30386b07d5593221c1f85ef565da0c6121b6ff005ec7d9c3bd9 jetty-http-9.4.33.v20201020.jar -e60e73ed3fd18e029c8e3cae04eac01d05f985dd0d9059eea620f4f9acac60799706d4b56b5a0f10cc33ff9272afdf11e712c604e31a77fa1afa1f95a57294ce jetty-server-9.4.33.v20201020.jar -35c5ad89d92e77f542d3ce42249f01c478706e2a013c5ab6a9504cf43520e3de90280d82a11389e9909060835421e3caada68e77d86df76a84856be60361d550 jetty-util-9.4.33.v20201020.jar -2d28d12196a7c2d342876d7e63c3a87fd613aadb32afad28d428d5dd9d9d0ebfa8300de3681d885455ac81d215326b11b845346416d5bd12d0e27c1763602caa tomcat-api-9.0.39.jar -661e613ae966e9b1fcc8815823c273fd7a05a6f8d3c469d86ce50650c1f350cbfb624fde8ee86235603078d9c5ccae5dfec8e03e10b5cb1e11109ae6ae4e85bb tomcat-el-api-9.0.39.jar -541d4794e1e15f26d7853cd7841f031e66fd3fc345102871cf58013591c8b57b6ab470d8ac28781c077f25e8d7fc06c19c6444db8e4a28ce4767ddbd907be004 tomcat-jasper-9.0.39.jar -57b916cb87f178604751f52f23f57fbd05da3001c9419602836e25d779727500bc1fceae195d5758aff28393b396751538f2ab7a9390738ebe4d0b4bd17b8ee4 tomcat-jasper-el-9.0.39.jar -d34deeecdecd59e40225ca3ad0ac197fc7f7845f09f551f5f17290ff9971741e62fac4bde16499d585b3d7c5574927c09740c0976dbddacecb19b4772f60c3e3 tomcat-jsp-api-9.0.39.jar -ee43f08f26e1d48c5cd3719e1eeec26e4ef389647a0bcd31435ed85c6c8770ab48fe287c60432aa8821b8fc8fce8ef0977a29b29c8c3b3cb246be53fb0182d1a tomcat-juli-9.0.39.jar -c387931fba85eae7ce030601dbd760cc7c2b0242a670b0c62321a8972e534076a40150044886053b3771099aa57c89057892d4f7fda84f65fa67b9c53dd51400 tomcat-servlet-api-9.0.39.jar -aa0b5ff10cdc686ba1dbc8a35d75aa42196126cbbde0d1ab1b9211ba57987a246bbe825c89a88104a0a60869fcbff4a8067bb247e42b69c887d6b48ee5c4a417 tomcat-util-9.0.39.jar -42c4b698cfb0a1fb154e290ac265c14693a9ef094e54116a324864f5b483f37d7a7decf67f7fe43b546cf1d2f25e9d763adc598a5e92979f756299e981dde43d tomcat-util-scan-9.0.39.jar +5105e9edf0fc6a4a51eb2bb1e2c23bb78a604fe2df3b1e814cf638ce22845a6ae57e75af31db9dd00d5c650403e751659cca8d3bc465fb96525c695188d2055f classgraph-4.8.102.jar +48cee25d195a5c713a962b035ecba633797753474f290c107a0ee96272cd9ae1b6b62b060ef37e0699f6a5af4d4b45e514ef710309f41bdd9440925cf60a111a ecj-3.25.0.jar +3f2a4a5b7f71c6a1317cec29ea12eb04eac68f4cee94c30ffb75fdd36dbc9c622059fb762e27f74f7b7a38eb84966732ba963cc294f5aaf8b7f5f8c9d60c8899 jetty-http-9.4.38.v20210224.jar +cc416b324841e9c259538a3ec678a9d8e07d3bea9b0bb687bc15a759c5065c7de6ea7bbbb15b369b8c6d2023c3294906d8f9cfda28e1b7859283008790581a4d jetty-server-9.4.38.v20210224.jar +efdbeae97c959459c10b05aae62189c535a0935dadf7debf4257257c31a98a4167ca1318daa81dae32161f51117b17468d5fb5a6bb4eea40864ce1265623d684 jetty-util-9.4.38.v20210224.jar +f2534f246c0cec9be576f18d67759b5a997074bb7870cbf7b9469f062ddc6932e5cec45fd439a5beacc8c6248d39dc458af81245a6eb988e294667f2bcd251df tomcat-api-9.0.44.jar +0c8050b04b02a6a1f1384d1a4041594c09868cfeb139978274c5e5797eb95e0668495f489eb61cfe742905e453184edc0ad8a9fd3b2796e960981a20ae4a0334 tomcat-el-api-9.0.44.jar +cc81a06795553f06d3dfe930429fdf47a8e0c1813c554b640d98090cc661c1eb27a91b9a9055bd14d918fc9451073632a635741dd413fd7b4a380d8907862e14 tomcat-jasper-9.0.44.jar +de50107ff31b8c5a7eb97fe86c2fdfa38305be632c8d62329219884dfb6bbe76372b40a67e808263a55b510a41cde639d55e7925d89db06472392519f0410063 tomcat-jasper-el-9.0.44.jar +69a79e58cea950b713f26a94e1db90221c297375a338f010d1332027ef5d93fd262163ec787b06d8cd41a4a31faa81bb4fc83836148eb14a6757591f6fe5f3c6 tomcat-jsp-api-9.0.44.jar +ca036312596dbd92ae43dda79a9a5ad168cf90a12369636fdc6febbedb559b83d5fa22d77629659b588d70990f8a077fd8356be1c56b0227e07688b67dd7c76e tomcat-juli-9.0.44.jar +952c122413805de16de603cfc233785e53b558b39f146b6fa4e11324e26572e4aee76fec2ee69adecc8f4271cd28acb917e1a9e61a908710b3582ab1f76c9706 tomcat-servlet-api-9.0.44.jar +6920bfb2b1ae173d716fedbf4f238003f569a161f277a888c2d53dac0af80ef0480c9ca3be0ede4583716c1b97c1cfa1665439d14274b7d73ec948fd9f952b89 tomcat-util-9.0.44.jar +915304750cbdffc4c9926fcb22eb928d2895cccd8b3f6f13aefb4e5302cccf5f513502b70812630026dd2968712c4c3b1cfe98d37ecf7b349988e7255ddc5b18 tomcat-util-scan-9.0.44.jar diff --git a/test/unit/applications/lang/java.py b/test/unit/applications/lang/java.py index b2e17f23..c9c2095e 100644 --- a/test/unit/applications/lang/java.py +++ b/test/unit/applications/lang/java.py @@ -52,7 +52,7 @@ class TestApplicationJava(TestApplicationProto): os.makedirs(classes_path) classpath = ( - option.current_dir + '/build/tomcat-servlet-api-9.0.39.jar' + option.current_dir + '/build/tomcat-servlet-api-9.0.44.jar' ) ws_jars = glob.glob( -- cgit From b04832da844d1c9e4ce7f7ff387059fbd07f78d3 Mon Sep 17 00:00:00 2001 From: Valentin Bartenev Date: Wed, 24 Mar 2021 08:05:07 +0300 Subject: Disabled logging alerts to syslog. It feels to be causing more harm than good, because syslog() can be blocking, which is even more critical under resource exhaustion conditions when some alerts are expected. --- src/nxt_app_log.c | 9 ++++++++- src/nxt_log.c | 9 ++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/nxt_app_log.c b/src/nxt_app_log.c index 0ecd9aac..ae57c2a2 100644 --- a/src/nxt_app_log.c +++ b/src/nxt_app_log.c @@ -19,7 +19,10 @@ static u_char *nxt_log_debug_time(u_char *buf, nxt_realtime_t *now, void nxt_cdecl nxt_log_time_handler(nxt_uint_t level, nxt_log_t *log, const char *fmt, ...) { - u_char *p, *syslogmsg, *end; + u_char *p, *end; +#if 0 + u_char *syslogmsg; +#endif va_list args; nxt_thread_t *thr; nxt_time_string_t *time_cache; @@ -34,7 +37,9 @@ nxt_log_time_handler(nxt_uint_t level, nxt_log_t *log, const char *fmt, ...) p = nxt_thread_time_string(thr, time_cache, msg); +#if 0 syslogmsg = p; +#endif #if 0 nxt_fid_t fid; @@ -79,6 +84,7 @@ nxt_log_time_handler(nxt_uint_t level, nxt_log_t *log, const char *fmt, ...) (void) nxt_write_console(nxt_stderr, msg, p - msg); +#if 0 if (level == NXT_LOG_ALERT) { *(p - nxt_length("\n")) = '\0'; @@ -88,6 +94,7 @@ nxt_log_time_handler(nxt_uint_t level, nxt_log_t *log, const char *fmt, ...) */ nxt_write_syslog(LOG_ALERT, syslogmsg); } +#endif } diff --git a/src/nxt_log.c b/src/nxt_log.c index 1c666961..58756816 100644 --- a/src/nxt_log.c +++ b/src/nxt_log.c @@ -66,7 +66,10 @@ nxt_log_set_ctx(nxt_log_t *log, nxt_log_ctx_handler_t handler, void *ctx) void nxt_cdecl nxt_log_handler(nxt_uint_t level, nxt_log_t *log, const char *fmt, ...) { - u_char *p, *syslogmsg, *end; + u_char *p, *end; +#if 0 + u_char *syslogmsg; +#endif va_list args; u_char msg[NXT_MAX_ERROR_STR]; @@ -79,7 +82,9 @@ nxt_log_handler(nxt_uint_t level, nxt_log_t *log, const char *fmt, ...) *p++ = ' '; } +#if 0 syslogmsg = p; +#endif p = nxt_sprintf(p, end, (log->ident != 0) ? "[%V] *%D " : "[%V] ", &nxt_log_levels[level], log->ident); @@ -100,6 +105,7 @@ nxt_log_handler(nxt_uint_t level, nxt_log_t *log, const char *fmt, ...) (void) nxt_write_console(nxt_stderr, msg, p - msg); +#if 0 if (level == NXT_LOG_ALERT) { *(p - nxt_length("\n")) = '\0'; @@ -109,4 +115,5 @@ nxt_log_handler(nxt_uint_t level, nxt_log_t *log, const char *fmt, ...) */ nxt_write_syslog(LOG_ALERT, syslogmsg); } +#endif } -- cgit From f267dd0a8da280d2a803b61c9a309fe51d60d95a Mon Sep 17 00:00:00 2001 From: Max Romanov Date: Wed, 24 Mar 2021 11:43:31 +0300 Subject: Workaround for an OpenSSL bug about not closing /dev/*random. This is a workaround for an issue in OpenSSL 1.1.1, where the /dev/random and /dev/urandom files remain open after all listening sockets were removed: - https://github.com/openssl/openssl/issues/7419 --- src/nxt_openssl.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/nxt_openssl.c b/src/nxt_openssl.c index 3c0212f7..835ca8b2 100644 --- a/src/nxt_openssl.c +++ b/src/nxt_openssl.c @@ -8,6 +8,7 @@ #include #include #include +#include typedef struct { @@ -355,6 +356,11 @@ fail: SSL_CTX_free(ctx); +#if (OPENSSL_VERSION_NUMBER >= 0x1010100fL \ + && OPENSSL_VERSION_NUMBER < 0x1010101fL) + RAND_keep_random_devices_open(0); +#endif + return NXT_ERROR; } @@ -442,6 +448,11 @@ static void nxt_openssl_server_free(nxt_task_t *task, nxt_tls_conf_t *conf) { SSL_CTX_free(conf->ctx); + +#if (OPENSSL_VERSION_NUMBER >= 0x1010100fL \ + && OPENSSL_VERSION_NUMBER < 0x1010101fL) + RAND_keep_random_devices_open(0); +#endif } -- cgit From 178f232b3ad36a763b3b5c2e0ef6f26cc1885229 Mon Sep 17 00:00:00 2001 From: Max Romanov Date: Wed, 24 Mar 2021 11:43:41 +0300 Subject: Tests: fixed racing condition in websocket test 5_15. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test case: "send a text message split into two fragments, then a continuation frame with FIN = false where there is nothing to continue, then an unfragmented text message, all sent in one chop". The test case investigates immediate connection closing since there is no message to continue. The mirror server may send a response for the first frame before the test сontinuation frame is received by the router. In this case, the test will receive a text frame before the close frame. --- test/test_asgi_websockets.py | 14 +++++++++++--- test/test_java_websockets.py | 14 +++++++++++--- test/test_node_websockets.py | 14 +++++++++++--- 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/test/test_asgi_websockets.py b/test/test_asgi_websockets.py index 6121fcc5..7218d526 100644 --- a/test/test_asgi_websockets.py +++ b/test/test_asgi_websockets.py @@ -30,8 +30,9 @@ class TestASGIWebsockets(TestApplicationPython): self.check_close(sock) - def check_close(self, sock, code=1000, no_close=False): - frame = self.ws.frame_read(sock) + def check_close(self, sock, code=1000, no_close=False, frame=None): + if frame == None: + frame = self.ws.frame_read(sock) assert frame['fin'] == True, 'close fin' assert frame['opcode'] == self.ws.OP_CLOSE, 'close opcode' @@ -930,7 +931,14 @@ class TestASGIWebsockets(TestApplicationPython): self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment2', fin=True) self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment3', fin=False) self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment4', fin=True) - self.check_close(sock, 1002) + + frame = self.ws.frame_read(sock) + + if frame['opcode'] == self.ws.OP_TEXT: + self.check_frame(frame, True, self.ws.OP_TEXT, 'fragment1fragment2') + frame = None + + self.check_close(sock, 1002, frame=frame) # 5_16 diff --git a/test/test_java_websockets.py b/test/test_java_websockets.py index 315c496d..df9e0885 100644 --- a/test/test_java_websockets.py +++ b/test/test_java_websockets.py @@ -27,8 +27,9 @@ class TestJavaWebsockets(TestApplicationJava): self.check_close(sock) - def check_close(self, sock, code=1000, no_close=False): - frame = self.ws.frame_read(sock) + def check_close(self, sock, code=1000, no_close=False, frame=None): + if frame == None: + frame = self.ws.frame_read(sock) assert frame['fin'] == True, 'close fin' assert frame['opcode'] == self.ws.OP_CLOSE, 'close opcode' @@ -862,7 +863,14 @@ class TestJavaWebsockets(TestApplicationJava): self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment2', fin=True) self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment3', fin=False) self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment4', fin=True) - self.check_close(sock, 1002) + + frame = self.ws.frame_read(sock) + + if frame['opcode'] == self.ws.OP_TEXT: + self.check_frame(frame, True, self.ws.OP_TEXT, 'fragment1fragment2') + frame = None + + self.check_close(sock, 1002, frame=frame) # 5_16 diff --git a/test/test_node_websockets.py b/test/test_node_websockets.py index 4f1e5906..d5f79811 100644 --- a/test/test_node_websockets.py +++ b/test/test_node_websockets.py @@ -27,8 +27,9 @@ class TestNodeWebsockets(TestApplicationNode): self.check_close(sock) - def check_close(self, sock, code=1000, no_close=False): - frame = self.ws.frame_read(sock) + def check_close(self, sock, code=1000, no_close=False, frame=None): + if frame == None: + frame = self.ws.frame_read(sock) assert frame['fin'] == True, 'close fin' assert frame['opcode'] == self.ws.OP_CLOSE, 'close opcode' @@ -881,7 +882,14 @@ class TestNodeWebsockets(TestApplicationNode): self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment2', fin=True) self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment3', fin=False) self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment4', fin=True) - self.check_close(sock, 1002) + + frame = self.ws.frame_read(sock) + + if frame['opcode'] == self.ws.OP_TEXT: + self.check_frame(frame, True, self.ws.OP_TEXT, 'fragment1fragment2') + frame = None + + self.check_close(sock, 1002, frame=frame) # 5_16 -- cgit From f18a41c84bb573607eaab9fec0c070cd159493f0 Mon Sep 17 00:00:00 2001 From: Valentin Bartenev Date: Wed, 24 Mar 2021 16:38:05 +0300 Subject: Certficates: fixed counting DNS SAN entries. Previously, entries of any type were counted during object allocation but only DNS type entries were actually processed. As a result, if some certificate entries had another type, returning information about the certificate caused uninitialized memory access. --- docs/changes.xml | 7 +++++++ src/nxt_cert.c | 7 +++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/docs/changes.xml b/docs/changes.xml index 22adc2dd..ad963c40 100644 --- a/docs/changes.xml +++ b/docs/changes.xml @@ -37,6 +37,13 @@ Linux, and all uploaded certificate bundles were forgotten after restart. + + +the controller process could crash while requesting information about a +certificate with a non-DNS SAN entry. + + + the Ruby module didn't respect user locale for defaults in the Encoding class. diff --git a/src/nxt_cert.c b/src/nxt_cert.c index 357a9211..0b986b0d 100644 --- a/src/nxt_cert.c +++ b/src/nxt_cert.c @@ -722,13 +722,16 @@ nxt_cert_name_details(nxt_mp_t *mp, X509 *x509, nxt_bool_t issuer) if (alt_names != NULL) { count = sk_GENERAL_NAME_num(alt_names); + n = 0; - for (n = 0; n != count; n++) { - name = sk_GENERAL_NAME_value(alt_names, n); + for (i = 0; i != count; i++) { + name = sk_GENERAL_NAME_value(alt_names, i); if (name->type != GEN_DNS) { continue; } + + n++; } names = nxt_conf_create_array(mp, n); -- cgit From a6c6dcf5f7856a96881373a2dbd1f14bda396c45 Mon Sep 17 00:00:00 2001 From: Valentin Bartenev Date: Wed, 24 Mar 2021 16:38:05 +0300 Subject: Certificates: moved SAN processing to a separate function. No functional changes. --- src/nxt_cert.c | 92 +++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 56 insertions(+), 36 deletions(-) diff --git a/src/nxt_cert.c b/src/nxt_cert.c index 0b986b0d..f3f4bace 100644 --- a/src/nxt_cert.c +++ b/src/nxt_cert.c @@ -46,6 +46,8 @@ static int nxt_nxt_cert_pem_suffix(char *pem_str, const char *suffix); static nxt_conf_value_t *nxt_cert_details(nxt_mp_t *mp, nxt_cert_t *cert); static nxt_conf_value_t *nxt_cert_name_details(nxt_mp_t *mp, X509 *x509, nxt_bool_t issuer); +static nxt_conf_value_t *nxt_cert_alt_names_details(nxt_mp_t *mp, + STACK_OF(GENERAL_NAME) *alt_names); static nxt_lvlhsh_t nxt_cert_info; @@ -654,7 +656,6 @@ nxt_cert_name_details(nxt_mp_t *mp, X509 *x509, nxt_bool_t issuer) nxt_str_t str; nxt_int_t ret; nxt_uint_t i, n, count; - GENERAL_NAME *name; nxt_conf_value_t *object, *names; STACK_OF(GENERAL_NAME) *alt_names; u_char buf[256]; @@ -721,46 +722,14 @@ nxt_cert_name_details(nxt_mp_t *mp, X509 *x509, nxt_bool_t issuer) } if (alt_names != NULL) { - count = sk_GENERAL_NAME_num(alt_names); - n = 0; + names = nxt_cert_alt_names_details(mp, alt_names); - for (i = 0; i != count; i++) { - name = sk_GENERAL_NAME_value(alt_names, i); - - if (name->type != GEN_DNS) { - continue; - } - - n++; - } + sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free); - names = nxt_conf_create_array(mp, n); if (nxt_slow_path(names == NULL)) { - goto fail; - } - - for (n = 0, i = 0; n != count; n++) { - name = sk_GENERAL_NAME_value(alt_names, n); - - if (name->type != GEN_DNS) { - continue; - } - - str.length = ASN1_STRING_length(name->d.dNSName); -#if OPENSSL_VERSION_NUMBER > 0x10100000L - str.start = (u_char *) ASN1_STRING_get0_data(name->d.dNSName); -#else - str.start = ASN1_STRING_data(name->d.dNSName); -#endif - - ret = nxt_conf_set_element_string_dup(names, mp, i++, &str); - if (nxt_slow_path(ret != NXT_OK)) { - goto fail; - } + return NULL; } - sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free); - nxt_conf_set_member(object, &alt_names_str, names, 1); } @@ -776,6 +745,57 @@ fail: } +static nxt_conf_value_t * +nxt_cert_alt_names_details(nxt_mp_t *mp, STACK_OF(GENERAL_NAME) *alt_names) +{ + nxt_str_t str; + nxt_int_t ret; + nxt_uint_t i, n, count; + GENERAL_NAME *name; + nxt_conf_value_t *array; + + count = sk_GENERAL_NAME_num(alt_names); + n = 0; + + for (i = 0; i != count; i++) { + name = sk_GENERAL_NAME_value(alt_names, i); + + if (name->type != GEN_DNS) { + continue; + } + + n++; + } + + array = nxt_conf_create_array(mp, n); + if (nxt_slow_path(array == NULL)) { + return NULL; + } + + for (n = 0, i = 0; n != count; n++) { + name = sk_GENERAL_NAME_value(alt_names, n); + + if (name->type != GEN_DNS) { + continue; + } + + str.length = ASN1_STRING_length(name->d.dNSName); +#if OPENSSL_VERSION_NUMBER > 0x10100000L + str.start = (u_char *) ASN1_STRING_get0_data(name->d.dNSName); +#else + str.start = ASN1_STRING_data(name->d.dNSName); +#endif + + ret = nxt_conf_set_element_string_dup(array, mp, i++, &str); + if (nxt_slow_path(ret != NXT_OK)) { + return NULL; + } + } + + return array; +} + + nxt_int_t nxt_cert_info_delete(nxt_str_t *name) { -- cgit From 699a3ea2ebc86f9e9dc9d59e1d9db488ac4ff352 Mon Sep 17 00:00:00 2001 From: Valentin Bartenev Date: Wed, 24 Mar 2021 16:55:47 +0300 Subject: Certificates: fixed in name attributes processing. The idea is to put SAN after CN, but the previous version of the code incorrectly assumed that CN was always present, which caused writes outside the allocated object if there were no standard name attributes. --- docs/changes.xml | 7 +++++++ src/nxt_cert.c | 41 ++++++++++++++++------------------------- 2 files changed, 23 insertions(+), 25 deletions(-) diff --git a/docs/changes.xml b/docs/changes.xml index ad963c40..3c25481a 100644 --- a/docs/changes.xml +++ b/docs/changes.xml @@ -44,6 +44,13 @@ certificate with a non-DNS SAN entry. + + +the controller process could crash on manipulations with a certificate +containing a SAN and no standart name attributes in subject or issuer. + + + the Ruby module didn't respect user locale for defaults in the Encoding class. diff --git a/src/nxt_cert.c b/src/nxt_cert.c index f3f4bace..3cdb69c1 100644 --- a/src/nxt_cert.c +++ b/src/nxt_cert.c @@ -690,12 +690,23 @@ nxt_cert_name_details(nxt_mp_t *mp, X509 *x509, nxt_bool_t issuer) NULL, NULL); if (alt_names != NULL) { + names = nxt_cert_alt_names_details(mp, alt_names); + + sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free); + + if (nxt_slow_path(names == NULL)) { + return NULL; + } + count++; + + } else { + names = NULL; } object = nxt_conf_create_object(mp, count); if (nxt_slow_path(object == NULL)) { - goto fail; + return NULL; } for (n = 0, i = 0; n != nxt_nitems(nids) && i != count; n++) { @@ -703,12 +714,12 @@ nxt_cert_name_details(nxt_mp_t *mp, X509 *x509, nxt_bool_t issuer) len = X509_NAME_get_text_by_NID(x509_name, nids[n].nid, (char *) buf, sizeof(buf)); - if (len < 0) { - continue; + if (n == 1 && names != NULL) { + nxt_conf_set_member(object, &alt_names_str, names, i++); } - if (i == 1 && alt_names != NULL) { - i++; + if (len < 0) { + continue; } str.length = len; @@ -717,31 +728,11 @@ nxt_cert_name_details(nxt_mp_t *mp, X509 *x509, nxt_bool_t issuer) ret = nxt_conf_set_member_string_dup(object, mp, &nids[n].name, &str, i++); if (nxt_slow_path(ret != NXT_OK)) { - goto fail; - } - } - - if (alt_names != NULL) { - names = nxt_cert_alt_names_details(mp, alt_names); - - sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free); - - if (nxt_slow_path(names == NULL)) { return NULL; } - - nxt_conf_set_member(object, &alt_names_str, names, 1); } return object; - -fail: - - if (alt_names != NULL) { - sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free); - } - - return NULL; } -- cgit From 4d28ea2e24d8815e65c100aa6256cc00dc9d5479 Mon Sep 17 00:00:00 2001 From: Artem Konev Date: Wed, 24 Mar 2021 15:43:16 +0000 Subject: Added a man page. Reviewed at https://rb.nginx.com/r/165/ --- docs/man/unitd.8.in | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 docs/man/unitd.8.in diff --git a/docs/man/unitd.8.in b/docs/man/unitd.8.in new file mode 100644 index 00000000..4d79d023 --- /dev/null +++ b/docs/man/unitd.8.in @@ -0,0 +1,79 @@ +.\" (C) 2017-2021, NGINX, Inc. +.\" +.Dd March 16, 2021 +.Dt UNITD 8 +.Os +.Sh NAME +.Nm unitd +.Nd "runs the NGINX Unit daemon" +.Sh SYNOPSIS +.Nm +.Op Fl Fl no-daemon +.Op Fl Fl control Ar socket +.Op Fl Fl group Ar name +.Op Fl Fl user Ar name +.Op Fl Fl log Ar file +.Op Fl Fl modules Ar directory +.Op Fl Fl pid Ar file +.Op Fl Fl state Ar directory +.Nm +.Op Fl h | Fl Fl help | v | Fl Fl version +.Sh DESCRIPTION +NGINX Unit is a polyglot app server, a reverse proxy, and a static file server +for UNIX-like systems. +It was built by +.Xr nginx 8 +team members from +scratch to be highly efficient and fully configurable at runtime. +.Sh OPTIONS +.Bl -tag -width indent +.It Fl h , Fl Fl help +Displays a summary of Unit's command-line options and their +compile-time defaults. +.It Fl v , Fl Fl version +Displays Unit's version and the +.Pa ./configure +settings it was built with. +.It Fl Fl no-daemon +Runs Unit in non-daemon mode. +.It Fl Fl control Ar socket +Overrides the control API's socket address in IPv4, IPv6, +or UNIX-domain format. +.It Fl Fl group Ar name , Fl Fl user Ar name +Override group name and user name used to run Unit's non-privileged processes. +.It Fl Fl log Ar file +Overrides the pathname for Unit's log. +.It Fl Fl modules Ar directory +Overrides the directory path for Unit's language modules +.Po Pa *.unit.so +.Pc files . +.It Fl Fl pid Ar file +Overrides the pathname for the PID file of Unit's main process. +.It Fl Fl state Ar directory +Overrides the directory path for Unit's state storage. +.El +.Sh EXIT STATUS +Exit status is 0 on success, or 1 if the daemon encounters an error. +.Sh FILES +.Bl -tag -width indent +.It Pa %%PID_PATH%% +The PID file of Unit's main process. +.It Pa %%ERROR_LOG_PATH%% +A general-purpose log for diagnostics and troubleshooting. +.Sh SOCKETS +.Bl -tag -width indent +.It Pa %%SOCKET_PATH%% +The socket address of Unit's control API. +.El +.Sh AUTHORS +(C) 2017-2021, NGINX, Inc. +.Sh SEE ALSO +.Pp +Website: +.Pa https://unit.nginx.org +.Pp +User mailing list: +.Pa https://mailman.nginx.org/mailman/listinfo/unit +.Pp +GitHub: +.Pa https://github.com/nginx/unit -- cgit From 6d7c6196e1ac412d1d9763c73e87afcd1cbf0ac4 Mon Sep 17 00:00:00 2001 From: Artem Konev Date: Wed, 24 Mar 2021 16:49:59 +0000 Subject: Added a missing .El directive in man page source. --- docs/man/unitd.8.in | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/man/unitd.8.in b/docs/man/unitd.8.in index 4d79d023..46182781 100644 --- a/docs/man/unitd.8.in +++ b/docs/man/unitd.8.in @@ -60,6 +60,7 @@ Exit status is 0 on success, or 1 if the daemon encounters an error. The PID file of Unit's main process. .It Pa %%ERROR_LOG_PATH%% A general-purpose log for diagnostics and troubleshooting. +.El .Sh SOCKETS .Bl -tag -width indent .It Pa %%SOCKET_PATH%% -- cgit From b33babcedaa032b901aa37aa57da46e6116509f0 Mon Sep 17 00:00:00 2001 From: Konstantin Pavlov Date: Wed, 24 Mar 2021 18:45:45 +0300 Subject: Added build system support for a man page. --- auto/help | 1 + auto/make | 33 +++++++++++++++++++++++++++------ auto/options | 6 ++++++ auto/summary | 1 + configure | 1 + docs/changes.xml | 6 ++++++ 6 files changed, 42 insertions(+), 6 deletions(-) diff --git a/auto/help b/auto/help index 31c68567..e2b81bc7 100644 --- a/auto/help +++ b/auto/help @@ -18,6 +18,7 @@ cat << END default: "$NXT_SBINDIR" --libdir=DIRECTORY set library directory name, default: "$NXT_LIBDIR" --incdir=DIRECTORY set includes directory name, default: "$NXT_INCDIR" + --mandir=DIRECTORY set man pages directory name, default: "$NXT_MANDIR" --modules=DIRECTORY set modules directory name, default: "$NXT_MODULES" --state=DIRECTORY set state directory name, default: "$NXT_STATE" --tmp=DIRECTORY set tmp directory name, default: "$NXT_TMP" diff --git a/auto/make b/auto/make index fcf258fa..18d23917 100644 --- a/auto/make +++ b/auto/make @@ -22,10 +22,11 @@ NXT_EXEC_LINK = $NXT_EXEC_LINK $NXT_LD_OPT NXT_SHARED_LOCAL_LINK = $NXT_SHARED_LOCAL_LINK $NXT_LD_OPT NXT_MODULE_LINK = $NXT_MODULE_LINK -all: $NXT_DAEMON +all: $NXT_DAEMON manpage -.PHONY: $NXT_DAEMON +.PHONY: $NXT_DAEMON manpage $NXT_DAEMON: $NXT_BUILD_DIR/$NXT_DAEMON +manpage: $NXT_BUILD_DIR/unitd.8 END @@ -305,6 +306,19 @@ $NXT_BUILD_DIR/$NXT_DAEMON: $NXT_BUILD_DIR/$NXT_LIB_STATIC \\ END +# unitd man page + +cat << END >> $NXT_MAKEFILE + +$NXT_BUILD_DIR/unitd.8: docs/man/unitd.8.in $NXT_BUILD_DIR/nxt_auto_config.h + sed -e "s|%%ERROR_LOG_PATH%%|$NXT_LOG|" \\ + -e "s|%%PID_PATH%%|$NXT_PID|" \\ + -e "s|%%SOCKET_PATH%%|$NXT_CONTROL|" \\ + < docs/man/unitd.8.in > \$@ + +END + + # unit object files. for nxt_src in $NXT_MAKE_SRCS @@ -334,9 +348,9 @@ done cat << END >> $NXT_MAKEFILE -.PHONY: install ${NXT_DAEMON}-install install-check +.PHONY: install ${NXT_DAEMON}-install install-check manpage-install -install: ${NXT_DAEMON}-install +install: ${NXT_DAEMON}-install manpage-install install-check: @test -n "\$(DESTDIR)$NXT_PREFIX" \\ @@ -352,15 +366,22 @@ ${NXT_DAEMON}-install: $NXT_DAEMON install-check install -p $NXT_BUILD_DIR/$NXT_DAEMON \$(DESTDIR)$NXT_SBINDIR/ install -d \$(DESTDIR)$NXT_STATE +manpage-install: manpage install-check + install -d \$(DESTDIR)$NXT_MANDIR/man8 + install -p $NXT_BUILD_DIR/unitd.8 \$(DESTDIR)$NXT_MANDIR/man8/ -.PHONY: uninstall ${NXT_DAEMON}-uninstall +.PHONY: uninstall ${NXT_DAEMON}-uninstall manpage-uninstall -uninstall: ${NXT_DAEMON}-uninstall +uninstall: ${NXT_DAEMON}-uninstall manpage-uninstall ${NXT_DAEMON}-uninstall: rm -f \$(DESTDIR)$NXT_SBINDIR/$NXT_DAEMON @rmdir -p \$(DESTDIR)$NXT_SBINDIR 2>/dev/null || true +manpage-uninstall: + rm -f \$(DESTDIR)$NXT_MANDIR/man8/unitd.8 + @rmdir -p \$(DESTDIR)$NXT_MANDIR/man8 2>/dev/null || true + END cat << END >> $NXT_MAKEFILE diff --git a/auto/options b/auto/options index b6007bc2..572d8a9b 100644 --- a/auto/options +++ b/auto/options @@ -59,6 +59,7 @@ do --sbindir=*) NXT_SBINDIR="$value" ;; --libdir=*) NXT_LIBDIR="$value" ;; --incdir=*) NXT_INCDIR="$value" ;; + --mandir=*) NXT_MANDIR="$value" ;; --modules=*) NXT_MODULES="$value" ;; --state=*) NXT_STATE="$value" ;; --tmp=*) NXT_TMP="$value" ;; @@ -144,6 +145,11 @@ case "$NXT_INCDIR" in *) NXT_INCDIR="$NXT_PREFIX$NXT_INCDIR" ;; esac +case "$NXT_MANDIR" in + /*) ;; + *) NXT_MANDIR="$NXT_PREFIX$NXT_MANDIR" ;; +esac + case "$NXT_MODULES" in /*) ;; *) NXT_MODULES="$NXT_PREFIX$NXT_MODULES" ;; diff --git a/auto/summary b/auto/summary index 833d20c0..84bfbb7f 100644 --- a/auto/summary +++ b/auto/summary @@ -11,6 +11,7 @@ Unit configuration summary: sbin directory: ............ "$NXT_SBINDIR" lib directory: ............. "$NXT_LIBDIR" include directory: ......... "$NXT_INCDIR" + man pages directory: ....... "$NXT_MANDIR" modules directory: ......... "$NXT_MODULES" state directory: ........... "$NXT_STATE" tmp directory: ............. "$NXT_TMP" diff --git a/configure b/configure index ece4f12a..c9264d59 100755 --- a/configure +++ b/configure @@ -35,6 +35,7 @@ NXT_BINDIR="bin" NXT_SBINDIR="sbin" NXT_LIBDIR="lib" NXT_INCDIR="include" +NXT_MANDIR="share/man" NXT_MODULES="modules" NXT_STATE="state" NXT_TMP="tmp" diff --git a/docs/changes.xml b/docs/changes.xml index 3c25481a..009866bb 100644 --- a/docs/changes.xml +++ b/docs/changes.xml @@ -9,6 +9,12 @@ date="" time="" packager="Andrei Belov <defan@nginx.com>"> + + +"--mandir" ./configure option to specify the directory for man page installation. + + + the router process could crash on premature TLS connection close; the bug had -- cgit From 4a2dcb46dd64e6cd23463127dbf95c80a2e33eb2 Mon Sep 17 00:00:00 2001 From: Konstantin Pavlov Date: Wed, 24 Mar 2021 18:45:45 +0300 Subject: Packages: added man page on debian-based systems. --- pkg/deb/Makefile | 2 +- pkg/deb/debian/rules.in | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/pkg/deb/Makefile b/pkg/deb/Makefile index 16e73b94..8c33fc53 100644 --- a/pkg/deb/Makefile +++ b/pkg/deb/Makefile @@ -227,7 +227,7 @@ endif debuild/unit_$(VERSION).orig.tar.gz: | debuild/$(SRCDIR)/debian cd ../.. && tar -czf pkg/deb/debuild/$(SRCDIR).tar.gz \ --transform "s#^#$(SRCDIR)/#" \ - LICENSE NOTICE CHANGES README configure auto src test version go + LICENSE NOTICE CHANGES README configure auto src test version go docs/man/unitd.8.in mv debuild/$(SRCDIR).tar.gz debuild/unit_$(VERSION).orig.tar.gz cd debuild && tar zxf unit_$(VERSION).orig.tar.gz diff --git a/pkg/deb/debian/rules.in b/pkg/deb/debian/rules.in index aa7921d1..c7a56b6b 100644 --- a/pkg/deb/debian/rules.in +++ b/pkg/deb/debian/rules.in @@ -33,6 +33,8 @@ config.env.%: cp -Pa $(CURDIR)/NOTICE $(BUILDDIR_$*)/ cp -Pa $(CURDIR)/README $(BUILDDIR_$*)/ cp -Pa $(CURDIR)/go $(BUILDDIR_$*)/ + mkdir -p $(BUILDDIR_$*)/docs/man + cp -Pa $(CURDIR)/docs/man/unitd.8.in $(BUILDDIR_$*)/docs/man/ touch $@ configure.unit: config.env.unit @@ -117,7 +119,7 @@ binary-indep: build install dh_testdir dh_testroot dh_installdocs - dh_installchangelogs + dh_installchangelogs dh_link dh_strip --dbg-package=unit-dbg dh_shlibdeps -- cgit From d62192738f2db9e22e1357daa7b7dccdce3c783f Mon Sep 17 00:00:00 2001 From: Konstantin Pavlov Date: Wed, 24 Mar 2021 18:45:45 +0300 Subject: Packages: added man page on rpm-based systems. --- pkg/rpm/Makefile | 2 +- pkg/rpm/unit.spec.in | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/rpm/Makefile b/pkg/rpm/Makefile index f0bd0cf9..75327c49 100644 --- a/pkg/rpm/Makefile +++ b/pkg/rpm/Makefile @@ -214,7 +214,7 @@ endif rpmbuild/SOURCES/unit-$(VERSION).tar.gz: cd ../.. && tar -czf pkg/rpm/rpmbuild/SOURCES/unit-$(VERSION).tar.gz \ --transform "s#^#unit-$(VERSION)/#" \ - LICENSE NOTICE CHANGES README configure auto src test version go + LICENSE NOTICE CHANGES README configure auto src test version go docs/man/unitd.8.in unit: check-build-depends-unit rpmbuild/SPECS/unit.spec rpmbuild/SOURCES/unit-$(VERSION).tar.gz @echo "===> Building $@ package" ; \ diff --git a/pkg/rpm/unit.spec.in b/pkg/rpm/unit.spec.in index 08db73e2..3a148b9d 100644 --- a/pkg/rpm/unit.spec.in +++ b/pkg/rpm/unit.spec.in @@ -98,7 +98,7 @@ Library and include files required for NGINX Unit modules development. %install %{__rm} -rf %{buildroot} %{__ln_s} build-nodebug build -DESTDIR=%{buildroot} make unitd-install libunit-install +DESTDIR=%{buildroot} make unitd-install libunit-install manpage-install %{__install} -m755 %{bdir}/build-debug/unitd \ %{buildroot}%{_sbindir}/unitd-debug %{__install} -m644 %{bdir}/build-debug/libunit.a \ @@ -205,6 +205,7 @@ BANNER %dir %{_sharedstatedir}/unit %dir %attr(0700,root,root) %{_localstatedir}/log/unit %config(noreplace) %{_sysconfdir}/logrotate.d/%{name} +%{_mandir}/man8/unitd.8* %files devel %{_libdir}/libunit.a -- cgit From d2b0882d89f29fea84b457e0709b6980c8a30a57 Mon Sep 17 00:00:00 2001 From: Andrey Suvorov Date: Wed, 24 Mar 2021 13:19:36 -0700 Subject: Added ability to configure multiple certificates on a listener. The certificate is selected by matching the arriving SNI to the common name and the alternatives names. If no certificate matches the name, the first bundle in the array is chosen. --- docs/changes.xml | 7 + src/nxt_conf_validation.c | 29 +++- src/nxt_openssl.c | 404 ++++++++++++++++++++++++++++++++++++++++++---- src/nxt_router.c | 123 ++++++++++---- src/nxt_tls.h | 29 +++- 5 files changed, 524 insertions(+), 68 deletions(-) diff --git a/docs/changes.xml b/docs/changes.xml index 009866bb..cca6bbc4 100644 --- a/docs/changes.xml +++ b/docs/changes.xml @@ -9,6 +9,13 @@ date="" time="" packager="Andrei Belov <defan@nginx.com>"> + + +support for multiple certificate bundles on a listener via Server Name +Indication (SNI) TLS extension. + + + "--mandir" ./configure option to specify the directory for man page installation. diff --git a/src/nxt_conf_validation.c b/src/nxt_conf_validation.c index 0e6fc135..8c5d1ec7 100644 --- a/src/nxt_conf_validation.c +++ b/src/nxt_conf_validation.c @@ -87,6 +87,8 @@ static nxt_int_t nxt_conf_vldt_listener(nxt_conf_validation_t *vldt, #if (NXT_TLS) static nxt_int_t nxt_conf_vldt_certificate(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, void *data); +static nxt_int_t nxt_conf_vldt_certificate_element(nxt_conf_validation_t *vldt, + nxt_conf_value_t *value); #endif static nxt_int_t nxt_conf_vldt_action(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, void *data); @@ -354,7 +356,7 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_listener_members[] = { static nxt_conf_vldt_object_t nxt_conf_vldt_tls_members[] = { { .name = nxt_string("certificate"), - .type = NXT_CONF_VLDT_STRING, + .type = NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY, .validator = nxt_conf_vldt_certificate, }, @@ -1826,10 +1828,35 @@ nxt_conf_vldt_match_patterns_set_member(nxt_conf_validation_t *vldt, static nxt_int_t nxt_conf_vldt_certificate(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, void *data) +{ + if (nxt_conf_type(value) == NXT_CONF_ARRAY) { + if (nxt_conf_array_elements_count(value) == 0) { + return nxt_conf_vldt_error(vldt, "The \"certificate\" array " + "must contain at least one element."); + } + + return nxt_conf_vldt_array_iterator(vldt, value, + &nxt_conf_vldt_certificate_element); + } + + /* NXT_CONF_STRING */ + + return nxt_conf_vldt_certificate_element(vldt, value); +} + + +static nxt_int_t +nxt_conf_vldt_certificate_element(nxt_conf_validation_t *vldt, + nxt_conf_value_t *value) { nxt_str_t name; nxt_conf_value_t *cert; + if (nxt_conf_type(value) != NXT_CONF_STRING) { + return nxt_conf_vldt_error(vldt, "The \"certificate\" array must " + "contain only string values."); + } + nxt_conf_get_string(value, &name); cert = nxt_cert_info_get(&name); diff --git a/src/nxt_openssl.c b/src/nxt_openssl.c index 835ca8b2..9b86150f 100644 --- a/src/nxt_openssl.c +++ b/src/nxt_openssl.c @@ -9,17 +9,19 @@ #include #include #include +#include typedef struct { - SSL *session; - nxt_conn_t *conn; + SSL *session; + nxt_conn_t *conn; - int ssl_error; - uint8_t times; /* 2 bits */ - uint8_t handshake; /* 1 bit */ + int ssl_error; + uint8_t times; /* 2 bits */ + uint8_t handshake; /* 1 bit */ - nxt_buf_mem_t buffer; + nxt_tls_conf_t *conf; + nxt_buf_mem_t buffer; } nxt_openssl_conn_t; @@ -40,8 +42,18 @@ static unsigned long nxt_openssl_thread_id(void); static void nxt_openssl_locks_free(void); #endif static nxt_int_t nxt_openssl_server_init(nxt_task_t *task, - nxt_tls_conf_t *conf); -static nxt_int_t nxt_openssl_chain_file(SSL_CTX *ctx, nxt_fd_t fd); + nxt_tls_conf_t *conf, nxt_mp_t *mp, nxt_bool_t last); +static nxt_int_t nxt_openssl_chain_file(nxt_task_t *task, SSL_CTX *ctx, + nxt_tls_conf_t *conf, nxt_mp_t *mp, nxt_bool_t single); +static nxt_uint_t nxt_openssl_cert_get_names(nxt_task_t *task, X509 *cert, + nxt_tls_conf_t *conf, nxt_mp_t *mp); +static nxt_int_t nxt_openssl_bundle_hash_test(nxt_lvlhsh_query_t *lhq, + void *data); +static nxt_int_t nxt_openssl_bundle_hash_insert(nxt_task_t *task, + nxt_lvlhsh_t *lvlhsh, nxt_tls_bundle_hash_item_t *item, nxt_mp_t * mp); +static nxt_int_t nxt_openssl_servername(SSL *s, int *ad, void *arg); +static nxt_tls_bundle_conf_t *nxt_openssl_find_ctx(nxt_tls_conf_t *conf, + nxt_str_t *sn); static void nxt_openssl_server_free(nxt_task_t *task, nxt_tls_conf_t *conf); static void nxt_openssl_conn_init(nxt_task_t *task, nxt_tls_conf_t *conf, nxt_conn_t *c); @@ -245,12 +257,13 @@ nxt_openssl_locks_free(void) static nxt_int_t -nxt_openssl_server_init(nxt_task_t *task, nxt_tls_conf_t *conf) +nxt_openssl_server_init(nxt_task_t *task, nxt_tls_conf_t *conf, + nxt_mp_t *mp, nxt_bool_t last) { - SSL_CTX *ctx; - nxt_fd_t fd; - const char *ciphers, *ca_certificate; - STACK_OF(X509_NAME) *list; + SSL_CTX *ctx; + const char *ciphers, *ca_certificate; + STACK_OF(X509_NAME) *list; + nxt_tls_bundle_conf_t *bundle; ctx = SSL_CTX_new(SSLv23_server_method()); if (ctx == NULL) { @@ -258,8 +271,10 @@ nxt_openssl_server_init(nxt_task_t *task, nxt_tls_conf_t *conf) return NXT_ERROR; } - conf->ctx = ctx; - conf->conn_init = nxt_openssl_conn_init; + bundle = conf->bundle; + nxt_assert(bundle != NULL); + + bundle->ctx = ctx; #ifdef SSL_OP_NO_RENEGOTIATION /* Renegration is not currently supported. */ @@ -287,11 +302,10 @@ nxt_openssl_server_init(nxt_task_t *task, nxt_tls_conf_t *conf) #endif - fd = conf->chain_file; - - if (nxt_openssl_chain_file(ctx, fd) != NXT_OK) { - nxt_openssl_log_error(task, NXT_LOG_ALERT, - "nxt_openssl_chain_file() failed"); + if (nxt_openssl_chain_file(task, ctx, conf, mp, + last && bundle->next == NULL) + != NXT_OK) + { goto fail; } /* @@ -350,6 +364,14 @@ nxt_openssl_server_init(nxt_task_t *task, nxt_tls_conf_t *conf) SSL_CTX_set_client_CA_list(ctx, list); } + if (last) { + conf->conn_init = nxt_openssl_conn_init; + + if (bundle->next != NULL) { + SSL_CTX_set_tlsext_servername_callback(ctx, nxt_openssl_servername); + } + } + return NXT_OK; fail: @@ -366,22 +388,27 @@ fail: static nxt_int_t -nxt_openssl_chain_file(SSL_CTX *ctx, nxt_fd_t fd) +nxt_openssl_chain_file(nxt_task_t *task, SSL_CTX *ctx, nxt_tls_conf_t *conf, + nxt_mp_t *mp, nxt_bool_t single) { - BIO *bio; - X509 *cert, *ca; - long reason; - EVP_PKEY *key; - nxt_int_t ret; + BIO *bio; + X509 *cert, *ca; + long reason; + EVP_PKEY *key; + nxt_int_t ret; + nxt_tls_bundle_conf_t *bundle; + + ret = NXT_ERROR; + cert = NULL; bio = BIO_new(BIO_s_fd()); if (bio == NULL) { - return NXT_ERROR; + goto end; } - BIO_set_fd(bio, fd, BIO_CLOSE); + bundle = conf->bundle; - ret = NXT_ERROR; + BIO_set_fd(bio, bundle->chain_file, BIO_CLOSE); cert = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL); if (cert == NULL) { @@ -392,6 +419,10 @@ nxt_openssl_chain_file(SSL_CTX *ctx, nxt_fd_t fd) goto end; } + if (!single && nxt_openssl_cert_get_names(task, cert, conf, mp) != NXT_OK) { + goto clean; + } + for ( ;; ) { ca = PEM_read_bio_X509(bio, NULL, NULL, NULL); @@ -437,17 +468,319 @@ nxt_openssl_chain_file(SSL_CTX *ctx, nxt_fd_t fd) end: - X509_free(cert); + if (ret != NXT_OK) { + nxt_openssl_log_error(task, NXT_LOG_ALERT, + "nxt_openssl_chain_file() failed"); + } + +clean: + BIO_free(bio); + X509_free(cert); return ret; } +static nxt_uint_t +nxt_openssl_cert_get_names(nxt_task_t *task, X509 *cert, nxt_tls_conf_t *conf, + nxt_mp_t *mp) +{ + int len; + nxt_str_t domain, str; + X509_NAME *x509_name; + nxt_uint_t i, n; + GENERAL_NAME *name; + nxt_tls_bundle_conf_t *bundle; + STACK_OF(GENERAL_NAME) *alt_names; + nxt_tls_bundle_hash_item_t *item; + + bundle = conf->bundle; + + alt_names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); + + if (alt_names != NULL) { + n = sk_GENERAL_NAME_num(alt_names); + + for (i = 0; i != n; i++) { + name = sk_GENERAL_NAME_value(alt_names, i); + + if (name->type != GEN_DNS) { + continue; + } + + str.length = ASN1_STRING_length(name->d.dNSName); +#if OPENSSL_VERSION_NUMBER > 0x10100000L + str.start = (u_char *) ASN1_STRING_get0_data(name->d.dNSName); +#else + str.start = ASN1_STRING_data(name->d.dNSName); +#endif + + domain.start = nxt_mp_nget(mp, str.length); + if (nxt_slow_path(domain.start == NULL)) { + goto fail; + } + + domain.length = str.length; + nxt_memcpy_lowcase(domain.start, str.start, str.length); + + item = nxt_mp_get(mp, sizeof(nxt_tls_bundle_hash_item_t)); + if (nxt_slow_path(item == NULL)) { + goto fail; + } + + item->name = domain; + item->bundle = bundle; + + if (nxt_openssl_bundle_hash_insert(task, &conf->bundle_hash, + item, mp) + == NXT_ERROR) + { + goto fail; + } + } + + sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free); + + } else { + x509_name = X509_get_subject_name(cert); + len = X509_NAME_get_text_by_NID(x509_name, NID_commonName, + NULL, 0); + if (len <= 0) { + nxt_log(task, NXT_LOG_WARN, "certificate \"%V\" has neither " + "Subject Alternative Name nor Common Name", bundle->name); + return NXT_OK; + } + + domain.start = nxt_mp_nget(mp, len + 1); + if (nxt_slow_path(domain.start == NULL)) { + return NXT_ERROR; + } + + domain.length = X509_NAME_get_text_by_NID(x509_name, NID_commonName, + (char *) domain.start, + len + 1); + nxt_memcpy_lowcase(domain.start, domain.start, domain.length); + + item = nxt_mp_get(mp, sizeof(nxt_tls_bundle_hash_item_t)); + if (nxt_slow_path(item == NULL)) { + return NXT_ERROR; + } + + item->name = domain; + item->bundle = bundle; + + if (nxt_openssl_bundle_hash_insert(task, &conf->bundle_hash, item, + mp) + == NXT_ERROR) + { + return NXT_ERROR; + } + } + + return NXT_OK; + +fail: + + sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free); + + return NXT_ERROR; +} + + +static const nxt_lvlhsh_proto_t nxt_openssl_bundle_hash_proto + nxt_aligned(64) = +{ + NXT_LVLHSH_DEFAULT, + nxt_openssl_bundle_hash_test, + nxt_mp_lvlhsh_alloc, + nxt_mp_lvlhsh_free, +}; + + +static nxt_int_t +nxt_openssl_bundle_hash_test(nxt_lvlhsh_query_t *lhq, void *data) +{ + nxt_tls_bundle_hash_item_t *item; + + item = data; + + return nxt_strstr_eq(&lhq->key, &item->name) ? NXT_OK : NXT_DECLINED; +} + + +static nxt_int_t +nxt_openssl_bundle_hash_insert(nxt_task_t *task, nxt_lvlhsh_t *lvlhsh, + nxt_tls_bundle_hash_item_t *item, nxt_mp_t *mp) +{ + nxt_str_t str; + nxt_int_t ret; + nxt_lvlhsh_query_t lhq; + nxt_tls_bundle_hash_item_t *old; + + str = item->name; + + if (item->name.start[0] == '*') { + item->name.start++; + item->name.length--; + + if (item->name.length == 0 || item->name.start[0] != '.') { + nxt_log(task, NXT_LOG_WARN, "ignored invalid name \"%V\" " + "in certificate \"%V\": missing \".\" " + "after wildcard symbol", &str, item->bundle->name); + return NXT_OK; + } + } + + lhq.pool = mp; + lhq.key = item->name; + lhq.value = item; + lhq.proto = &nxt_openssl_bundle_hash_proto; + lhq.replace = 0; + lhq.key_hash = nxt_murmur_hash2(item->name.start, item->name.length); + + ret = nxt_lvlhsh_insert(lvlhsh, &lhq); + if (nxt_fast_path(ret == NXT_OK)) { + nxt_debug(task, "name \"%V\" for certificate \"%V\" is inserted", + &str, item->bundle->name); + return NXT_OK; + } + + if (nxt_fast_path(ret == NXT_DECLINED)) { + old = lhq.value; + if (old->bundle != item->bundle) { + nxt_log(task, NXT_LOG_WARN, "ignored duplicate name \"%V\" " + "in certificate \"%V\", identical name appears in \"%V\"", + &str, old->bundle->name, item->bundle->name); + + old->bundle = item->bundle; + } + + return NXT_OK; + } + + return NXT_ERROR; +} + + +static nxt_int_t +nxt_openssl_servername(SSL *s, int *ad, void *arg) +{ + nxt_str_t str; + nxt_uint_t i; + nxt_conn_t *c; + const char *servername; + nxt_tls_conf_t *conf; + nxt_openssl_conn_t *tls; + nxt_tls_bundle_conf_t *bundle; + + c = SSL_get_ex_data(s, nxt_openssl_connection_index); + + if (nxt_slow_path(c == NULL)) { + nxt_thread_log_alert("SSL_get_ex_data() failed"); + return SSL_TLSEXT_ERR_ALERT_FATAL; + } + + servername = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name); + if (nxt_slow_path(servername == NULL)) { + nxt_log(c->socket.task, NXT_LOG_ALERT, "SSL_get_servername() returned " + "NULL in server name callback"); + return SSL_TLSEXT_ERR_ALERT_FATAL; + } + + str.length = nxt_strlen(servername); + if (str.length == 0) { + nxt_debug(c->socket.task, "client sent zero-length server name"); + goto done; + } + + if (servername[0] == '.') { + nxt_debug(c->socket.task, "ignored the server name \"%s\": " + "leading \".\"", servername); + goto done; + } + + nxt_debug(c->socket.task, "tls with servername \"%s\"", servername); + + str.start = nxt_mp_nget(c->mem_pool, str.length); + if (nxt_slow_path(str.start == NULL)) { + return SSL_TLSEXT_ERR_ALERT_FATAL; + } + + nxt_memcpy_lowcase(str.start, (const u_char *) servername, str.length); + + tls = c->u.tls; + conf = tls->conf; + + bundle = nxt_openssl_find_ctx(conf, &str); + + if (bundle == NULL) { + for (i = 1; i < str.length; i++) { + if (str.start[i] == '.') { + str.start += i; + str.length -= i; + + bundle = nxt_openssl_find_ctx(conf, &str); + break; + } + } + } + + if (bundle != NULL) { + nxt_debug(c->socket.task, "new tls context found for \"%V\": \"%V\" " + "(old: \"%V\")", &str, bundle->name, + conf->bundle->name); + + if (bundle != conf->bundle) { + if (SSL_set_SSL_CTX(s, bundle->ctx) == NULL) { + nxt_openssl_log_error(c->socket.task, NXT_LOG_ALERT, + "SSL_set_SSL_CTX() failed"); + + return SSL_TLSEXT_ERR_ALERT_FATAL; + } + } + } + +done: + + return SSL_TLSEXT_ERR_OK; +} + + +static nxt_tls_bundle_conf_t * +nxt_openssl_find_ctx(nxt_tls_conf_t *conf, nxt_str_t *sn) +{ + nxt_int_t ret; + nxt_lvlhsh_query_t lhq; + nxt_tls_bundle_hash_item_t *item; + + lhq.key_hash = nxt_murmur_hash2(sn->start, sn->length); + lhq.key = *sn; + lhq.proto = &nxt_openssl_bundle_hash_proto; + + ret = nxt_lvlhsh_find(&conf->bundle_hash, &lhq); + if (ret != NXT_OK) { + return NULL; + } + + item = lhq.value; + + return item->bundle; +} + + static void nxt_openssl_server_free(nxt_task_t *task, nxt_tls_conf_t *conf) { - SSL_CTX_free(conf->ctx); + nxt_tls_bundle_conf_t *bundle; + + bundle = conf->bundle; + nxt_assert(bundle != NULL); + + do { + SSL_CTX_free(bundle->ctx); + bundle = bundle->next; + } while (bundle != NULL); #if (OPENSSL_VERSION_NUMBER >= 0x1010100fL \ && OPENSSL_VERSION_NUMBER < 0x1010101fL) @@ -474,7 +807,7 @@ nxt_openssl_conn_init(nxt_task_t *task, nxt_tls_conf_t *conf, nxt_conn_t *c) c->u.tls = tls; nxt_buf_mem_set_size(&tls->buffer, conf->buffer_size); - ctx = conf->ctx; + ctx = conf->bundle->ctx; s = SSL_new(ctx); if (s == NULL) { @@ -483,6 +816,8 @@ nxt_openssl_conn_init(nxt_task_t *task, nxt_tls_conf_t *conf, nxt_conn_t *c) } tls->session = s; + /* To pass TLS config to the nxt_openssl_servername() callback. */ + tls->conf = conf; tls->conn = c; ret = SSL_set_fd(s, c->socket.fd); @@ -504,6 +839,11 @@ nxt_openssl_conn_init(nxt_task_t *task, nxt_tls_conf_t *conf, nxt_conn_t *c) c->sendfile = NXT_CONN_SENDFILE_OFF; nxt_openssl_conn_handshake(task, c, c->socket.data); + /* + * TLS configuration might be destroyed after the TLS connection + * is established. + */ + tls->conf = NULL; return; fail: diff --git a/src/nxt_router.c b/src/nxt_router.c index 4be4197a..0ecaefa1 100644 --- a/src/nxt_router.c +++ b/src/nxt_router.c @@ -51,8 +51,10 @@ typedef struct { typedef struct { + nxt_str_t *name; nxt_socket_conf_t *socket_conf; nxt_router_temp_conf_t *temp_conf; + nxt_bool_t last; } nxt_socket_rpc_t; @@ -116,9 +118,11 @@ static void nxt_router_listen_socket_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, void *data); #if (NXT_TLS) static void nxt_router_tls_rpc_create(nxt_task_t *task, - nxt_router_temp_conf_t *tmcf, nxt_router_tlssock_t *tls); + nxt_router_temp_conf_t *tmcf, nxt_router_tlssock_t *tls, nxt_bool_t last); static void nxt_router_tls_rpc_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, void *data); +static nxt_int_t nxt_router_conf_tls_insert(nxt_router_temp_conf_t *tmcf, + nxt_conf_value_t *value, nxt_socket_conf_t *skcf); #endif static void nxt_router_app_rpc_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, nxt_app_t *app); @@ -944,14 +948,15 @@ nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data) } #if (NXT_TLS) - qlk = nxt_queue_first(&tmcf->tls); + qlk = nxt_queue_last(&tmcf->tls); - if (qlk != nxt_queue_tail(&tmcf->tls)) { + if (qlk != nxt_queue_head(&tmcf->tls)) { nxt_queue_remove(qlk); tls = nxt_queue_link_data(qlk, nxt_router_tlssock_t, link); - nxt_router_tls_rpc_create(task, tmcf, tls); + nxt_router_tls_rpc_create(task, tmcf, tls, + nxt_queue_is_empty(&tmcf->tls)); return; } #endif @@ -990,7 +995,7 @@ nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data) nxt_router_apps_sort(task, router, tmcf); - nxt_router_apps_hash_use(task, rtcf, 1); + nxt_router_apps_hash_use(task, rtcf, 1); nxt_router_engines_post(router, tmcf); @@ -1332,6 +1337,9 @@ nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, nxt_port_t *port; nxt_router_t *router; nxt_app_joint_t *app_joint; +#if (NXT_TLS) + nxt_conf_value_t *certificate; +#endif nxt_conf_value_t *conf, *http, *value, *websocket; nxt_conf_value_t *applications, *application; nxt_conf_value_t *listeners, *listener; @@ -1343,9 +1351,6 @@ nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, nxt_router_app_conf_t apcf; nxt_router_access_log_t *access_log; nxt_router_listener_conf_t lscf; -#if (NXT_TLS) - nxt_router_tlssock_t *tls; -#endif static nxt_str_t http_path = nxt_string("/settings/http"); static nxt_str_t applications_path = nxt_string("/applications"); @@ -1729,20 +1734,30 @@ nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, } #if (NXT_TLS) - value = nxt_conf_get_path(listener, &certificate_path); + certificate = nxt_conf_get_path(listener, &certificate_path); - if (value != NULL) { - nxt_conf_get_string(value, &name); + if (certificate != NULL) { + if (nxt_conf_type(certificate) == NXT_CONF_ARRAY) { + n = nxt_conf_array_elements_count(certificate); - tls = nxt_mp_get(mp, sizeof(nxt_router_tlssock_t)); - if (nxt_slow_path(tls == NULL)) { - goto fail; - } + for (i = 0; i < n; i++) { + value = nxt_conf_get_array_element(certificate, i); - tls->name = name; - tls->conf = skcf; + nxt_assert(value != NULL); - nxt_queue_insert_tail(&tmcf->tls, &tls->link); + ret = nxt_router_conf_tls_insert(tmcf, value, skcf); + if (nxt_slow_path(ret != NXT_OK)) { + goto fail; + } + } + + } else { + /* NXT_CONF_STRING */ + ret = nxt_router_conf_tls_insert(tmcf, certificate, skcf); + if (nxt_slow_path(ret != NXT_OK)) { + goto fail; + } + } } #endif @@ -1828,6 +1843,38 @@ fail: } +#if (NXT_TLS) + +static nxt_int_t +nxt_router_conf_tls_insert(nxt_router_temp_conf_t *tmcf, + nxt_conf_value_t *value, nxt_socket_conf_t *skcf) +{ + nxt_mp_t *mp; + nxt_str_t str; + nxt_router_tlssock_t *tls; + + mp = tmcf->router_conf->mem_pool; + + tls = nxt_mp_get(mp, sizeof(nxt_router_tlssock_t)); + if (nxt_slow_path(tls == NULL)) { + return NXT_ERROR; + } + + tls->conf = skcf; + nxt_conf_get_string(value, &str); + + if (nxt_slow_path(nxt_str_dup(mp, &tls->name, &str) == NULL)) { + return NXT_ERROR; + } + + nxt_queue_insert_tail(&tmcf->tls, &tls->link); + + return NXT_OK; +} + +#endif + + static nxt_int_t nxt_router_conf_process_static(nxt_task_t *task, nxt_router_conf_t *rtcf, nxt_conf_value_t *conf) @@ -2383,7 +2430,7 @@ nxt_router_listen_socket_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, static void nxt_router_tls_rpc_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, - nxt_router_tlssock_t *tls) + nxt_router_tlssock_t *tls, nxt_bool_t last) { nxt_socket_rpc_t *rpc; @@ -2393,8 +2440,10 @@ nxt_router_tls_rpc_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, return; } + rpc->name = &tls->name; rpc->socket_conf = tls->conf; rpc->temp_conf = tmcf; + rpc->last = last; nxt_cert_store_get(task, &tls->name, tmcf->mem_pool, nxt_router_tls_rpc_handler, rpc); @@ -2405,11 +2454,12 @@ static void nxt_router_tls_rpc_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, void *data) { - nxt_mp_t *mp; - nxt_int_t ret; - nxt_tls_conf_t *tlscf; - nxt_socket_rpc_t *rpc; - nxt_router_temp_conf_t *tmcf; + nxt_mp_t *mp; + nxt_int_t ret; + nxt_tls_conf_t *tlscf; + nxt_socket_rpc_t *rpc; + nxt_tls_bundle_conf_t *bundle; + nxt_router_temp_conf_t *tmcf; nxt_debug(task, "tls rpc handler"); @@ -2422,20 +2472,33 @@ nxt_router_tls_rpc_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, mp = tmcf->router_conf->mem_pool; - tlscf = nxt_mp_zget(mp, sizeof(nxt_tls_conf_t)); - if (nxt_slow_path(tlscf == NULL)) { + if (rpc->socket_conf->tls == NULL){ + tlscf = nxt_mp_zget(mp, sizeof(nxt_tls_conf_t)); + if (nxt_slow_path(tlscf == NULL)) { + goto fail; + } + + rpc->socket_conf->tls = tlscf; + + } else { + tlscf = rpc->socket_conf->tls; + } + + bundle = nxt_mp_get(mp, sizeof(nxt_tls_bundle_conf_t)); + if (nxt_slow_path(bundle == NULL)) { goto fail; } - tlscf->chain_file = msg->fd[0]; + bundle->name = rpc->name; + bundle->chain_file = msg->fd[0]; + bundle->next = tlscf->bundle; + tlscf->bundle = bundle; - ret = task->thread->runtime->tls->server_init(task, tlscf); + ret = task->thread->runtime->tls->server_init(task, tlscf, mp, rpc->last); if (nxt_slow_path(ret != NXT_OK)) { goto fail; } - rpc->socket_conf->tls = tlscf; - nxt_work_queue_add(&task->thread->engine->fast_work_queue, nxt_router_conf_apply, task, tmcf, NULL); return; diff --git a/src/nxt_tls.h b/src/nxt_tls.h index d9fcc6a8..c44bfe56 100644 --- a/src/nxt_tls.h +++ b/src/nxt_tls.h @@ -23,28 +23,47 @@ #define NXT_TLS_BUFFER_SIZE 4096 -typedef struct nxt_tls_conf_s nxt_tls_conf_t; - +typedef struct nxt_tls_conf_s nxt_tls_conf_t; +typedef struct nxt_tls_bundle_conf_s nxt_tls_bundle_conf_t; typedef struct { nxt_int_t (*library_init)(nxt_task_t *task); void (*library_free)(nxt_task_t *task); nxt_int_t (*server_init)(nxt_task_t *task, - nxt_tls_conf_t *conf); + nxt_tls_conf_t *conf, nxt_mp_t *mp, + nxt_bool_t last); void (*server_free)(nxt_task_t *task, nxt_tls_conf_t *conf); } nxt_tls_lib_t; -struct nxt_tls_conf_s { +typedef struct { + nxt_tls_bundle_conf_t *bundle; + + nxt_str_t name; +} nxt_tls_bundle_hash_item_t; + + +struct nxt_tls_bundle_conf_s { void *ctx; + + nxt_fd_t chain_file; + nxt_str_t *name; + + nxt_tls_bundle_conf_t *next; +}; + + +struct nxt_tls_conf_s { + nxt_tls_bundle_conf_t *bundle; + nxt_lvlhsh_t bundle_hash; + void (*conn_init)(nxt_task_t *task, nxt_tls_conf_t *conf, nxt_conn_t *c); const nxt_tls_lib_t *lib; - nxt_fd_t chain_file; char *ciphers; char *ca_certificate; -- cgit From 9957a959dfd6e60e6fce02c904ad6f768f69c44b Mon Sep 17 00:00:00 2001 From: Max Romanov Date: Thu, 25 Mar 2021 14:16:30 +0300 Subject: Releasing shm buffers for large body requests. This fixes memory and shm file descriptor leakage that occurred when a large request body was passed via shared memory. The leakage was caught with the "test_settings_body_buffer_size" test. The main condition is the "body_buffer_size" value exceeding 10 Mb (a shm segment). Thus, the router was forced to split the body into several shm segments, but these buffers were not freed because of dummy completion handlers. --- src/nxt_router.c | 15 ++++----------- src/nxt_router_request.h | 1 - 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/nxt_router.c b/src/nxt_router.c index 0ecaefa1..8524b358 100644 --- a/src/nxt_router.c +++ b/src/nxt_router.c @@ -523,12 +523,11 @@ nxt_router_msg_cancel(nxt_task_t *task, nxt_request_rpc_data_t *req_rpc_data) next = b->next; b->next = NULL; - b->completion_handler = msg_info->completion_handler; - if (b->is_port_mmap_sent) { b->is_port_mmap_sent = cancelled == 0; - b->completion_handler(task, b, b->parent); } + + b->completion_handler(task, b, b->parent); } msg_info->buf = NULL; @@ -4113,6 +4112,8 @@ nxt_router_req_headers_ack_handler(nxt_task_t *task, if (b != NULL) { /* First buffer is already sent. Start from second. */ b = b->next; + + req_rpc_data->msg_info.buf->next = NULL; } if (req_rpc_data->msg_info.body_fd != -1 || b != NULL) { @@ -5025,14 +5026,6 @@ nxt_router_app_prepare_request(nxt_task_t *task, port->socket.fd); req_rpc_data->msg_info.buf = buf; - req_rpc_data->msg_info.completion_handler = buf->completion_handler; - - do { - buf->completion_handler = nxt_router_dummy_buf_completion; - buf = buf->next; - } while (buf != NULL); - - buf = req_rpc_data->msg_info.buf; body = req_rpc_data->request->body; diff --git a/src/nxt_router_request.h b/src/nxt_router_request.h index 95044dbb..6e226bae 100644 --- a/src/nxt_router_request.h +++ b/src/nxt_router_request.h @@ -11,7 +11,6 @@ typedef struct { nxt_buf_t *buf; nxt_fd_t body_fd; uint32_t tracking_cookie; - nxt_work_handler_t completion_handler; } nxt_msg_info_t; -- cgit From c849483862cba283a123354b9fda7687a9fa32fd Mon Sep 17 00:00:00 2001 From: Max Romanov Date: Thu, 25 Mar 2021 16:09:24 +0300 Subject: Node.js: fixing module global installation. Globally installed modules require a globally installed libunit. The "binding_pub.gyp" file is the correct version, otherwise linked module may have unresolved symbols because libunit is not linked. --- auto/modules/nodejs | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/auto/modules/nodejs b/auto/modules/nodejs index edaf99ac..100defe4 100644 --- a/auto/modules/nodejs +++ b/auto/modules/nodejs @@ -122,8 +122,11 @@ fi NXT_NODE_TMP=${NXT_BUILD_DIR}/src/${NXT_NODE}/unit-http +NXT_NODE_TMP_G=${NXT_BUILD_DIR}/src/${NXT_NODE}/unit-http-g NXT_NODE_TARBALL=${NXT_BUILD_DIR}/${NXT_NODE}-unit-http.tar.gz -NXT_NODE_VERSION_FILE=${NXT_NODE_TMP}/version.h +NXT_NODE_TARBALL_G=${NXT_BUILD_DIR}/${NXT_NODE}-unit-http-g.tar.gz +NXT_NODE_VERSION_FILE=${NXT_BUILD_DIR}/src/${NXT_NODE}/version.h +NXT_NODE_PACKAGE_FILE=${NXT_BUILD_DIR}/src/${NXT_NODE}/package.json NXT_NODE_EXPORTS="export UNIT_SRC_PATH=${PWD}/src \ && export UNIT_BUILD_PATH=${PWD}/${NXT_BUILD_DIR} \ && export UNIT_LIB_STATIC_PATH=${PWD}/${NXT_BUILD_DIR}/libunit.a" @@ -138,6 +141,7 @@ cat << END >> $NXT_MAKEFILE .PHONY: ${NXT_NODE} .PHONY: ${NXT_NODE}-copy +.PHONY: ${NXT_NODE}-copy-g .PHONY: ${NXT_NODE}-install .PHONY: ${NXT_NODE}-uninstall .PHONY: ${NXT_NODE}-local-check @@ -149,27 +153,37 @@ ${NXT_NODE}: ${NXT_NODE}-copy $NXT_BUILD_DIR/$NXT_LIB_UNIT_STATIC ${NXT_NODE_EXPORTS} && \\ cd ${NXT_NODE_TMP} && ${NXT_NODE_GYP} configure build clean -${NXT_NODE}-copy: ${NXT_NODE_VERSION_FILE} - mkdir -p ${NXT_BUILD_DIR}/src/ - cp -rp src/nodejs/* ${NXT_BUILD_DIR}/src/${NXT_NODE} +${NXT_NODE}-copy: ${NXT_NODE_VERSION_FILE} ${NXT_NODE_PACKAGE_FILE} + mkdir -p ${NXT_NODE_TMP} + cp -rp src/nodejs/unit-http/* ${NXT_NODE_TMP}/ + cp -p ${NXT_NODE_VERSION_FILE} ${NXT_NODE_PACKAGE_FILE} ${NXT_NODE_TMP}/ + +${NXT_NODE}-copy-g: ${NXT_NODE_VERSION_FILE} ${NXT_NODE_PACKAGE_FILE} + mkdir -p ${NXT_NODE_TMP_G} + cp -rp src/nodejs/unit-http/* ${NXT_NODE_TMP_G}/ + cp -p ${NXT_NODE_VERSION_FILE} ${NXT_NODE_PACKAGE_FILE} ${NXT_NODE_TMP_G}/ + mv ${NXT_NODE_TMP_G}/binding_pub.gyp ${NXT_NODE_TMP_G}/binding.gyp ${NXT_NODE_VERSION_FILE}: ${NXT_VERSION_H} - mkdir -p ${NXT_NODE_TMP} + mkdir -p ${NXT_BUILD_DIR}/src/${NXT_NODE} $echo '#define NXT_NODE_VERNUM \$(NXT_VERNUM)' > $NXT_NODE_VERSION_FILE -${NXT_NODE_TARBALL}: ${NXT_NODE}-copy +${NXT_NODE_PACKAGE_FILE}: ${NXT_VERSION_H} src/nodejs/unit-http/package.json + mkdir -p ${NXT_BUILD_DIR}/src/${NXT_NODE} sed -e 's/"version"\s*:.*/"version": "\$(NXT_VERSION)",/' \ - ${NXT_NODE_TMP}/package.json > ${NXT_NODE_TMP}/package.json.tmp - mv ${NXT_NODE_TMP}/package.json.tmp ${NXT_NODE_TMP}/package.json + src/nodejs/unit-http/package.json > ${NXT_NODE_PACKAGE_FILE} + +${NXT_NODE_TARBALL}: ${NXT_NODE}-copy tar -zcvf ${NXT_NODE_TARBALL} -C ${NXT_NODE_TMP} . +${NXT_NODE_TARBALL_G}: ${NXT_NODE}-copy-g + tar -zcvf ${NXT_NODE_TARBALL_G} -C ${NXT_NODE_TMP_G} . + install: ${NXT_NODE}-$NXT_NODE_INSTALL -${NXT_NODE}-install: ${NXT_NODE_TARBALL} \ - $NXT_BUILD_DIR/$NXT_LIB_UNIT_STATIC - ${NXT_NODE_EXPORTS} && \\ - ${NXT_NPM} install -g --unsafe-perm ${PWD}/${NXT_NODE_TARBALL} +${NXT_NODE}-install: ${NXT_NODE_TARBALL_G} libunit-install + ${NXT_NPM} install -g --unsafe-perm ${PWD}/${NXT_NODE_TARBALL_G} ${NXT_NODE}-uninstall: ${NXT_NPM} uninstall -g unit-http -- cgit From 067c6096e2ec306c4fdae6993140fbbdf4f9a6fd Mon Sep 17 00:00:00 2001 From: Valentin Bartenev Date: Thu, 25 Mar 2021 16:15:03 +0300 Subject: Node.js: used distinct placeholder for version in "package.json". This makes the "sed" instruction simpler and more portable, as the previous variant didn't work well on BSD systems due to the "\s" metacharacter. Thanks to Sergey A. Osokin for spotting this issue. Also, this should prevent accidentally creating a version 1.0.0 package. --- auto/modules/nodejs | 2 +- src/nodejs/unit-http/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/auto/modules/nodejs b/auto/modules/nodejs index 100defe4..b2309143 100644 --- a/auto/modules/nodejs +++ b/auto/modules/nodejs @@ -170,7 +170,7 @@ ${NXT_NODE_VERSION_FILE}: ${NXT_VERSION_H} ${NXT_NODE_PACKAGE_FILE}: ${NXT_VERSION_H} src/nodejs/unit-http/package.json mkdir -p ${NXT_BUILD_DIR}/src/${NXT_NODE} - sed -e 's/"version"\s*:.*/"version": "\$(NXT_VERSION)",/' \ + sed -e "s|%%VERSION%%|\$(NXT_VERSION)|" \ src/nodejs/unit-http/package.json > ${NXT_NODE_PACKAGE_FILE} ${NXT_NODE_TARBALL}: ${NXT_NODE}-copy diff --git a/src/nodejs/unit-http/package.json b/src/nodejs/unit-http/package.json index 7ee01346..81f06bd4 100644 --- a/src/nodejs/unit-http/package.json +++ b/src/nodejs/unit-http/package.json @@ -1,6 +1,6 @@ { "name": "unit-http", - "version": "1.0.0", + "version": "%%VERSION%%", "description": "HTTP module for NGINX Unit", "main": "http.js", "files": [ -- cgit From b8052b050e0111400c59f35e76c013d8ee553ea9 Mon Sep 17 00:00:00 2001 From: Max Romanov Date: Thu, 25 Mar 2021 16:55:16 +0300 Subject: Fixing shm buffer leakage when sending over the port queue. When the shm buffer is sent over the port queue, it needs to be completed because it's sent over the port socket. --- docs/changes.xml | 7 ++++ src/nxt_port_socket.c | 97 ++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 91 insertions(+), 13 deletions(-) diff --git a/docs/changes.xml b/docs/changes.xml index cca6bbc4..89c4630d 100644 --- a/docs/changes.xml +++ b/docs/changes.xml @@ -36,6 +36,13 @@ appeared in 1.6. + + +a descriptor and memory leak occurring in the router process when processing +small WebSocket frames from a client; the bug had appeared in 1.19.0. + + + a descriptor leak occurring in the router process when removing or diff --git a/src/nxt_port_socket.c b/src/nxt_port_socket.c index 9d8096b2..3cf2e79a 100644 --- a/src/nxt_port_socket.c +++ b/src/nxt_port_socket.c @@ -6,8 +6,16 @@ #include #include +#include +#define NXT_PORT_MAX_ENQUEUE_BUF_SIZE \ + (int) (NXT_PORT_QUEUE_MSG_SIZE - sizeof(nxt_port_msg_t)) + + +static nxt_bool_t nxt_port_can_enqueue_buf(nxt_buf_t *b); +static uint8_t nxt_port_enqueue_buf(nxt_task_t *task, nxt_port_msg_t *pm, + void *qbuf, nxt_buf_t *b); static nxt_int_t nxt_port_msg_chk_insert(nxt_task_t *task, nxt_port_t *port, nxt_port_send_msg_t *msg); static nxt_port_send_msg_t *nxt_port_msg_alloc(nxt_port_send_msg_t *m); @@ -151,10 +159,13 @@ nxt_port_socket_write2(nxt_task_t *task, nxt_port_t *port, nxt_uint_t type, nxt_buf_t *b) { int notify; - uint8_t *p; + uint8_t qmsg_size; nxt_int_t res; nxt_port_send_msg_t msg; - uint8_t qmsg[NXT_PORT_QUEUE_MSG_SIZE]; + struct { + nxt_port_msg_t pm; + uint8_t buf[NXT_PORT_MAX_ENQUEUE_BUF_SIZE]; + } qmsg; msg.link.next = NULL; msg.link.prev = NULL; @@ -177,21 +188,31 @@ nxt_port_socket_write2(nxt_task_t *task, nxt_port_t *port, nxt_uint_t type, if (port->queue != NULL && type != _NXT_PORT_MSG_READ_QUEUE) { - if (fd == -1 - && (b == NULL - || nxt_buf_mem_used_size(&b->mem) - <= (int) (NXT_PORT_QUEUE_MSG_SIZE - sizeof(nxt_port_msg_t)))) - { - p = nxt_cpymem(qmsg, &msg.port_msg, sizeof(nxt_port_msg_t)); + if (fd == -1 && nxt_port_can_enqueue_buf(b)) { + qmsg.pm = msg.port_msg; + + qmsg_size = sizeof(qmsg.pm); + if (b != NULL) { - p = nxt_cpymem(p, b->mem.pos, nxt_buf_mem_used_size(&b->mem)); + qmsg_size += nxt_port_enqueue_buf(task, &qmsg.pm, qmsg.buf, b); } - res = nxt_port_queue_send(port->queue, qmsg, p - qmsg, ¬ify); + res = nxt_port_queue_send(port->queue, &qmsg, qmsg_size, ¬ify); nxt_debug(task, "port{%d,%d} %d: enqueue %d notify %d, %d", (int) port->pid, (int) port->id, port->socket.fd, - (int) (p - qmsg), notify, res); + (int) qmsg_size, notify, res); + + if (b != NULL && nxt_fast_path(res == NXT_OK)) { + if (qmsg.pm.mmap) { + b->is_port_mmap_sent = 1; + } + + b->mem.pos = b->mem.free; + + nxt_work_queue_add(&task->thread->engine->fast_work_queue, + b->completion_handler, task, b, b->parent); + } if (notify == 0) { return res; @@ -201,9 +222,9 @@ nxt_port_socket_write2(nxt_task_t *task, nxt_port_t *port, nxt_uint_t type, msg.buf = NULL; } else { - qmsg[0] = _NXT_PORT_MSG_READ_SOCKET; + qmsg.buf[0] = _NXT_PORT_MSG_READ_SOCKET; - res = nxt_port_queue_send(port->queue, qmsg, 1, ¬ify); + res = nxt_port_queue_send(port->queue, qmsg.buf, 1, ¬ify); nxt_debug(task, "port{%d,%d} %d: enqueue 1 notify %d, %d", (int) port->pid, (int) port->id, port->socket.fd, @@ -225,6 +246,56 @@ nxt_port_socket_write2(nxt_task_t *task, nxt_port_t *port, nxt_uint_t type, } +static nxt_bool_t +nxt_port_can_enqueue_buf(nxt_buf_t *b) +{ + if (b == NULL) { + return 1; + } + + if (b->next != NULL) { + return 0; + } + + return (nxt_buf_mem_used_size(&b->mem) <= NXT_PORT_MAX_ENQUEUE_BUF_SIZE + || nxt_buf_is_port_mmap(b)); +} + + +static uint8_t +nxt_port_enqueue_buf(nxt_task_t *task, nxt_port_msg_t *pm, void *qbuf, + nxt_buf_t *b) +{ + ssize_t size; + nxt_port_mmap_msg_t *mm; + nxt_port_mmap_header_t *hdr; + nxt_port_mmap_handler_t *mmap_handler; + + size = nxt_buf_mem_used_size(&b->mem); + + if (size <= NXT_PORT_MAX_ENQUEUE_BUF_SIZE) { + nxt_memcpy(qbuf, b->mem.pos, size); + + return size; + } + + mmap_handler = b->parent; + hdr = mmap_handler->hdr; + mm = qbuf; + + mm->mmap_id = hdr->id; + mm->chunk_id = nxt_port_mmap_chunk_id(hdr, b->mem.pos); + mm->size = nxt_buf_mem_used_size(&b->mem); + + pm->mmap = 1; + + nxt_debug(task, "mmap_msg={%D, %D, %D}", mm->mmap_id, mm->chunk_id, + mm->size); + + return sizeof(nxt_port_mmap_msg_t); +} + + static nxt_int_t nxt_port_msg_chk_insert(nxt_task_t *task, nxt_port_t *port, nxt_port_send_msg_t *msg) -- cgit From 0e91854ad470b760f1814baa565e8dfdc28d2282 Mon Sep 17 00:00:00 2001 From: Artem Konev Date: Thu, 25 Mar 2021 14:03:45 +0000 Subject: Fixed wording in docs/changes.xml for the 1.23.0 release. --- docs/changes.xml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/docs/changes.xml b/docs/changes.xml index 89c4630d..7b27caf0 100644 --- a/docs/changes.xml +++ b/docs/changes.xml @@ -11,14 +11,15 @@ -support for multiple certificate bundles on a listener via Server Name +support for multiple certificate bundles on a listener via the Server Name Indication (SNI) TLS extension. -"--mandir" ./configure option to specify the directory for man page installation. +"--mandir" ./configure option to specify the directory for man page +installation. @@ -31,21 +32,21 @@ appeared in 1.17.0. -a connection leak occurring on premature TLS connection close; the bug had +a connection leak occurred on premature TLS connection close; the bug had appeared in 1.6. -a descriptor and memory leak occurring in the router process when processing +a descriptor and memory leak occurred in the router process when processing small WebSocket frames from a client; the bug had appeared in 1.19.0. -a descriptor leak occurring in the router process when removing or +a descriptor leak occurred in the router process when removing or reconfiguring an application; the bug had appeared in 1.19.0. @@ -67,13 +68,14 @@ certificate with a non-DNS SAN entry. the controller process could crash on manipulations with a certificate -containing a SAN and no standart name attributes in subject or issuer. +containing a SAN and no standard name attributes in subject or issuer. -the Ruby module didn't respect user locale for defaults in the Encoding class. +the Ruby module didn't respect the user locale for defaults in the Encoding +class. -- cgit From 6ecc9e81980550a35183cd19640da1982f10f28a Mon Sep 17 00:00:00 2001 From: Valentin Bartenev Date: Thu, 25 Mar 2021 17:14:27 +0300 Subject: Added version 1.23.0 CHANGES. --- CHANGES | 40 ++++++++++++++++++++++++++++++++++++++++ docs/changes.xml | 24 +++++++++++++++++++++++- 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 0f558c6f..b411e816 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,44 @@ +Changes with Unit 1.23.0 25 Mar 2021 + + *) Feature: support for multiple certificate bundles on a listener via + the Server Name Indication (SNI) TLS extension. + + *) Feature: "--mandir" ./configure option to specify the directory for + man page installation. + + *) Bugfix: the router process could crash on premature TLS connection + close; the bug had appeared in 1.17.0. + + *) Bugfix: a connection leak occurred on premature TLS connection close; + the bug had appeared in 1.6. + + *) Bugfix: a descriptor and memory leak occurred in the router process + when processing small WebSocket frames from a client; the bug had + appeared in 1.19.0. + + *) Bugfix: a descriptor leak occurred in the router process when + removing or reconfiguring an application; the bug had appeared in + 1.19.0. + + *) Bugfix: persistent storage of certificates might've not worked with + some filesystems in Linux, and all uploaded certificate bundles were + forgotten after restart. + + *) Bugfix: the controller process could crash while requesting + information about a certificate with a non-DNS SAN entry. + + *) Bugfix: the controller process could crash on manipulations with a + certificate containing a SAN and no standard name attributes in + subject or issuer. + + *) Bugfix: the Ruby module didn't respect the user locale for defaults + in the Encoding class. + + *) Bugfix: the PHP 5 module failed to build with thread safety enabled; + the bug had appeared in 1.22.0. + + Changes with Unit 1.22.0 04 Feb 2021 *) Feature: the ServerRequest and ServerResponse objects of Node.js diff --git a/docs/changes.xml b/docs/changes.xml index 7b27caf0..7656c15a 100644 --- a/docs/changes.xml +++ b/docs/changes.xml @@ -5,8 +5,30 @@ + + + + +NGINX Unit updated to 1.23.0. + + + + + + -- cgit From 71d3700951f04a8f69664b5671864c824874b18e Mon Sep 17 00:00:00 2001 From: Valentin Bartenev Date: Thu, 25 Mar 2021 17:15:30 +0300 Subject: Generated Dockerfiles for Unit 1.23.0. --- pkg/docker/Dockerfile.go1.15 | 2 +- pkg/docker/Dockerfile.jsc11 | 2 +- pkg/docker/Dockerfile.minimal | 2 +- pkg/docker/Dockerfile.node15 | 2 +- pkg/docker/Dockerfile.perl5.32 | 2 +- pkg/docker/Dockerfile.php8.0 | 2 +- pkg/docker/Dockerfile.python3.9 | 2 +- pkg/docker/Dockerfile.ruby2.7 | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pkg/docker/Dockerfile.go1.15 b/pkg/docker/Dockerfile.go1.15 index ea83d2df..45642662 100644 --- a/pkg/docker/Dockerfile.go1.15 +++ b/pkg/docker/Dockerfile.go1.15 @@ -8,7 +8,7 @@ RUN set -ex \ && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ && hg clone https://hg.nginx.org/unit \ && cd unit \ - && hg up 1.22.0 \ + && hg up 1.23.0 \ && NCPU="$(getconf _NPROCESSORS_ONLN)" \ && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ && CC_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_CFLAGS_MAINT_APPEND="-Wp,-D_FORTIFY_SOURCE=2 -fPIC" dpkg-buildflags --get CFLAGS)" \ diff --git a/pkg/docker/Dockerfile.jsc11 b/pkg/docker/Dockerfile.jsc11 index abb21023..4cfc541d 100644 --- a/pkg/docker/Dockerfile.jsc11 +++ b/pkg/docker/Dockerfile.jsc11 @@ -8,7 +8,7 @@ RUN set -ex \ && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ && hg clone https://hg.nginx.org/unit \ && cd unit \ - && hg up 1.22.0 \ + && hg up 1.23.0 \ && NCPU="$(getconf _NPROCESSORS_ONLN)" \ && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ && CC_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_CFLAGS_MAINT_APPEND="-Wp,-D_FORTIFY_SOURCE=2 -fPIC" dpkg-buildflags --get CFLAGS)" \ diff --git a/pkg/docker/Dockerfile.minimal b/pkg/docker/Dockerfile.minimal index 7ff5057a..59aaa6a3 100644 --- a/pkg/docker/Dockerfile.minimal +++ b/pkg/docker/Dockerfile.minimal @@ -8,7 +8,7 @@ RUN set -ex \ && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ && hg clone https://hg.nginx.org/unit \ && cd unit \ - && hg up 1.22.0 \ + && hg up 1.23.0 \ && NCPU="$(getconf _NPROCESSORS_ONLN)" \ && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ && CC_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_CFLAGS_MAINT_APPEND="-Wp,-D_FORTIFY_SOURCE=2 -fPIC" dpkg-buildflags --get CFLAGS)" \ diff --git a/pkg/docker/Dockerfile.node15 b/pkg/docker/Dockerfile.node15 index a392045f..7eddfb26 100644 --- a/pkg/docker/Dockerfile.node15 +++ b/pkg/docker/Dockerfile.node15 @@ -8,7 +8,7 @@ RUN set -ex \ && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ && hg clone https://hg.nginx.org/unit \ && cd unit \ - && hg up 1.22.0 \ + && hg up 1.23.0 \ && NCPU="$(getconf _NPROCESSORS_ONLN)" \ && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ && CC_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_CFLAGS_MAINT_APPEND="-Wp,-D_FORTIFY_SOURCE=2 -fPIC" dpkg-buildflags --get CFLAGS)" \ diff --git a/pkg/docker/Dockerfile.perl5.32 b/pkg/docker/Dockerfile.perl5.32 index a9813f47..aa000f63 100644 --- a/pkg/docker/Dockerfile.perl5.32 +++ b/pkg/docker/Dockerfile.perl5.32 @@ -8,7 +8,7 @@ RUN set -ex \ && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ && hg clone https://hg.nginx.org/unit \ && cd unit \ - && hg up 1.22.0 \ + && hg up 1.23.0 \ && NCPU="$(getconf _NPROCESSORS_ONLN)" \ && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ && CC_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_CFLAGS_MAINT_APPEND="-Wp,-D_FORTIFY_SOURCE=2 -fPIC" dpkg-buildflags --get CFLAGS)" \ diff --git a/pkg/docker/Dockerfile.php8.0 b/pkg/docker/Dockerfile.php8.0 index d4b02940..4534f9b5 100644 --- a/pkg/docker/Dockerfile.php8.0 +++ b/pkg/docker/Dockerfile.php8.0 @@ -8,7 +8,7 @@ RUN set -ex \ && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ && hg clone https://hg.nginx.org/unit \ && cd unit \ - && hg up 1.22.0 \ + && hg up 1.23.0 \ && NCPU="$(getconf _NPROCESSORS_ONLN)" \ && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ && CC_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_CFLAGS_MAINT_APPEND="-Wp,-D_FORTIFY_SOURCE=2 -fPIC" dpkg-buildflags --get CFLAGS)" \ diff --git a/pkg/docker/Dockerfile.python3.9 b/pkg/docker/Dockerfile.python3.9 index 29ce7f3b..e8650d44 100644 --- a/pkg/docker/Dockerfile.python3.9 +++ b/pkg/docker/Dockerfile.python3.9 @@ -8,7 +8,7 @@ RUN set -ex \ && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ && hg clone https://hg.nginx.org/unit \ && cd unit \ - && hg up 1.22.0 \ + && hg up 1.23.0 \ && NCPU="$(getconf _NPROCESSORS_ONLN)" \ && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ && CC_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_CFLAGS_MAINT_APPEND="-Wp,-D_FORTIFY_SOURCE=2 -fPIC" dpkg-buildflags --get CFLAGS)" \ diff --git a/pkg/docker/Dockerfile.ruby2.7 b/pkg/docker/Dockerfile.ruby2.7 index a2fb0b26..aa8cdb3f 100644 --- a/pkg/docker/Dockerfile.ruby2.7 +++ b/pkg/docker/Dockerfile.ruby2.7 @@ -8,7 +8,7 @@ RUN set -ex \ && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ && hg clone https://hg.nginx.org/unit \ && cd unit \ - && hg up 1.22.0 \ + && hg up 1.23.0 \ && NCPU="$(getconf _NPROCESSORS_ONLN)" \ && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ && CC_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_CFLAGS_MAINT_APPEND="-Wp,-D_FORTIFY_SOURCE=2 -fPIC" dpkg-buildflags --get CFLAGS)" \ -- cgit From 3c969905bd6db6446b5213acb616e8c04ff546f4 Mon Sep 17 00:00:00 2001 From: Valentin Bartenev Date: Thu, 25 Mar 2021 17:25:18 +0300 Subject: Added tag 1.23.0 for changeset 49ee24c03f57 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index ca8e46f9..91de390f 100644 --- a/.hgtags +++ b/.hgtags @@ -29,3 +29,4 @@ b391df5f0102aa6afe660cfc863729c1b1111c9e 1.12.0 0e985b30067380782125f1c479eda4ef909418df 1.20.0 f804aaf7eee10a7d8116820840d6312dd4914a41 1.21.0 331bdadeca30a49dd11b86af99124c2ffeb22d05 1.22.0 +49ee24c03f5749f8a1b69dc1c600ad48517d9d7a 1.23.0 -- cgit