mirror of
https://github.com/e1732a364fed/v2ray_simple.git
synced 2025-12-24 13:27:56 +08:00
修订代码;粘连vmess的请求包以及首包
发现clash的代码似乎没有粘包发送,而是会分包发送,则会造成明显流量特征。 我们粘着发送,就没有 握手包的特征了. 服务端的响应包也同理处理。
This commit is contained in:
@@ -547,3 +547,89 @@ func UDPAddr2AddrPort(ua *net.UDPAddr) netip.AddrPort {
|
||||
a, _ := netip.AddrFromSlice(ua.IP)
|
||||
return netip.AddrPortFrom(a, uint16(ua.Port))
|
||||
}
|
||||
|
||||
//依照 vmess/vless 协议的格式 依次读取 地址的 port, 域名/ip 信息
|
||||
func V2rayGetAddrFrom(buf utils.ByteReader) (addr Addr, err error) {
|
||||
|
||||
pb1, err := buf.ReadByte()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
pb2, err := buf.ReadByte()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
port := uint16(pb1)<<8 + uint16(pb2)
|
||||
if port == 0 {
|
||||
err = utils.ErrInvalidData
|
||||
return
|
||||
}
|
||||
addr.Port = int(port)
|
||||
|
||||
var b1 byte
|
||||
|
||||
b1, err = buf.ReadByte()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
switch b1 {
|
||||
case AtypDomain:
|
||||
var b2 byte
|
||||
b2, err = buf.ReadByte()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if b2 == 0 {
|
||||
err = errors.New("got ATypDomain but domain lenth is marked to be 0")
|
||||
return
|
||||
}
|
||||
|
||||
bs := utils.GetBytes(int(b2))
|
||||
var n int
|
||||
n, err = buf.Read(bs)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if n != int(b2) {
|
||||
err = utils.ErrShortRead
|
||||
return
|
||||
}
|
||||
addr.Name = string(bs[:n])
|
||||
|
||||
case AtypIP4:
|
||||
bs := make([]byte, 4)
|
||||
var n int
|
||||
n, err = buf.Read(bs)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if n != 4 {
|
||||
err = utils.ErrShortRead
|
||||
return
|
||||
}
|
||||
addr.IP = bs
|
||||
case AtypIP6:
|
||||
bs := make([]byte, net.IPv6len)
|
||||
var n int
|
||||
n, err = buf.Read(bs)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if n != 4 {
|
||||
err = utils.ErrShortRead
|
||||
return
|
||||
}
|
||||
addr.IP = bs
|
||||
default:
|
||||
err = utils.ErrInvalidData
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ func (*Server) CanFallback() bool {
|
||||
func (s *Server) Name() string { return Name }
|
||||
|
||||
// 返回的bytes.Buffer 是用于 回落使用的,内含了整个读取的数据;不回落时不要使用该Buffer
|
||||
func (s *Server) Handshake(underlay net.Conn) (result net.Conn, msgConn netLayer.MsgConn, targetAddr netLayer.Addr, returnErr error) {
|
||||
func (s *Server) Handshake(underlay net.Conn) (tcpConn net.Conn, msgConn netLayer.MsgConn, targetAddr netLayer.Addr, returnErr error) {
|
||||
|
||||
if err := proxy.SetCommonReadTimeout(underlay); err != nil {
|
||||
returnErr = err
|
||||
@@ -225,7 +225,7 @@ realPart:
|
||||
|
||||
case CmdTCP, CmdUDP:
|
||||
|
||||
targetAddr, err = GetAddrFrom(readbuf)
|
||||
targetAddr, err = netLayer.V2rayGetAddrFrom(readbuf)
|
||||
if err != nil {
|
||||
|
||||
returnErr = utils.ErrInErr{ErrDesc: "fallback, reason 4", ErrDetail: err}
|
||||
|
||||
@@ -196,7 +196,7 @@ func (u *UDPConn) ReadMsgFrom() ([]byte, netLayer.Addr, error) {
|
||||
bs, err := u.readData_with_len()
|
||||
return bs, u.raddr, err
|
||||
case 1:
|
||||
raddr, err := GetAddrFrom(u.bufr)
|
||||
raddr, err := netLayer.V2rayGetAddrFrom(u.bufr)
|
||||
if err != nil {
|
||||
return nil, raddr, err
|
||||
}
|
||||
@@ -209,7 +209,7 @@ func (u *UDPConn) ReadMsgFrom() ([]byte, netLayer.Addr, error) {
|
||||
return bs, u.raddr, err
|
||||
}
|
||||
} else {
|
||||
raddr, err := GetAddrFrom(u.bufr)
|
||||
raddr, err := netLayer.V2rayGetAddrFrom(u.bufr)
|
||||
if err != nil {
|
||||
return nil, raddr, err
|
||||
}
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
package vless
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -27,92 +25,6 @@ const (
|
||||
CmdMux
|
||||
)
|
||||
|
||||
//依照 vless 协议的格式 依次读取 地址的 port, 域名/ip 信息
|
||||
func GetAddrFrom(buf utils.ByteReader) (addr netLayer.Addr, err error) {
|
||||
|
||||
pb1, err := buf.ReadByte()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
pb2, err := buf.ReadByte()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
port := uint16(pb1)<<8 + uint16(pb2)
|
||||
if port == 0 {
|
||||
err = utils.ErrInvalidData
|
||||
return
|
||||
}
|
||||
addr.Port = int(port)
|
||||
|
||||
var b1 byte
|
||||
|
||||
b1, err = buf.ReadByte()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
switch b1 {
|
||||
case netLayer.AtypDomain:
|
||||
var b2 byte
|
||||
b2, err = buf.ReadByte()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if b2 == 0 {
|
||||
err = errors.New("got ATypDomain but domain lenth is marked to be 0")
|
||||
return
|
||||
}
|
||||
|
||||
bs := utils.GetBytes(int(b2))
|
||||
var n int
|
||||
n, err = buf.Read(bs)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if n != int(b2) {
|
||||
err = utils.ErrShortRead
|
||||
return
|
||||
}
|
||||
addr.Name = string(bs[:n])
|
||||
|
||||
case netLayer.AtypIP4:
|
||||
bs := make([]byte, 4)
|
||||
var n int
|
||||
n, err = buf.Read(bs)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if n != 4 {
|
||||
err = utils.ErrShortRead
|
||||
return
|
||||
}
|
||||
addr.IP = bs
|
||||
case netLayer.AtypIP6:
|
||||
bs := make([]byte, net.IPv6len)
|
||||
var n int
|
||||
n, err = buf.Read(bs)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if n != 4 {
|
||||
err = utils.ErrShortRead
|
||||
return
|
||||
}
|
||||
addr.IP = bs
|
||||
default:
|
||||
err = utils.ErrInvalidData
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
//依照 vless 协议的格式 依次写入 地址的 port, 域名/ip 信息
|
||||
func WriteAddrTo(writeBuf utils.ByteWriter, raddr netLayer.Addr) {
|
||||
writeBuf.WriteByte(byte(raddr.Port >> 8))
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package vmess
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/md5"
|
||||
@@ -157,20 +158,17 @@ func (c *Client) commonHandshake(underlay net.Conn, firstPayload []byte, target
|
||||
|
||||
// Request
|
||||
if target.IsUDP() {
|
||||
err = conn.handshake(CmdUDP)
|
||||
err = conn.handshake(CmdUDP, firstPayload)
|
||||
conn.theTarget = target
|
||||
|
||||
} else {
|
||||
err = conn.handshake(CmdTCP)
|
||||
err = conn.handshake(CmdTCP, firstPayload)
|
||||
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(firstPayload) > 0 {
|
||||
_, err = conn.Write(firstPayload)
|
||||
}
|
||||
|
||||
return conn, err
|
||||
}
|
||||
@@ -197,6 +195,8 @@ type ClientConn struct {
|
||||
|
||||
dataReader io.Reader
|
||||
dataWriter io.Writer
|
||||
|
||||
vmessout []byte
|
||||
}
|
||||
|
||||
func (c *ClientConn) CloseConnWithRaddr(_ netLayer.Addr) error {
|
||||
@@ -228,7 +228,7 @@ func (c *ClientConn) WriteMsgTo(b []byte, _ netLayer.Addr) error {
|
||||
}
|
||||
|
||||
// handshake sends request to server.
|
||||
func (c *ClientConn) handshake(cmd byte) error {
|
||||
func (c *ClientConn) handshake(cmd byte, firstpayload []byte) error {
|
||||
buf := utils.GetBuf()
|
||||
defer utils.PutBuf(buf)
|
||||
|
||||
@@ -273,8 +273,11 @@ func (c *ClientConn) handshake(cmd byte) error {
|
||||
|
||||
var fixedLengthCmdKey [16]byte
|
||||
copy(fixedLengthCmdKey[:], GetKey(c.V2rayUser))
|
||||
vmessout := sealVMessAEADHeader(fixedLengthCmdKey, buf.Bytes(), time.Now())
|
||||
_, err = c.Conn.Write(vmessout)
|
||||
vmessout := sealAEADHeader(fixedLengthCmdKey, buf.Bytes(), time.Now())
|
||||
c.vmessout = vmessout
|
||||
|
||||
_, err = c.Write(firstpayload)
|
||||
|
||||
return err
|
||||
|
||||
}
|
||||
@@ -331,17 +334,37 @@ func (c *ClientConn) Write(b []byte) (n int, err error) {
|
||||
if c.dataWriter != nil {
|
||||
return c.dataWriter.Write(b)
|
||||
}
|
||||
|
||||
c.dataWriter = c.Conn
|
||||
|
||||
switchChan := make(chan struct{})
|
||||
var outBuf *bytes.Buffer
|
||||
if len(b) == 0 {
|
||||
_, err = c.Conn.Write(c.vmessout)
|
||||
c.vmessout = nil
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
} else {
|
||||
outBuf = bytes.NewBuffer(c.vmessout)
|
||||
writer := &utils.WriteSwitcher{
|
||||
Old: outBuf,
|
||||
New: c.Conn,
|
||||
SwitchChan: switchChan,
|
||||
Closer: c.Conn,
|
||||
}
|
||||
|
||||
c.dataWriter = writer
|
||||
}
|
||||
|
||||
if c.opt&OptChunkStream == OptChunkStream {
|
||||
switch c.security {
|
||||
case SecurityNone:
|
||||
c.dataWriter = ChunkedWriter(c.Conn)
|
||||
c.dataWriter = ChunkedWriter(c.dataWriter)
|
||||
|
||||
case SecurityAES128GCM:
|
||||
block, _ := aes.NewCipher(c.reqBodyKey[:])
|
||||
aead, _ := cipher.NewGCM(block)
|
||||
c.dataWriter = AEADWriter(c.Conn, aead, c.reqBodyIV[:])
|
||||
c.dataWriter = AEADWriter(c.dataWriter, aead, c.reqBodyIV[:])
|
||||
|
||||
case SecurityChacha20Poly1305:
|
||||
key := utils.GetBytes(32)
|
||||
@@ -350,12 +373,22 @@ func (c *ClientConn) Write(b []byte) (n int, err error) {
|
||||
t = md5.Sum(key[:16])
|
||||
copy(key[16:], t[:])
|
||||
aead, _ := chacha20poly1305.New(key)
|
||||
c.dataWriter = AEADWriter(c.Conn, aead, c.reqBodyIV[:])
|
||||
c.dataWriter = AEADWriter(c.dataWriter, aead, c.reqBodyIV[:])
|
||||
utils.PutBytes(key)
|
||||
}
|
||||
}
|
||||
|
||||
return c.dataWriter.Write(b)
|
||||
n, err = c.dataWriter.Write(b)
|
||||
if len(b) != 0 {
|
||||
close(switchChan)
|
||||
c.vmessout = nil
|
||||
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, err = c.Conn.Write(outBuf.Bytes())
|
||||
return
|
||||
}
|
||||
|
||||
func (c *ClientConn) Read(b []byte) (n int, err error) {
|
||||
|
||||
@@ -30,6 +30,8 @@ const (
|
||||
kdfSaltConstVMessHeaderPayloadLengthAEADIV = "VMess Header AEAD Nonce_Length"
|
||||
)
|
||||
|
||||
const authid_len = 16
|
||||
|
||||
func kdf(key []byte, path ...string) []byte {
|
||||
hmacCreator := &hMacCreator{value: []byte(kdfSaltConstVMessAEADKDF)}
|
||||
for _, v := range path {
|
||||
@@ -58,7 +60,7 @@ func (h *hMacCreator) Create() hash.Hash {
|
||||
}
|
||||
|
||||
//https://github.com/v2fly/v2fly-github-io/issues/20
|
||||
func createAuthID(cmdKey []byte, time int64) [16]byte {
|
||||
func createAuthID(cmdKey []byte, time int64) (result [authid_len]byte) {
|
||||
buf := &bytes.Buffer{}
|
||||
binary.Write(buf, binary.BigEndian, time)
|
||||
|
||||
@@ -69,7 +71,7 @@ func createAuthID(cmdKey []byte, time int64) [16]byte {
|
||||
binary.Write(buf, binary.BigEndian, zero)
|
||||
|
||||
aesBlock, _ := generateCipher(cmdKey)
|
||||
var result [16]byte
|
||||
|
||||
aesBlock.Encrypt(result[:], buf.Bytes())
|
||||
return result
|
||||
}
|
||||
@@ -78,9 +80,7 @@ func generateCipher(cmdKey []byte) (cipher.Block, error) {
|
||||
return aes.NewCipher(kdf16(cmdKey, kdfSaltConstAuthIDEncryptionKey))
|
||||
}
|
||||
func generateCipherByV2rayUser(u utils.V2rayUser) (cipher.Block, error) {
|
||||
var fixedLengthCmdKey [16]byte
|
||||
copy(fixedLengthCmdKey[:], GetKey(u))
|
||||
return generateCipher(fixedLengthCmdKey[:])
|
||||
return generateCipher(GetKey(u))
|
||||
}
|
||||
|
||||
//为0表示匹配成功
|
||||
@@ -90,10 +90,10 @@ func tryMatchAuthIDByBlock(block cipher.Block, bs []byte) (failReason int) {
|
||||
var rand int32
|
||||
var zero uint32
|
||||
|
||||
if len(bs) < utils.UUID_BytesLen {
|
||||
if len(bs) < authid_len {
|
||||
return 1
|
||||
}
|
||||
data := utils.GetBytes(utils.UUID_BytesLen)
|
||||
data := utils.GetBytes(authid_len)
|
||||
block.Decrypt(data, bs)
|
||||
|
||||
buf := bytes.NewBuffer(data)
|
||||
@@ -114,7 +114,7 @@ func tryMatchAuthIDByBlock(block cipher.Block, bs []byte) (failReason int) {
|
||||
return 0
|
||||
}
|
||||
|
||||
func sealVMessAEADHeader(key [16]byte, data []byte, t time.Time) []byte {
|
||||
func sealAEADHeader(key [16]byte, data []byte, t time.Time) []byte {
|
||||
generatedAuthID := createAuthID(key[:], t.Unix())
|
||||
connectionNonce := make([]byte, 8)
|
||||
rand.Read(connectionNonce)
|
||||
|
||||
@@ -96,7 +96,7 @@ func (s *Server) addUser(u utils.V2rayUser) {
|
||||
s.authPairList = append(s.authPairList, p)
|
||||
}
|
||||
|
||||
func (s *Server) Handshake(underlay net.Conn) (result net.Conn, msgConn netLayer.MsgConn, targetAddr netLayer.Addr, returnErr error) {
|
||||
func (s *Server) Handshake(underlay net.Conn) (tcpConn net.Conn, msgConn netLayer.MsgConn, targetAddr netLayer.Addr, returnErr error) {
|
||||
if err := proxy.SetCommonReadTimeout(underlay); err != nil {
|
||||
returnErr = err
|
||||
return
|
||||
@@ -109,18 +109,18 @@ func (s *Server) Handshake(underlay net.Conn) (result net.Conn, msgConn netLayer
|
||||
if err != nil {
|
||||
returnErr = err
|
||||
return
|
||||
} else if n < utils.UUID_BytesLen {
|
||||
} else if n < authid_len {
|
||||
returnErr = utils.NumErr{E: utils.ErrInvalidData, N: 1}
|
||||
return
|
||||
}
|
||||
user, ok := authUserByAuthPairList(data[:utils.UUID_BytesLen], s.authPairList)
|
||||
user, ok := authUserByAuthPairList(data[:authid_len], s.authPairList)
|
||||
if !ok {
|
||||
returnErr = utils.NumErr{E: utils.ErrInvalidData, N: 2}
|
||||
return
|
||||
}
|
||||
|
||||
cmdKey := GetKey(user)
|
||||
remainBuf := bytes.NewBuffer(data[utils.UUID_BytesLen:n])
|
||||
remainBuf := bytes.NewBuffer(data[authid_len:n])
|
||||
|
||||
aeadData, shouldDrain, bytesRead, errorReason := openAEADHeader(cmdKey, data[:16], remainBuf)
|
||||
if errorReason != nil {
|
||||
@@ -160,7 +160,7 @@ func (s *Server) Handshake(underlay net.Conn) (result net.Conn, msgConn netLayer
|
||||
switch sc.cmd {
|
||||
//我们 不支持vmess 的 mux.cool
|
||||
case CmdTCP, CmdUDP:
|
||||
ad, err := GetAddrFrom(aeadDataBuf)
|
||||
ad, err := netLayer.V2rayGetAddrFrom(aeadDataBuf)
|
||||
if err != nil {
|
||||
returnErr = utils.NumErr{E: utils.ErrInvalidData, N: 3}
|
||||
return
|
||||
@@ -183,14 +183,19 @@ func (s *Server) Handshake(underlay net.Conn) (result net.Conn, msgConn netLayer
|
||||
fnv1a.Write(F)
|
||||
*/
|
||||
|
||||
sc.remainBuf = remainBuf
|
||||
sc.remainReadBuf = remainBuf
|
||||
|
||||
buf := utils.GetBuf()
|
||||
|
||||
sc.aead_encodeRespHeader(buf)
|
||||
sc.Conn.Write(buf.Bytes())
|
||||
sc.firstWriteBuf = buf
|
||||
|
||||
result = sc
|
||||
if sc.cmd == CmdTCP {
|
||||
tcpConn = sc
|
||||
|
||||
} else {
|
||||
msgConn = sc
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
@@ -212,7 +217,7 @@ type ServerConn struct {
|
||||
respBodyIV [16]byte
|
||||
respBodyKey [16]byte
|
||||
|
||||
remainBuf *bytes.Buffer
|
||||
remainReadBuf, firstWriteBuf *bytes.Buffer
|
||||
|
||||
dataReader io.Reader
|
||||
dataWriter io.Writer
|
||||
@@ -261,17 +266,26 @@ func (c *ServerConn) Write(b []byte) (n int, err error) {
|
||||
if c.dataWriter != nil {
|
||||
return c.dataWriter.Write(b)
|
||||
}
|
||||
switchChan := make(chan struct{})
|
||||
|
||||
c.dataWriter = c.Conn
|
||||
//使用 WriteSwitcher 来 粘连 服务器vmess响应 以及第一个数据响应
|
||||
writer := &utils.WriteSwitcher{
|
||||
Old: c.firstWriteBuf,
|
||||
New: c.Conn,
|
||||
SwitchChan: switchChan,
|
||||
Closer: c.Conn,
|
||||
}
|
||||
|
||||
c.dataWriter = writer
|
||||
if c.opt&OptChunkStream == OptChunkStream {
|
||||
switch c.security {
|
||||
case SecurityNone:
|
||||
c.dataWriter = ChunkedWriter(c.Conn)
|
||||
c.dataWriter = ChunkedWriter(writer)
|
||||
|
||||
case SecurityAES128GCM:
|
||||
block, _ := aes.NewCipher(c.respBodyKey[:])
|
||||
aead, _ := cipher.NewGCM(block)
|
||||
c.dataWriter = AEADWriter(c.Conn, aead, c.respBodyIV[:])
|
||||
c.dataWriter = AEADWriter(writer, aead, c.respBodyIV[:])
|
||||
|
||||
case SecurityChacha20Poly1305:
|
||||
key := utils.GetBytes(32)
|
||||
@@ -280,12 +294,22 @@ func (c *ServerConn) Write(b []byte) (n int, err error) {
|
||||
t = md5.Sum(key[:16])
|
||||
copy(key[16:], t[:])
|
||||
aead, _ := chacha20poly1305.New(key)
|
||||
c.dataWriter = AEADWriter(c.Conn, aead, c.respBodyIV[:])
|
||||
c.dataWriter = AEADWriter(writer, aead, c.respBodyIV[:])
|
||||
utils.PutBytes(key)
|
||||
}
|
||||
}
|
||||
|
||||
return c.dataWriter.Write(b)
|
||||
n, err = c.dataWriter.Write(b)
|
||||
|
||||
close(switchChan)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, err = c.Conn.Write(c.firstWriteBuf.Bytes())
|
||||
utils.PutBuf(c.firstWriteBuf)
|
||||
c.firstWriteBuf = nil
|
||||
return
|
||||
}
|
||||
|
||||
func (c *ServerConn) Read(b []byte) (n int, err error) {
|
||||
@@ -294,8 +318,8 @@ func (c *ServerConn) Read(b []byte) (n int, err error) {
|
||||
return c.dataReader.Read(b)
|
||||
}
|
||||
var curReader io.Reader
|
||||
if c.remainBuf != nil && c.remainBuf.Len() > 0 {
|
||||
curReader = io.MultiReader(c.remainBuf, c.Conn)
|
||||
if c.remainReadBuf != nil && c.remainReadBuf.Len() > 0 {
|
||||
curReader = io.MultiReader(c.remainReadBuf, c.Conn)
|
||||
} else {
|
||||
curReader = c.Conn
|
||||
|
||||
@@ -327,3 +351,28 @@ func (c *ServerConn) Read(b []byte) (n int, err error) {
|
||||
return c.dataReader.Read(b)
|
||||
|
||||
}
|
||||
|
||||
func (c *ServerConn) ReadMsgFrom() (bs []byte, target netLayer.Addr, err error) {
|
||||
bs = utils.GetPacket()
|
||||
var n int
|
||||
n, err = c.Read(bs)
|
||||
if err != nil {
|
||||
utils.PutPacket(bs)
|
||||
bs = nil
|
||||
return
|
||||
}
|
||||
bs = bs[:n]
|
||||
target = c.theTarget
|
||||
return
|
||||
}
|
||||
|
||||
func (c *ServerConn) WriteMsgTo(b []byte, _ netLayer.Addr) error {
|
||||
_, e := c.Write(b)
|
||||
return e
|
||||
}
|
||||
func (c *ServerConn) CloseConnWithRaddr(_ netLayer.Addr) error {
|
||||
return c.Conn.Close()
|
||||
}
|
||||
func (c *ServerConn) Fullcone() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -9,16 +9,25 @@ from github.com/Dreamacro/clash/tree/master/transport/vmess/
|
||||
aead:
|
||||
|
||||
https://github.com/v2fly/v2fly-github-io/issues/20
|
||||
|
||||
|
||||
Implementation Details
|
||||
|
||||
本作在chash 的 vmess 客户端的 基础上,反推出了 对称的 vmess 服务端,不过为了方便,也使用了 v2ray的 OpenVMessAEADHeader 函数.
|
||||
|
||||
实际上 clash的 sealAEADHeader 的代码也是 和v2ray的响应代码十分接近的。这倒不重要,因为文档给出的算法是固定的,所以实现代码都是一样的。二者区别主要是读写代码的结构。
|
||||
|
||||
vmess 协议是一个很老旧的协议,有很多向前兼容的代码,很多地方都已经废弃了,我们这里只支持最新的aead.
|
||||
|
||||
我们所实现的vmess 服务端 力求简单、最新,不求兼容所有老旧客户端。
|
||||
|
||||
*/
|
||||
package vmess
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"net"
|
||||
|
||||
"github.com/e1732a364fed/v2ray_simple/netLayer"
|
||||
"github.com/e1732a364fed/v2ray_simple/utils"
|
||||
)
|
||||
|
||||
@@ -68,89 +77,3 @@ func TimestampHash(unixSec int64) []byte {
|
||||
md5hash.Write(ts)
|
||||
return md5hash.Sum(nil)
|
||||
}
|
||||
|
||||
//依照 vmess 协议的格式 依次读取 地址的 port, 域名/ip 信息(与vless相同)
|
||||
func GetAddrFrom(buf utils.ByteReader) (addr netLayer.Addr, err error) {
|
||||
|
||||
pb1, err := buf.ReadByte()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
pb2, err := buf.ReadByte()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
port := uint16(pb1)<<8 + uint16(pb2)
|
||||
if port == 0 {
|
||||
err = utils.ErrInvalidData
|
||||
return
|
||||
}
|
||||
addr.Port = int(port)
|
||||
|
||||
var b1 byte
|
||||
|
||||
b1, err = buf.ReadByte()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
switch b1 {
|
||||
case netLayer.AtypDomain:
|
||||
var b2 byte
|
||||
b2, err = buf.ReadByte()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if b2 == 0 {
|
||||
err = errors.New("got ATypDomain but domain lenth is marked to be 0")
|
||||
return
|
||||
}
|
||||
|
||||
bs := utils.GetBytes(int(b2))
|
||||
var n int
|
||||
n, err = buf.Read(bs)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if n != int(b2) {
|
||||
err = utils.ErrShortRead
|
||||
return
|
||||
}
|
||||
addr.Name = string(bs[:n])
|
||||
|
||||
case netLayer.AtypIP4:
|
||||
bs := make([]byte, 4)
|
||||
var n int
|
||||
n, err = buf.Read(bs)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if n != 4 {
|
||||
err = utils.ErrShortRead
|
||||
return
|
||||
}
|
||||
addr.IP = bs
|
||||
case netLayer.AtypIP6:
|
||||
bs := make([]byte, net.IPv6len)
|
||||
var n int
|
||||
n, err = buf.Read(bs)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if n != 4 {
|
||||
err = utils.ErrShortRead
|
||||
return
|
||||
}
|
||||
addr.IP = bs
|
||||
default:
|
||||
err = utils.ErrInvalidData
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
25
utils/io.go
25
utils/io.go
@@ -5,6 +5,13 @@ import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
type WriteWrapper interface {
|
||||
io.Writer
|
||||
|
||||
GetRawWriter() io.Writer
|
||||
SetRawWriter(io.Writer)
|
||||
}
|
||||
|
||||
// bufio.Reader and bytes.Buffer implemented ByteReader
|
||||
type ByteReader interface {
|
||||
ReadByte() (byte, error)
|
||||
@@ -146,17 +153,25 @@ type WriteSwitcher struct {
|
||||
Old, New io.Writer //non-nil
|
||||
SwitchChan chan struct{} //non-nil
|
||||
io.Closer
|
||||
|
||||
switched bool
|
||||
}
|
||||
|
||||
func (d *WriteSwitcher) Write(p []byte) (int, error) {
|
||||
|
||||
select {
|
||||
case <-d.SwitchChan:
|
||||
return d.New.Write(p)
|
||||
if !d.switched {
|
||||
select {
|
||||
case <-d.SwitchChan:
|
||||
d.switched = true
|
||||
return d.New.Write(p)
|
||||
|
||||
default:
|
||||
return d.Old.Write(p)
|
||||
default:
|
||||
return d.Old.Write(p)
|
||||
}
|
||||
} else {
|
||||
return d.New.Write(p)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (d *WriteSwitcher) Close() error {
|
||||
|
||||
Reference in New Issue
Block a user