前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >透明代理解决方案(一)

透明代理解决方案(一)

作者头像
siri
发布2022-11-18 14:18:10
1.2K0
发布2022-11-18 14:18:10
举报
文章被收录于专栏:siri的开发之路siri的开发之路

透明代理解决方案(一)


最近做基于 Iptables REDIRECT 的透明代理方案时遇到一个问题,解决的过程中涉及到几个重要的网络相关知识点,记录在这里以便查找。

方案说明

网上有很多种透明代理的解决方案,使用最多的是通过 libev 或者其他的 ss 版本与 Iptables、TProxy 等等技术结合进行搭建,如果对速度要求高的话,还需要加上黑白名单功能进行分流。( 如果需要命令行代理的话推荐 proxychains ) 透明代理一般分为客户端和服务端,客户端安装在用户机器上,配置好后不用再对其他进程做额外配置,服务端则常运行在 VPS 上,已经有很多成熟的软件,比如 http 代理 squid,socks 代理 ss-server 等等。 项目的代理服务端已经配好了(squid),而透明代理的客户端需要自动截取用户指定端口/协议的流量,这里就遇到第一个问题,如何对指定端口的流量进行自动转发。

Iptables REDIRECT

对数据包的自动转发可以使用 Iptables 的重定向机制,通过如下命令实现。这条命令实际上是进行一个端口映射,将 80 端口的数据包重定向到 8118 端口。

iptables -t nat -A OUTPUT -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 8118

但要注意的是这条命令中还指定了其他参数,OUTPUT 指的是 Iptables 的 OUTPUT 链,它截获并处理的是所有从这台机器上发出去的所有数据包 (客户端形式);还有一种做法是设置 PREROUTING 链,只处理进入当前主机的数据包,但这样截获不到本机进程发送的包 (网关形式) 。具体应该选择哪种做法,需要自己深入理解 Iptables 四表五链的原理后确定。

如果透明代理客户端程序和用户进程在同一台主机上,Iptables 转发的目标端口就是客户端程序所在的端口,这时会遇到第二个问题,如何获取用户进程数据包的源地址和端口。

获取源IP和端口

Iptables 重定向的策略很简单,直接修改需要重定向的数据包的五元组 (协议, 本地地址, 本地端口, 远端地址, 远端端口),将远端地址和远端端口改为重定向目标的地址和端口。但这样会导致客户端找不到原本的目标地址和端口,以致无法告诉代理服务器需要代理连接哪个目标。 因此借用了 ss-redir 中的一个方法,其主要代码如下所示。getdestaddr 函数通过连接跟踪机制,查询 Iptables 修改之前的源地址和端口,并存在 sockaddr_storage 结构体中。需要注意的是此方法只支持 TCP 协议的查找,不支持 UDP,这篇文章 对原因进行了分析。

代码语言:javascript
复制
int getdestaddr(int fd, struct sockaddr_storage *destaddr)
{
    socklen_t socklen = sizeof(*destaddr);
    int error         = 0;

    error = getsockopt(fd, SOL_IPV6, IP6T_SO_ORIGINAL_DST, destaddr, &socklen);
    if (error) {
        error = getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, destaddr, &socklen);
        if (error) {
            return -1;
        }
    }
    return 0;
}

sockaddr_storage 中的 IP 地址和端口号并不能直接使用,还要经过如下的转化,之前自己试了很久,直接把这段代码贴出来以防有人碰到同样的问题。

代码语言:javascript
复制
	char * original_ip;
	int original_port = 0;
    original_ip = inet_ntoa(((struct sockaddr_in*)((struct sockaddr*)&destaddr))->sin_addr);
    original_port = ntohs(((struct sockaddr_in*)((struct sockaddr*)&destaddr))->sin_port);
事件库

解决了主要的问题之后,剩下的功能就比较常见了。代理客户端一方面作为服务器接收用户进程的数据包,一方面作为客户端向代理服务器发送数据包,反之亦然。代理客户端可能同时需要接收很多个连接请求,需要一个性能良好的事件库保证不会崩溃,这里推荐 ss-libev 用的事件库 libev,上手简单且性能不错,适合搭建类似的代理程序。

除此之外,为了功能完备性,最好加上黑白名单,以及在设置 Iptables 重定向时过滤内网地址,保证不会拦截不需要的流量等等。

ps : 虽然不能贴源码,但如果有人想看的话后续可以把实现的思路和框架讲一遍,基本模仿 ss 的 python/C++ 版本实现。


本文为博主原创,转载请注明出处

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-02-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 透明代理解决方案(一)
    • 方案说明
      • Iptables REDIRECT
        • 获取源IP和端口
          • 事件库
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档