跳到主要内容

stunnel

apk add stunnel      # AlpineLinux
brew install stunnel # macOS

echo -n psk: > /etc/stunnel/psk.txt
openssl rand -base64 180 | tr -d '\n' >> /etc/stunnel/psk.txt
# sed --in-place '1s/^/psk:/' /etc/stunnel/psk.txt

echo -e '\xef\xbb\xbf;BOM Here' > /etc/stunnel/stunnel.conf
# 服务端
cat << CONF >> /etc/stunnel/stunnel.conf
setuid = stunnel
setgid = stunnel
pid = /run/stunnel/stunnel.pid
socket = l:TCP_NODELAY=1
socket = r:TCP_NODELAY=1
debug = 5

; 配置在服务端
[test server]
client = no
accept = 18080
connect = 8080
ciphers = PSK
PSKsecrets = /etc/stunnel/psk.txt

; 配置在客户端
[test client]
client = yes
accept = 8081
connect = 127.0.0.1:18080 ; host 会变
ciphers = PSK
PSKsecrets = /etc/stunnel/psk.txt
CONF

socat -u tcp-l:8080,fork exec:/bin/cat # 服务端
echo Hello | nc 127.0.0.1 8080 # 本地能通

mkdir -p /run/stunnel
chown stunnel /run/stunnel

stunnel

echo Hello | nc 127.0.0.1 8081 # Tunnel 后的端口
  • /etc/stunnel/stunnel.conf

类似工具

openssl s_client -connect server.com:443 -quiet

socat TCP-LISTEN:8888 OPENSSL:server.com:443,verify=0

SSH over TLS

Host server.com
ProxyCommand openssl s_client -connect server.com:443 -quiet
  • HAProxy 也可以 terminate TLS 然后转发到 TCP
backend secure_http
reqadd X-Forwarded-Proto:\ https
rspadd Strict-Transport-Security:\ max-age=31536000
mode http
option httplog
option forwardfor
server local_http_server 127.0.0.1:80

backend ssh
mode tcp
option tcplog
server ssh 127.0.0.1:22
timeout server 2h

frontend ssl
bind X.X.X.X:443 ssl crt /etc/ssl/private/certs.pem no-sslv3
mode tcp
option tcplog
tcp-request inspect-delay 5s
tcp-request content accept if HTTP

acl client_attempts_ssh payload(0,7) -m bin 5353482d322e30

use_backend ssh if !HTTP
use_backend ssh if client_attempts_ssh
use_backend secure_http if HTTP

stunnel.conf

  • protocol
    • socks - 监听 SOCKS - 作为 socks 代理服务
    • connect - HTTP 1.1 CONNECT - 只能 client 模式
    • cifs, capwin, capwinctrl, connect, imap, ldap, nntp, pgsql, pop3, proxy, smtp, socks
  • verify
    • 1 - prefer
    • 2 - CA
    • 3 - CA+Cert
  • client
    • yes - 远程服务使用 TLS
  • connect - 可配置多个 - round-robin
foreground=no ; yes, quite
log=append ; overwrite
; output=
; pid=
; service= ; inetd
syslog=yes

; chroot=
; compression= ; deflate, zlib
debug= ; 1-7
; EGE= ; Entropy Gathering Daemon
engine=auto

[SERVICE NAME]
client=no ; yes
; 监听端口
; server - 服务端协议
; client - 通道后的协议
accept=
; 连接端口
; server - 上游
; client - 服务端
connect=

exec= ; inetd-type program
execArgs=
retry=no ; connect+exec
pty= ; yes, no

failover=prio; rr

PSKidentity= ; psk client
PSKsecrets= ; IDENTITY:KEY

; cifs, capwin, capwinctrl, connect, imap, ldap, nntp, pgsql, pop3, proxy, smtp, socks
protocol=
protocolAuthentication=
protocolDomain=
protocolHeader=
protocolHost=
protocolPassword=
protocolUsername=

redirect=
renegotiation=yes

reset=yes ; TCP RST

ident= ; USERNAME
include= ; DIR
config= ; openssl config
CApath=
CAfile=
cert=
key=
; server - 匹配的名字
; client - 定义名字
sni=
requireCert=no
checkEmail=
checkHots=
checkIP=
cipgers=
ciphersuites=
CRLpath=
CRLfile=
curves=
logID=
debug=
delay=no ; delay DNS lookup for connect
engineId=
engineNum=
libwrap=no ; /etc/hosts.allow, /etc/hosts.deny
local=
sslVersion=
sslVersionMax=
sslVersionMin=
stack=

OCSP=
OCSPaia=
OCSPflag=
OCSPnonce=
options= ; SSL Options

securityLevel=

setgid=
setuid=

sessionCacheSize=
sessionCacheTimeout=
sessionResume=yes
sessiond= # TLS cache server

socket=
ticketKeySecret=
ticketMacSecret=

TIMEOUTbusy=
TIMEOUTclose=
TIMEOUTconnect=
TIMEOUTidle=

transparent= ; none | source | destination | both

verify=
verifyChain=
verifyPeer=no

pgsql

[pg]
client = yes
protocol = pgsql
accept = 0.0.0.0:5432
connect = pg-b:15432
options = NO_TICKET
retry = yes
create extension sslinfo();
select ssl_is_used()

cert

# cert 和 key 也可以在同一个文件
openssl req -new -days 365 -nodes -x509 -out cert.pem -keyout key.pem

cat key.pem cert.pem >> /etc/stunnel/stunnel.pem
cert=cert.pem
key=key.pem
CAfile=cert.pem
verify=3
client=no

sni

openssl req -new -days 365 -nodes -x509 -out cert.pem -keyout key.pem

openssl genrsa -out c1.key 1024
openssl req -new -key c1.key -out c1.csr

openssl ca -extensions v3_ca -days 365 -out c1.cer -policy policy_anything -in c1.csr
[virtual]
; 无 SNI 时
was not correct
accept = 443
cert = /usr/local/etc/stunnel/stunnel.pem
exec = /usr/local/bin/hello

[server s1]
sni = virtual:*.example.com
cert = /usr/local/etc/stunnel/public_cert.pem
connect = 10.10.10.11:80

[server s2]
sni = virtual:secret.net
cert = /usr/local/etc/stunnel/secret_cert.pem
connect = localhost:888
verifyPeer = yes
CAfile = /usr/local/etc/stunnel/allowed-clients.pem


[cleint]
client = yes
sni = c1.example.com
accept = 127.0.0.1:80
connect = 10.10.10.12:443
cert = stunnel.pem
verifyPeer = yes
CAfile = sni_certs.pem