Hello. I'm trying to configure "protocol = socks" with "redirect = 127.0.0.1:80" and "verifyPeer = yes", but accordingly to the debug logs stunnel doesn't verify peer when I'm trying to connect without client's certificate, for an example, from browser: https://192.168.200.131:9013/, where 192.168.200.131 is stunnel server. Config file: [socks] cert = /usr/local/etc/stunnel/server.pem CAfile = /usr/local/etc/stunnel/client.crt verifyPeer = yes
redirect = 127.0.0.1:80 accept = 0.0.0.0:9013 protocol = socks
Debug log: 2024.10.02 07:24:19 LOG6[9]: No peer certificate received 2024.10.02 07:24:19 LOG6[9]: Session id: AFA5F9CE2997328612F76E3B3572FE00C71C53ED31A98567E56DCC084EF580AD 2024.10.02 07:24:19 LOG7[9]: TLS state (accept): SSLv3/TLS write session ticket 2024.10.02 07:24:19 LOG6[9]: TLS accepted: new session negotiated 2024.10.02 07:24:19 LOG6[9]: TLSv1.3 ciphersuite: TLS_AES_128_GCM_SHA256 (128-bit encryption) 2024.10.02 07:24:19 LOG6[9]: Peer temporary key: X25519, 253 bits 2024.10.02 07:24:19 LOG7[9]: Compression: null, expansion: null 2024.10.02 07:24:19 LOG7[9]: Waiting for the SOCKS request 2024.10.02 07:24:19 LOG3[9]: Unsupported SOCKS version 0x47 2024.10.02 07:24:19 LOG5[9]: Connection reset: 0 byte(s) sent to TLS, 0 byte(s) sent to socket
It tries to accept SOCKS info even without certificate and doesn't redirect to 127.0.0.1:80.
In browser, I'm getting:
Secure Connection Failed An error occurred during a connection to 192.168.200.131:9013. PR_CONNECT_RESET_ERROR Error code: PR_CONNECT_RESET_ERROR
Can you check why it happens?
Thank you.
FYI: I use the latest stunnel version: stunnel 5.73 on x86_64-pc-linux-gnu platform Compiled/running with OpenSSL 3.0.14 4 Jun 2024
I'm not fully sure but seems like "redirect" + "verifyPeer = yes" doesn't work with any "protocol". Or i'm doing something wrong....
I've sort of managed how to fix it, but i'm afraid it's a wrong one. In "client_try" method I've made these changes: ssl_start(c);
if (c->opt->protocol) { if(redirect(c)) { /* process "redirect" first */ s_log(LOG_NOTICE, "Redirecting connection"); /* c->connect_addr.addr may be allocated in protocol negotiations */ str_free(c->connect_addr.addr); addrlist_dup(&c->connect_addr, &c->opt->redirect_addr); } else if(c->opt->protocol_middle) { c->opt->protocol_middle(c); } }
remote_start(c);
instead of: ssl_start(c);
if(c->opt->protocol_middle) { c->opt->protocol_middle(c); }
remote_start(c); ---
It works, but in the log I see a doubled "Redirecting connection" message, however it redirects only once.
Sorry, I'm not a fully C coder.
I guess doubling happens because of "remote_start" called at the end, which calls "connect_remote(c); -> connect_setup(c); -> redirect(c)" again.
Or it would work merely modifying "socks_server_middle" (add the fix at the beginning of function) function, since I need only "protocol = socks" to be fixed: SSL_SESSION *sess; void *ex_data;
if(!c->ssl) return; else { sess=SSL_get1_session(c->ssl); if(!sess) return; else { ex_data=SSL_SESSION_get_ex_data(sess, index_session_authenticated); SSL_SESSION_free(sess); if (ex_data == NULL) return; } }
I checked it out. No double "Redirecting connection" anymore, also "socks" works as expected and redirects to 127.0.0.1:80 when there's no verified peer is connected (from browsers for an example).
or probably this one would do the trick for all protocols: if((!c->opt->protocol || !redirect(c)) && c->opt->protocol_middle) { c->opt->protocol_middle(c); }
or probably just: if(c->opt->protocol_middle && !redirect(c)) { c->opt->protocol_middle(c); }
---
Anyway, i'm not confident in all these fixes. Please help if you can.
Eventually I kept "if(c->opt->protocol_middle && !redirect(c)) {" and using it like this without any problems with "socks". After couple days I will let you know about its stability.
Finally, stopped with this final patch: client.c:client_try() function ... ssl_start(c); if(c->opt->protocol_middle) { if (redirect(c)) c->opt->already_redirected = 1; else c->opt->protocol_middle(c); } remote_start(c); ... ---
client.c:redirect() function (to prevent all the logic in redirect() function called twice - saves some ticks, kind of): NOEXPORT int redirect(CLI *c) { ... if (c->opt->already_redirected) { c->opt->already_redirected = 0; return 1; } ...
---
Works as a charm. Now "protocol = socks" "accept" port doesn't expose itself to non-authorized connections.
Created this PR on github: https://github.com/mtrojnar/stunnel/pull/21
Please, when you have time, check it out and if you have any concerns about memory leaking and etc. - please advise. I've been using this fix for a month without any issues.