用Rust手把手编写一个Proxy(代理), UDP绑定篇

用Rust手把手编写一个Proxy(代理), UDP绑定篇

项目 ++wmproxy++

gite: https://gitee.com/tickbh/wmproxy

github: https://github.com/tickbh/wmproxy

了解UDP

特点

UDP是基于IP的简单协议,不可靠的协议。
UDP的优点:简单,轻量化。
UDP的缺点:没有流控制,没有应答确认机制,不能解决丢包、重发、错序问题。

这里需要注意一点,并不是所有使用UDP协议的应用层都是不可靠的,应用程序可以自己实现可靠的数据传输,通过增加确认和重传机制,所以使用UDP 协议最大的特点就是速度快。如HTTP3就是用UDP标准下实现的上层协议。

适用场景

UDP协议一般作为重速度,但可以接受轻微损失的如流媒体应用、语音交流、视频会议所使用的传输层协议,还有许多基于互联网的电话服务使用的VOIP也是基于UDP运行的,实时视频和音频流协议旨在处理偶尔丢失的数据包,因此,如果重新传输丢失的数据包,则只会发生质量略有下降,而不是出现较大的延迟。
最常用到的为DNS协议,希望能以更小的包(包头tcp20字节,udp8字节),更快速的解析得到地址。

socks5 udp协议

协议说明

UDP 关联请求用于在UDP中继进程内建立关联以处理UDP数据报。DST.ADDR和DST.PORT字段包含客户端期望用于发送UDP数据报的地址和端口。服务器可以使用此信息来限制对关联的访问。如果客户端在UDP 关联请求时没有掌握此信息,客户端必须使用端口号和地址都为零的地址。

UDP关联会在随着的TCP连接终止时终止。

在UDP 关联请求的回复中,BND.PORT和BND.ADDR字段指示客户端必须发送UDP请求消息以进行中继的端口号/地址。

协议详情

基于UDP的客户端必须将其数据报发送到UDP端口,该端口在UDP关联请求的回复中的BND.PORT指示。如果所选的认证方法提供了封装用于身份验证、完整性、和/或机密性,则数据报必须使用适当的封装。每个UDP数据报都带有UDP请求头:

  +----+------+------+----------+----------+----------+
  |RSV | FRAG | ATYP | DST.ADDR | DST.PORT |   DATA   |
  +----+------+------+----------+----------+----------+
  | 2  |  1   |  1   | Variable |    2     | Variable |
  +----+------+------+----------+----------+----------+
  
  RSV: 保留2字节
  FRAG:当前分片, 请求时为0
  ATYP:地址类型,0x01为ipv4,0x03为域名地址,0x04为ipv6
  DST.ADDR:目标地址,根据类型读取相应字节
  DST.PORT: 目标端口号,2字节
  DATA:发送数据

当一个UDP中继服务器决定中继UDP数据报时,它会默默地这样做,不需要向请求的客户端发送任何通知。同样,它会丢弃它不能或不愿意中继的数据报。当一个UDP中继服务器从远程主机接收到回复数据报时,它必须使用上述UDP请求头和任何与认证方法相关的封装对数据报进行封装。

UDP中继服务器必须从SOCKS服务器获取将发送数据报到BND.PORT的客户端的预期IP地址,该地址在UDP关联请求的回复中给出。它必须丢弃来自除为特定关联记录的IP地址以外的任何源IP地址的所有数据报。

FRAG字段指示此数据报是否是多个片段之一。如果实现,高位比特指示片段序列的结束,而值为X’00’表示此数据报是独立的。值在1和127之间的值表示片段在片段序列中的位置。每个接收器都有一个重新组装队列和与这些片段关联的重新组装定时器。每当重新组装定时器到期或接收到携带FRAG字段值小于为该片段序列处理的最高FRAG值的新数据报时,必须重新初始化重新组装队列并丢弃关联的片段。重新组装定时器必须不小于5秒。建议应用程序尽可能避免分片。

分片实施是可选项;不支持分片的实现必须丢弃任何FRAG字段值不是X’00’的数据报。

协议流程图

UDP协议实现的是本地和远程地址中间构建出一条UDP链路,常用的如DNS解析。

你可能感兴趣的:(rust,udp,单片机)