Linux使用TPROXY进行UDP的透明代理
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux使用TPROXY进行UDP的透明代理相关的知识,希望对你有一定的参考价值。
参考技术A在进行TCP的代理时,只要在NET表上无脑进行REDIRECT就好了。例如使用ss-redir,你只要把tcp的流量redirect到ss-redir监听的端口上就OK了。但是当你使用这种方法的时候,就会不正常,因为对于UDP进行redirect之后,原始的目的地址和端口就找不到了。
这是为什么呢?
ss-redir的原理很简单:使用iptables对PREROUTING与OUTPUT的TCP/UDP流量进行REDIRECT(REDIRECT是DNAT的特例),ss—redir在捕获网络流量后,通过一些技术手段获取REDIRECT之前的目的地址(dst)与端口(port),连同网络流量一起转发至远程服务器。
针对TCP连接,的确是因为Linux Kernel连接跟踪机制的实现才使获取数据包原本的dst和port成为可能,但这种连接跟踪机制并非只存在于TCP连接中,UDP连接同样存在,conntrack -p udp便能看到UDP的连接跟踪记录。内核中有关TCP与UDP的NAT源码/net/netfilter/nf_nat_proto_tcp.c和/net/netfilter/nf_nat_proto_udp.c几乎一模一样,都是根据NAT的类型做SNAT或DNAT。
那这究竟是怎么一回事?为什么对于UDP连接就失效了呢?
回过头来看看ss-redir有关获取TCP原本的dst和port的源码,核心函数是getdestaddr:
在内核源码中搜了下有关SO_ORIGINAL_DST的东西,看到了getorigdst:
We only do TCP and SCTP at the moment。Oh,shit!只针对TCP与SCTP才能这么做,并非技术上不可行,只是人为地阻止罢了。
为了在redirect UDP后还能够获取原本的dst和port,ss-redir采用了TPROXY。Linux系统有关TPROXY的设置是以下三条命令:
大意就是在mangle表的PREROUTING中为每个UDP数据包打上0x2333/0x2333标志,之后在路由选择中将具有0x2333/0x2333标志的数据包投递到本地环回设备上的1080端口;对监听0.0.0.0地址的1080端口的socket启用IP_TRANSPARENT标志,使IPv4路由能够将非本机的数据报投递到传输层,传递给监听1080端口的ss-redir。IP_RECVORIGDSTADDR与IPV6_RECVORIGDSTADDR则表示获取送达数据包的dst与port。
可问题来了:要知道mangle表并不会修改数据包,那么TPROXY是如何做到在不修改数据包的前提下将非本机dst的数据包投递到换回设备上的1080端口呢?
这个问题在内核中时如何实现的,还待研究,但是确定是TPROXY做了某些工作。
TPROXY主要功能:
TPROXY要解决的两个重要的问题
参考:
https://blog.csdn.net/ts__cf/article/details/78942294
https://vvl.me/2018/06/09/from-ss-redir-to-linux-nat/
构建Squid代理服务器-传统代理透明代理反向代理
Squid是Linux系统中最常用的一款开源代理服务软件,主要提供缓存加速和应用层过滤控制的功能,可以很好的实现HTTP、FTP、DNS查询以及SSL等应用的缓存代理。
正向代理:
根据实现的方式不同,代理服务可分为传统代理和透明代理。
- 传统代理:普通的代理服务,多见于Internet环境,必须在客户机的浏览器、QQ聊天工具、下载软件等程序中手动设置代理服务器对的地址和端口,才能使用代理服务器来访问网络。对于网页浏览器,访问网站时的域名解析请求会发送给指定的代理服务器。
- 透明代理:提供与传统代理相同的功能和服务,多见于局域网环境,其区别在于客户机不需要指定代理服务器的地址和端口,而是通过默认路由、防火墙策略将Web访问重定向,实际上仍然交给代理服务器处理。网页浏览器访问网站时的域名解析请求会优先发给DNS服务器。
反向代理:将不同的URL请求分发到后台不同的Web服务器上,通过squid反向代理,可以加速网站的访问速度,同时互联网用户只能看到反向代理服务器的地址,加强网站的访问安全。
官方地址:http://www.squid-cache.org/
参考文档:http://www.squid-cache.org/Doc/config/
Squid安装
1.编译安装Squid
将下载的Squid软件包解压至/opt目录下。
[[email protected] abc]# tar zxvf squid-3.5.28.tar.gz -C /opt/
准备编译环境,配置Squid的编译选项并进行安装。
yum install -y gcc gcc-c++ make
cd /opt/squid-3.5.28
./configure --prefix=/usr/local/squid //安装目录
--sysconfdir=/etc //单独将配置文件修改到其他目录
--enable-arp-acl //可以在规则中设置为直接通过客户端MAC进行管理,防止客户端使用IP欺骗
--enable-linux-netfilter //使用内核过滤
--enable-linux-tproxy //支持透明模式
--enable-async-io=100 //异步I/O,提升存储性能
--enable-err-language="Simplify_Chinese" //错误信息的显示语言
--enable-underscore //允许URL中有下划线
--enable-poll //使用Poll()模式,提升性能
--enable-gnuregex //提升GNU正则表达式
make && make install
2.安装完成后,创建链接文件、创建用户和组。
ln -s /usr/local/squid/sbin/* /usr/local/sbin/ //便于使用squid命令
useradd -M -s /sbin/nologin squid //创建用户和组
chown -R squid.squid /usr/local/squid/var/ //创建文件的属性
3.编辑配置文件/etc/squid.conf
vim /etc/squid.conf
cache_effective_user squid //添加 指定squid的程序用户,用来设置初始化、运行时缓存的账户,否则启动不成功
cache_effective_group squid //添加 指定账号的基本组
coredump_dir /usr/local/squid/var/cache/squid
4.启动squid服务,使用squid服务脚本。
(1)检查配置文件的语法是否正确。
squid -k parse
(2)先初始化缓存目录,调用squid程序来启动服务。
squid -z //初始化缓存目录
squid //启动服务
确认服务处于监听状态。
[[email protected] squid-4.1]# netstat -ntap | grep squid
tcp6 0 0 :::3128 :::* LISTEN 86805/(squid-1)
(3)编写squid启动脚本,并使用chkconfig和service工具进行管理。
vim /etc/init.d/squid
#!/bin/bash
#chkconfig: 2345 90 25
PID="/usr/local/squid/var/run/squid.pid"
CONF="/etc/squid.conf"
CMD="/usr/local/squid/sbin/squid"
case "$1" in
start)
netstat -natp | grep squid &> /dev/null
if [ $? -eq 0 ]
then
echo "squid is running"
else
echo "正在启动 squid..."
$CMD
fi
;;
stop)
$CMD -k kill &> /dev/null
rm -rf $PID &> /dev/null
;;
status)
[ -f $PID ] &> /dev/null
if [ $? -eq 0 ]
then
netstat -natp | grep squid
else
echo "squid is not running"
fi
;;
restart)
$0 stop &> /dev/null
echo "正在关闭 squid..."
$0 start &> /dev/null
echo "正在启动 squid..."
;;
reload)
$CMD -k reconfigure
;;
check)
$CMD -k parse
;;
*)
echo "用法:$0{start|stop|status|reload|check|restart}"
;;
esac
chmod +x /etc/init.d/squid //执行权限
chkconfig --add squid //添加为系统服务
chkconfig --level 35 squid on
构建传统代理服务器
案例需求描述:
- 基于Internet环境。
- 一台Linux主机作为web服务器,启用httpd服务。
- 一台Linux主机构建Squid服务,允许客户机使用代理。
- 一台Windows7主机,指定所使用的代理服务器地址、端口号信息。
主机 | 系统 | IP |
---|---|---|
squid 主机 | CentOS7 | 172.16.100.110 |
web服务器 | CentOS7 | 172.16.100.100 |
客户机 | windows 7 | 172.16.100.50 |
1.squid服务器的配置
(1)修改squid.conf配置文件
vim /etc/squid.conf
http_access allow all //允许任意客户机使用代理服务
http_access deny all
http_port 3128
cache_mem 64 MB //指定缓存功能所使用的内存空间大小,便于保持访问较频繁的WEB对象,容量最好为4的倍数,单位为MB,建议设为物理内存的1/4
reply_body_max_size 10 MB //允许用户下载的最大文件大小,以字节为单位。默认设置0表示不进行限制
maximum_object_size 4096 KB
(2)在防火墙上添加允许策略
iptables -F
setenforce 0
iptables -I INPUT -p tcp --dport 3128 -j ACCEPT
(3)重载squid服务
service squid reload //生效修改后的配置文件
2.客户机的代理设置
(1)Windows客户机的代理配置
打开浏览器(以IE为例,其他类似),菜单栏 -> 工具 -> Internet 选项 -> 连接 -> 局域网设置 -> 代理服务器,按照以下格式设置。
(2)Linux客户机的代理配置
在命令行界面中使用代理服务器如elinks网页浏览器、wget下载工具,必须通过环境变量来指定代理服务器的地址、端口等信息。
vim /etc/profile
HTTP_PROXY=http://192.168.235.206:3128 //使用HTTP协议指定代理
HTTPS_PROXY=http://192.168.235.206:3128 //使用HTTPS协议指定代理
FTP_PROXY=http://192.168.235.206:3128 //使用FTP协议指定代理
NO_PROXY=192.168.10.,192.168.20. //对两个局域网段指定代理
export HTTP_PROXY HTTPS_PROXY FTP_PROXY NO_PROXY
source /etc/profile
3.网站服务器的设置
(1)安装httpd,关闭防火墙
yum install httpd -y
systemctl stop firewalld.servie
setenforce 0
(2)启动httpd服务并加入开机自启动
systemctl start httpd.service
chkconfig httpd on
(3)创建index.html
echo "<h1>Squid-Web1</h1>" > /var/www/html/index.html
4.代理服务的验证
在客户机中通过浏览器访问目标网站http://172.16.100.100/
查看Squid访问日志的新增记录
查看Web访问日志的新增记录
当客户机使用代理后,web服务器并不知道客户机的真实ip,实际上是由代理服务器访问。
构建透明代理服务器
案例需求描述:
- 基于局域网主机通过Linux网关访问Internet的环境。
- 一台Linux主机作为Internet上的web服务器,启动httpd服务。
- 一台Linux主机作为网关服务器,并构建Squid服务提供代理服务。
- 一台windows7主机作为局域网的客户机,只需正确设置IP地址、默认网关。
主机 | 系统 | IP |
---|---|---|
squid 网关 | CentOS7 | ens33:192.168.100.1 ens37:12.0.0.1 |
web服务器 | CentOS7 | 12.0.0.12 |
客户机 | windows 7 | 192.168.100.20 |
1.配置Squid支持透明代理
vim /etc/squid.conf
http_port 192.168.100.1:3128 transparent //添加 提供透明服务
service squid reload //重新加载服务
配置文件其余地方的修改参考前面的传统代理的配置处。
2.设置iptables的重定向策略
将局域网段192.168.100.0/24且访问HTTP、HTTPS等协议的数据包转交给运行在本机3128端口上的Squid服务进行处理。
iptables -F
iptables -t nat -I PREROUTING -i ens33 -s 192.168.100.0/24 -p tcp --dport 80 -j REDIRECT --to 3128
iptables -t nat -I PREROUTING -i ens33 -s 192.168.100.0/24 -p tcp --dport 443 -j REDIRECT --to 3128
iptables -I INPUT -p tcp --dport 3218 -j ACCEPT
3.开启路由转发功能
vim /etc/sysctl.conf
net.ipv4.ip_forward = 1
sysctl -p
4.网站服务器配置如上述,操作步骤一样
5.验证透明代理的使用
如果客户机上存在手动指定的代理服务器设置,应将其去除。在Linux客户机,可以通过unset命令清除。
unset HTTP_PROXY HTTPS_PROXY
在客户机中通过浏览器访问目标网站http://12.0.0.12/
验证结果:
在Squid代理服务器中,发现客户机访问网站服务器的记录;
在被访问的web服务器中,发现来自代理服务器的访问记录。
反向代理
客户端请求访问 WEB 服务时,DNS 将访问的域名解析为 Squid 反向代理服务器的 IP 地址,这样客户端的 URL 请求将被发送到反向代理服务器。如果 Squid 反向代理服务器中缓存了该请求的资源,则将该请求的资源直接返回给客户端,否则反向代理服务器将向后台的 WEB 服务器请求资源,然后将请求的应答返回给客户端,同时也将该应答缓存在本地,供下一个请求者使用。
案例环境: 主机 |
系统 | IP |
---|---|---|
squid 网关 | CentOS7 | ens33:192.168.100.1 ens37:12.0.0.1 |
web1服务器 | CentOS7 | 192.168.100.100 |
web2服务器 | CentOS7 | 192.168.100.120 |
客户机 | windows 7 | 12.0.0.50 |
1.配置squid服务器
vim /etc/squid.conf
http_port 192.168.100.1:3128 transparent //启动透明代理
http_port 12.0.0.1.1:80 accel vhost vport
cache_peer 192.168.100.100 parent 80 0 no-query originserver round-robin max_conn=30 weight=1 name=web1
cache_peer 192.168.100.120 parent 80 0 no-query originserver round-robin max_conn=30 weight=1 name=web2
cache_peer_domain web1 web2 www.yun.com
service squid restart
2.配置防火墙策略
iptables -t nat -I PREROUTING -i ens33 -s 192.168.100.0/24 -p tcp --dport 80 -j REDIRECT --to 3128
iptables -t nat -I PREROUTING -i ens33 -s 192.168.100.0/24 -p tcp --dport 443 -j REDIRECT --to 3128
iptables -I INPUT -p tcp --dport 3218 -j ACCEPT
3.配置两个网站服务器,操作步骤如上述一样,不同的是修改web主页。
#web1
echo "<h1>Squid-Web1</h1>" > /var/www/html/index.html
#web2
echo "<h1>Squid-Web2</h1>" > /var/www/html/index.html
4.配置客户端
这里可以使用DNS服务来解析,这里我们为了方便,就在hosts 文件里直接指定。
修改C:WindowsSystem32driversetchosts 文件
5.测试反向代理
在客户端访问目标网站www.yun.com
关闭web1的httpd服务,在web1服务器清除缓存,访问网站,如图所示:
然后在客户端清除缓存访问www.yun.com ,如图所示:
刷新一次:
可以看到反向代理缓存成功。
以上是关于Linux使用TPROXY进行UDP的透明代理的主要内容,如果未能解决你的问题,请参考以下文章