# stunnel ## Install ```bash brew install stunnel ``` ### [[Homebrew]] post-installation notes ```text A bogus SSL server certificate has been installed to: /usr/local/etc/stunnel/stunnel.pem This certificate will be used by default unless a config file says otherwise! Stunnel will refuse to load the sample configuration file if left unedited. In your stunnel configuration, specify a SSL certificate with the "cert =" option for each service. To use Stunnel with Homebrew services, make sure to set "foreground = yes" in your Stunnel configuration. To start stunnel: brew services start stunnel Or, if you don't want/need a background service you can just run: /usr/local/opt/stunnel/bin/stunnel ``` ## Docs None lol, just refers us to the manual Web version here: https://www.stunnel.org/docs.html See manual on command line: ```bash man stunnel ``` See help: ```bash stunnel -help ``` ### Man page SERVICE-LEVEL OPTIONS Each configuration section begins with a service name in square brackets. The service name is used for libwrap (TCP Wrappers) access control and lets you distinguish stunnel services in your log files. accept = [HOST:]PORT accept connections on specified address If no host specified, defaults to all IPv4 addresses for the local host. To listen on all IPv6 addresses use: `accept = :::PORT` connect = [HOST:]PORT connect to a remote address If no host is specified, the host defaults to localhost. Multiple connect options are allowed in a single service section. If host resolves to multiple addresses and/or if multiple connect options are specified, then the remote address is chosen using a round-robin algorithm. redirect = [HOST:]PORT redirect TLS client connections on certificate-based authentication failures **This option only works in server mode.** Some protocol negotiations are also incompatible with the redirect option. ### Sample UNIX Configuration File - Web-hosted version: https://www.stunnel.org/config_unix.html - Also available at `/usr/local/etc/stunnel/stunnel.conf-sample` after installation via [[Homebrew]] This seems pertinent... after all, [[stunnel]] is used for a lot more things than just [[HTTPS]] ```text ; TLS front-end to a web server ;[https] ;accept = 443 ;connect = 80 ;cert = /usr/local/etc/stunnel/stunnel.pem ; "TIMEOUTclose = 0" is a workaround for a design flaw in Microsoft SChannel ; Microsoft implementations do not use TLS close-notify alert and thus they ; are vulnerable to truncation attacks ;TIMEOUTclose = 0 ``` ### SSL Certificates HOWTO (Linked on docs page) https://tldp.org/HOWTO/SSL-Certificates-HOWTO/ - The other links in the same section are mostly about [[CA]]s ![[Screen Shot 2021-08-29 at 4.00.12 AM.png]] ## Resources ### [[macOS]] specific Pretty much nothing comes up if you google "guide to stunnel on Mac" - There's a guy asking for help (no reply) and the following guide, otherwise looks like need to figure out how it works from the sample UNIX conf and man pages ### Stunnel + [[OpenVPN]] Installation Guide for [[macOS]] https://help.vpntunnel.com/support/solutions/articles/5000756213-vpntunnel-stunnel-openvpn-installation-guide-for-mac - Last updated in 2017 - They have preconfigured stunnel.confs, doesn't seem to be useful ### Stunnel HOWTO https://www.stunnel.org/howto.html - Looks useful! - "Running stunnel is daemon mode" - Generating certificate, getting it signed by a [[CA]] ### [[Stack Overflow]]: Wrapping the PHP Development Server using [[stunnel]] https://stackoverflow.com/a/12946566 ```bash # Install stunnel brew install stunnel php -S localhost:8000 & stunnel3 -d 443 -r 8080 ``` Possible helpful comments: - "Re the code above (php -S localhost:8000 &; stunnel3 -d 443 -r 8080) The stunnel3 command appears to redirect port 443 https request to port 8080, and the php command appears to serve requests to port 8000. Should the stunnel3 command redirect to port 8000 instead?" - I had to: `openssl req -new -x509 -days 365 -nodes -out stunnel.pem -keyout stunnel.pem && sudo mv stunnel.pem /etc/stunnel && sudo stunnel3 -p /etc/stunnel/stunnel.pem -d 443 -r 8000` - First line appears to generate a new cert - Second line moves the cert to somewhere useful - Third line runs stunnel, `accept`ing connections at port 443 and `redirect`ing requests to port 8000 - Update: It should be `connect` to port 8000 - Ended up adding my own answer: https://stackoverflow.com/a/68972141/ ### "Connect using TLS with public Web Server" https://www.stunnel.org/pipermail/stunnel-users/2018-March/005944.html Their config: ```text [omgeo] client = yes accept = 127.0.0.1:19201 connect = ctm.omgeo.net:443 verify = 2 CApath = /etc/ssl/certs/ ``` - Should I be specifying `127.0.0.1:8000` as my hostname instead of just `8000`? ### SOLUTION: Red Hat Customer Portal: "3.6.2 Configuring Stunnel as a TLS Wrapper" https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/security_guide/sec-configuring_stunnel_wrapper The clear definitions below fixed the configuration issue: >- `accept` — the port to listen on >- `connect` — the port to connect to; this must be the port that the service you are securing uses tl;dr: Use `connect` instead of `redirect` ## Setup ```bash cd /usr/local/etc/stunnel # Copy the sample conf file to actual conf file cp stunnel.conf-sample stunnel.conf # Edit conf vim stunnel.conf ``` ### stunnel.conf Modify`stunnel.conf` so it looks like this: (all other options can be deleted) ```text ; ************************************************************************** ; * Global options * ; ************************************************************************** ; Debugging stuff (may be useful for troubleshooting) ; Enable foreground = yes to make stunnel work with Homebrew services foreground = yes debug = info output = /usr/local/var/log/stunnel.log ; ************************************************************************** ; * Service definitions (remove all services for inetd mode) * ; ************************************************************************** ; ***************************************** Example TLS server mode services ; TLS front-end to a web server [https] accept = 443 connect = 8000 cert = /usr/local/etc/stunnel/stunnel.pem ; "TIMEOUTclose = 0" is a workaround for a design flaw in Microsoft SChannel ; Microsoft implementations do not use TLS close-notify alert and thus they ; are vulnerable to truncation attacks ;TIMEOUTclose = 0 ``` - Not including the Microsoft workaround for now, can try it if there is a problem with it later - The [[#Homebrew post-installation notes]] also mentions that `foreground = yes` must be added to `stunnel.conf` if [[stunnel]] is to be as a background process (i.e. daemon) via [[Homebrew]] services - Info on [[Homebrew]] services: https://github.com/Homebrew/homebrew-services ## Usage ### Start / stop via [[Homebrew]] services ```bash # Start stunnel brew services start stunnel # Stop stunnel brew services stop stunnel # Restart stunnel brew services restart stunnel ``` ## Debugging Notes ### [[PHP]] Development Server only accepts localhost, not `127.0.0.1` - Works: http://localhost:8000/ - Doesn't work: http://127.0.0.1:8000/ So I should probably redirect to specifically `localhost:8000` - Update, it's not `redirect`, it's `connect`, and the value can be either `localhost:8000` or `8000` (both worked in tests) ### connect option is currently unused Description: "Connect to a remote address" - Doesn't seem right the right option - Can't see how setting it to e.g. localhost:443 might change anything ### No log output Logs should be stored at `/usr/local/var/log/stunnel.log` but still nothing is showing up after `brew services restart stunnel` - I also tried changing `debug = info` to `debug = debug` to no avail - I also tried `touch stunnel.log` and restarting, but it remains empty #### Update: Logs started appearing after stunnel was configured correctly ```bash tail -n 20 -f stunnel.log ``` ### Broken curl -v outputs ```bash echo "\nTrying http://localhost:8000" curl -v http://localhost:8000 # Works echo "\nTrying http://127.0.0.1:8000" curl -v http://127.0.0.1:8000 # Connection refused echo "\nTrying https://localhost:443" curl -v https://localhost:443 # Connection refused echo "\nTrying https://127.0.0.1:443" curl -v https://127.0.0.1:443 # Connection refused ``` - "Connection refused" means the port is closed, i.e. there isn't actually something running at that hostname:port #### Update: Working curl -v outputs ```bash echo "\nTrying http://localhost:8000" curl -v http://localhost:8000 # Works echo "\nTrying http://127.0.0.1:8000" curl -v http://127.0.0.1:8000 # Connection refused echo "\nTrying https://localhost:443" curl -v https://localhost:443 # Cert error echo "\nTrying https://127.0.0.1:443" curl -v https://127.0.0.1:443 # Cert error ``` Cert error message from curl ```text Trying https://localhost:443 * Trying ::1... * TCP_NODELAY set * Connected to localhost (::1) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: /etc/ssl/cert.pem CApath: none * TLSv1.2 (OUT), TLS handshake, Client hello (1): * TLSv1.2 (IN), TLS handshake, Server hello (2): * TLSv1.2 (IN), TLS handshake, Certificate (11): * TLSv1.2 (OUT), TLS alert, unknown CA (560): * SSL certificate problem: self signed certificate * Closing connection 0 curl: (60) SSL certificate problem: self signed certificate More details here: https://curl.haxx.se/docs/sslcerts.html curl failed to verify the legitimacy of the server and therefore could not establish a secure connection to it. To learn more about this situation and how to fix it, please visit the web page mentioned above. ``` ### Update: curl ngrok ```bash echo "\nTrying http://max.ngrok.io" curl -v http://max.ngrok.io # Works echo "\nTrying https://max.ngrok.io" curl -v https://max.ngrok.io # Works echo "\nTrying http://max.ngrok.io/nds/fas-aes-https.php" curl -v http://max.ngrok.io/nds/fas-aes-https.php # 301 echo "\nTrying https://max.ngrok.io/nds/fas-aes-https.php" curl -v https://max.ngrok.io/nds/fas-aes-https.php # 301 ```