重构所有udp部分的代码! 摒弃了过去非常复杂的upd转发机制;

不再使用 UDP_Putter 等机制去转发udp,而是用一个 netLayer.MsgConn 结构

proxy.Server 和 proxy.Client 接口改动,

Client在握手udp时不再使用handshake方法, 而是用新的 EstablishUDPChannel 方法

Server 在 Handshake时会选择性返回两种接口,io.ReadWriteCloser 用于tcp, netLayer.MsgConn 用于 udp

此时vless、socks5、direct 的udp转发都已经成功经过了 go test 验证, 但是 main.go 还未修改。
This commit is contained in:
hahahrfool
2022-04-08 13:49:56 +08:00
parent d3ec3fddcd
commit 447bd8749a
22 changed files with 766 additions and 741 deletions
+1 -1
View File
@@ -907,7 +907,7 @@ afterLocalServerHandshake:
if client.Name() == "direct" {
uc := wlc.(*vless.UserConn)
uc := wlc.(*vless.UserTCPConn)
if uc.GetProtocolVersion() < 1 {
break
+7 -1
View File
@@ -84,6 +84,7 @@ func NewAddrByHostPort(hostPortStr string) (Addr, error) {
a := Addr{Port: port}
if ip := net.ParseIP(host); ip != nil {
a.IP = ip
} else {
a.Name = host
@@ -184,7 +185,12 @@ func NewAddrFromAny(thing any) (addr Addr, err error) {
}
func (a *Addr) GetHashable() (ha HashableAddr) {
ip, _ := netip.AddrFromSlice(a.IP)
theip := a.IP
if i4 := a.IP.To4(); i4 != nil {
theip = i4 //能转成ipv4则必须转,否则虽然是同一个ip,但是如果被表示成了ipv6的形式,相等比较还是会失败
}
ip, _ := netip.AddrFromSlice(theip)
ha.AddrPort = netip.AddrPortFrom(ip, uint16(a.Port))
ha.Network = a.Network
ha.Name = a.Name
+39 -23
View File
@@ -50,29 +50,6 @@ func HasIpv6Interface() bool {
return false
}
/*
if utils.LogLevel == utils.Log_debug {
log.Println("interfaces", len(addrs), addrs)
for _, address := range addrs {
if ipnet, ok := address.(*net.IPNet); ok {
isipv6 := false
if !ipnet.IP.IsLoopback() && !ipnet.IP.IsPrivate() && !ipnet.IP.IsLinkLocalUnicast() {
if ipnet.IP.To4() == nil {
isipv6 = true
}
}
log.Println(ipnet.IP.String(), isipv6)
}
}
}*/
for _, address := range addrs {
if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() && !ipnet.IP.IsPrivate() && !ipnet.IP.IsLinkLocalUnicast() {
// IsLinkLocalUnicast: something starts with fe80:
@@ -119,3 +96,42 @@ func IsStrUDP_network(s string) bool {
}
return false
}
//使用Addr,是因为有可能申请的是域名,而不是ip
type MsgConn interface {
ReadFrom() ([]byte, Addr, error)
WriteTo([]byte, Addr) error
}
type UDPMsgConnWrapper struct {
*net.UDPConn
IsClient bool
FirstAddr Addr
}
func (u *UDPMsgConnWrapper) ReadFrom() ([]byte, Addr, error) {
bs := utils.GetPacket()
n, ad, err := u.UDPConn.ReadFromUDP(bs)
if err != nil {
return nil, Addr{}, err
}
return bs[:n], NewAddrFromUDPAddr(ad), err
}
func (u *UDPMsgConnWrapper) WriteTo(bs []byte, ad Addr) error {
if u.IsClient {
if ad.GetHashable() == u.FirstAddr.GetHashable() {
_, err := u.UDPConn.Write(bs)
return err
} else {
return utils.ErrNotImplemented
}
} else {
_, err := u.UDPConn.WriteTo(bs, ad.ToUDPAddr())
return err
}
}
+12 -5
View File
@@ -22,28 +22,35 @@ var (
//本文件内含 一些 转发 udp 数据的 接口与方法
// 阻塞.
func RelayUDP(putter UDP_Putter, extractor UDP_Extractor, dialFunc func(targetAddr Addr) (io.ReadWriter, error)) {
func RelayUDP(conn1, conn2 MsgConn) {
go func() {
for {
raddr, bs, err := extractor.GetNewUDPRequest()
bs, raddr, err := conn1.ReadFrom()
if err != nil {
//log.Println("RelayUDP e1", err)
break
}
err = putter.WriteUDPRequest(raddr, bs, dialFunc)
err = conn2.WriteTo(bs, raddr)
if err != nil {
//log.Println("RelayUDP e2", err)
break
}
}
}()
for {
raddr, bs, err := putter.GetNewUDPResponse()
bs, raddr, err := conn2.ReadFrom()
if err != nil {
//log.Println("RelayUDP e3", err)
break
}
err = extractor.WriteUDPResponse(raddr, bs)
err = conn1.WriteTo(bs, raddr)
if err != nil {
//log.Println("RelayUDP e4", err)
break
}
}
+8 -8
View File
@@ -17,8 +17,8 @@ import (
type UDPListener struct {
conn *net.UDPConn
newConnChan chan *UDPConn
connMap map[netip.AddrPort]*UDPConn
newConnChan chan *Uni_UDPConn
connMap map[netip.AddrPort]*Uni_UDPConn
mux sync.RWMutex
isclosed bool
}
@@ -35,20 +35,20 @@ func NewUDPListener(laddr *net.UDPAddr) (*UDPListener, error) {
func NewUDPListenerConn(conn *net.UDPConn) (*UDPListener, error) {
ul := new(UDPListener)
ul.conn = conn
ul.connMap = make(map[netip.AddrPort]*UDPConn)
ul.newConnChan = make(chan *UDPConn, 100)
ul.connMap = make(map[netip.AddrPort]*Uni_UDPConn)
ul.newConnChan = make(chan *Uni_UDPConn, 100)
go ul.run()
return ul, nil
}
//It can be used to dial a remote udp
func (ul *UDPListener) NewConn(raddr *net.UDPAddr) *UDPConn {
func (ul *UDPListener) NewConn(raddr *net.UDPAddr) *Uni_UDPConn {
return ul.newConn(raddr, UDPAddr2AddrPort(raddr))
}
//newConn 创建一个新的 UDPConn,并存储在 ul.connMap 中
func (ul *UDPListener) newConn(raddr *net.UDPAddr, addrport netip.AddrPort) *UDPConn {
func (ul *UDPListener) newConn(raddr *net.UDPAddr, addrport netip.AddrPort) *Uni_UDPConn {
newC := NewUDPConn(raddr, ul.conn, false)
ul.mux.Lock()
ul.connMap[addrport] = newC
@@ -101,7 +101,7 @@ func (ul *UDPListener) closeClients() error {
for _, c := range ul.connMap {
close(c.inMsgChan)
}
ul.connMap = make(map[netip.AddrPort]*UDPConn)
ul.connMap = make(map[netip.AddrPort]*Uni_UDPConn)
ul.mux.Unlock()
return nil
@@ -120,7 +120,7 @@ func (ul *UDPListener) run() {
go func(theraddr *net.UDPAddr, thebuf []byte) {
addrport := UDPAddr2AddrPort(theraddr)
var oldConn *UDPConn
var oldConn *Uni_UDPConn
ul.mux.RLock()
oldConn = ul.connMap[addrport]
+4 -9
View File
@@ -49,13 +49,8 @@ func (d *Client) Handshake(underlay net.Conn, target netLayer.Addr) (io.ReadWrit
}
func (d *Client) GetNewUDP_Putter() netLayer.UDP_Putter {
//单单的pipe是无法做到转发的,它就像一个缓存一样;
// 一方是未知的,向 UDP_Putter 放入请求,
// 然后我们这边就要通过一个 goroutine 来不断提取请求然后转发到direct.
pipe := netLayer.NewUDP_Pipe()
go netLayer.RelayUDP_to_Direct(pipe)
return pipe
//direct的Client的 EstablishUDPChannel 实际上就是直接拨号udp
func (d *Client) EstablishUDPChannel(_ net.Conn, target netLayer.Addr) (netLayer.MsgConn, error) {
conn, err := net.DialUDP("udp", nil, target.ToUDPAddr())
return &netLayer.UDPMsgConnWrapper{UDPConn: conn, IsClient: true, FirstAddr: target}, err
}
+3 -2
View File
@@ -82,6 +82,7 @@ func NewServer() (proxy.Server, error) {
}
func (d *Server) Name() string { return name }
func (s *Server) Handshake(underlay net.Conn) (io.ReadWriteCloser, netLayer.Addr, error) {
return underlay, s.targetAddr, nil
//因为dokodemo的单目标性质, 不会建立任何udp通道.
func (s *Server) Handshake(underlay net.Conn) (io.ReadWriteCloser, netLayer.MsgConn, netLayer.Addr, error) {
return underlay, nil, s.targetAddr, nil
}
+1 -1
View File
@@ -48,7 +48,7 @@ func (_ Server) Name() string {
return name
}
func (s *Server) Handshake(underlay net.Conn) (newconn io.ReadWriteCloser, targetAddr netLayer.Addr, err error) {
func (s *Server) Handshake(underlay net.Conn) (newconn io.ReadWriteCloser, _ netLayer.MsgConn, targetAddr netLayer.Addr, err error) {
var b = utils.GetMTU() //一般要获取请求信息,不需要那么长; 就算是http,加了path,也不用太长
//因为要储存为 firstdata,所以也无法直接放回
+7 -3
View File
@@ -35,12 +35,15 @@ func PrintAllClientNames() {
//服务端是一种 “泛目标”代理,所以我们客户端的 Handshake 要传入目标地址, 来告诉它 我们 想要到达的 目标地址.
// 一个Client 掌握从最底层的tcp等到最上层的 代理协议间的所有数据;
// 一旦一个 Client 被完整定义,则它的数据的流向就被完整确定了.
//
// 然而, udp的转发则不一样. 一般来说, udp只handshake一次, 建立一个通道, 然后在这个通道上
// 不断申请发送到 各个远程udp地址的连接。客户端也可以选择建立多个udp通道。
type Client interface {
ProxyCommon
// Handshake的 underlay有可能传入nil,所以要求 所有的 Client 都要能够自己dial
// 不过目前暂时全在main函数里dial
Handshake(underlay net.Conn, target netLayer.Addr) (io.ReadWriteCloser, error)
EstablishUDPChannel(underlay net.Conn, target netLayer.Addr) (netLayer.MsgConn, error)
}
// Server 用于监听 客户端 的连接.
@@ -50,7 +53,8 @@ type Client interface {
type Server interface {
ProxyCommon
Handshake(underlay net.Conn) (io.ReadWriteCloser, netLayer.Addr, error)
//ReadWriteCloser 为请求地址为tcp的情况, net.PacketConn 为 请求建立的udp通道
Handshake(underlay net.Conn) (io.ReadWriteCloser, netLayer.MsgConn, netLayer.Addr, error)
}
// FullName 可以完整表示 一个 代理的 VSI 层级.
+88 -131
View File
@@ -11,7 +11,6 @@ import (
"github.com/hahahrfool/v2ray_simple/netLayer"
"github.com/hahahrfool/v2ray_simple/utils"
"go.uber.org/zap"
"github.com/hahahrfool/v2ray_simple/proxy"
)
@@ -46,8 +45,8 @@ func (s *Server) Name() string { return Name }
//中文: https://aber.sh/articles/Socks5/
// 参考 https://studygolang.com/articles/31404
// 处理tcp收到的请求. 注意, udp associate后的 udp请求并不通过此函数处理, 而是由 UDPConn.StartReadRequest 处理
func (s *Server) Handshake(underlay net.Conn) (result io.ReadWriteCloser, targetAddr netLayer.Addr, returnErr error) {
// 处理tcp收到的请求. 注意, udp associate后的 udp请求并不通过此函数处理, 而是由 UDPConn 处理
func (s *Server) Handshake(underlay net.Conn) (result io.ReadWriteCloser, udpChannel netLayer.MsgConn, targetAddr netLayer.Addr, returnErr error) {
// Set handshake timeout 4 seconds
if err := underlay.SetReadDeadline(time.Now().Add(time.Second * 4)); err != nil {
returnErr = err
@@ -179,7 +178,7 @@ func (s *Server) Handshake(underlay net.Conn) (result io.ReadWriteCloser, target
clientSupposedAddr: clientFutureAddr.ToUDPAddr(),
UDPConn: udpRC,
}
return uc, clientFutureAddr, nil
return nil, uc, clientFutureAddr, nil
} else {
@@ -207,167 +206,125 @@ func (s *Server) Handshake(underlay net.Conn) (result io.ReadWriteCloser, target
Port: thePort,
}
return underlay, targetAddr, nil
return underlay, nil, targetAddr, nil
}
}
//用于socks5服务端的 udp连接, 实现 netLayer.MsgConn
type UDPConn struct {
*net.UDPConn
clientSupposedAddr *net.UDPAddr //客户端指定的客户端自己未来将使用的公网UDP的Addr
}
// 阻塞
// 从 udpPutter.GetNewUDPResponse 循环阅读 所有需要发送给客户端的 数据,然后通过 u.UDPConn.Write 发送给客户端
// 这些响应数据是 在其它地方 写入 udpPutter 的, 本 u 是不管 谁、如何 把这个信息 放进去的。
func (u *UDPConn) StartPushResponse(udpPutter netLayer.UDP_Putter) {
for {
raddr, bs, err := udpPutter.GetNewUDPResponse()
//log.Println("StartPushResponse got new response", raddr, string(bs), err)
if err != nil {
u.UDPConn.Close()
break
}
buf := &bytes.Buffer{}
buf.WriteByte(0) //rsv
buf.WriteByte(0) //rsv
buf.WriteByte(0) //frag
//将远程地址发来的响应 传给客户端
func (u *UDPConn) WriteTo(bs []byte, raddr netLayer.Addr) error {
var atyp byte = ATypIP4
if len(raddr.IP) > 4 {
atyp = ATypIP6
}
buf.WriteByte(atyp)
buf.Write(raddr.IP)
buf.WriteByte(byte(int16(raddr.Port) >> 8))
buf.WriteByte(byte(int16(raddr.Port) << 8 >> 8))
buf.Write(bs)
//必须要指明raddr
_, err = u.UDPConn.WriteToUDP(buf.Bytes(), u.clientSupposedAddr)
if err != nil {
if ce := utils.CanLogErr("socks5, StartPushResponse, write"); ce != nil {
//log.Println("socks5, StartPushResponse, write err ", err)
ce.Write(zap.Error(err))
}
break
}
buf := &bytes.Buffer{}
buf.WriteByte(0) //rsv
buf.WriteByte(0) //rsv
buf.WriteByte(0) //frag
var atyp byte = ATypIP4
if len(raddr.IP) > 4 {
atyp = ATypIP6
}
buf.WriteByte(atyp)
buf.Write(raddr.IP)
buf.WriteByte(byte(int16(raddr.Port) >> 8))
buf.WriteByte(byte(int16(raddr.Port) << 8 >> 8))
buf.Write(bs)
//必须要指明raddr
_, err := u.UDPConn.WriteToUDP(buf.Bytes(), u.clientSupposedAddr)
return err
}
// 阻塞
// 监听 与客户端的udp连接 (u.UDPConn);循环查看客户端发来的请求信息;
// 然后将该请求 用 udpPutter.WriteUDPRequest 发送给 udpPutter
// 至于fullcone与否它是不管的。
// 如果客户端一开始没有指明自己连接本服务端的ip和端口, 则将第一个发来的正确的socks5请求视为该客户端,并记录。
func (u *UDPConn) StartReadRequest(udpPutter netLayer.UDP_Putter, dialFunc func(targetAddr netLayer.Addr) (io.ReadWriter, error)) {
//从 客户端读取 udp请求
func (u *UDPConn) ReadFrom() ([]byte, netLayer.Addr, error) {
var clientSupposedAddrIsNothing bool
if len(u.clientSupposedAddr.IP) < 3 || u.clientSupposedAddr.IP.IsUnspecified() {
clientSupposedAddrIsNothing = true
}
bs := make([]byte, netLayer.MaxUDP_packetLen)
for {
bs := utils.GetPacket()
n, addr, err := u.UDPConn.ReadFromUDP(bs)
if err != nil {
n, addr, err := u.UDPConn.ReadFromUDP(bs)
if err != nil {
u.UDPConn.Close()
udpPutter.CloseUDPRequestWriter() //只要读udp发生致命错误,我们就关闭RequestWriter,这样 StartPushResponse 方法中调用的 udpPutter.GetNewUDPResponse 就应该同步退出了
if ce := utils.CanLogWarn("socks5 failed UDPConn read"); ce != nil {
ce.Write(zap.Error(err))
}
break
if n <= 0 {
return nil, netLayer.Addr{}, err
}
return bs[:n], netLayer.NewAddrFromUDPAddr(addr), err
}
if n < 6 {
if ce := utils.CanLogWarn("socks5 UDPConn short read"); ce != nil {
if n < 6 {
ce.Write(zap.Error(err))
}
continue
}
return nil, netLayer.Addr{}, utils.ErrInErr{ErrDesc: "socks5 UDPConn short read", Data: n}
}
if !clientSupposedAddrIsNothing {
if !clientSupposedAddrIsNothing {
if !addr.IP.Equal(u.clientSupposedAddr.IP) || addr.Port != u.clientSupposedAddr.Port {
if !addr.IP.Equal(u.clientSupposedAddr.IP) || addr.Port != u.clientSupposedAddr.Port {
//just random attack message.
continue
}
}
atyp := bs[3]
l := 2 //supposed Minimum Remain Data Lenth
off := 4 //offset from which the addr data really starts
var theIP net.IP
switch atyp {
case ATypIP4:
l += net.IPv4len
theIP = make(net.IP, net.IPv4len)
case ATypIP6:
l += net.IPv6len
theIP = make(net.IP, net.IPv6len)
case ATypDomain:
l += int(bs[4])
off = 5
default:
if ce := utils.CanLogWarn("socks5 read UDPConn unknown address"); ce != nil {
ce.Write(zap.Uint8("atype", atyp))
}
continue
//just random attack message.
return nil, netLayer.Addr{}, errors.New("socks5 UDPConn random attack message")
}
}
if len(bs[off:]) < l {
if ce := utils.CanLogWarn("socks5 UDPConn short command request"); ce != nil {
atyp := bs[3]
ce.Write(zap.Uint8("atype", atyp))
}
continue
l := 2 //supposed Minimum Remain Data Lenth
off := 4 //offset from which the addr data really starts
}
var theIP net.IP
switch atyp {
case ATypIP4:
l += net.IPv4len
theIP = make(net.IP, net.IPv4len)
case ATypIP6:
l += net.IPv6len
theIP = make(net.IP, net.IPv6len)
case ATypDomain:
l += int(bs[4])
off = 5
default:
var theName string
if theIP != nil {
copy(theIP, bs[off:])
} else {
theName = string(bs[off : off+l-2])
}
var thePort int
thePort = int(bs[off+l-2])<<8 | int(bs[off+l-1])
newStart := off + l
//为了解析域名, 我们用 netLayer.Addr 作为中介.
requestAddr := &netLayer.Addr{
IP: theIP,
Name: theName,
Port: thePort,
Network: "udp",
}
if clientSupposedAddrIsNothing {
clientSupposedAddrIsNothing = false
u.clientSupposedAddr = addr
}
//log.Println("socks5 server,StartReadRequest, got msg", thisaddr, string(bs[newStart:n]))
udpPutter.WriteUDPRequest(*requestAddr.ToUDPAddr(), bs[newStart:n], dialFunc)
return nil, netLayer.Addr{}, utils.ErrInErr{ErrDesc: "socks5 read UDPConn unknown atype", Data: atyp}
}
if len(bs[off:]) < l {
return nil, netLayer.Addr{}, utils.ErrInErr{ErrDesc: "socks5 UDPConn short command request", Data: atyp}
}
var theName string
if theIP != nil {
copy(theIP, bs[off:])
} else {
theName = string(bs[off : off+l-2])
}
var thePort int
thePort = int(bs[off+l-2])<<8 | int(bs[off+l-1])
newStart := off + l
if clientSupposedAddrIsNothing {
clientSupposedAddrIsNothing = false
u.clientSupposedAddr = addr
}
return bs[newStart:n], netLayer.Addr{
IP: theIP,
Name: theName,
Port: thePort,
Network: "udp",
}, nil
}
+29 -28
View File
@@ -1,7 +1,6 @@
package socks5_test
import (
"io"
"net"
"strconv"
"strings"
@@ -38,44 +37,46 @@ func TestUDP(t *testing.T) {
t.Fail()
}
t.Log("socks5 server got new conn")
wlc, targetAddr, err := s.Handshake(lc)
_, wlc, targetAddr, err := s.Handshake(lc)
if targetAddr.IsUDP() {
t.Log("socks5 server got udp associate")
}
//此时wlc返回的是socks5新监听的 conn
udpConn := wlc.(*socks5.UDPConn)
go func() {
for {
t.Log("socks5 server start read udp channel")
dialFunc := func(targetAddr netLayer.Addr) (io.ReadWriter, error) {
return targetAddr.Dial()
}
bs, addr, err := wlc.ReadFrom()
if err != nil {
t.Log("socks5 server read udp channel err,", err)
if putter, ok := direct.(netLayer.UDP_Putter); ok {
break
}
//UDP_Putter 不使用传统的Handshake过程,因为Handshake是用于第一次数据,然后后面接着的双向传输都不再需要额外信息;而 UDP_Putter 每一次数据传输都是需要传输 目标地址的,所以每一次都需要一些额外数据,这就是我们 UDP_Putter 接口去解决的事情。
t.Log("socks5 server got udp msg")
//因为UDP Associate后,就会保证以后的向 wlc 的 所有请求数据都是udp请求,所以可以在这里直接循环转发了。
go udpConn.StartPushResponse(putter)
udpConn.StartReadRequest(putter, dialFunc)
} else if pc, ok := direct.(netLayer.UDP_Putter_Generator); ok {
// direct 通过 UDP_Pipe和 RelayUDP_to_Direct函数 实现了 UDP_Putter_Generator
putter := pc.GetNewUDP_Putter()
if putter != nil {
go udpConn.StartPushResponse(putter)
udpConn.StartReadRequest(putter, dialFunc)
msgConn, err := direct.EstablishUDPChannel(nil, addr)
if err != nil {
t.Fail()
return
}
err = msgConn.WriteTo(bs, addr)
if err != nil {
t.Log("socks5 server Write To direct failed,", len(bs), err)
}
go func() {
for {
rbs, raddr, err := msgConn.ReadFrom()
if err != nil {
break
}
wlc.WriteTo(rbs, raddr)
}
}()
}
} else {
}()
t.Log("socks5 server -> client for udp, but client didn't implement netLayer.UDP_Putter", direct.Name())
t.Fail()
return
}
}
}()
+36 -20
View File
@@ -1,6 +1,7 @@
package trojan
import (
"bytes"
"errors"
"io"
"net"
@@ -38,20 +39,8 @@ type Client struct {
func (c *Client) Name() string {
return name
}
func (c *Client) Handshake(underlay net.Conn, target netLayer.Addr) (io.ReadWriteCloser, error) {
if target.Port <= 0 {
return nil, errors.New("Trojan Client Handshake failed, target port invalid")
}
buf := utils.GetBuf()
buf.Write(c.password_hexStringBytes)
buf.Write(crlf)
isudp := target.IsUDP()
if isudp {
buf.WriteByte(CmdUDPAssociate)
} else {
buf.WriteByte(CmdConnect)
}
func WriteTargetToBuf(target netLayer.Addr, buf *bytes.Buffer) {
if len(target.IP) > 0 {
if ip4 := target.IP.To4(); ip4 == nil {
buf.WriteByte(netLayer.AtypIP6)
@@ -64,21 +53,48 @@ func (c *Client) Handshake(underlay net.Conn, target netLayer.Addr) (io.ReadWrit
buf.WriteByte(ATypDomain)
buf.WriteByte(byte(l))
buf.WriteString(target.Name)
} else {
return nil, errors.New("Trojan Client Handshake failed, target has no domain and ip at all.")
}
buf.WriteByte(byte(target.Port >> 8))
buf.WriteByte(byte(target.Port << 8 >> 8))
buf.Write(crlf)
}
func (c *Client) Handshake(underlay net.Conn, target netLayer.Addr) (io.ReadWriteCloser, error) {
if target.Port <= 0 {
return nil, errors.New("Trojan Client Handshake failed, target port invalid")
}
buf := utils.GetBuf()
buf.Write(c.password_hexStringBytes)
buf.Write(crlf)
buf.WriteByte(CmdConnect)
WriteTargetToBuf(target, buf)
_, err := underlay.Write(buf.Bytes())
utils.PutBuf(buf)
if err != nil {
return nil, err
}
if isudp {
return UDPConn{underlay}, nil
} else {
return underlay, nil
}
return underlay, nil
}
func (c *Client) EstablishUDPChannel(underlay net.Conn, target netLayer.Addr) (netLayer.MsgConn, error) {
if target.Port <= 0 {
return nil, errors.New("Trojan Client Handshake failed, target port invalid")
}
buf := utils.GetBuf()
buf.Write(c.password_hexStringBytes)
buf.Write(crlf)
buf.WriteByte(CmdUDPAssociate)
WriteTargetToBuf(target, buf)
_, err := underlay.Write(buf.Bytes())
utils.PutBuf(buf)
if err != nil {
return nil, err
}
return UDPConn{underlay}, nil
}
+15 -1
View File
@@ -1,7 +1,21 @@
package trojan
import "net"
import (
"net"
"github.com/hahahrfool/v2ray_simple/netLayer"
)
type UDPConn struct {
net.Conn
}
func (u UDPConn) ReadFrom() ([]byte, netLayer.Addr, error) {
return nil, netLayer.Addr{}, nil
}
func (u UDPConn) WriteTo([]byte, netLayer.Addr) error {
return nil
}
+68 -118
View File
@@ -105,61 +105,10 @@ func (c *Client) GetUser() proxy.User {
func (c *Client) Handshake(underlay net.Conn, target netLayer.Addr) (io.ReadWriteCloser, error) {
var err error
if underlay == nil {
underlay, err = target.Dial() //不建议传入underlay为nil,因为这里dial处于裸奔状态
if err != nil {
return nil, err
}
}
port := target.Port
addr, atyp := target.AddressBytes()
cmd := CmdTCP
if target.Network == "udp" {
if c.version == 1 && !c.is_CRUMFURS_established {
//log.Println("尝试拨号 Cmd_CRUMFURS 信道")
//这段代码明显有问题,如果直接dial的话,那就是脱离tls的裸协议,所以这里以后需要处理一下
UMFURS_conn, err := target.Dial()
if err != nil {
if ce := utils.CanLogErr("尝试拨号 Cmd_CRUMFURS 信道时发生错误"); ce != nil {
//log.Println("尝试拨号 Cmd_CRUMFURS 信道时发生错误")
ce.Write(zap.Error(err))
}
return nil, err
}
buf := c.getBufWithCmd(Cmd_CRUMFURS)
UMFURS_conn.Write(buf.Bytes())
utils.PutBuf(buf)
bs := []byte{0}
n, err := UMFURS_conn.Read(bs)
if err != nil || n == 0 || bs[0] != CRUMFURS_ESTABLISHED {
if ce := utils.CanLogErr("尝试读取 Cmd_CRUMFURS 信道返回值 时发生错误"); ce != nil {
//log.Println("尝试读取 Cmd_CRUMFURS 信道返回值 时发生错误")
ce.Write(zap.Error(err))
}
return nil, err
}
c.is_CRUMFURS_established = true
// 循环监听 UMFURS 信息
go c.handle_CRUMFURS(UMFURS_conn)
}
cmd = CmdUDP
}
buf := c.getBufWithCmd(cmd)
buf := c.getBufWithCmd(CmdTCP)
buf.WriteByte(byte(uint16(port) >> 8))
buf.WriteByte(byte(uint16(port) << 8 >> 8))
@@ -171,74 +120,75 @@ func (c *Client) Handshake(underlay net.Conn, target netLayer.Addr) (io.ReadWrit
utils.PutBuf(buf)
return &UserConn{
Conn: underlay,
uuid: *c.user,
version: c.version,
isUDP: target.IsUDP(),
underlayIsBasic: netLayer.IsBasicConn(underlay),
}, err
}
func (u *Client) CloseUDPRequestWriter() {
//因为我们的vless的client是 【一个 outClient实例 处理 一切 dial 的udp连接】
// 所以不能直接close c.udpResponseChan
}
func (c *Client) GetNewUDPResponse() (net.UDPAddr, []byte, error) {
x := <-c.udpResponseChan //v1的话,由 handle_CRUMFURS 以及 WriteUDPRequest 中的 goroutine 填充;v0的话,由 WriteUDPRequest 填充
return x.Addr, x.Data, nil
}
//一般由socks5或者透明代理等地方 获取到 udp请求后,被传入这里
func (c *Client) WriteUDPRequest(a net.UDPAddr, b []byte, dialFunc func(targetAddr netLayer.Addr) (io.ReadWriter, error)) (err error) {
astr := a.String()
c.mutex.RLock()
knownConn := c.knownUDPDestinations[astr]
c.mutex.RUnlock()
if knownConn == nil {
knownConn, err = dialFunc(netLayer.NewAddrFromUDPAddr(&a))
if err != nil || knownConn == nil {
return utils.ErrInErr{ErrDesc: "vless WriteUDPRequest, err when creating an underlay", ErrDetail: err}
}
//这里原来的代码是调用 c.Handshake,会自动帮我们拨号代理节点CmdUDP
// 但是有问题,因为不应该由client自己拨号vless,因为我们还有上层的tls;
// 自己拨号的话,那就是裸奔状态
// 最新代码采用dialFunc的方式解决
c.mutex.Lock()
c.knownUDPDestinations[astr] = knownConn
c.mutex.Unlock()
go func() {
bs := make([]byte, netLayer.MaxUDP_packetLen)
for {
n, err := knownConn.Read(bs)
//一般knownConn为tcp连接. 在远程节点的 udp的direct的Read一直读不到数据导致timeout后, 就会关闭对应的vless的tcp连接, 然后我们这里的Read就会收到通知
// 不过我们不用管 inServer的conn的关闭, 因为监听udp的conn是不需要关闭的, 它还要接着监听其它客户端发来的连接.
if err != nil {
break
}
if n <= 0 {
continue
}
msg := make([]byte, n)
copy(msg, bs[:n])
c.udpResponseChan <- netLayer.UDPAddrData{
Addr: a,
Data: msg,
}
}
}()
if c.version == 0 {
return &UserTCPConn{
Conn: underlay,
uuid: *c.user,
version: c.version,
underlayIsBasic: netLayer.IsBasicConn(underlay),
}, err
} else {
return underlay, nil
}
_, err = knownConn.Write(b)
return
}
func (c *Client) EstablishUDPChannel(underlay net.Conn, target netLayer.Addr) (netLayer.MsgConn, error) {
var err error
if c.version == 1 && !c.is_CRUMFURS_established {
//log.Println("尝试拨号 Cmd_CRUMFURS 信道")
//这段代码明显有问题,如果直接dial的话,那就是脱离tls的裸协议,所以这里以后需要处理一下
UMFURS_conn, err := target.Dial()
if err != nil {
if ce := utils.CanLogErr("尝试拨号 Cmd_CRUMFURS 信道时发生错误"); ce != nil {
//log.Println("尝试拨号 Cmd_CRUMFURS 信道时发生错误")
ce.Write(zap.Error(err))
}
return nil, err
}
buf := c.getBufWithCmd(Cmd_CRUMFURS)
UMFURS_conn.Write(buf.Bytes())
utils.PutBuf(buf)
bs := []byte{0}
n, err := UMFURS_conn.Read(bs)
if err != nil || n == 0 || bs[0] != CRUMFURS_ESTABLISHED {
if ce := utils.CanLogErr("尝试读取 Cmd_CRUMFURS 信道返回值 时发生错误"); ce != nil {
//log.Println("尝试读取 Cmd_CRUMFURS 信道返回值 时发生错误")
ce.Write(zap.Error(err))
}
return nil, err
}
c.is_CRUMFURS_established = true
// 循环监听 UMFURS 信息
go c.handle_CRUMFURS(UMFURS_conn)
}
buf := c.getBufWithCmd(CmdUDP)
port := target.Port
buf.WriteByte(byte(uint16(port) >> 8))
buf.WriteByte(byte(uint16(port) << 8 >> 8))
addr, atyp := target.AddressBytes()
buf.WriteByte(atyp)
buf.Write(addr)
_, err = underlay.Write(buf.Bytes())
utils.PutBuf(buf)
return &UDPConn{Conn: underlay, version: c.version, isClientEnd: true, raddr: target}, err
}
func (c *Client) getBufWithCmd(cmd byte) *bytes.Buffer {
+24 -12
View File
@@ -6,6 +6,7 @@ import (
"errors"
"fmt"
"io"
"log"
"net"
"net/url"
"sync"
@@ -133,7 +134,7 @@ func (s *Server) GetUserByStr(str string) proxy.User {
func (s *Server) Name() string { return Name }
// 返回的bytes.Buffer 是用于 回落使用的,内含了整个读取的数据;不回落时不要使用该Buffer
func (s *Server) Handshake(underlay net.Conn) (result io.ReadWriteCloser, targetAddr netLayer.Addr, returnErr error) {
func (s *Server) Handshake(underlay net.Conn) (result io.ReadWriteCloser, msgConn netLayer.MsgConn, targetAddr netLayer.Addr, returnErr error) {
if err := underlay.SetReadDeadline(time.Now().Add(time.Second * 4)); err != nil {
returnErr = err
@@ -147,7 +148,6 @@ func (s *Server) Handshake(underlay net.Conn) (result io.ReadWriteCloser, target
readbs := utils.GetBytes(utils.StandardBytesLength)
//var auth [17]byte
wholeReadLen, err := underlay.Read(readbs)
if err != nil {
returnErr = utils.ErrInErr{ErrDesc: "read err", ErrDetail: err, Data: wholeReadLen}
@@ -334,6 +334,7 @@ realPart:
_, err = readbuf.Read(ip_or_domain)
if err != nil {
utils.PutBytes(ip_or_domain)
returnErr = errors.New("fallback, reason 6")
return
}
@@ -352,16 +353,27 @@ realPart:
goto errorPart
}
return &UserConn{
Conn: underlay,
optionalReader: io.MultiReader(readbuf, underlay),
remainFirstBufLen: readbuf.Len(),
uuid: thisUUIDBytes,
version: int(version),
isUDP: targetAddr.IsUDP(),
underlayIsBasic: netLayer.IsBasicConn(underlay),
isServerEnd: true,
}, targetAddr, nil
if targetAddr.IsUDP() {
log.Println("targetAddr", targetAddr.IP, targetAddr.Name)
return nil, &UDPConn{
Conn: underlay,
version: int(version),
raddr: targetAddr,
optionalReader: io.MultiReader(readbuf, underlay),
remainFirstBufLen: readbuf.Len(),
}, targetAddr, nil
} else {
return &UserTCPConn{
Conn: underlay,
optionalReader: io.MultiReader(readbuf, underlay),
remainFirstBufLen: readbuf.Len(),
uuid: thisUUIDBytes,
version: int(version),
underlayIsBasic: netLayer.IsBasicConn(underlay),
isServerEnd: true,
}, nil, targetAddr, nil
}
}
+248
View File
@@ -0,0 +1,248 @@
package vless
import (
"bufio"
"bytes"
"errors"
"io"
"net"
"github.com/hahahrfool/v2ray_simple/netLayer"
"github.com/hahahrfool/v2ray_simple/utils"
)
//实现 net.Conn, io.ReaderFrom, utils.MultiWriter, netLayer.Splicer
type UserTCPConn struct {
net.Conn
optionalReader io.Reader //在使用了缓存读取握手包头后,就产生了buffer中有剩余数据的可能性,此时就要使用MultiReader
remainFirstBufLen int //记录读取握手包头时读到的buf的长度. 如果我们读超过了这个部分的话,实际上我们就可以不再使用 optionalReader 读取, 而是直接从Conn读取
underlayIsBasic bool
uuid [16]byte
convertedUUIDStr string
version int
isServerEnd bool //for v0
// udpUnreadPart 不为空,则表示上一次读取没读完整个包(给Read传入的buf太小),须接着读
udpUnreadPart []byte //for udp
bufr *bufio.Reader //for udp
isntFirstPacket bool //for v0
hasAdvancedLayer bool //for v1, 在用ws或grpc时,这个开关保持打开
}
func (uc *UserTCPConn) GetProtocolVersion() int {
return uc.version
}
func (uc *UserTCPConn) GetIdentityStr() string {
if uc.convertedUUIDStr == "" {
uc.convertedUUIDStr = utils.UUIDToStr(uc.uuid)
}
return uc.convertedUUIDStr
}
//当前连接状态是否可以直接写入底层Conn而不经任何改动/包装
func (c *UserTCPConn) canDirectWrite() bool {
return c.version == 1 || c.version == 0 && !(c.isServerEnd && !c.isntFirstPacket)
}
func (c *UserTCPConn) EverPossibleToSplice() bool {
if netLayer.IsBasicConn(c.Conn) {
return true
}
if s, ok := c.Conn.(netLayer.Splicer); ok {
return s.EverPossibleToSplice()
}
return false
}
func (c *UserTCPConn) CanSplice() (r bool, conn net.Conn) {
if !c.canDirectWrite() {
return
}
if netLayer.IsBasicConn(c.Conn) {
r = true
conn = c.Conn
} else if s, ok := c.Conn.(netLayer.Splicer); ok {
r, conn = s.CanSplice()
}
return
}
func (c *UserTCPConn) WriteBuffers(buffers [][]byte) (int64, error) {
if c.canDirectWrite() {
//底层连接可以是 ws,或者 tls,或者 基本连接; tls 我们暂不支持 utils.MultiWriter
// 理论上tls是可以支持的,但是要我们魔改tls库
//本作的 ws.Conn 实现了 utils.MultiWriter
if c.underlayIsBasic {
//如果是基本Conn,则不用担心 WriteTo篡改buffers的问题, 因为它会直接调用底层 writev
//nb := net.Buffers(buffers)
//return nb.WriteTo(c.Conn) //发现它还是会篡改??什么鬼
return utils.BuffersWriteTo(buffers, c.Conn)
} else if mr, ok := c.Conn.(utils.MultiWriter); ok {
return mr.WriteBuffers(buffers)
}
}
bigbs, dup := utils.MergeBuffers(buffers)
n, e := c.Write(bigbs)
if dup {
utils.PutPacket(bigbs)
}
return int64(n), e
}
//专门适用于 裸奔splice的情况
func (uc *UserTCPConn) ReadFrom(r io.Reader) (written int64, err error) {
return netLayer.TryReadFrom_withSplice(uc, uc.Conn, r, uc.canDirectWrite)
}
//如果是udp,则是多线程不安全的,如果是tcp,则安不安全看底层的链接。
// 这里规定,如果是UDP,则 每Write一遍,都要Write一个 完整的UDP 数据包
func (uc *UserTCPConn) Write(p []byte) (int, error) {
if uc.version == 0 {
originalSupposedWrittenLenth := len(p)
var writeBuf *bytes.Buffer
if uc.isServerEnd && !uc.isntFirstPacket {
uc.isntFirstPacket = true
writeBuf = utils.GetBuf()
//v0 中,服务端的回复的第一个包也是要有数据头的(和客户端的handshake类似,只是第一个包有),第一字节版本,第二字节addon长度(都是0)
writeBuf.WriteByte(0)
writeBuf.WriteByte(0)
}
if writeBuf != nil {
writeBuf.Write(p)
_, err := uc.Conn.Write(writeBuf.Bytes()) //“直接return这个的长度” 是错的,因为写入长度只能小于等于len(p)
utils.PutBuf(writeBuf)
if err != nil {
return 0, err
}
return originalSupposedWrittenLenth, nil
} else {
_, err := uc.Conn.Write(p) //“直接return这个的长度” 是错的,因为写入长度只能小于等于len(p)
if err != nil {
return 0, err
}
return originalSupposedWrittenLenth, nil
}
} else {
/*
if uc.isUDP && !uc.hasAdvancedLayer {
// 这里暂时认为包裹它的连接是 tcp或者tls,而不是udp,如果udp的话,就不需要考虑粘包问题了,比如socks5的实现
// 我们目前认为只有tls是最防墙的,而且 魔改tls是有毒的,所以反推过来,这里udp就必须加长度头。
// 目前是这个样子。之后verysimple实现了websocket和grpc后,会添加判断,如果连接是websocket或者grpc连接,则不再加长度头
// tls和tcp都是基于流的,可以分开写两次,不需要buf存在;如果连接是websocket或者grpc的话,直接传输。
l := int16(len(p))
var lenBytes []byte
if l <= 255 {
lenBytes = []byte{0, byte(l)}
}
lenBytes = []byte{byte(l >> 8), byte(l << 8 >> 8)}
_, err := uc.Conn.Write(lenBytes)
if err != nil {
return 0, err
}
return uc.Conn.Write(p)
}
*/
return uc.Conn.Write(p)
}
}
//如果是udp,则是多线程不安全的,如果是tcp,则安不安全看底层的链接。
// 这里规定,如果是UDP,则 每次 Read 得到的都是一个 完整的UDP 数据包,除非p给的太小……
func (uc *UserTCPConn) Read(p []byte) (int, error) {
var from io.Reader = uc.Conn
if uc.optionalReader != nil {
from = uc.optionalReader
}
if uc.version == 0 {
if !uc.isServerEnd && !uc.isntFirstPacket {
//先读取响应头
uc.isntFirstPacket = true
bs := utils.GetPacket()
n, e := from.Read(bs)
if e != nil {
utils.PutPacket(bs)
return 0, e
}
if n < 2 {
utils.PutPacket(bs)
return 0, errors.New("vless response head too short")
}
n = copy(p, bs[2:n])
utils.PutPacket(bs)
return n, nil
}
return from.Read(p)
} else {
/*
if uc.isUDP && !uc.hasAdvancedLayer {
if len(uc.udpUnreadPart) > 0 {
copiedN := copy(p, uc.udpUnreadPart)
if copiedN < len(uc.udpUnreadPart) {
uc.udpUnreadPart = uc.udpUnreadPart[copiedN:]
} else {
uc.udpUnreadPart = nil
}
return copiedN, nil
}
return uc.readudp_withLenthHead(p)
}*/
return from.Read(p)
}
}
+129
View File
@@ -0,0 +1,129 @@
package vless
import (
"bufio"
"io"
"net"
"github.com/hahahrfool/v2ray_simple/netLayer"
"github.com/hahahrfool/v2ray_simple/utils"
)
type UDPConn struct {
net.Conn
optionalReader io.Reader
remainFirstBufLen int
version int
isClientEnd bool
bufr *bufio.Reader
notFirst bool //for v0
raddr netLayer.Addr
}
func (u *UDPConn) WriteTo(p []byte, raddr netLayer.Addr) error {
//v0很垃圾,不支持fullcone,无视raddr,始终向最开始的raddr发送。
if u.version == 0 {
writeBuf := utils.GetBuf()
if !u.isClientEnd && !u.notFirst {
u.notFirst = true
//v0 中,服务端的回复的第一个包也是要有数据头的(和客户端的handshake类似,只是第一个包有),第一字节版本,第二字节addon长度(都是0)
writeBuf.WriteByte(0)
writeBuf.WriteByte(0)
}
l := int16(len(p))
writeBuf.WriteByte(byte(l >> 8))
writeBuf.WriteByte(byte(l << 8 >> 8))
writeBuf.Write(p)
_, err := u.Conn.Write(writeBuf.Bytes()) //“直接return这个的长度” 是错的,因为写入长度只能小于等于len(p)
utils.PutBuf(writeBuf)
if err != nil {
return err
}
return nil
} else {
}
return nil
}
//从 客户端读取 udp请求
func (u *UDPConn) ReadFrom() ([]byte, netLayer.Addr, error) {
var from io.Reader = u.Conn
if u.optionalReader != nil {
from = u.optionalReader
}
if u.version == 0 {
if u.isClientEnd {
if !u.notFirst {
u.notFirst = true
u.bufr = bufio.NewReader(from)
_, err := u.bufr.ReadByte() //version byte
if err != nil {
return nil, netLayer.Addr{}, err
}
_, err = u.bufr.ReadByte() //addon len byte
if err != nil {
return nil, netLayer.Addr{}, err
}
}
} else {
if u.bufr == nil {
u.bufr = bufio.NewReader(from)
}
}
bs, err := u.read_with_v0_Head()
return bs, u.raddr, err
} else {
}
return nil, netLayer.Addr{}, nil
}
func (uc *UDPConn) read_with_v0_Head() ([]byte, error) {
b1, err := uc.bufr.ReadByte()
if err != nil {
return nil, err
}
b2, err := uc.bufr.ReadByte()
if err != nil {
return nil, err
}
l := int(int16(b1)<<8 + int16(b2))
bs := utils.GetBytes(l)
n, err := io.ReadFull(uc.bufr, bs)
if err != nil {
return nil, err
}
return bs[:n], nil
}
-345
View File
@@ -1,345 +0,0 @@
package vless
import (
"bufio"
"bytes"
"errors"
"io"
"net"
"github.com/hahahrfool/v2ray_simple/netLayer"
"github.com/hahahrfool/v2ray_simple/utils"
)
//实现 net.Conn, io.ReaderFrom, utils.MultiWriter, netLayer.Splicer
type UserConn struct {
net.Conn
optionalReader io.Reader //在使用了缓存读取握手包头后,就产生了buffer中有剩余数据的可能性,此时就要使用MultiReader
remainFirstBufLen int //记录读取握手包头时读到的buf的长度. 如果我们读超过了这个部分的话,实际上我们就可以不再使用 optionalReader 读取, 而是直接从Conn读取
underlayIsBasic bool
uuid [16]byte
convertedUUIDStr string
version int
isUDP bool
isServerEnd bool //for v0
// udpUnreadPart 不为空,则表示上一次读取没读完整个包(给Read传入的buf太小),须接着读
udpUnreadPart []byte //for udp
bufr *bufio.Reader //for udp
isntFirstPacket bool //for v0
hasAdvancedLayer bool //for v1, 在用ws或grpc时,这个开关保持打开
}
func (uc *UserConn) GetProtocolVersion() int {
return uc.version
}
func (uc *UserConn) GetIdentityStr() string {
if uc.convertedUUIDStr == "" {
uc.convertedUUIDStr = utils.UUIDToStr(uc.uuid)
}
return uc.convertedUUIDStr
}
//当前连接状态是否可以直接写入底层Conn而不经任何改动/包装
func (c *UserConn) canDirectWrite() bool {
return c.version == 1 && !c.isUDP || c.version == 0 && !(c.isServerEnd && !c.isntFirstPacket)
}
func (c *UserConn) EverPossibleToSplice() bool {
if c.isUDP {
return false //udp 在底层就是无法splice的,没办法
}
if netLayer.IsBasicConn(c.Conn) {
return true
}
if s, ok := c.Conn.(netLayer.Splicer); ok {
return s.EverPossibleToSplice()
}
return false
}
func (c *UserConn) CanSplice() (r bool, conn net.Conn) {
if c.isUDP {
return
}
if !c.canDirectWrite() {
return
}
if netLayer.IsBasicConn(c.Conn) {
r = true
conn = c.Conn
} else if s, ok := c.Conn.(netLayer.Splicer); ok {
r, conn = s.CanSplice()
}
return
}
func (c *UserConn) WriteBuffers(buffers [][]byte) (int64, error) {
if c.canDirectWrite() {
//底层连接可以是 ws,或者 tls,或者 基本连接; tls 我们暂不支持 utils.MultiWriter
// 理论上tls是可以支持的,但是要我们魔改tls库
//本作的 ws.Conn 实现了 utils.MultiWriter
if c.underlayIsBasic {
//如果是基本Conn,则不用担心 WriteTo篡改buffers的问题, 因为它会直接调用底层 writev
//nb := net.Buffers(buffers)
//return nb.WriteTo(c.Conn) //发现它还是会篡改??什么鬼
return utils.BuffersWriteTo(buffers, c.Conn)
} else if mr, ok := c.Conn.(utils.MultiWriter); ok {
return mr.WriteBuffers(buffers)
}
}
bigbs, dup := utils.MergeBuffers(buffers)
n, e := c.Write(bigbs)
if dup {
utils.PutPacket(bigbs)
}
return int64(n), e
}
//专门适用于 裸奔splice的情况
func (uc *UserConn) ReadFrom(r io.Reader) (written int64, err error) {
if uc.isUDP {
return netLayer.ClassicCopy(uc, r)
}
return netLayer.TryReadFrom_withSplice(uc, uc.Conn, r, uc.canDirectWrite)
}
//如果是udp,则是多线程不安全的,如果是tcp,则安不安全看底层的链接。
// 这里规定,如果是UDP,则 每Write一遍,都要Write一个 完整的UDP 数据包
func (uc *UserConn) Write(p []byte) (int, error) {
if uc.version == 0 {
originalSupposedWrittenLenth := len(p)
var writeBuf *bytes.Buffer
if uc.isServerEnd && !uc.isntFirstPacket {
uc.isntFirstPacket = true
writeBuf = utils.GetBuf()
//v0 中,服务端的回复的第一个包也是要有数据头的(和客户端的handshake类似,只是第一个包有),第一字节版本,第二字节addon长度(都是0)
writeBuf.WriteByte(0)
writeBuf.WriteByte(0)
}
if !uc.isUDP {
if writeBuf != nil {
writeBuf.Write(p)
_, err := uc.Conn.Write(writeBuf.Bytes()) //“直接return这个的长度” 是错的,因为写入长度只能小于等于len(p)
utils.PutBuf(writeBuf)
if err != nil {
return 0, err
}
return originalSupposedWrittenLenth, nil
} else {
_, err := uc.Conn.Write(p) //“直接return这个的长度” 是错的,因为写入长度只能小于等于len(p)
if err != nil {
return 0, err
}
return originalSupposedWrittenLenth, nil
}
} else {
l := int16(len(p))
if writeBuf == nil {
writeBuf = utils.GetBuf()
}
writeBuf.WriteByte(byte(l >> 8))
writeBuf.WriteByte(byte(l << 8 >> 8))
writeBuf.Write(p)
_, err := uc.Conn.Write(writeBuf.Bytes()) //“直接return这个的长度” 是错的,因为写入长度只能小于等于len(p)
utils.PutBuf(writeBuf)
if err != nil {
return 0, err
}
return originalSupposedWrittenLenth, nil
}
} else {
if uc.isUDP && !uc.hasAdvancedLayer {
// 这里暂时认为包裹它的连接是 tcp或者tls,而不是udp,如果udp的话,就不需要考虑粘包问题了,比如socks5的实现
// 我们目前认为只有tls是最防墙的,而且 魔改tls是有毒的,所以反推过来,这里udp就必须加长度头。
// 目前是这个样子。之后verysimple实现了websocket和grpc后,会添加判断,如果连接是websocket或者grpc连接,则不再加长度头
// tls和tcp都是基于流的,可以分开写两次,不需要buf存在;如果连接是websocket或者grpc的话,直接传输。
l := int16(len(p))
var lenBytes []byte
if l <= 255 {
lenBytes = []byte{0, byte(l)}
}
lenBytes = []byte{byte(l >> 8), byte(l << 8 >> 8)}
_, err := uc.Conn.Write(lenBytes)
if err != nil {
return 0, err
}
return uc.Conn.Write(p)
}
return uc.Conn.Write(p)
}
}
//如果是udp,则是多线程不安全的,如果是tcp,则安不安全看底层的链接。
// 这里规定,如果是UDP,则 每次 Read 得到的都是一个 完整的UDP 数据包,除非p给的太小……
func (uc *UserConn) Read(p []byte) (int, error) {
var from io.Reader = uc.Conn
if uc.optionalReader != nil {
from = uc.optionalReader
}
if uc.version == 0 {
if !uc.isUDP {
if !uc.isServerEnd && !uc.isntFirstPacket {
//先读取响应头
uc.isntFirstPacket = true
bs := utils.GetPacket()
n, e := from.Read(bs)
if e != nil {
utils.PutPacket(bs)
return 0, e
}
if n < 2 {
utils.PutPacket(bs)
return 0, errors.New("vless response head too short")
}
n = copy(p, bs[2:n])
utils.PutPacket(bs)
return n, nil
}
return from.Read(p)
} else {
if uc.bufr == nil {
uc.bufr = bufio.NewReader(from)
}
if len(uc.udpUnreadPart) > 0 {
copiedN := copy(p, uc.udpUnreadPart)
if copiedN < len(uc.udpUnreadPart) {
uc.udpUnreadPart = uc.udpUnreadPart[copiedN:]
} else {
uc.udpUnreadPart = nil
}
return copiedN, nil
}
//v0 先读取vless响应头,再读取udp长度头
if !uc.isServerEnd && !uc.isntFirstPacket {
uc.isntFirstPacket = true
_, err := uc.bufr.ReadByte() //version byte
if err != nil {
return 0, err
}
_, err = uc.bufr.ReadByte() //addon len byte
if err != nil {
return 0, err
}
}
return uc.readudp_withLenthHead(p)
}
} else {
if uc.isUDP && !uc.hasAdvancedLayer {
if len(uc.udpUnreadPart) > 0 {
copiedN := copy(p, uc.udpUnreadPart)
if copiedN < len(uc.udpUnreadPart) {
uc.udpUnreadPart = uc.udpUnreadPart[copiedN:]
} else {
uc.udpUnreadPart = nil
}
return copiedN, nil
}
return uc.readudp_withLenthHead(p)
}
return from.Read(p)
}
}
func (uc *UserConn) readudp_withLenthHead(p []byte) (int, error) {
if uc.bufr == nil {
uc.bufr = bufio.NewReader(uc.Conn)
}
b1, err := uc.bufr.ReadByte()
if err != nil {
return 0, err
}
b2, err := uc.bufr.ReadByte()
if err != nil {
return 0, err
}
l := int(int16(b1)<<8 + int16(b2))
bs := utils.GetBytes(l)
n, err := io.ReadFull(uc.bufr, bs)
if err != nil {
return 0, err
}
/*// 测试代码
if uc.version == 1 {
log.Println("read", bs[:n], string(bs[:n]))
}*/
copiedN := copy(p, bs)
if copiedN < n { //p is short
uc.udpUnreadPart = bs[copiedN:]
}
return copiedN, nil
}
+42 -31
View File
@@ -55,7 +55,7 @@ func testVLess(version int, port string, t *testing.T) {
t.Log("vless server got new conn")
go func() {
defer lc.Close()
wlc, targetAddr, err := server.Handshake(lc)
wlc, _, targetAddr, err := server.Handshake(lc)
if err != nil {
t.Logf("failed in handshake form %v: %v", server.AddrStr(), err)
t.Fail()
@@ -141,6 +141,8 @@ func testVLessUDP(version int, port string, t *testing.T) {
thePort := netLayer.RandPort()
t.Log("fake remote udp server port is ", thePort)
fakeRealUDPServerListener, err := net.ListenUDP("udp4", &net.UDPAddr{
IP: net.IPv4(0, 0, 0, 0),
Port: thePort,
@@ -201,7 +203,7 @@ func testVLessUDP(version int, port string, t *testing.T) {
targetStr_forFakeUDPServer := "127.0.0.1:" + strconv.Itoa(thePort)
targetStruct_forFakeUDPServer := netLayer.Addr{
Name: "127.0.0.1",
IP: net.IPv4(127, 0, 0, 1),
Port: thePort,
Network: "udp",
}
@@ -222,7 +224,7 @@ func testVLessUDP(version int, port string, t *testing.T) {
}
go func() {
defer lc.Close()
wlc, targetAddr, err := fakeServerEndLocalServer.Handshake(lc)
_, wlc, targetAddr, err := fakeServerEndLocalServer.Handshake(lc)
if err != nil {
t.Logf("failed in handshake form %v: %v", fakeServerEndLocalServer.AddrStr(), err)
t.Fail()
@@ -230,13 +232,31 @@ func testVLessUDP(version int, port string, t *testing.T) {
}
remoteAddrStr := targetAddr.String()
t.Log("vless server got new wlc", remoteAddrStr)
if remoteAddrStr != targetStr_forFakeUDPServer || targetAddr.Network != "udp" {
t.Log("remoteAddrStr != targetStr_forFakeUDPServer || targetAddr.IsUDP == false ")
t.Log("remoteAddrStr != targetStr_forFakeUDPServer || targetAddr.IsUDP == false ", remoteAddrStr, targetStr_forFakeUDPServer, targetAddr.Network)
t.Fail()
return
}
//这里的测试是,第一个发来的包必须是 hello,然后传递到目标udp服务器中
//发现既可能读取 firstbuf,也可能读取 wlc,随机发生?
t.Log("vless read from wlc")
bs, raddr, _ := wlc.ReadFrom()
t.Log("vless got wlc", bs)
if !bytes.Equal(bs, hellodata) {
t.Log("!bytes.Equal(hello[:], hellodata)")
t.Fail()
return
}
t.Log("vless got wlc with right hello data")
rc, err := net.Dial("udp", remoteAddrStr)
if err != nil {
t.Logf("failed to connect FakeUDPServer : %v", err)
@@ -244,33 +264,27 @@ func testVLessUDP(version int, port string, t *testing.T) {
return
}
//这里的测试是,第一个发来的包必须是 hello,然后传递到目标udp服务器中
t.Log("vless server dialed remote udp server", remoteAddrStr)
var hello [5]byte
//发现既可能读取 firstbuf,也可能读取 wlc,随机发生?
na, _ := netLayer.NewAddr(remoteAddrStr)
na.Network = "udp"
t.Log("read from wlc")
io.ReadFull(wlc, hello[:])
wrc := &netLayer.UDPMsgConnWrapper{UDPConn: rc.(*net.UDPConn), IsClient: true, FirstAddr: na}
if !bytes.Equal(hello[:], hellodata) {
t.Log("!bytes.Equal(hello[:], hellodata)")
t.Fail()
return
}
_, err = rc.Write(hello[:])
_, err = rc.Write(bs)
if err != nil {
t.Logf("failed to write to FakeUDPServer : %v", err)
t.Fail()
return
}
_, err = io.ReadFull(rc, hello[:])
_, err = io.ReadFull(rc, bs)
if err != nil {
t.Logf("failed io.ReadFull(rc, hello[:]) : %v", err)
t.Fail()
return
}
_, err = wlc.Write(hello[:])
err = wlc.WriteTo(bs, raddr)
if err != nil {
t.Logf("failed wlc.Write(hello[:]) : %v", err)
t.Fail()
@@ -278,8 +292,7 @@ func testVLessUDP(version int, port string, t *testing.T) {
}
// 之后转发所有流量,不再特定限制数据
go io.Copy(rc, wlc)
_, err = io.Copy(wlc, rc)
netLayer.RelayUDP(wlc, wrc)
t.Log("Copy End?!", err)
}()
@@ -292,7 +305,7 @@ func testVLessUDP(version int, port string, t *testing.T) {
t.Log("client Dial success")
wrc, err := fakeClientEndRemoteClient.Handshake(rc, targetStruct_forFakeUDPServer)
wrc, err := fakeClientEndRemoteClient.EstablishUDPChannel(rc, targetStruct_forFakeUDPServer)
if err != nil {
log.Printf("failed in handshake to %v: %v", fakeServerEndLocalServer.AddrStr(), err)
t.FailNow()
@@ -300,7 +313,7 @@ func testVLessUDP(version int, port string, t *testing.T) {
t.Log("client vless handshake success")
_, err = wrc.Write(hellodata)
err = wrc.WriteTo(hellodata, targetStruct_forFakeUDPServer)
if err != nil {
t.Log("failed in write to ", fakeServerEndLocalServer.AddrStr(), err)
t.FailNow()
@@ -308,10 +321,9 @@ func testVLessUDP(version int, port string, t *testing.T) {
t.Log("client write hello success")
var world [5]byte
io.ReadFull(wrc, world[:])
if !bytes.Equal(world[:], replydata) {
t.Log("!bytes.Equal(world[:], replydata) ", world[:], replydata)
bs, _, _ := wrc.ReadFrom()
if !bytes.Equal(bs, replydata) {
t.Log("!bytes.Equal(world[:], replydata) ", bs, replydata)
t.FailNow()
}
t.Log("读到正确reply")
@@ -330,7 +342,7 @@ func testVLessUDP(version int, port string, t *testing.T) {
t.Log("rand generated", len(longbs))
_, err = wrc.Write(longbs)
err = wrc.WriteTo(longbs, targetStruct_forFakeUDPServer)
if err != nil {
t.Log("failed in write long data to ", fakeServerEndLocalServer.AddrStr(), err)
t.FailNow()
@@ -338,17 +350,16 @@ func testVLessUDP(version int, port string, t *testing.T) {
t.Log("data written")
var world [5]byte
n, err := io.ReadFull(wrc, world[:])
bs, _, _ := wrc.ReadFrom()
if err != nil {
t.Log("ReadFull err ", n, err)
t.Log("ReadFull err ", err)
t.FailNow()
}
t.Log("data read complete")
if !bytes.Equal(world[:], replydata) {
t.Log("reply not equal ", string(replydata), string(world[:]))
if !bytes.Equal(bs, replydata) {
t.Log("reply not equal ", string(replydata), string(bs))
t.FailNow()
}
t.Log("compare success")
+1 -1
View File
@@ -73,7 +73,7 @@ func testTls(protocol string, port string, t *testing.T) {
t.Log("server pass tls handshake")
wlc, targetAddr, err := server.Handshake(lc)
wlc, _, targetAddr, err := server.Handshake(lc)
if err != nil {
t.Log("failed in handshake from ", server.AddrStr(), err)
t.Fail()
+1 -1
View File
@@ -83,7 +83,7 @@ func tryTlsLazyRawCopy(useSecureMethod bool, proxy_client proxy.UserClient, prox
// 不过实际上客户端 wrc 是 vless的 UserConn 而UserConn的底层连接才是TLS
// 很明显,目前我们只支持vless所以才可这么操作,以后再说。
wrcVless := wrc.(*vless.UserConn)
wrcVless := wrc.(*vless.UserTCPConn)
tlsConn := wrcVless.Conn.(*tlsLayer.Conn)
rawWRC = tlsConn.GetRaw(tls_lazy_encrypt)
+3
View File
@@ -2,10 +2,13 @@ package utils
import (
"bytes"
"errors"
"fmt"
"strconv"
)
var ErrNotImplemented = errors.New("not implemented")
//没啥特殊的
type NumErr struct {
N int