Files
v2ray_simple/proxy/vless/server.go
e1732a364fed a704f77eb4 重构readv代码,将MultiReader分为 BuffersReader和Readver两种
Readver是因为可以暴露出底层连接所以能加速;而BuffersReader是
因为协议对于多buf的读取支持良好所以可以加速,逻辑完全不同
2022-12-26 07:50:44 +08:00

314 lines
7.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 (
"bytes"
"errors"
"io"
"net"
"net/url"
"unsafe"
"github.com/e1732a364fed/v2ray_simple/netLayer"
"github.com/e1732a364fed/v2ray_simple/proxy"
"github.com/e1732a364fed/v2ray_simple/utils"
"go.uber.org/zap"
)
func init() {
proxy.RegisterServer(Name, &ServerCreator{})
}
type ServerCreator struct{ proxy.CreatorCommonStruct }
// 如果 lc.Version==0, 则只支持 v0.
func (ServerCreator) NewServer(lc *proxy.ListenConf) (proxy.Server, error) {
uuidStr := lc.Uuid
onlyV0 := lc.Version == 0
var s *Server
if uuidStr != "" {
var err error
s, err = newServerWithConf(uuidStr, onlyV0)
if err != nil {
return nil, err
}
} else {
s = newServer(onlyV0)
}
if len(lc.Users) > 0 {
us := utils.InitV2rayUsers(lc.Users)
s.LoadUsers(us)
}
return s, nil
}
// 如果 v=0, 则只支持 v0.
func (ServerCreator) URLToListenConf(url *url.URL, lc *proxy.ListenConf, format int) (*proxy.ListenConf, error) {
switch format {
case proxy.UrlStandardFormat:
if lc == nil {
lc = &proxy.ListenConf{}
uuidStr := url.User.Username()
lc.Uuid = uuidStr
}
return lc, nil
default:
return lc, utils.ErrUnImplemented
}
}
func newServer(onlyV0 bool) *Server {
s := &Server{
MultiUserMap: utils.NewMultiUserMap(),
onlyV0: onlyV0,
}
s.SetUseUUIDStr_asKey()
return s
}
func newServerWithConf(uuid string, onlyV0 bool) (*Server, error) {
v2rayUser, err := utils.NewV2rayUser(uuid)
if err != nil {
return nil, err
}
s := newServer(onlyV0)
s.AddUser(v2rayUser)
return s, nil
}
// Server 同时支持vless v0 和 v1
// 实现 proxy.UserServer 以及 tlsLayer.UserHaser
type Server struct {
proxy.Base
*utils.MultiUserMap
onlyV0 bool
}
func (s *Server) HasInnerMux() (int, string) {
if s.onlyV0 {
return 0, ""
} else {
return 1, "simplesocks"
}
}
func (*Server) CanFallback() bool {
return true
}
func (s *Server) Name() string { return Name }
// 返回的bytes.Buffer 是用于 回落使用的,内含了整个读取的数据;不回落时不要使用该Buffer
func (s *Server) Handshake(underlay net.Conn) (tcpConn net.Conn, msgConn netLayer.MsgConn, targetAddr netLayer.Addr, returnErr error) {
if err := netLayer.SetCommonReadTimeout(underlay); err != nil {
returnErr = err
return
}
defer netLayer.PersistConn(underlay)
//这里我们本 不用再创建一个buffer来缓存数据因为tls包本身就是有缓存的所以一点一点读就行tcp本身系统也是有缓存的
// 因此v1.0.3以及更老版本都是直接一段一段read的。
//但是因为需要支持fallback技术所以还是要 进行缓存
readbs := utils.GetBytes(utils.MTU)
wholeReadLen, err := underlay.Read(readbs)
if err != nil {
returnErr = utils.ErrInErr{ErrDesc: "Vless read err", ErrDetail: err, Data: wholeReadLen}
return
}
if wholeReadLen < 17 {
//根据下面回答HTTP的最小长度恰好是16字节但是是0.9版本。1.0是18字节1.1还要更长。总之我们可以直接不返回fallback地址
//https://stackoverflow.com/questions/25047905/http-request-minimum-size-in-bytes/25065089
returnErr = utils.ErrInErr{ErrDesc: "Vless msg too short", Data: wholeReadLen}
return
}
readbuf := bytes.NewBuffer(readbs[:wholeReadLen])
var use_udp_multi bool
goto realPart
errorPart:
//所返回的buffer必须包含所有数据而Buffer不支持回退所以只能重新New
returnErr = &utils.ErrBuffer{
Err: returnErr,
Buf: bytes.NewBuffer(readbs[:wholeReadLen]),
}
return
realPart:
//这部分过程可以参照 v2ray的 proxy/vless/encoding/encoding.go DecodeRequestHeader 方法
//see https://github.com/v2fly/v2ray-core/blob/master/proxy/vless/inbound/inbound.go
auth := readbuf.Next(17)
version := auth[0]
if version > 1 {
returnErr = utils.ErrInErr{ErrDesc: "Vless Invalid version ", ErrDetail: utils.ErrInvalidData, Data: version}
goto errorPart
}
idBytes := auth[1:17]
thisUUIDBytes := *(*[16]byte)(unsafe.Pointer(&idBytes[0]))
if s.AuthUserByBytes(thisUUIDBytes[:]) != nil {
} else {
returnErr = utils.ErrInErr{ErrDesc: "Vless Invalid user ", ErrDetail: utils.ErrInvalidData, Data: utils.UUIDToStr(thisUUIDBytes[:])}
goto errorPart
}
if version == 0 {
addonLenByte, err := readbuf.ReadByte()
if err != nil {
returnErr = err
return
}
if addonLenByte != 0 {
//v2ray的vless中没有对应的任何处理。
//v2ray 的 vless 虽然有一个没用的Flow但是 EncodeBodyAddons里根本没向里写任何数据。所以理论上正常这部分始终应该为0
if ce := utils.CanLogWarn("Vless potential illegal client"); ce != nil {
ce.Write(zap.Uint8("addonLenByte", addonLenByte))
}
if tmpbs := readbuf.Next(int(addonLenByte)); len(tmpbs) != int(addonLenByte) {
returnErr = errors.New("vless short read in addon")
return
}
}
} else {
addonFlagByte, err := readbuf.ReadByte()
if err != nil {
returnErr = err
return
}
switch addonFlagByte {
case addon_udp_multi_flag:
use_udp_multi = true
}
}
commandByte, err := readbuf.ReadByte()
if err != nil {
returnErr = utils.ErrInErr{ErrDesc: "Vless read commandByte failed ", ErrDetail: err}
goto errorPart
}
var isudp, ismux bool
switch commandByte {
case CmdMux:
//verysimple 没有实现 mux.cool, 因为 v2ray的 mux.cool 有很多问题, 本作不会支持v0 的mux
if version == 0 {
returnErr = errors.New("mux for vless v0 is not supported by verysimple")
return // 这个就不回落了.
} else {
//v1我们将采用 smux+simplesocks 的方式
ismux = true
}
fallthrough
case CmdTCP, CmdUDP:
targetAddr, err = netLayer.V2rayGetAddrFrom(readbuf)
if err != nil {
returnErr = utils.ErrInErr{ErrDesc: "Vless parse addr failed", ErrDetail: err}
goto errorPart
}
if commandByte == CmdUDP {
targetAddr.Network = "udp"
isudp = true
}
default:
returnErr = utils.ErrInErr{ErrDesc: "Vless Invalid command ", ErrDetail: utils.ErrInvalidData, Data: commandByte}
goto errorPart
}
if ismux {
mm := &proxy.MuxMarkerConn{
ReadWrapper: netLayer.ReadWrapper{
Conn: underlay,
},
}
if l := readbuf.Len(); l > 0 {
mm.RemainFirstBufLen = l
mm.OptionalReader = io.MultiReader(readbuf, underlay)
}
return mm, nil, targetAddr, nil
}
if isudp {
return nil, &UDPConn{
Conn: underlay,
V2rayUser: thisUUIDBytes,
version: version,
optionalReader: io.MultiReader(readbuf, underlay),
raddr: targetAddr,
remainFirstBufLen: readbuf.Len(),
udp_multi: use_udp_multi,
fullcone: s.IsFullcone,
}, targetAddr, nil
} else {
uc := &UserTCPConn{
Conn: underlay,
V2rayUser: thisUUIDBytes,
version: version,
optionalReader: io.MultiReader(readbuf, underlay),
remainFirstBufLen: readbuf.Len(),
underlayIsBasic: netLayer.IsBasicConn(underlay),
isServerEnd: true,
}
if r, rr := netLayer.IsConnGoodForReadv(underlay); r != 0 {
//一般而言,裸奔时, readvType == -1
// 使用普通tls时 readvType ==0
//使用 shadowTls 时, readvType == 1
uc.rr = rr
uc.readvType = r
if r == 1 {
uc.br = underlay.(utils.BuffersReader)
}
}
return uc, nil, targetAddr, nil
}
}