b64_pton and b64_ntop functions are not portable and cannot be found in
all C library implementations (e.g. uClibc, musl).
Since c-websockify already has explicit dependency to openssl it can be
used to replace b64_pton/ntop with versions that are portable without
introducing too much additional code or dependencies.
Instead of single certificate in one file it is sometimes customary to
chain multiple certificates into the same file. This is common practice
for CAs like letsencrypt that are providing intermediate certificates.
This patch switches loading of only one certificate to loading whole chain
of certificates.
The effects can be seen with e.g. the following command:
openssl s_client -showcerts -connect websockify-hostname:8080
Before the change the verify fails:
Certificate chain
0 s:/CN=websockify-hostname
i:/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
After the change the verify passes:
Certificate chain
0 s:/CN=websockify-hostname
i:/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
1 s:/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
i:/O=Digital Signature Trust Co./CN=DST Root CA X3
Regression caused by a29946e9. We were no longer detecting a cleanly
closed proxy socket. This is not a WebSocket, but an ordinary one,
so we should be checking for "" rather that None.
If option '--key' is not specified. 'WebSockifyServer class' will
inital self.key as empty string. but ssl load_cert_chain function
will raise error 'no such file' with keyfile param empty string.
* Incorporates #190 without breaking compatibility towards old Python versions.
* A new plugin allows authenticating clients by the "common name" defined in their certificate.
* Added manual for certificate-based client authentication, including hints to which Python versions allow client certificate authentication.
* Adjusted test to work with new ssl.create_default_context.
Fixes a problem that occurs in Chrome 61 where the following error message appears in the console:
'Failed to load module script: The server responded with a non-JavaScript MIME type of "".
Strict MIME type checking is enforced for module scripts per HTML spec.'
In python 2 the ssl.wrap_socket doesn't work on sockets created using socket.fromfd.
The workaround is to wrap the socket returned by socket.fromfd into another socket
object using the private _sock constructor parameter.
With the --inetd parameter, websockify doesn't require the source_addr and
source_port paramters and it expects that stdin is already opened and listening
socket.
This way websockify can be used with (x)inetd or as a systemd socket-activated
service.
This only enables the SIGCHLD handler if SIGCHLD
exists, such that platforms without SIGCHLD (such
as windows) can still run websockify natively.
See #108
The socket.sendall method is called indirectly via calls
to the python3.6 BaseHTTPRequestHandler.send_error method
which is called by both the Web*RequestHandler classes as
shown below:
======================================================================
ERROR: test_list_dir_with_file_only_returns_error (test_websockifyserver.WebSockifyRequestHandlerTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "tests/test_websockifyserver.py", line 115, in test_list_dir_with_file_only_returns_error
FakeSocket('GET / HTTP/1.1'), '127.0.0.1', server)
File "websockify/websockifyserver.py", line 94, in __init__
WebSocketRequestHandler.__init__(self, req, addr, server)
File "websockify/websocketserver.py", line 34, in __init__
BaseHTTPRequestHandler.__init__(self, request, client_address, server)
File "/usr/lib64/python3.6/socketserver.py", line 696, in __init__
self.handle()
File "websockify/websockifyserver.py", line 293, in handle
SimpleHTTPRequestHandler.handle(self)
File "/usr/lib64/python3.6/http/server.py", line 418, in handle
self.handle_one_request()
File "websockify/websocketserver.py", line 46, in handle_one_request
BaseHTTPRequestHandler.handle_one_request(self)
File "/usr/lib64/python3.6/http/server.py", line 406, in handle_one_request
method()
File "websockify/websocketserver.py", line 58, in _websocket_do_GET
self.do_GET()
File "websockify/websockifyserver.py", line 259, in do_GET
SimpleHTTPRequestHandler.do_GET(self)
File "/usr/lib64/python3.6/http/server.py", line 636, in do_GET
f = self.send_head()
File "/usr/lib64/python3.6/http/server.py", line 679, in send_head
return self.list_directory(path)
File "websockify/websockifyserver.py", line 263, in list_directory
self.send_error(404, "No such file")
File "/usr/lib64/python3.6/http/server.py", line 470, in send_error
self.end_headers()
File "/usr/lib64/python3.6/http/server.py", line 520, in end_headers
self.flush_headers()
File "/usr/lib64/python3.6/http/server.py", line 524, in flush_headers
self.wfile.write(b"".join(self._headers_buffer))
File "/usr/lib64/python3.6/socketserver.py", line 775, in write
self._sock.sendall(b)
AttributeError: 'FakeSocket' object has no attribute 'sendall'
======================================================================
ERROR: test_normal_get_with_only_upgrade_returns_error (test_websockifyserver.WebSockifyRequestHandlerTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "tests/test_websockifyserver.py", line 101, in test_normal_get_with_only_upgrade_returns_error
FakeSocket('GET /tmp.txt HTTP/1.1'), '127.0.0.1', server)
File "websockify/websockifyserver.py", line 94, in __init__
WebSocketRequestHandler.__init__(self, req, addr, server)
File "websockify/websocketserver.py", line 34, in __init__
BaseHTTPRequestHandler.__init__(self, request, client_address, server)
File "/usr/lib64/python3.6/socketserver.py", line 696, in __init__
self.handle()
File "websockify/websockifyserver.py", line 293, in handle
SimpleHTTPRequestHandler.handle(self)
File "/usr/lib64/python3.6/http/server.py", line 418, in handle
self.handle_one_request()
File "websockify/websocketserver.py", line 46, in handle_one_request
BaseHTTPRequestHandler.handle_one_request(self)
File "/usr/lib64/python3.6/http/server.py", line 406, in handle_one_request
method()
File "websockify/websocketserver.py", line 58, in _websocket_do_GET
self.do_GET()
File "websockify/websockifyserver.py", line 257, in do_GET
self.send_error(405, "Method Not Allowed")
File "/usr/lib64/python3.6/http/server.py", line 470, in send_error
self.end_headers()
File "/usr/lib64/python3.6/http/server.py", line 520, in end_headers
self.flush_headers()
File "/usr/lib64/python3.6/http/server.py", line 524, in flush_headers
self.wfile.write(b"".join(self._headers_buffer))
File "/usr/lib64/python3.6/socketserver.py", line 775, in write
self._sock.sendall(b)
AttributeError: 'FakeSocket' object has no attribute 'sendall'