Files
v2ray_simple/proxy/vless/tcpconn.go
hahahrfool 447bd8749a 重构所有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 还未修改。
2022-04-08 13:49:56 +08:00

249 lines
6.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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