diff options
author | Andrew Clayton <a.clayton@nginx.com> | 2023-05-15 22:48:31 +0100 |
---|---|---|
committer | Andrew Clayton <a.clayton@nginx.com> | 2023-05-18 15:57:11 +0100 |
commit | 47683c4704572bbe0efb3b989b35a3912b65ac83 (patch) | |
tree | e52c8cd0e1ca8795a8856a19bd2df23f3350528b | |
parent | aa45d17dc610387e6e4f550626005d209fe0a6a0 (diff) | |
download | unit-47683c4704572bbe0efb3b989b35a3912b65ac83.tar.gz unit-47683c4704572bbe0efb3b989b35a3912b65ac83.tar.bz2 |
Python: Fix ASGI applications accessed over IPv6.
There are a couple of reports on GitHub about issues accessing Python
ASGI based applications over IPv6.
A request over IPv6 would result in an error like
2023/05/13 17:49:12 [alert] 47202#47202 [unit] #10: Python failed to create 'client' pair
2023/05/13 17:49:12 [alert] 47202#47202 [unit] Python failed to call 'loop.call_soon'
ValueError: invalid literal for int() with base 10: 'db8:1:1:1ee7:dead:beef:cafe'
The above error was the direct cause of the following exception:
Traceback (most recent call last):
File "/usr/lib64/python3.11/asyncio/base_events.py", line 765, in call_soon
handle = self._call_soon(callback, args, context)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib64/python3.11/asyncio/base_events.py", line 781, in _call_soon
handle = events.Handle(callback, args, self, context)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
SystemError: <class 'asyncio.events.Handle'> returned a result with an exception set
This issue occurred in the nxt_py_asgi_create_ip_address() function
where it tries to create an IP address / port number pair.
It does this by looking for the first ':' in the address and taking
everything after it as the port number. Like in the above error message,
if we tried to access the server @ 2001:db8:1:1:1ee7:dead:beef:cafe,
then we'd end up with the port number as 'db8:1:1:1ee7:dead:beef:cafe'.
There are two issues with this
1) The IP address and port number are already flowed through
separately.
2) Even if (1) wasn't true, it would still be broken for IPv6 as we'd
expect to a get an address literal like
[2001:db8:1:1:1ee7:dead:beef:cafe]:8080, however there was no code to
handle the []'s.
The fix is to simply not try looking for a port number. We pass a port
number into this function to use in the case where we don't find a port
number, we never will...
A further cleanup would be to flow through the server port number when
creating the 'server pair' PyTuple, rather than just using the hard
coded 80.
Closes: <https://github.com/nginx/unit/issues/793>
Closes: <https://github.com/nginx/unit/issues/874>
Reviewed-by: Alejandro Colomar <alx@nginx.com>
Signed-off-by: Andrew Clayton <a.clayton@nginx.com>
-rw-r--r-- | src/python/nxt_python_asgi.c | 14 |
1 files changed, 3 insertions, 11 deletions
diff --git a/src/python/nxt_python_asgi.c b/src/python/nxt_python_asgi.c index adf03e2b..9f6cde3b 100644 --- a/src/python/nxt_python_asgi.c +++ b/src/python/nxt_python_asgi.c @@ -828,7 +828,7 @@ nxt_py_asgi_create_address(nxt_unit_sptr_t *sptr, uint8_t len, uint16_t port) static PyObject * nxt_py_asgi_create_ip_address(nxt_unit_sptr_t *sptr, uint8_t len, uint16_t port) { - char *p, *s; + char *p; PyObject *pair, *v; pair = PyTuple_New(2); @@ -837,9 +837,8 @@ nxt_py_asgi_create_ip_address(nxt_unit_sptr_t *sptr, uint8_t len, uint16_t port) } p = nxt_unit_sptr_get(sptr); - s = memchr(p, ':', len); - v = PyString_FromStringAndSize(p, s == NULL ? len : s - p); + v = PyString_FromStringAndSize(p, len); if (nxt_slow_path(v == NULL)) { Py_DECREF(pair); @@ -848,14 +847,7 @@ nxt_py_asgi_create_ip_address(nxt_unit_sptr_t *sptr, uint8_t len, uint16_t port) PyTuple_SET_ITEM(pair, 0, v); - if (s != NULL) { - p += len; - v = PyLong_FromString(s + 1, &p, 10); - - } else { - v = PyLong_FromLong(port); - } - + v = PyLong_FromLong(port); if (nxt_slow_path(v == NULL)) { Py_DECREF(pair); |