# 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
```