如何分析Haproxy端口复用

本文作者:Spark(Ms08067内网安全小组成员)

一、概述

Haproxy是一个使用c语言开发的高性能负载均衡代理软件,提供tcp和http的应用程序代理,免费、快速且可靠。类似frp,使用一个配置文件+一个server就可以运行。优点:

大型业务领域应用广泛

一、浅析Haproxy端口复用的实现原理

支持四层代理(传输层)以及七层代理(应用层)

支持acl(访问控制列表),可灵活配置路由

windows使用cygwin编译后可运行(可跨平台)

访问控制列表(Access Control Lists,ACL)是应用在路由器接口的指令列表,这些指令列表用来告诉路由器哪些数据包可以接受,哪些数据包需要拒绝。

二、配置

官方配置手册:https://cbonte.github.io/haproxy-dconv/2.2/configuration.html配置文件由全局配置和代理配置组成:全局配置(global):定义haproxy进程管理安全及性能相关的参数

代理设定(proxies):

defaults:为其他配置段提供默认参数,默认配置参数可由下一个"
defaults"
重新设定

frontend:定义一系列监听的套接字,这些套接字可接受客户端请求并与之建立连接

backend:定义"
后端"
服务器,前端代理服务器将会把哭护短的请求调度至这些服务器

listen:定义监听的套接字和后端的服务器,类似于将frontend和backend段放在一起

示例:

global
defaults
log global
mode tcp
option dontlognull
timeout connect 5000
timeout client 50000
timeout server 50000

frontend main
mode tcp
bind *:8888
option forwardfor except 127.0.0.1
option forwardfor header X‐Real‐IP

# 配置acl规则
acl is‐proxy‐now urlp_reg(proxy) ^(http|https|socks5)$
# 分发到对应的backend
use_backend socks5 if is‐proxy‐now
use_backend http
backend socks5
mode tcp
timeout server 1h
server ss 127.0.0.1:50000
backend http
mode tcp
server http 127.0.0.1:80

重点关注frontend和backend。Frontend中需要编写acl规则,配置转发。比如,当http流量来的时候,转发给web服务;当rdp流量来的时候,转发给rdp服务。Backend中需要编写具体的操作,就是转达到哪个目标的哪个端口。

三、思路(1) 思路一(通用)

编写acl规则,在四层(传输层)进行负载,根据协议类型进行分发,例如:遇到http流量发送给http服务,遇到rdp发送给rdp服务等。

(2) 思路二

编写acl规则,在七层(应用层)进行负载,判断应用类型进行分发,例如,遇到http分发到http服务,否则发送到xxx服务。

四、步骤

以思路一为例:

通过wireshark捕获tpkt(应用层数据传输协议)信息

编写acl规则路由进行流量分发

添加后端server

原始接口接管

完成

4.1 捕获tpkt

关于tpkt可百度或查看参考链接三次握手后,开始应用层数据传输。使用wireshark抓包:ssh协议:

前三个包为三次握手,第四个包的起始三位,便是我们需要的tpkt,例如ssh为535348。rdp协议:030000

速查:

协议TPKTSSH535348RDP030000HTTP(GET)474554HTTP(POS)504f53HTTP(PUT)505554HTTP(DEL)44454cHTTP(OPT)4f5054HTTP(HEA)484541HTTP(CON)434f4eHTTP(TRA)545241HTTPS1603014.2 编写acl规则global
defaults
timeout connect 5000
timeout client 50000
timeout server 50000
frontend main
mode tcp
bind *:8888
# 重点:编写acl规则进行转发
tcp‐request inspect‐delay 3s
acl is_http req.payload(0,3) ‐m bin 474554 504f53 505554 44454c 4f5054 484541 434f4e 545241
acl is_ssh req.payload(0,3) ‐m bin 535348
acl is_rdp req.payload(0,3) ‐m bin 030000
# 设置四层允许通过
tcp‐request content accept if is_http
tcp‐request content accept if is_ssh
tcp‐request content accept if is_rdp
tcp‐request content accept
# 分发到对应的backend
use_backend http if is_http
use_backend ssh if is_ssh
use_backend rdp if is_rdp
use_backend socks5
backend socks5
mode tcp
timeout server 1h
server ss 127.0.0.1:50000
backend http
mode tcp
server http 127.0.0.1:80
backend ssh
mode tcp
server ssh 127.0.0.1:22
backend rdp
mode tcp
server rdp 192.168.213.129:3389

该配置文件的功能是监听8888端口,将http流量(速查表中http协议的8种tpkt)转发到本地的80上,将ssh流量转发到本地的22端口上,将rdp流量转发到另一主机的3389上。

五、实验

Target1:Ubuntu 16.04 x64

IP:192.168.213.128

开启22端口、80端口

Target2:Win7 x64

IP:192.168.213.129

开启3389端口

启动haproxy,-f 指定配置文件,开启8888端口表示启动成功。-d:调试模式,可不加。

HTTP协议:访问靶机的8888端口,流量被haproxy分发至本机的80。

RDP协议:访问靶机的8888端口,流量被haproxy分发至192.168.213.129的3389。

SSH协议:访问靶机的8888端口,流量被haproxy分发至本机的22。

haproxy日志:

六、端口重定向

为了不影响常规的80端口访问,将输入的80端口流量重定向到8888端口。当用户以正常方式访问80端口时,流量将转发到8888端口,然后由haproxy再次转发回80端口。

  • Linux:iptables(不需要重启服务)

iptables ‐t nat ‐A PREROUTING ‐i eth0 ‐p tcp ‐‐dport 80 ‐j REDIRECT ‐‐to‐port 8888

访问80可以正常访问:

Haproxy日志有记录,说明流量由80先到8888,再回到80。

  • Windows:netsh(需要重启web服务)

netsh interface portproxy add v4tov4 listenport=80 connectport=8888 connectaddress=127.0.0.1

注意:如果在windows下启用端口重定向,需要在端口启动前添加netsh端口转发规则。



Haproxy是一款高性能的负载均衡软件,支持监听多个端口,而端口数量是有限的。端口复用是一种优化方式,能让多个应用程序共享同一个监听端口,从而提高资源利用率和性能表现。在Haproxy中,端口复用不仅可以提高网络吞吐量,而且还能增加应用程序的可扩展性和可靠性。
二、端口复用的实现方法和适用场景
Haproxy利用Linux内核提供的SO_REUSEPORT选项和SO_BINDTODEVICE选项实现端口复用。这种方式可以将多个应用程序都绑定到同一个端口上,同时也能保证每个应用程序的数据不会被其他应用程序读取。端口复用适用于那些需要监听大量端口且每个端口的并发请求不是特别高的场景,比如负载均衡和反向代理。
三、如何优化Haproxy的端口复用性能
为了提高端口复用的性能,我们可以在Haproxy的配置文件中进行一些设置,比如增加worker线程数和使用TCP_DEFER_ACCEPT选项。此外,还可以使用多网卡绑定功能,使得每个网卡对应不同的服务器,从而进一步提高负载均衡的效率。
四、端口复用的注意事项和常见问题解决方法
在使用端口复用时,需要注意防火墙等安全策略的设置,避免被攻击者利用端口复用漏洞进行攻击。此外,如果端口复用出现问题,我们可以使用lsof或netstat命令查询当前端口的占用情况,并检查错误日志或查找相应的解决方法。
总之,端口复用是一项非常有用的技术,能有效提高负载均衡的效率和应用程序的可靠性。在Haproxy中,端口复用也是一项重要的功能,常用于多个应用程序共享同一个端口的情况。有了端口复用的优化和配置,我们能够更好地应对高并发和海量请求的挑战。