null

Запускаем OpenVPN, HTTPS, SSH и Socks5 на одном порту

Многие уже знакомы с "официальным" способом запуска связки OpenVPN + nginx на одном порту, но
можем ли мы пойти дальше и расширить количество программ?

Для распределения запросов по конечным сервисам, потребуется отдельный демон, который будет слушать необходимый порт, распознавать сигнатуры подключений и направлять их далее на тот или иной локальный порт приложений.

Для реализации подобного распределения, возпользуемся балансирующим реверс-прокси сервером haproxy.

Начнём сразу с готового конфига и далее разберём на его примере работу всей связки.

global
	log /dev/log	local0
	log /dev/log	local1 notice
	chroot /var/lib/haproxy
	stats socket /run/haproxy/admin.sock mode 660 level admin
	stats timeout 30s
	user haproxy
	group haproxy
	daemon

	# Default SSL material locations
	ca-base /etc/ssl/certs
	crt-base /etc/ssl/private

	# Default ciphers to use on SSL-enabled listening sockets.
	# For more information, see ciphers(1SSL). This list is from:
	#  https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/
	# An alternative list with additional directives can be obtained from
	#  https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=haproxy
	ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS
	ssl-default-bind-options no-sslv3
	tune.ssl.default-dh-param 2048

defaults
	log	global
	mode	tcp
	option	tcplog
	#option	httplog
	#option	dontlognull
        timeout connect 5000
        timeout client  50000
        timeout server  50000
	errorfile 400 /etc/haproxy/errors/400.http
	errorfile 403 /etc/haproxy/errors/403.http
	errorfile 408 /etc/haproxy/errors/408.http
	errorfile 500 /etc/haproxy/errors/500.http
	errorfile 502 /etc/haproxy/errors/502.http
	errorfile 503 /etc/haproxy/errors/503.http
	errorfile 504 /etc/haproxy/errors/504.http

frontend ssl
	mode tcp
	bind 0.0.0.0:443
	timeout client-fin 5m
	tcp-request inspect-delay 5s
	tcp-request content accept	if { req.ssl_hello_type 1 }
	use_backend https		if { req.ssl_hello_type 1 }
	use_backend ssh			if !{ req.ssl_hello_type 1 } { payload(0,7) -m bin 5353482d322e30 } OR !{ req.ssl_hello_type 1 } { req.len 0 }
	use_backend socks		if { req.payload(0,3) -m bin 050102 } OR { req.payload(0,4) -m bin 05020002 }
	use_backend openvpn		if !{ req.ssl_hello_type 1 } !{ req.len 0 }

backend https
	mode tcp
	timeout server 2h
	server https-localhost 127.0.0.1:4433

backend openvpn
	mode tcp
	timeout tunnel 12h
	server openvpn-localhost 127.0.0.1:1195

backend ssh
	mode tcp
	timeout tunnel 12h
	server ssh-localhost 127.0.0.1:22

backend socks
	mode tcp
	timeout tunnel 12h
	server socks-localhost 127.0.0.1:1080

Самое сложное - понять, по какому принципу осуществлять определение тех или иных протоколов. В этом нам помогают наборы условий в haproxy, позволяющие алаизировать содеримое пришедших пакетов.

HTTPS подкючения отсеиваются по успешному парсингу типа SSL Hello сообщения, отправляемого клиентом серверу при установлении SSL соединения.

SSH подключение характеризуется наличием строки SSH-2.0 в начале первого пакета, посылаемого клюентом. HEX-последовательность 5353482d322e30 как раз и представляет собой эту строку в 16-ричном представлении.

Socks5 парсится так же, как и SSH: простым разбором протокола по RFC.

05 - версия протокола
02 - количество способов аутентификации
00 - без аутентификации
02 - аутентификация по логину и паролю

Соответственно, при использовании других методов, рекомендуется предварительно прослушать трафик Wireshark'ом и понять, что шлёт клиент при подключении.

На OpenVPN по сути заворачивается весь остальной трафик, который не удалось распарсить как валидный SSL.