Chore: use protobytes replace most of bytes.Buffer
This commit is contained in:
parent
df61a586c9
commit
b7aade5e11
@ -1,7 +1,6 @@
|
|||||||
package outbound
|
package outbound
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"net"
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
@ -9,6 +8,8 @@ import (
|
|||||||
"github.com/Dreamacro/clash/component/resolver"
|
"github.com/Dreamacro/clash/component/resolver"
|
||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
"github.com/Dreamacro/clash/transport/socks5"
|
"github.com/Dreamacro/clash/transport/socks5"
|
||||||
|
|
||||||
|
"github.com/Dreamacro/protobytes"
|
||||||
)
|
)
|
||||||
|
|
||||||
func tcpKeepAlive(c net.Conn) {
|
func tcpKeepAlive(c net.Conn) {
|
||||||
@ -19,24 +20,24 @@ func tcpKeepAlive(c net.Conn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func serializesSocksAddr(metadata *C.Metadata) []byte {
|
func serializesSocksAddr(metadata *C.Metadata) []byte {
|
||||||
var buf [][]byte
|
buf := protobytes.BytesWriter{}
|
||||||
|
|
||||||
addrType := metadata.AddrType()
|
addrType := metadata.AddrType()
|
||||||
aType := uint8(addrType)
|
buf.PutUint8(uint8(addrType))
|
||||||
|
|
||||||
p, _ := strconv.ParseUint(metadata.DstPort, 10, 16)
|
p, _ := strconv.ParseUint(metadata.DstPort, 10, 16)
|
||||||
port := []byte{uint8(p >> 8), uint8(p & 0xff)}
|
|
||||||
switch addrType {
|
switch addrType {
|
||||||
case socks5.AtypDomainName:
|
case socks5.AtypDomainName:
|
||||||
len := uint8(len(metadata.Host))
|
buf.PutUint8(uint8(len(metadata.Host)))
|
||||||
host := []byte(metadata.Host)
|
buf.PutString(metadata.Host)
|
||||||
buf = [][]byte{{aType, len}, host, port}
|
|
||||||
case socks5.AtypIPv4:
|
case socks5.AtypIPv4:
|
||||||
host := metadata.DstIP.To4()
|
buf.PutSlice(metadata.DstIP.To4())
|
||||||
buf = [][]byte{{aType}, host, port}
|
|
||||||
case socks5.AtypIPv6:
|
case socks5.AtypIPv6:
|
||||||
host := metadata.DstIP.To16()
|
buf.PutSlice(metadata.DstIP.To16())
|
||||||
buf = [][]byte{{aType}, host, port}
|
|
||||||
}
|
}
|
||||||
return bytes.Join(buf, nil)
|
|
||||||
|
buf.PutUint16be(uint16(p))
|
||||||
|
return buf.Bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
func resolveUDPAddr(network, address string) (*net.UDPAddr, error) {
|
func resolveUDPAddr(network, address string) (*net.UDPAddr, error) {
|
||||||
|
@ -3,9 +3,14 @@ package pool
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/Dreamacro/protobytes"
|
||||||
)
|
)
|
||||||
|
|
||||||
var bufferPool = sync.Pool{New: func() any { return &bytes.Buffer{} }}
|
var (
|
||||||
|
bufferPool = sync.Pool{New: func() any { return &bytes.Buffer{} }}
|
||||||
|
bytesBufferPool = sync.Pool{New: func() any { return &protobytes.BytesWriter{} }}
|
||||||
|
)
|
||||||
|
|
||||||
func GetBuffer() *bytes.Buffer {
|
func GetBuffer() *bytes.Buffer {
|
||||||
return bufferPool.Get().(*bytes.Buffer)
|
return bufferPool.Get().(*bytes.Buffer)
|
||||||
@ -15,3 +20,12 @@ func PutBuffer(buf *bytes.Buffer) {
|
|||||||
buf.Reset()
|
buf.Reset()
|
||||||
bufferPool.Put(buf)
|
bufferPool.Put(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetBytesBuffer() *protobytes.BytesWriter {
|
||||||
|
return bytesBufferPool.Get().(*protobytes.BytesWriter)
|
||||||
|
}
|
||||||
|
|
||||||
|
func PutBytesBuffer(buf *protobytes.BytesWriter) {
|
||||||
|
buf.Reset()
|
||||||
|
bufferPool.Put(buf)
|
||||||
|
}
|
||||||
|
1
go.mod
1
go.mod
@ -26,6 +26,7 @@ require (
|
|||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/Dreamacro/protobytes v0.0.0-20230324064118-87bc784139cd // indirect
|
||||||
github.com/ajg/form v1.5.1 // indirect
|
github.com/ajg/form v1.5.1 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/google/go-cmp v0.5.9 // indirect
|
github.com/google/go-cmp v0.5.9 // indirect
|
||||||
|
2
go.sum
2
go.sum
@ -1,3 +1,5 @@
|
|||||||
|
github.com/Dreamacro/protobytes v0.0.0-20230324064118-87bc784139cd h1:ygk7IF14j4ep4H2ZyeDe3IEoMZF8JdbX851RVVa/4D8=
|
||||||
|
github.com/Dreamacro/protobytes v0.0.0-20230324064118-87bc784139cd/go.mod h1:QvmEZ/h6KXszPOr2wUFl7Zn3hfFNYdfbXwPVDTyZs6k=
|
||||||
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
|
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
|
||||||
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
|
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package route
|
package route
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -9,6 +8,7 @@ import (
|
|||||||
|
|
||||||
"github.com/Dreamacro/clash/tunnel/statistic"
|
"github.com/Dreamacro/clash/tunnel/statistic"
|
||||||
|
|
||||||
|
"github.com/Dreamacro/protobytes"
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
"github.com/go-chi/render"
|
"github.com/go-chi/render"
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
@ -47,11 +47,11 @@ func getConnections(w http.ResponseWriter, r *http.Request) {
|
|||||||
interval = t
|
interval = t
|
||||||
}
|
}
|
||||||
|
|
||||||
buf := &bytes.Buffer{}
|
buf := protobytes.BytesWriter{}
|
||||||
sendSnapshot := func() error {
|
sendSnapshot := func() error {
|
||||||
buf.Reset()
|
buf.Reset()
|
||||||
snapshot := statistic.DefaultManager.Snapshot()
|
snapshot := statistic.DefaultManager.Snapshot()
|
||||||
if err := json.NewEncoder(buf).Encode(snapshot); err != nil {
|
if err := json.NewEncoder(&buf).Encode(snapshot); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ import (
|
|||||||
"github.com/Dreamacro/clash/log"
|
"github.com/Dreamacro/clash/log"
|
||||||
"github.com/Dreamacro/clash/tunnel/statistic"
|
"github.com/Dreamacro/clash/tunnel/statistic"
|
||||||
|
|
||||||
|
"github.com/Dreamacro/protobytes"
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
"github.com/go-chi/cors"
|
"github.com/go-chi/cors"
|
||||||
"github.com/go-chi/render"
|
"github.com/go-chi/render"
|
||||||
@ -151,12 +152,12 @@ func traffic(w http.ResponseWriter, r *http.Request) {
|
|||||||
tick := time.NewTicker(time.Second)
|
tick := time.NewTicker(time.Second)
|
||||||
defer tick.Stop()
|
defer tick.Stop()
|
||||||
t := statistic.DefaultManager
|
t := statistic.DefaultManager
|
||||||
buf := &bytes.Buffer{}
|
buf := protobytes.BytesWriter{}
|
||||||
var err error
|
var err error
|
||||||
for range tick.C {
|
for range tick.C {
|
||||||
buf.Reset()
|
buf.Reset()
|
||||||
up, down := t.Now()
|
up, down := t.Now()
|
||||||
if err := json.NewEncoder(buf).Encode(Traffic{
|
if err := json.NewEncoder(&buf).Encode(Traffic{
|
||||||
Up: up,
|
Up: up,
|
||||||
Down: down,
|
Down: down,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
@ -126,11 +126,11 @@ func (g *Conn) Write(b []byte) (n int, err error) {
|
|||||||
grpcPayloadLen := uint32(varuintSize + 1 + len(b))
|
grpcPayloadLen := uint32(varuintSize + 1 + len(b))
|
||||||
binary.BigEndian.PutUint32(grpcHeader[1:5], grpcPayloadLen)
|
binary.BigEndian.PutUint32(grpcHeader[1:5], grpcPayloadLen)
|
||||||
|
|
||||||
buf := pool.GetBuffer()
|
buf := pool.GetBytesBuffer()
|
||||||
defer pool.PutBuffer(buf)
|
defer pool.PutBytesBuffer(buf)
|
||||||
buf.Write(grpcHeader)
|
buf.PutSlice(grpcHeader)
|
||||||
buf.Write(protobufHeader[:varuintSize+1])
|
buf.PutSlice(protobufHeader[:varuintSize+1])
|
||||||
buf.Write(b)
|
buf.PutSlice(b)
|
||||||
|
|
||||||
_, err = g.writer.Write(buf.Bytes())
|
_, err = g.writer.Write(buf.Bytes())
|
||||||
if err == io.ErrClosedPipe && g.err != nil {
|
if err == io.ErrClosedPipe && g.err != nil {
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package obfs
|
package obfs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"io"
|
"io"
|
||||||
@ -9,6 +8,8 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/common/pool"
|
"github.com/Dreamacro/clash/common/pool"
|
||||||
|
|
||||||
|
"github.com/Dreamacro/protobytes"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -99,11 +100,11 @@ func (to *TLSObfs) write(b []byte) (int, error) {
|
|||||||
return len(b), err
|
return len(b), err
|
||||||
}
|
}
|
||||||
|
|
||||||
buf := pool.GetBuffer()
|
buf := pool.GetBytesBuffer()
|
||||||
defer pool.PutBuffer(buf)
|
defer pool.PutBytesBuffer(buf)
|
||||||
buf.Write([]byte{0x17, 0x03, 0x03})
|
buf.PutSlice([]byte{0x17, 0x03, 0x03})
|
||||||
binary.Write(buf, binary.BigEndian, uint16(len(b)))
|
buf.PutUint16be(uint16(len(b)))
|
||||||
buf.Write(b)
|
buf.PutSlice(b)
|
||||||
_, err := to.Conn.Write(buf.Bytes())
|
_, err := to.Conn.Write(buf.Bytes())
|
||||||
return len(b), err
|
return len(b), err
|
||||||
}
|
}
|
||||||
@ -119,35 +120,29 @@ func NewTLSObfs(conn net.Conn, server string) net.Conn {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func makeClientHelloMsg(data []byte, server string) []byte {
|
func makeClientHelloMsg(data []byte, server string) []byte {
|
||||||
random := make([]byte, 28)
|
buf := protobytes.BytesWriter{}
|
||||||
sessionID := make([]byte, 32)
|
|
||||||
rand.Read(random)
|
|
||||||
rand.Read(sessionID)
|
|
||||||
|
|
||||||
buf := &bytes.Buffer{}
|
|
||||||
|
|
||||||
// handshake, TLS 1.0 version, length
|
// handshake, TLS 1.0 version, length
|
||||||
buf.WriteByte(22)
|
buf.PutUint8(22)
|
||||||
buf.Write([]byte{0x03, 0x01})
|
buf.PutSlice([]byte{0x03, 0x01})
|
||||||
length := uint16(212 + len(data) + len(server))
|
length := uint16(212 + len(data) + len(server))
|
||||||
buf.WriteByte(byte(length >> 8))
|
buf.PutUint16be(length)
|
||||||
buf.WriteByte(byte(length & 0xff))
|
|
||||||
|
|
||||||
// clientHello, length, TLS 1.2 version
|
// clientHello, length, TLS 1.2 version
|
||||||
buf.WriteByte(1)
|
buf.PutUint8(1)
|
||||||
buf.WriteByte(0)
|
buf.PutUint8(0)
|
||||||
binary.Write(buf, binary.BigEndian, uint16(208+len(data)+len(server)))
|
buf.PutUint16be(uint16(208 + len(data) + len(server)))
|
||||||
buf.Write([]byte{0x03, 0x03})
|
buf.PutSlice([]byte{0x03, 0x03})
|
||||||
|
|
||||||
// random with timestamp, sid len, sid
|
// random with timestamp, sid len, sid
|
||||||
binary.Write(buf, binary.BigEndian, uint32(time.Now().Unix()))
|
buf.PutUint32be(uint32(time.Now().Unix()))
|
||||||
buf.Write(random)
|
buf.ReadFull(rand.Reader, 28)
|
||||||
buf.WriteByte(32)
|
buf.PutUint8(32)
|
||||||
buf.Write(sessionID)
|
buf.ReadFull(rand.Reader, 32)
|
||||||
|
|
||||||
// cipher suites
|
// cipher suites
|
||||||
buf.Write([]byte{0x00, 0x38})
|
buf.PutSlice([]byte{0x00, 0x38})
|
||||||
buf.Write([]byte{
|
buf.PutSlice([]byte{
|
||||||
0xc0, 0x2c, 0xc0, 0x30, 0x00, 0x9f, 0xcc, 0xa9, 0xcc, 0xa8, 0xcc, 0xaa, 0xc0, 0x2b, 0xc0, 0x2f,
|
0xc0, 0x2c, 0xc0, 0x30, 0x00, 0x9f, 0xcc, 0xa9, 0xcc, 0xa8, 0xcc, 0xaa, 0xc0, 0x2b, 0xc0, 0x2f,
|
||||||
0x00, 0x9e, 0xc0, 0x24, 0xc0, 0x28, 0x00, 0x6b, 0xc0, 0x23, 0xc0, 0x27, 0x00, 0x67, 0xc0, 0x0a,
|
0x00, 0x9e, 0xc0, 0x24, 0xc0, 0x28, 0x00, 0x6b, 0xc0, 0x23, 0xc0, 0x27, 0x00, 0x67, 0xc0, 0x0a,
|
||||||
0xc0, 0x14, 0x00, 0x39, 0xc0, 0x09, 0xc0, 0x13, 0x00, 0x33, 0x00, 0x9d, 0x00, 0x9c, 0x00, 0x3d,
|
0xc0, 0x14, 0x00, 0x39, 0xc0, 0x09, 0xc0, 0x13, 0x00, 0x33, 0x00, 0x9d, 0x00, 0x9c, 0x00, 0x3d,
|
||||||
@ -155,42 +150,42 @@ func makeClientHelloMsg(data []byte, server string) []byte {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// compression
|
// compression
|
||||||
buf.Write([]byte{0x01, 0x00})
|
buf.PutSlice([]byte{0x01, 0x00})
|
||||||
|
|
||||||
// extension length
|
// extension length
|
||||||
binary.Write(buf, binary.BigEndian, uint16(79+len(data)+len(server)))
|
buf.PutUint16be(uint16(79 + len(data) + len(server)))
|
||||||
|
|
||||||
// session ticket
|
// session ticket
|
||||||
buf.Write([]byte{0x00, 0x23})
|
buf.PutSlice([]byte{0x00, 0x23})
|
||||||
binary.Write(buf, binary.BigEndian, uint16(len(data)))
|
buf.PutUint16be(uint16(len(data)))
|
||||||
buf.Write(data)
|
buf.PutSlice(data)
|
||||||
|
|
||||||
// server name
|
// server name
|
||||||
buf.Write([]byte{0x00, 0x00})
|
buf.PutSlice([]byte{0x00, 0x00})
|
||||||
binary.Write(buf, binary.BigEndian, uint16(len(server)+5))
|
buf.PutUint16be(uint16(len(server) + 5))
|
||||||
binary.Write(buf, binary.BigEndian, uint16(len(server)+3))
|
buf.PutUint16be(uint16(len(server) + 3))
|
||||||
buf.WriteByte(0)
|
buf.PutUint8(0)
|
||||||
binary.Write(buf, binary.BigEndian, uint16(len(server)))
|
buf.PutUint16be(uint16(len(server)))
|
||||||
buf.Write([]byte(server))
|
buf.PutSlice([]byte(server))
|
||||||
|
|
||||||
// ec_point
|
// ec_point
|
||||||
buf.Write([]byte{0x00, 0x0b, 0x00, 0x04, 0x03, 0x01, 0x00, 0x02})
|
buf.PutSlice([]byte{0x00, 0x0b, 0x00, 0x04, 0x03, 0x01, 0x00, 0x02})
|
||||||
|
|
||||||
// groups
|
// groups
|
||||||
buf.Write([]byte{0x00, 0x0a, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x19, 0x00, 0x18})
|
buf.PutSlice([]byte{0x00, 0x0a, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x19, 0x00, 0x18})
|
||||||
|
|
||||||
// signature
|
// signature
|
||||||
buf.Write([]byte{
|
buf.PutSlice([]byte{
|
||||||
0x00, 0x0d, 0x00, 0x20, 0x00, 0x1e, 0x06, 0x01, 0x06, 0x02, 0x06, 0x03, 0x05,
|
0x00, 0x0d, 0x00, 0x20, 0x00, 0x1e, 0x06, 0x01, 0x06, 0x02, 0x06, 0x03, 0x05,
|
||||||
0x01, 0x05, 0x02, 0x05, 0x03, 0x04, 0x01, 0x04, 0x02, 0x04, 0x03, 0x03, 0x01,
|
0x01, 0x05, 0x02, 0x05, 0x03, 0x04, 0x01, 0x04, 0x02, 0x04, 0x03, 0x03, 0x01,
|
||||||
0x03, 0x02, 0x03, 0x03, 0x02, 0x01, 0x02, 0x02, 0x02, 0x03,
|
0x03, 0x02, 0x03, 0x03, 0x02, 0x01, 0x02, 0x02, 0x02, 0x03,
|
||||||
})
|
})
|
||||||
|
|
||||||
// encrypt then mac
|
// encrypt then mac
|
||||||
buf.Write([]byte{0x00, 0x16, 0x00, 0x00})
|
buf.PutSlice([]byte{0x00, 0x16, 0x00, 0x00})
|
||||||
|
|
||||||
// extended master secret
|
// extended master secret
|
||||||
buf.Write([]byte{0x00, 0x17, 0x00, 0x00})
|
buf.PutSlice([]byte{0x00, 0x17, 0x00, 0x00})
|
||||||
|
|
||||||
return buf.Bytes()
|
return buf.Bytes()
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package snell
|
package snell
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@ -83,22 +82,22 @@ func (s *Snell) Read(b []byte) (int, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func WriteHeader(conn net.Conn, host string, port uint, version int) error {
|
func WriteHeader(conn net.Conn, host string, port uint, version int) error {
|
||||||
buf := pool.GetBuffer()
|
buf := pool.GetBytesBuffer()
|
||||||
defer pool.PutBuffer(buf)
|
defer pool.PutBytesBuffer(buf)
|
||||||
buf.WriteByte(Version)
|
buf.PutUint8(Version)
|
||||||
if version == Version2 {
|
if version == Version2 {
|
||||||
buf.WriteByte(CommandConnectV2)
|
buf.PutUint8(CommandConnectV2)
|
||||||
} else {
|
} else {
|
||||||
buf.WriteByte(CommandConnect)
|
buf.PutUint8(CommandConnect)
|
||||||
}
|
}
|
||||||
|
|
||||||
// clientID length & id
|
// clientID length & id
|
||||||
buf.WriteByte(0)
|
buf.PutUint8(0)
|
||||||
|
|
||||||
// host & port
|
// host & port
|
||||||
buf.WriteByte(uint8(len(host)))
|
buf.PutUint8(uint8(len(host)))
|
||||||
buf.WriteString(host)
|
buf.PutString(host)
|
||||||
binary.Write(buf, binary.BigEndian, uint16(port))
|
buf.PutUint16be(uint16(port))
|
||||||
|
|
||||||
if _, err := conn.Write(buf.Bytes()); err != nil {
|
if _, err := conn.Write(buf.Bytes()); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -146,25 +145,25 @@ func PacketConn(conn net.Conn) net.PacketConn {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func writePacket(w io.Writer, socks5Addr, payload []byte) (int, error) {
|
func writePacket(w io.Writer, socks5Addr, payload []byte) (int, error) {
|
||||||
buf := pool.GetBuffer()
|
buf := pool.GetBytesBuffer()
|
||||||
defer pool.PutBuffer(buf)
|
defer pool.PutBytesBuffer(buf)
|
||||||
|
|
||||||
// compose snell UDP address format (refer: icpz/snell-server-reversed)
|
// compose snell UDP address format (refer: icpz/snell-server-reversed)
|
||||||
// a brand new wheel to replace socks5 address format, well done Yachen
|
// a brand new wheel to replace socks5 address format, well done Yachen
|
||||||
buf.WriteByte(CommondUDPForward)
|
buf.PutUint8(CommondUDPForward)
|
||||||
switch socks5Addr[0] {
|
switch socks5Addr[0] {
|
||||||
case socks5.AtypDomainName:
|
case socks5.AtypDomainName:
|
||||||
hostLen := socks5Addr[1]
|
hostLen := socks5Addr[1]
|
||||||
buf.Write(socks5Addr[1 : 1+1+hostLen+2])
|
buf.PutSlice(socks5Addr[1 : 1+1+hostLen+2])
|
||||||
case socks5.AtypIPv4:
|
case socks5.AtypIPv4:
|
||||||
buf.Write([]byte{0x00, 0x04})
|
buf.PutSlice([]byte{0x00, 0x04})
|
||||||
buf.Write(socks5Addr[1 : 1+net.IPv4len+2])
|
buf.PutSlice(socks5Addr[1 : 1+net.IPv4len+2])
|
||||||
case socks5.AtypIPv6:
|
case socks5.AtypIPv6:
|
||||||
buf.Write([]byte{0x00, 0x06})
|
buf.PutSlice([]byte{0x00, 0x06})
|
||||||
buf.Write(socks5Addr[1 : 1+net.IPv6len+2])
|
buf.PutSlice(socks5Addr[1 : 1+net.IPv6len+2])
|
||||||
}
|
}
|
||||||
|
|
||||||
buf.Write(payload)
|
buf.PutSlice(payload)
|
||||||
_, err := w.Write(buf.Bytes())
|
_, err := w.Write(buf.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
package socks4
|
package socks4
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"encoding/binary"
|
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
|
"net/netip"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/component/auth"
|
"github.com/Dreamacro/clash/component/auth"
|
||||||
|
|
||||||
|
"github.com/Dreamacro/protobytes"
|
||||||
)
|
)
|
||||||
|
|
||||||
const Version = 0x04
|
const Version = 0x04
|
||||||
@ -46,21 +47,17 @@ func ServerHandshake(rw io.ReadWriter, authenticator auth.Authenticator) (addr s
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if req[0] != Version {
|
r := protobytes.BytesReader(req[:])
|
||||||
|
if r.ReadUint8() != Version {
|
||||||
err = errVersionMismatched
|
err = errVersionMismatched
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if command = req[1]; command != CmdConnect {
|
if command = r.ReadUint8(); command != CmdConnect {
|
||||||
err = errCommandNotSupported
|
err = errCommandNotSupported
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
dstIP = req[4:8] // [4]byte
|
|
||||||
dstPort = req[2:4] // [2]byte
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
host string
|
host string
|
||||||
port string
|
port string
|
||||||
@ -71,7 +68,9 @@ func ServerHandshake(rw io.ReadWriter, authenticator auth.Authenticator) (addr s
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if isReservedIP(dstIP) {
|
dstAddr := r.ReadIPv4()
|
||||||
|
dstPort := r.ReadUint16be()
|
||||||
|
if isReservedIP(dstAddr) {
|
||||||
var target []byte
|
var target []byte
|
||||||
if target, err = readUntilNull(rw); err != nil {
|
if target, err = readUntilNull(rw); err != nil {
|
||||||
return
|
return
|
||||||
@ -79,11 +78,11 @@ func ServerHandshake(rw io.ReadWriter, authenticator auth.Authenticator) (addr s
|
|||||||
host = string(target)
|
host = string(target)
|
||||||
}
|
}
|
||||||
|
|
||||||
port = strconv.Itoa(int(binary.BigEndian.Uint16(dstPort)))
|
port = strconv.Itoa(int(dstPort))
|
||||||
if host != "" {
|
if host != "" {
|
||||||
addr = net.JoinHostPort(host, port)
|
addr = net.JoinHostPort(host, port)
|
||||||
} else {
|
} else {
|
||||||
addr = net.JoinHostPort(net.IP(dstIP).String(), port)
|
addr = net.JoinHostPort(dstAddr.String(), port)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SOCKS4 only support USERID auth.
|
// SOCKS4 only support USERID auth.
|
||||||
@ -94,13 +93,13 @@ func ServerHandshake(rw io.ReadWriter, authenticator auth.Authenticator) (addr s
|
|||||||
err = ErrRequestIdentdMismatched
|
err = ErrRequestIdentdMismatched
|
||||||
}
|
}
|
||||||
|
|
||||||
var reply [8]byte
|
reply := protobytes.BytesWriter(make([]byte, 0, 8))
|
||||||
reply[0] = 0x00 // reply code
|
reply.PutUint8(0) // reply code
|
||||||
reply[1] = code // result code
|
reply.PutUint8(code) // result code
|
||||||
copy(reply[4:8], dstIP)
|
reply.PutSlice(dstAddr.AsSlice())
|
||||||
copy(reply[2:4], dstPort)
|
reply.PutUint16be(dstPort)
|
||||||
|
|
||||||
_, wErr := rw.Write(reply[:])
|
_, wErr := rw.Write(reply.Bytes())
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = wErr
|
err = wErr
|
||||||
}
|
}
|
||||||
@ -118,26 +117,24 @@ func ClientHandshake(rw io.ReadWriter, addr string, command Command, userID stri
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
ip := net.ParseIP(host)
|
ip, err := netip.ParseAddr(host)
|
||||||
if ip == nil /* HOST */ {
|
if err != nil { // Host
|
||||||
ip = net.IPv4(0, 0, 0, 1).To4()
|
ip = netip.AddrFrom4([4]byte{0, 0, 0, 1})
|
||||||
} else if ip.To4() == nil /* IPv6 */ {
|
} else if ip.Is6() { // IPv6
|
||||||
return errIPv6NotSupported
|
return errIPv6NotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
dstIP := ip.To4()
|
req := protobytes.BytesWriter{}
|
||||||
|
req.PutUint8(Version)
|
||||||
|
req.PutUint8(command)
|
||||||
|
req.PutUint16be(uint16(port))
|
||||||
|
req.Write(ip.AsSlice())
|
||||||
|
req.PutString(userID)
|
||||||
|
req.PutUint8(0) /* NULL */
|
||||||
|
|
||||||
req := &bytes.Buffer{}
|
if isReservedIP(ip) /* SOCKS4A */ {
|
||||||
req.WriteByte(Version)
|
req.PutString(host)
|
||||||
req.WriteByte(command)
|
req.PutUint8(0) /* NULL */
|
||||||
binary.Write(req, binary.BigEndian, uint16(port))
|
|
||||||
req.Write(dstIP)
|
|
||||||
req.WriteString(userID)
|
|
||||||
req.WriteByte(0) /* NULL */
|
|
||||||
|
|
||||||
if isReservedIP(dstIP) /* SOCKS4A */ {
|
|
||||||
req.WriteString(host)
|
|
||||||
req.WriteByte(0) /* NULL */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err = rw.Write(req.Bytes()); err != nil {
|
if _, err = rw.Write(req.Bytes()); err != nil {
|
||||||
@ -174,17 +171,17 @@ func ClientHandshake(rw io.ReadWriter, addr string, command Command, userID stri
|
|||||||
// Internet Assigned Numbers Authority -- such an address is inadmissible
|
// Internet Assigned Numbers Authority -- such an address is inadmissible
|
||||||
// as a destination IP address and thus should never occur if the client
|
// as a destination IP address and thus should never occur if the client
|
||||||
// can resolve the domain name.)
|
// can resolve the domain name.)
|
||||||
func isReservedIP(ip net.IP) bool {
|
func isReservedIP(ip netip.Addr) bool {
|
||||||
subnet := net.IPNet{
|
subnet := netip.PrefixFrom(
|
||||||
IP: net.IPv4zero,
|
netip.AddrFrom4([4]byte{0, 0, 0, 0}),
|
||||||
Mask: net.IPv4Mask(0xff, 0xff, 0xff, 0x00),
|
24,
|
||||||
}
|
)
|
||||||
|
|
||||||
return !ip.IsUnspecified() && subnet.Contains(ip)
|
return !ip.IsUnspecified() && subnet.Contains(ip)
|
||||||
}
|
}
|
||||||
|
|
||||||
func readUntilNull(r io.Reader) ([]byte, error) {
|
func readUntilNull(r io.Reader) ([]byte, error) {
|
||||||
buf := &bytes.Buffer{}
|
buf := protobytes.BytesWriter{}
|
||||||
var data [1]byte
|
var data [1]byte
|
||||||
|
|
||||||
for {
|
for {
|
||||||
@ -194,6 +191,6 @@ func readUntilNull(r io.Reader) ([]byte, error) {
|
|||||||
if data[0] == 0 {
|
if data[0] == 0 {
|
||||||
return buf.Bytes(), nil
|
return buf.Bytes(), nil
|
||||||
}
|
}
|
||||||
buf.WriteByte(data[0])
|
buf.PutUint8(data[0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,8 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/component/auth"
|
"github.com/Dreamacro/clash/component/auth"
|
||||||
|
|
||||||
|
"github.com/Dreamacro/protobytes"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Error represents a SOCKS error
|
// Error represents a SOCKS error
|
||||||
@ -235,12 +237,12 @@ func ClientHandshake(rw io.ReadWriter, addr Addr, command Command, user *User) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
// password protocol version
|
// password protocol version
|
||||||
authMsg := &bytes.Buffer{}
|
authMsg := protobytes.BytesWriter{}
|
||||||
authMsg.WriteByte(1)
|
authMsg.PutUint8(1)
|
||||||
authMsg.WriteByte(uint8(len(user.Username)))
|
authMsg.PutUint8(uint8(len(user.Username)))
|
||||||
authMsg.WriteString(user.Username)
|
authMsg.PutString(user.Username)
|
||||||
authMsg.WriteByte(uint8(len(user.Password)))
|
authMsg.PutUint8(uint8(len(user.Password)))
|
||||||
authMsg.WriteString(user.Password)
|
authMsg.PutString(user.Password)
|
||||||
|
|
||||||
if _, err := rw.Write(authMsg.Bytes()); err != nil {
|
if _, err := rw.Write(authMsg.Bytes()); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -330,29 +332,26 @@ func SplitAddr(b []byte) Addr {
|
|||||||
|
|
||||||
// ParseAddr parses the address in string s. Returns nil if failed.
|
// ParseAddr parses the address in string s. Returns nil if failed.
|
||||||
func ParseAddr(s string) Addr {
|
func ParseAddr(s string) Addr {
|
||||||
var addr Addr
|
buf := protobytes.BytesWriter{}
|
||||||
host, port, err := net.SplitHostPort(s)
|
host, port, err := net.SplitHostPort(s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if ip := net.ParseIP(host); ip != nil {
|
if ip := net.ParseIP(host); ip != nil {
|
||||||
if ip4 := ip.To4(); ip4 != nil {
|
if ip4 := ip.To4(); ip4 != nil {
|
||||||
addr = make([]byte, 1+net.IPv4len+2)
|
buf.PutUint8(AtypIPv4)
|
||||||
addr[0] = AtypIPv4
|
buf.PutSlice(ip4)
|
||||||
copy(addr[1:], ip4)
|
|
||||||
} else {
|
} else {
|
||||||
addr = make([]byte, 1+net.IPv6len+2)
|
buf.PutUint8(AtypIPv6)
|
||||||
addr[0] = AtypIPv6
|
buf.PutSlice(ip)
|
||||||
copy(addr[1:], ip)
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if len(host) > 255 {
|
if len(host) > 255 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
addr = make([]byte, 1+1+len(host)+2)
|
buf.PutUint8(AtypDomainName)
|
||||||
addr[0] = AtypDomainName
|
buf.PutUint8(byte(len(host)))
|
||||||
addr[1] = byte(len(host))
|
buf.PutString(host)
|
||||||
copy(addr[2:], host)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
portnum, err := strconv.ParseUint(port, 10, 16)
|
portnum, err := strconv.ParseUint(port, 10, 16)
|
||||||
@ -360,9 +359,8 @@ func ParseAddr(s string) Addr {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
addr[len(addr)-2], addr[len(addr)-1] = byte(portnum>>8), byte(portnum)
|
buf.PutUint16be(uint16(portnum))
|
||||||
|
return Addr(buf.Bytes())
|
||||||
return addr
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseAddrToSocksAddr parse a socks addr from net.addr
|
// ParseAddrToSocksAddr parse a socks addr from net.addr
|
||||||
@ -383,20 +381,19 @@ func ParseAddrToSocksAddr(addr net.Addr) Addr {
|
|||||||
return ParseAddr(addr.String())
|
return ParseAddr(addr.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
var parsed Addr
|
var parsed protobytes.BytesWriter
|
||||||
if ip4 := hostip.To4(); ip4.DefaultMask() != nil {
|
if ip4 := hostip.To4(); ip4.DefaultMask() != nil {
|
||||||
parsed = make([]byte, 1+net.IPv4len+2)
|
parsed = make([]byte, 0, 1+net.IPv4len+2)
|
||||||
parsed[0] = AtypIPv4
|
parsed.PutUint8(AtypIPv4)
|
||||||
copy(parsed[1:], ip4)
|
parsed.PutSlice(ip4)
|
||||||
binary.BigEndian.PutUint16(parsed[1+net.IPv4len:], uint16(port))
|
parsed.PutUint16be(uint16(port))
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
parsed = make([]byte, 1+net.IPv6len+2)
|
parsed = make([]byte, 0, 1+net.IPv6len+2)
|
||||||
parsed[0] = AtypIPv6
|
parsed.PutUint8(AtypIPv6)
|
||||||
copy(parsed[1:], hostip)
|
parsed.PutSlice(hostip)
|
||||||
binary.BigEndian.PutUint16(parsed[1+net.IPv6len:], uint16(port))
|
parsed.PutUint16be(uint16(port))
|
||||||
}
|
}
|
||||||
return parsed
|
return Addr(parsed)
|
||||||
}
|
}
|
||||||
|
|
||||||
func AddrFromStdAddrPort(addrPort netip.AddrPort) Addr {
|
func AddrFromStdAddrPort(addrPort netip.AddrPort) Addr {
|
||||||
@ -416,28 +413,31 @@ func AddrFromStdAddrPort(addrPort netip.AddrPort) Addr {
|
|||||||
|
|
||||||
// DecodeUDPPacket split `packet` to addr payload, and this function is mutable with `packet`
|
// DecodeUDPPacket split `packet` to addr payload, and this function is mutable with `packet`
|
||||||
func DecodeUDPPacket(packet []byte) (addr Addr, payload []byte, err error) {
|
func DecodeUDPPacket(packet []byte) (addr Addr, payload []byte, err error) {
|
||||||
if len(packet) < 5 {
|
r := protobytes.BytesReader(packet)
|
||||||
|
|
||||||
|
if r.Len() < 5 {
|
||||||
err = errors.New("insufficient length of packet")
|
err = errors.New("insufficient length of packet")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// packet[0] and packet[1] are reserved
|
// packet[0] and packet[1] are reserved
|
||||||
if !bytes.Equal(packet[:2], []byte{0, 0}) {
|
reserved, r := r.SplitAt(2)
|
||||||
|
if !bytes.Equal(reserved, []byte{0, 0}) {
|
||||||
err = errors.New("reserved fields should be zero")
|
err = errors.New("reserved fields should be zero")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if packet[2] != 0 /* fragments */ {
|
if r.ReadUint8() != 0 /* fragments */ {
|
||||||
err = errors.New("discarding fragmented payload")
|
err = errors.New("discarding fragmented payload")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
addr = SplitAddr(packet[3:])
|
addr = SplitAddr(r)
|
||||||
if addr == nil {
|
if addr == nil {
|
||||||
err = errors.New("failed to read UDP header")
|
err = errors.New("failed to read UDP header")
|
||||||
}
|
}
|
||||||
|
|
||||||
payload = packet[3+len(addr):]
|
_, payload = r.SplitAt(len(addr))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -446,6 +446,10 @@ func EncodeUDPPacket(addr Addr, payload []byte) (packet []byte, err error) {
|
|||||||
err = errors.New("address is invalid")
|
err = errors.New("address is invalid")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
packet = bytes.Join([][]byte{{0, 0, 0}, addr, payload}, []byte{})
|
w := protobytes.BytesWriter{}
|
||||||
|
w.PutSlice([]byte{0, 0, 0})
|
||||||
|
w.PutSlice(addr)
|
||||||
|
w.PutSlice(payload)
|
||||||
|
packet = w.Bytes()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -12,10 +12,11 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/common/pool"
|
|
||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
"github.com/Dreamacro/clash/transport/socks5"
|
"github.com/Dreamacro/clash/transport/socks5"
|
||||||
"github.com/Dreamacro/clash/transport/vmess"
|
"github.com/Dreamacro/clash/transport/vmess"
|
||||||
|
|
||||||
|
"github.com/Dreamacro/protobytes"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -105,15 +106,13 @@ func (t *Trojan) StreamWebsocketConn(conn net.Conn, wsOptions *WebsocketOption)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *Trojan) WriteHeader(w io.Writer, command Command, socks5Addr []byte) error {
|
func (t *Trojan) WriteHeader(w io.Writer, command Command, socks5Addr []byte) error {
|
||||||
buf := pool.GetBuffer()
|
buf := protobytes.BytesWriter{}
|
||||||
defer pool.PutBuffer(buf)
|
buf.PutSlice(t.hexPassword)
|
||||||
|
buf.PutSlice(crlf)
|
||||||
|
|
||||||
buf.Write(t.hexPassword)
|
buf.PutUint8(command)
|
||||||
buf.Write(crlf)
|
buf.PutSlice(socks5Addr)
|
||||||
|
buf.PutSlice(crlf)
|
||||||
buf.WriteByte(command)
|
|
||||||
buf.Write(socks5Addr)
|
|
||||||
buf.Write(crlf)
|
|
||||||
|
|
||||||
_, err := w.Write(buf.Bytes())
|
_, err := w.Write(buf.Bytes())
|
||||||
return err
|
return err
|
||||||
@ -126,14 +125,11 @@ func (t *Trojan) PacketConn(conn net.Conn) net.PacketConn {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func writePacket(w io.Writer, socks5Addr, payload []byte) (int, error) {
|
func writePacket(w io.Writer, socks5Addr, payload []byte) (int, error) {
|
||||||
buf := pool.GetBuffer()
|
buf := protobytes.BytesWriter{}
|
||||||
defer pool.PutBuffer(buf)
|
buf.PutSlice(socks5Addr)
|
||||||
|
buf.PutUint16be(uint16(len(payload)))
|
||||||
buf.Write(socks5Addr)
|
buf.PutSlice(crlf)
|
||||||
binary.Write(buf, binary.BigEndian, uint16(len(payload)))
|
buf.PutSlice(payload)
|
||||||
buf.Write(crlf)
|
|
||||||
buf.Write(payload)
|
|
||||||
|
|
||||||
return w.Write(buf.Bytes())
|
return w.Write(buf.Bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
package obfs
|
package obfs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
|
"net/netip"
|
||||||
|
|
||||||
|
"github.com/Dreamacro/protobytes"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SessionStatus = byte
|
type SessionStatus = byte
|
||||||
@ -33,7 +35,7 @@ type MuxOption struct {
|
|||||||
// Mux is an mux-compatible client for v2ray-plugin, not a complete implementation
|
// Mux is an mux-compatible client for v2ray-plugin, not a complete implementation
|
||||||
type Mux struct {
|
type Mux struct {
|
||||||
net.Conn
|
net.Conn
|
||||||
buf bytes.Buffer
|
buf protobytes.BytesWriter
|
||||||
id [2]byte
|
id [2]byte
|
||||||
length [2]byte
|
length [2]byte
|
||||||
status [2]byte
|
status [2]byte
|
||||||
@ -112,11 +114,11 @@ func (m *Mux) Write(b []byte) (int, error) {
|
|||||||
m.otb = nil
|
m.otb = nil
|
||||||
}
|
}
|
||||||
m.buf.Reset()
|
m.buf.Reset()
|
||||||
binary.Write(&m.buf, binary.BigEndian, uint16(4))
|
m.buf.PutUint16be(4)
|
||||||
m.buf.Write(m.id[:])
|
m.buf.PutSlice(m.id[:])
|
||||||
m.buf.WriteByte(SessionStatusKeep)
|
m.buf.PutUint8(SessionStatusKeep)
|
||||||
m.buf.WriteByte(OptionData)
|
m.buf.PutUint8(OptionData)
|
||||||
binary.Write(&m.buf, binary.BigEndian, uint16(len(b)))
|
m.buf.PutUint16be(uint16(len(b)))
|
||||||
m.buf.Write(b)
|
m.buf.Write(b)
|
||||||
|
|
||||||
return m.Conn.Write(m.buf.Bytes())
|
return m.Conn.Write(m.buf.Bytes())
|
||||||
@ -131,35 +133,35 @@ func (m *Mux) Close() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewMux(conn net.Conn, option MuxOption) *Mux {
|
func NewMux(conn net.Conn, option MuxOption) *Mux {
|
||||||
buf := &bytes.Buffer{}
|
buf := protobytes.BytesWriter{}
|
||||||
|
|
||||||
// fill empty length
|
// fill empty length
|
||||||
buf.Write([]byte{0x0, 0x0})
|
buf.PutSlice([]byte{0x0, 0x0})
|
||||||
buf.Write(option.ID[:])
|
buf.PutSlice(option.ID[:])
|
||||||
buf.WriteByte(SessionStatusNew)
|
buf.PutUint8(SessionStatusNew)
|
||||||
buf.WriteByte(OptionNone)
|
buf.PutUint8(OptionNone)
|
||||||
|
|
||||||
// tcp
|
// tcp
|
||||||
netType := byte(0x1)
|
netType := byte(0x1)
|
||||||
if option.Type == "udp" {
|
if option.Type == "udp" {
|
||||||
netType = byte(0x2)
|
netType = byte(0x2)
|
||||||
}
|
}
|
||||||
buf.WriteByte(netType)
|
buf.PutUint8(netType)
|
||||||
|
|
||||||
// port
|
// port
|
||||||
binary.Write(buf, binary.BigEndian, option.Port)
|
buf.PutUint16be(option.Port)
|
||||||
|
|
||||||
// address
|
// address
|
||||||
ip := net.ParseIP(option.Host)
|
ip, err := netip.ParseAddr(option.Host)
|
||||||
if ip == nil {
|
if err != nil {
|
||||||
buf.WriteByte(0x2)
|
buf.PutUint8(0x2)
|
||||||
buf.WriteString(option.Host)
|
buf.PutString(option.Host)
|
||||||
} else if ipv4 := ip.To4(); ipv4 != nil {
|
} else if ip.Is4() {
|
||||||
buf.WriteByte(0x1)
|
buf.PutUint8(0x1)
|
||||||
buf.Write(ipv4)
|
buf.PutSlice(ip.AsSlice())
|
||||||
} else {
|
} else {
|
||||||
buf.WriteByte(0x3)
|
buf.PutUint8(0x3)
|
||||||
buf.Write(ip.To16())
|
buf.PutSlice(ip.AsSlice())
|
||||||
}
|
}
|
||||||
|
|
||||||
metadata := buf.Bytes()
|
metadata := buf.Bytes()
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package vmess
|
package vmess
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"crypto/aes"
|
"crypto/aes"
|
||||||
"crypto/cipher"
|
"crypto/cipher"
|
||||||
"crypto/hmac"
|
"crypto/hmac"
|
||||||
@ -16,6 +15,7 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/Dreamacro/protobytes"
|
||||||
"golang.org/x/crypto/chacha20poly1305"
|
"golang.org/x/crypto/chacha20poly1305"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -57,48 +57,46 @@ func (vc *Conn) Read(b []byte) (int, error) {
|
|||||||
func (vc *Conn) sendRequest() error {
|
func (vc *Conn) sendRequest() error {
|
||||||
timestamp := time.Now()
|
timestamp := time.Now()
|
||||||
|
|
||||||
mbuf := &bytes.Buffer{}
|
mbuf := protobytes.BytesWriter{}
|
||||||
|
|
||||||
if !vc.isAead {
|
if !vc.isAead {
|
||||||
h := hmac.New(md5.New, vc.id.UUID.Bytes())
|
h := hmac.New(md5.New, vc.id.UUID.Bytes())
|
||||||
binary.Write(h, binary.BigEndian, uint64(timestamp.Unix()))
|
binary.Write(h, binary.BigEndian, uint64(timestamp.Unix()))
|
||||||
mbuf.Write(h.Sum(nil))
|
mbuf.PutSlice(h.Sum(nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
buf := &bytes.Buffer{}
|
buf := protobytes.BytesWriter{}
|
||||||
|
|
||||||
// Ver IV Key V Opt
|
// Ver IV Key V Opt
|
||||||
buf.WriteByte(Version)
|
buf.PutUint8(Version)
|
||||||
buf.Write(vc.reqBodyIV[:])
|
buf.PutSlice(vc.reqBodyIV[:])
|
||||||
buf.Write(vc.reqBodyKey[:])
|
buf.PutSlice(vc.reqBodyKey[:])
|
||||||
buf.WriteByte(vc.respV)
|
buf.PutUint8(vc.respV)
|
||||||
buf.WriteByte(vc.option)
|
buf.PutUint8(vc.option)
|
||||||
|
|
||||||
p := mathRand.Intn(16)
|
p := mathRand.Intn(16)
|
||||||
// P Sec Reserve Cmd
|
// P Sec Reserve Cmd
|
||||||
buf.WriteByte(byte(p<<4) | vc.security)
|
buf.PutUint8(byte(p<<4) | vc.security)
|
||||||
buf.WriteByte(0)
|
buf.PutUint8(0)
|
||||||
if vc.dst.UDP {
|
if vc.dst.UDP {
|
||||||
buf.WriteByte(CommandUDP)
|
buf.PutUint8(CommandUDP)
|
||||||
} else {
|
} else {
|
||||||
buf.WriteByte(CommandTCP)
|
buf.PutUint8(CommandTCP)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Port AddrType Addr
|
// Port AddrType Addr
|
||||||
binary.Write(buf, binary.BigEndian, uint16(vc.dst.Port))
|
buf.PutUint16be(uint16(vc.dst.Port))
|
||||||
buf.WriteByte(vc.dst.AddrType)
|
buf.PutUint8(vc.dst.AddrType)
|
||||||
buf.Write(vc.dst.Addr)
|
buf.PutSlice(vc.dst.Addr)
|
||||||
|
|
||||||
// padding
|
// padding
|
||||||
if p > 0 {
|
if p > 0 {
|
||||||
padding := make([]byte, p)
|
buf.ReadFull(rand.Reader, p)
|
||||||
rand.Read(padding)
|
|
||||||
buf.Write(padding)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fnv1a := fnv.New32a()
|
fnv1a := fnv.New32a()
|
||||||
fnv1a.Write(buf.Bytes())
|
fnv1a.Write(buf.Bytes())
|
||||||
buf.Write(fnv1a.Sum(nil))
|
buf.PutSlice(fnv1a.Sum(nil))
|
||||||
|
|
||||||
if !vc.isAead {
|
if !vc.isAead {
|
||||||
block, err := aes.NewCipher(vc.id.CmdKey)
|
block, err := aes.NewCipher(vc.id.CmdKey)
|
||||||
@ -108,7 +106,7 @@ func (vc *Conn) sendRequest() error {
|
|||||||
|
|
||||||
stream := cipher.NewCFBEncrypter(block, hashTimestamp(timestamp))
|
stream := cipher.NewCFBEncrypter(block, hashTimestamp(timestamp))
|
||||||
stream.XORKeyStream(buf.Bytes(), buf.Bytes())
|
stream.XORKeyStream(buf.Bytes(), buf.Bytes())
|
||||||
mbuf.Write(buf.Bytes())
|
mbuf.PutSlice(buf.Bytes())
|
||||||
_, err = vc.Conn.Write(mbuf.Bytes())
|
_, err = vc.Conn.Write(mbuf.Bytes())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package vmess
|
package vmess
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"crypto/aes"
|
"crypto/aes"
|
||||||
"crypto/cipher"
|
"crypto/cipher"
|
||||||
"crypto/hmac"
|
"crypto/hmac"
|
||||||
@ -11,6 +10,8 @@ import (
|
|||||||
"hash"
|
"hash"
|
||||||
"hash/crc32"
|
"hash/crc32"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/Dreamacro/protobytes"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -49,14 +50,11 @@ func (h *hMacCreator) Create() hash.Hash {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func createAuthID(cmdKey []byte, time int64) [16]byte {
|
func createAuthID(cmdKey []byte, time int64) [16]byte {
|
||||||
buf := &bytes.Buffer{}
|
buf := protobytes.BytesWriter{}
|
||||||
binary.Write(buf, binary.BigEndian, time)
|
buf.PutUint64be(uint64(time))
|
||||||
|
buf.ReadFull(rand.Reader, 4)
|
||||||
random := make([]byte, 4)
|
|
||||||
rand.Read(random)
|
|
||||||
buf.Write(random)
|
|
||||||
zero := crc32.ChecksumIEEE(buf.Bytes())
|
zero := crc32.ChecksumIEEE(buf.Bytes())
|
||||||
binary.Write(buf, binary.BigEndian, zero)
|
buf.PutUint32be(zero)
|
||||||
|
|
||||||
aesBlock, _ := aes.NewCipher(kdf(cmdKey[:], kdfSaltConstAuthIDEncryptionKey)[:16])
|
aesBlock, _ := aes.NewCipher(kdf(cmdKey[:], kdfSaltConstAuthIDEncryptionKey)[:16])
|
||||||
var result [16]byte
|
var result [16]byte
|
||||||
@ -92,12 +90,12 @@ func sealVMessAEADHeader(key [16]byte, data []byte, t time.Time) []byte {
|
|||||||
payloadHeaderAEADEncrypted = payloadHeaderAEAD.Seal(nil, payloadHeaderAEADNonce, data, generatedAuthID[:])
|
payloadHeaderAEADEncrypted = payloadHeaderAEAD.Seal(nil, payloadHeaderAEADNonce, data, generatedAuthID[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
outputBuffer := &bytes.Buffer{}
|
outputBuffer := protobytes.BytesWriter{}
|
||||||
|
|
||||||
outputBuffer.Write(generatedAuthID[:])
|
outputBuffer.PutSlice(generatedAuthID[:])
|
||||||
outputBuffer.Write(payloadHeaderLengthAEADEncrypted)
|
outputBuffer.PutSlice(payloadHeaderLengthAEADEncrypted)
|
||||||
outputBuffer.Write(connectionNonce)
|
outputBuffer.PutSlice(connectionNonce)
|
||||||
outputBuffer.Write(payloadHeaderAEADEncrypted)
|
outputBuffer.PutSlice(payloadHeaderAEADEncrypted)
|
||||||
|
|
||||||
return outputBuffer.Bytes()
|
return outputBuffer.Bytes()
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user