46从零开始用Rust编写nginx,数据还能这么传,多层代理(IP多级代理)搭建
wmproxy
wmproxy已用Rust实现http/https代理, socks5代理, 反向代理, 负载均衡, 静态文件服务器,websocket代理,四层TCP/UDP转发,内网穿透等,会将实现过程分享出来,感兴趣的可以一起造个轮子
项目地址
国内: https://gitee.com/tickbh/wmproxy
github: https://github.com/tickbh/wmproxy
设计目标
通过多层代理的代理结构,构建出属于自己的网络通道。
多层代理能做什么
多层代理(也称为IP多级代理)是一种网络代理技术
它通过多个代理服务器来接收和发送数据包,从而隐藏真实IP地址。每个代理服务器都可以处理一个或多个网络请求,通过这种方式,可以在防火墙后面传输数据,同时隐藏真实IP地址和用户身份。这种技术通常用于企业网络和互联网上的安全传输。
当前多层代理的工作原理是在应用层上进行代理传输,从而将原始IP地址和用户身份隐藏起来。在发送数据时,发送方的IP地址会被伪装成目标IP地址的某个IP地址,而接收方的IP地址则会被隐藏在多个IP地址中。这种层层转发网络流量的方式,使得最终目标服务器无法直接获取到请求的真实IP地址,从而增加了网络的安全性和匿名性。
但是请注意,使用多层代理也可能会导致网络连接速度变慢,因为数据需要通过多个代理服务器进行传输。同时如果代理服务器被攻击或出现故障,也可能会影响网络的稳定性和可靠性。因此在选择是否使用多层代理时,需要综合考虑其优缺点,并根据实际需求做出决策。
如何部署
通常了解一个程序如何运行最快的方式除了官方文档,另一种就是查找当前程序的help,通常wmproxy --help或者wmproxy -h就可以查询到帮助信息。此时我们是子命令代理,通过wmproxy proxy -h,可以查询控制消息
Usage: wmproxy.exe proxy [-s=ARG] [-b=ARG] [-c=ARG] [--flag=ARG] [-S=ARG] [--user=ARG] [--pass=ARG] [
--udp-bind=ARG] [--map-http-bind=ARG] [--map-https-bind=ARG] [--map-tcp-bind=ARG] [--map-proxy-bind=ARG
] [--map-cert=ARG] [--map-key=ARG] [--ts] [--tc] [--two-way-tls] [--domain=ARG] [--cert=ARG] [--key=ARG
] [--mappings=ARG]... [--control=ARG] [--disable-stdout] [--disable-control] [-v] [--default-level=ARG
]
代理类, 一个代理类启动一种类型的代理
-s, --server-id=ARG 代理id
[default: 0]
-b, --bind=ARG 代理绑定端口地址
-c, --center-addr=ARG 中心代理绑定端口地址
--flag=ARG 代理种类, 如http https socks5
-S, --server=ARG 连接代理服务端地址
--user=ARG 用于socks验证及中心服务器验证
--pass=ARG 用于socks验证及中心服务器验证
--udp-bind=ARG udp的绑定地址
--map-http-bind=ARG 内网http的映射地址
--map-https-bind=ARG 内网https的映射地址
--map-tcp-bind=ARG 内网tcp的映射地址
--map-proxy-bind=ARG 内网代理的映射地址
--map-cert=ARG 内网映射的证书cert
--map-key=ARG 内网映射的证书key
--ts 连接服务端是否启用tls
--tc 接收客户端是否启用tls
--two-way-tls 双向认证是否启用
--domain=ARG tls证书所用的域名
--cert=ARG 公开的证书公钥文件
--key=ARG 隐私的证书私钥文件
--mappings=ARG
此时我们绑定端口分为两种
-b, --bind=ARG 代理绑定端口地址
-c, --center-addr=ARG 中心代理绑定端口地址
- 其中
-b是绑定来自于第三方代理客户端发起(http/https/socks)代理请求的信息 - 其中
-c是绑定来自于客户端与服务端建立的代理请求信息。是服务器内部间构建的信息通道。 - 其中
-S或者--server表示该程序需连接到代理服务端,将数据请求发送到服务器处理。 - 其中
--ts表示连接服务端时是否启用tls - 其中
--tc表示接收客户端时是否需要tls,这两个需要正确配对并设置相应的--cert及--key
以下流程图,展示数据的处理流程,其中代理B的角色可以是0个也可以是若干个。
participant Client as 用户端
participant A as 代理端A<br/>监听-b 8090
participant B as 代理端B<br/>监听"-c 8091"
participant C as 代理端C<br/>监听"-c 8092"
B->>C: 主动连接127.0.0.1:8092<br/>建立内部通道
A->>B: 主动连接127.0.0.1:8091<br/>建立内部通道
Client->>A: 发起HTTP代理请求
A->>B: 构建内部通讯协议<br/>创建唯一id
B->>C: 构建代理A与C中转通道<br/>双向绑定中转数据
C->>C: 解析数据,并处理代理
C->>B: 返回代理数据
B->>A: A与C的中转通道
A->>Client: 解析数据转成代理请求发送
- 代理C的启动命令:
wmproxy proxy -c :8092
- 代理B的启动命令:
wmproxy proxy -c :8091 -S 127.0.0.1:8092
- 代理A的启动命令:
wmproxy proxy -b :8090 -S 127.0.0.1:8091
通过如何我们就构建出了一条内部的代理通道,此时通过curl测试
curl.exe --proxy http://127.0.0.1:8090 https://www.baidu.com -I
可以得到以下正确返回200信息
HTTP/1.1 200 OK
Server: wenmeng
content-length: 0
HTTP/1.1 200 OK
Accept-Ranges: bytes
Cache-Control: private, no-cache, no-store, proxy-revalidate, no-transform
Connection: keep-alive
Content-Length: 277
Content-Type: text/html
Date: Fri, 26 Jan 2024 02:27:04 GMT
Etag: "575e1f71-115"
Last-Modified: Mon, 13 Jun 2016 02:50:25 GMT
Pragma: no-cache
Server: bfe/1.0.8.18
源码剥析
关于server_id
因为在构建tcp唯一映射的时候,是通过本地的自增id来进行处理。
pub fn calc_next_id(&mut self) -> u64 {
let id = self.next_id;
self.next_id = self.next_id.wrapping_add(2);
Helper::calc_sock_map(self.option.server_id, id)
}
即当出口处理的服务器如果前端有多条客户端的时候存在冲突的可能的。就比如id均为2,那么服务端将无法正确处理是来自哪个客户端的数据,也无法进行相应的转发。所以此处我们引入server_id的概念,通过server_id与id进行组合运算,得出系统内的唯一id,保证数据没有冲突。
let mut map = HashMap::<u64, Sender<ProtFrame>>::new();
关于中心客户端
- 源码:
center_client - 类名:
CenterClient - 功能:它负责将客户端的数据转化成服务器内部的通讯,并将内部的通讯转化成客户端的数据。
- 构建:当仅它有
-b监听第三方客户端的时候构建。 - 核心函数:
async fn inner_serve<T>(
option: &ProxyConfig,
stream: T,
sender: &mut Sender<ProtFrame>,
receiver_work: &mut Receiver<(ProtCreate, Sender<ProtFrame>)>,
receiver: &mut Receiver<ProtFrame>,
mappings: &mut Vec<MappingConfig>,
) -> ProxyResult<()>
关于中心服务端
- 源码:
center_server - 类名:
CenterServer - 功能:它负责将服务器内部的数据进行解析,并发起http代理的请求,此处他为出口
- 构建:当仅他的目标上级服务器不存在时且
-c参数被设置进行构建。即-S没有设置 - 核心函数:
pub async fn inner_serve<T>(
stream: T,
option: ProxyConfig,
sender: Sender<ProtFrame>,
mut receiver: Receiver<ProtFrame>,
mut receiver_work: Receiver<(ProtCreate, Sender<ProtFrame>)>,
mappings: Arc<RwLock<Vec<MappingConfig>>>,
) -> ProxyResult<()>
关于中心转发服
- 源码:
center_trans - 类名:
CenterTrans - 功能:它负责将来自代理客户端的请求转发给代理服务端
- 构建:当且仅当
-c被设置且-S被设置,即监听中心客户端又连接中心服务端,充当转发功能,由于不存在任何解析,性能高。 - 核心函数:
pub async fn serve<T>(&mut self, mut stream: T) -> ProxyResult<()>
where
T: AsyncRead + AsyncWrite + Unpin + Send + 'static,
{
let mut server = if self.tls_client.is_some() {
let connector = TlsConnector::from(self.tls_client.clone().unwrap());
let stream = HealthCheck::connect(&self.server).await?;
// 这里的域名只为认证设置
let domain = rustls::ServerName::try_from(
&*self
.domain
.clone()
.unwrap_or("soft.wm-proxy.com".to_string()),
)
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid dnsname"))?;
let outbound = connector.connect(domain, stream).await?;
MaybeHttpsStream::Https(outbound)
} else {
let outbound = HealthCheck::connect(&self.server).await?;
MaybeHttpsStream::Http(outbound)
};
tokio::spawn(async move {
let _ = tokio::io::copy_bidirectional(&mut stream, &mut server).await;
});
Ok(())
}
小结
多层代理可以帮助我们在有限的情况下构建出更稳定的代理通道,可以更好的保护源站,也可以利用该方法给企业构建出稳定的内网通道。也可以在统一出口的情况下保护内网的数据。
点击 [关注],[在看],[点赞] 是对作者最大的支持
46从零开始用Rust编写nginx,数据还能这么传,多层代理(IP多级代理)搭建的更多相关文章
- bloom-server 基于 rust 编写的 rest api cache 中间件
bloom-server 基于 rust 编写的 rest api cache 中间件,他位于lb 与api worker 之间,使用redis 作为缓存内容存储, 我们需要做的就是配置proxy,同 ...
- 【ODI】| 数据ETL:从零开始使用Oracle ODI完成数据集成(二)
前一节已经完成了Oracle数据库和ODI的安装,并已经为ODI在Oracle数据库中创建了两个用户,分别用于存放主资料库数据和工作资料库数据,在ODI中完成主资料库和工作资料库的创建,也分别为其创建 ...
- 【ODI】| 数据ETL:从零开始使用Oracle ODI完成数据集成(一)
0. 环境说明及软件准备 ODI(Oracle Data Integrator)是Oracle公司提供的一种数据集成工具,能高效地实现批量数据的抽取.转换和加载.ODI可以实现当今大多数的主流关系型数 ...
- centos LNMP第一部分环境搭建 LAMP LNMP安装先后顺序 php安装 安装nginx 编写nginx启动脚本 懒汉模式 mv /usr/php/{p.conf.default,p.conf} php运行方式SAPI介绍 第二十三节课
centos LNMP第一部分环境搭建 LAMP安装先后顺序 LNMP安装先后顺序 php安装 安装nginx 编写nginx启动脚本 懒汉模式 mv /usr/local/php/{ ...
- 【ODI】| 数据ETL:从零开始使用Oracle ODI完成数据集成(三)
资料库的创建.体系结构的创建.模型反向工程都已经完成了,下面就是创建以及执行接口来完成工作了. 浏览前两节请点击: [ODI]| 数据ETL:从零开始使用Oracle ODI完成数据集成(一) [OD ...
- C#开发BIMFACE系列46 服务端API之离线数据包下载及结构详解
BIMFACE二次开发系列目录 [已更新最新开发文章,点击查看详细] 在前一篇博客<C#开发BIMFACE系列45 服务端API之创建离线数据包>中通过调用接口成功的创建一个离线数 ...
- java编写网站数据抓取
来公司已经俩月了,每天加班平均工时11个小时的我又想起了老东家温馨舒适安逸的生活.已经有好久没时间读博客写博客了,我觉得我退步了,嗯嗯,我很不开心 今天记录下抓数据的一些东西吧. 数据抓取现在是很普遍 ...
- Nginx正向代理、反向代理、负载均衡及性能优化
一.Nginx是什么 Nginx是一款高性能的 HTTP 和反向代理服务器,由俄罗斯人Igor Sysoev(伊戈尔·赛索耶夫)为俄罗斯网站Rambler.ru开发的,在Rambler.ru网站平稳的 ...
- Centos8 Docker+Nginx部署Asp.Net Core Nginx正向代理与反向代理 负载均衡实现无状态更新
首先了解Nginx 相关介绍(正向代理和反向代理区别) 所谓代理就是一个代表.一个渠道: 此时就涉及到两个角色,一个是被代理角色,一个是目标角色,被代理角色通过这个代理访问目标角色完成一些任务的过程称 ...
- nginx正向代理,反向代理,透明代理(总结)
1正向代理 正向代理,也就是传说中的代理,他的工作原理就像一个跳板, 简单的说, 我是一个用户,我访问不了某网站,但是我能访问一个代理服务器 这个代理服务器呢,他能访问那个我不能访问的网站 于是我先连 ...
随机推荐
- 【QT 学习之路】事件
事件(event)是由系统或者 Qt 本身在不同的时刻发出的.当用户按下鼠标.敲下键盘,或者是窗口需要重新绘制的时候,都会发出一个相应的事件.一些事件在对用户操作做出响应时发出,如键盘事件等:另一些事 ...
- Codeforces Round #741 (Div. 2) 个人题解 A~D
比赛链接:Here 1562A. The Miracle and the Sleeper 题意: 给出 \(l,r\) 求出最大化的 \(a\ mod\ b\) (\(l\le b\le b\le a ...
- AtCoder Beginner Contest 214 (D并查集,E反悔贪心,F公共子序列DP)
题目链接:Here ABC水题, D - Sum of Maximum Weights 上图中最大权 \(9\) 对答案的贡献是这条边两边的连通块的 size 的乘积再乘以 9 受到上面的启发,我们可 ...
- 【每日一题】20.K-th Number (二分 + 尺取)
关于此题,我们分析一下: 一个区间第k大的数不小于x的条件是什么? 答案就是一个区间内不小于x的数的个数不小于k 那么,我们就会发现,我们其实并不需要知道每个数的值,实际上对我们有用的只有每个数与x的 ...
- 一、java发送http的各类请求
导航 一.java发送http的各类请求 二.java发送https的各类请求 java开发中需要调用其他服务的对外提供的http请求可以参考如下代码: 注:调用的主类比较简单就不写了. pom.xm ...
- WebGPU光追引擎基础课系列目录
大家好~我开设了"WebGPU光追引擎基础课"的线上课程,从0开始,在课上带领大家现场写代码,使用WebGPU开发基础的光线追踪引擎 课程重点在于基于GPU并行计算,实现BVH构建 ...
- 彻底解决 gcr、quay、DockerHub 镜像下载难题
在使用 Docker 和 Kubernetes 时,我们经常需要访问 gcr.io 和 quay.io 镜像仓库,由于众所周知的原因,这些镜像仓库在中国都无法访问,唯一能访问的是 Docker Hub ...
- /etc/profile,/etc/bashrc,~/.profile,~/.bashrc 的区别及使用
转载请注明出处: /etc/profile 为系统的全局环境变量设置,此文件为系统的每个用户设置环境信息 /etc/bashrc 为每一个运行bash shell的用户执行此文件.当bash ...
- 在线photoshop网页版工具开发
基于javascript开发的在线ps工具,打包方式webpack 在线预览 在线ps网页版 源码地址 https://github.com/geeeeeeeek 功能介绍 在线图像编辑器允许您使用H ...
- spring启动流程 (3) BeanDefinition详解
BeanDefinition在Spring初始化阶段保存Bean的元数据信息,包括Class名称.Scope.构造方法参数.属性值等信息,本文将介绍一下BeanDefinition接口.重要的实现类, ...