首页 > 系统相关 >46从零开始用Rust编写nginx,数据还能这么传,多层代理(IP多级代理)搭建

46从零开始用Rust编写nginx,数据还能这么传,多层代理(IP多级代理)搭建

时间:2024-01-30 09:44:06浏览次数:24  
标签:map mut 46 IP 代理 -- ARG id

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个也可以是若干个。

sequenceDiagram 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(())
}

小结

多层代理可以帮助我们在有限的情况下构建出更稳定的代理通道,可以更好的保护源站,也可以利用该方法给企业构建出稳定的内网通道。也可以在统一出口的情况下保护内网的数据。

点击 [关注][在看][点赞] 是对作者最大的支持

标签:map,mut,46,IP,代理,--,ARG,id
From: https://www.cnblogs.com/wmproxy/p/17995823/wmproxy46

相关文章

  • swiper实现滚动效果
    css.swiper-wrapper{-webkit-transition-timing-function:linear;/*之前是ease-out*/-moz-transition-timing-function:linear;-ms-transition-timing-function:linear;-o-transition-timing-function:linear;......
  • llama-recipes fine-tuning 3
    multipleGPUsinsinglenodeclicktoviewthecodetorchrun--nnodes1--nproc_per_node2examples/finetuning.py--enable_fsdp--use_peft--peft_methodlora--datasetmedcqa_dataset--model_namemeta-llama/Llama-2-7b-hf--fsdp_config.pure_bf16--output......
  • [Typescript 5] infer Constraints
    Sincetypescript5,weareabletoaddconstraintsoverinfer.Followingcodedoesn'tapplyconstraints,sotheinferredelementcouldbe stringand numbertypeGetFirstStringIshElement<T>=Textendsreadonly[inferS,..._:any[]]?S:n......
  • IDS与IPS
    一、入侵检测系统IDS入侵检测系统IDS(IntrusionDetectionSystems),依照一定的安全策略,通过软、硬件,对网络、系统的运行状况进行监视,尽可能发现各种攻击企图、攻击行为或者攻击结果,以保证网络系统资源的机密性、完整性和可用性。如:假如防火墙是一幢大楼的门锁,那么IDS就是大楼里......
  • 【容斥反演】Nanami and Trip Schemes Count Problem
    链接给定\(k\)个特殊格子,求从(1,1)往右或往上走到(n,m),在经过不超过\(p\)个特殊格的情况下的方案数设\(f(S)\)表示钦定走S集合中格子的方案,\(g(S)\)为恰好走S集合的方案,那么\(f\)与\(g\)的关系就是一个\(\subseteq\)意义下的前缀和。即\[f(S)=\sum_{S\subs......
  • java——ip黑名单设计方案(大全+实战)
    java——ip黑名单设计方案(大全+实战)大家好,今天来设计一个ip黑名单功能。即封禁一些类似ddos的非法ip环境:springboot+jdk11本文源码地址:https://gitee.com/xue-shangren/blog-src/tree/master/java-blacklist-design自定义拦截器思路:将黑名单ip存入一个txt文件中(置于resource......
  • CF1925D Good Trip 题解
    考虑分别计算\(p\)和\(q\)。按照期望的定义,\(q\)应该等于方案的总数,也就是\(s^k\),其中\(s\)表示一共有多少个不同的组。考虑如何求\(p\),我们先只计算第\(i\)组对\(p\)的贡献。如果第\(i\)组一共被选了\(1\)次,那么贡献为:\[g=f_i\timesC_{k}^{1}\times(s-1)^{......
  • 在内网(不通公网)的情况下,使用pip安装python依赖包
    1.施工服务器后端部署一:准备一台环境与内网虚拟机相同的可以连接外网的虚拟机,python版本,操作系统版本保持一致二:在可以链接外网的机器上使用pip将依赖包的whl文件(也有可能是tar.gz或者tar格式,不过不影响后续使用)#将依赖下载到本地的某个文件中root@iZ8v2rbZ:/sdwork/pyyl#......
  • Apipost中API如何调用本地文件
    近期版本更新中Apipost推出插件管理,可以直接在预、后执行脚本中调用本地的脚本文件导入脚本在「系统设置」—「插件管理」中打开目录将要执行的脚本文件拖入到文件夹下 执行脚本需要获取请求参数:constrequestData=request.request_bodys;在预、后执行脚本输入框中输入......
  • 服务器IP地址的分类
    1、A类IP地址:一个A类IP地址由1字节的网络地址和3字节主机地址组成,网络地址的最高位必须是“0”,地址范围从1.0.0.0到126.0.0.0。可用的A类网络有126个,每个网络能容纳1亿多个主机。2、B类IP地址:一个B类IP地址由2个字节的网络地址和2个字节的主机地址组成,网络地址的最高位必须是......