Files
v2ray_simple/proxy/vless/server.go
2022-03-27 14:09:53 +08:00

407 lines
8.9 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"
"encoding/binary"
"errors"
"fmt"
"io"
"log"
"net"
"net/url"
"sync"
"time"
"unsafe"
"github.com/hahahrfool/v2ray_simple/netLayer"
"github.com/hahahrfool/v2ray_simple/proxy"
"github.com/hahahrfool/v2ray_simple/utils"
)
func init() {
proxy.RegisterServer(Name, &ServerCreator{})
}
//实现 proxy.UserServer 以及 tlsLayer.UserHaser
type Server struct {
proxy.ProxyCommonStruct
userHashes map[[16]byte]*proxy.V2rayUser
userCRUMFURS map[[16]byte]*CRUMFURS
mux4Hashes sync.RWMutex
}
type ServerCreator struct{}
func (_ ServerCreator) NewServer(lc *proxy.ListenConf) (proxy.Server, error) {
uuidStr := lc.Uuid
id, err := proxy.NewV2rayUser(uuidStr)
if err != nil {
return nil, err
}
s := &Server{
userHashes: make(map[[16]byte]*proxy.V2rayUser),
userCRUMFURS: make(map[[16]byte]*CRUMFURS),
}
s.addV2User(id)
return s, nil
}
func (_ ServerCreator) NewServerFromURL(u *url.URL) (proxy.Server, error) {
return NewServer(u)
}
func NewServer(url *url.URL) (proxy.Server, error) {
addr := url.Host
uuidStr := url.User.Username()
id, err := proxy.NewV2rayUser(uuidStr)
if err != nil {
return nil, err
}
s := &Server{
ProxyCommonStruct: proxy.ProxyCommonStruct{Addr: addr},
userHashes: make(map[[16]byte]*proxy.V2rayUser),
userCRUMFURS: make(map[[16]byte]*CRUMFURS),
}
s.ProxyCommonStruct.InitFromUrl(url)
s.addV2User(id)
return s, nil
}
func (s *Server) CanFallback() bool {
return true
}
func (s *Server) addV2User(u *proxy.V2rayUser) {
s.userHashes[*u] = u
}
func (s *Server) AddV2User(u *proxy.V2rayUser) {
s.mux4Hashes.Lock()
s.userHashes[*u] = u
s.mux4Hashes.Unlock()
}
func (s *Server) DelV2User(u *proxy.V2rayUser) {
s.mux4Hashes.RLock()
hasu := s.userHashes[*u]
if hasu == nil {
s.mux4Hashes.RUnlock()
return
}
s.mux4Hashes.Lock()
delete(s.userHashes, *u)
s.mux4Hashes.Unlock()
}
func (s *Server) GetUserByBytes(bs []byte) proxy.User {
if len(bs) < 16 {
return nil
}
thisUUIDBytes := *(*[16]byte)(unsafe.Pointer(&bs[0]))
if s.userHashes[thisUUIDBytes] != nil {
return proxy.V2rayUser(thisUUIDBytes)
}
return nil
}
func (s *Server) HasUserByBytes(bs []byte) bool {
if len(bs) < 16 {
return false
}
if s.userHashes[*(*[16]byte)(unsafe.Pointer(&bs[0]))] != nil {
return true
}
return false
}
func (s *Server) UserBytesLen() int {
return 16
}
func (s *Server) GetUserByStr(str string) proxy.User {
u, e := utils.StrToUUID(str)
if e != nil {
return nil
}
return s.GetUserByBytes(u[:])
}
func (s *Server) Name() string { return Name }
// 返回的bytes.Buffer 是用于 回落使用的,内含了整个读取的数据;不回落时不要使用该Buffer
func (s *Server) Handshake(underlay net.Conn) (io.ReadWriter, *netLayer.Addr, error) {
if err := underlay.SetReadDeadline(time.Now().Add(time.Second * 4)); err != nil {
return nil, nil, err
}
defer underlay.SetReadDeadline(time.Time{})
//这里我们本 不用再创建一个buffer来缓存数据因为tls包本身就是有缓存的所以一点一点读就行tcp本身系统也是有缓存的
// 因此v1.0.3以及更老版本都是直接一段一段read的。
//但是因为需要支持fallback技术所以还是要 进行缓存
readbs := utils.GetBytes(utils.StandardBytesLength)
//var auth [17]byte
wholeReadLen, err := underlay.Read(readbs)
if err != nil {
return nil, nil, utils.NewDataErr("read err", err, wholeReadLen)
}
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
return nil, nil, utils.NewDataErr("fallback, msg too short", nil, wholeReadLen)
}
readbuf := bytes.NewBuffer(readbs[:wholeReadLen])
var returnErr error
goto realPart
errorPart:
//所返回的buffer必须包含所有数据而Buffer不支持回退所以只能重新New
return nil, nil, &utils.ErrFirstBuffer{
Err: returnErr,
First: bytes.NewBuffer(readbs[:wholeReadLen]),
}
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.NewDataErr("Vless invalid version ", nil, version)
goto errorPart
}
idBytes := auth[1:17]
s.mux4Hashes.RLock()
thisUUIDBytes := *(*[16]byte)(unsafe.Pointer(&idBytes[0])) //下面crumfurs也有用到
if user := s.userHashes[thisUUIDBytes]; user != nil {
s.mux4Hashes.RUnlock()
} else {
s.mux4Hashes.RUnlock()
returnErr = errors.New("invalid user")
goto errorPart
}
if version == 0 {
addonLenByte, err := readbuf.ReadByte()
if err != nil {
return nil, nil, err //凡是和的层Read相关的错误一律不再返回Fallback信息因为连接已然不可用
}
if addonLenByte != 0 {
//v2ray的vless中没有对应的任何处理。
//v2ray 的 vless 虽然有一个没用的Flow但是 EncodeBodyAddons里根本没向里写任何数据。所以理论上正常这部分始终应该为0
if utils.CanLogWarn() {
log.Println("potential illegal client", addonLenByte)
}
//读一下然后直接舍弃
/*
tmpBuf := utils.GetBytes(int(addonLenByte))
underlay.Read(tmpBuf)
utils.PutBytes(tmpBuf)
*/
if tmpbs := readbuf.Next(int(addonLenByte)); len(tmpbs) != int(addonLenByte) {
return nil, nil, errors.New("vless short read in addon")
}
}
}
commandByte, err := readbuf.ReadByte()
if err != nil {
returnErr = errors.New("fallback, reason 2")
goto errorPart
}
addr := &netLayer.Addr{}
switch commandByte {
case CmdMux: //实际目前verysimple 暂时还未实现mux先这么写
addr.Port = 0
addr.Name = "v1.mux.cool"
case Cmd_CRUMFURS:
if version != 1 {
returnErr = errors.New("在vless的vesion不为1时使用了 CRUMFURS 命令")
goto errorPart
}
_, err = underlay.Write([]byte{CRUMFURS_ESTABLISHED})
if err != nil {
returnErr = utils.NewErr("write to crumfurs err", err)
goto errorPart
}
addr.Name = CRUMFURS_Established_Str // 使用这个特殊的办法来告诉调用者,预留了 CRUMFURS 信道,防止其关闭上层连接导致 CRUMFURS 信道 被关闭。
theCRUMFURS := &CRUMFURS{
Conn: underlay,
}
s.mux4Hashes.Lock()
s.userCRUMFURS[thisUUIDBytes] = theCRUMFURS
s.mux4Hashes.Unlock()
return nil, addr, nil
case CmdTCP, CmdUDP:
portbs := readbuf.Next(2)
if err != nil || len(portbs) != 2 {
returnErr = errors.New("fallback, reason 3")
goto errorPart
}
addr.Port = int(binary.BigEndian.Uint16(portbs))
if commandByte == CmdUDP {
addr.Network = "udp"
}
var ip_or_domain_bytesLength byte = 0
addrTypeByte, err := readbuf.ReadByte()
if err != nil {
returnErr = errors.New("fallback, reason 4")
goto errorPart
}
switch addrTypeByte {
case netLayer.AtypIP4:
ip_or_domain_bytesLength = net.IPv4len
addr.IP = utils.GetBytes(net.IPv4len)
case netLayer.AtypDomain:
// 解码域名的长度
domainNameLenByte, err := readbuf.ReadByte()
if err != nil {
returnErr = errors.New("fallback, reason 5")
goto errorPart
}
ip_or_domain_bytesLength = domainNameLenByte
case netLayer.AtypIP6:
ip_or_domain_bytesLength = net.IPv6len
addr.IP = utils.GetBytes(net.IPv6len)
default:
returnErr = fmt.Errorf("unknown address type %v", addrTypeByte)
goto errorPart
}
ip_or_domain := utils.GetBytes(int(ip_or_domain_bytesLength))
_, err = readbuf.Read(ip_or_domain)
if err != nil {
return nil, nil, errors.New("fallback, reason 6")
}
if addr.IP != nil {
copy(addr.IP, ip_or_domain)
} else {
addr.Name = string(ip_or_domain)
}
utils.PutBytes(ip_or_domain)
default:
returnErr = errors.New("invalid vless command")
goto errorPart
}
return &UserConn{
Conn: underlay,
optionalReader: io.MultiReader(readbuf, underlay),
remainFirstBufLen: readbuf.Len(),
uuid: thisUUIDBytes,
version: int(version),
isUDP: addr.IsUDP(),
underlayIsBasic: netLayer.IsBasicConn(underlay),
isServerEnd: true,
}, addr, nil
}
func (s *Server) Get_CRUMFURS(id string) *CRUMFURS {
bs, err := utils.StrToUUID(id)
if err != nil {
return nil
}
return s.userCRUMFURS[bs]
}
type CRUMFURS struct {
net.Conn
hasAdvancedLayer bool //在用ws或grpc时这个开关保持打开
}
func (c *CRUMFURS) WriteUDPResponse(a *net.UDPAddr, b []byte) (err error) {
atype := netLayer.AtypIP4
if len(a.IP) > 4 {
atype = netLayer.AtypIP6
}
buf := utils.GetBuf()
buf.WriteByte(atype)
buf.Write(a.IP)
buf.WriteByte(byte(int16(a.Port) >> 8))
buf.WriteByte(byte(int16(a.Port) << 8 >> 8))
if !c.hasAdvancedLayer {
lb := int16(len(b))
buf.WriteByte(byte(lb >> 8))
buf.WriteByte(byte(lb << 8 >> 8))
}
buf.Write(b)
_, err = c.Write(buf.Bytes())
utils.PutBuf(buf)
return
}