mirror of
https://github.com/v2fly/v2ray-core.git
synced 2024-12-22 18:17:52 -05:00
8433420654
also fix a domain length check bug
322 lines
7.3 KiB
Go
322 lines
7.3 KiB
Go
package trojan
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"io"
|
|
gonet "net"
|
|
|
|
"github.com/v2fly/v2ray-core/v5/common/buf"
|
|
"github.com/v2fly/v2ray-core/v5/common/net"
|
|
"github.com/v2fly/v2ray-core/v5/common/protocol"
|
|
)
|
|
|
|
var (
|
|
crlf = []byte{'\r', '\n'}
|
|
|
|
addrParser = protocol.NewAddressParser(
|
|
protocol.AddressFamilyByte(0x01, net.AddressFamilyIPv4),
|
|
protocol.AddressFamilyByte(0x04, net.AddressFamilyIPv6),
|
|
protocol.AddressFamilyByte(0x03, net.AddressFamilyDomain),
|
|
)
|
|
)
|
|
|
|
const (
|
|
commandTCP byte = 1
|
|
commandUDP byte = 3
|
|
)
|
|
|
|
// ConnWriter is TCP Connection Writer Wrapper for trojan protocol
|
|
type ConnWriter struct {
|
|
io.Writer
|
|
Target net.Destination
|
|
Account *MemoryAccount
|
|
headerSent bool
|
|
}
|
|
|
|
// Write implements io.Writer
|
|
func (c *ConnWriter) Write(p []byte) (n int, err error) {
|
|
if !c.headerSent {
|
|
if err := c.writeHeader(); err != nil {
|
|
return 0, newError("failed to write request header").Base(err)
|
|
}
|
|
}
|
|
|
|
return c.Writer.Write(p)
|
|
}
|
|
|
|
// WriteMultiBuffer implements buf.Writer
|
|
func (c *ConnWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
|
defer buf.ReleaseMulti(mb)
|
|
|
|
for _, b := range mb {
|
|
if !b.IsEmpty() {
|
|
if _, err := c.Write(b.Bytes()); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c *ConnWriter) WriteHeader() error {
|
|
if !c.headerSent {
|
|
if err := c.writeHeader(); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *ConnWriter) writeHeader() error {
|
|
buffer := buf.StackNew()
|
|
defer buffer.Release()
|
|
|
|
command := commandTCP
|
|
if c.Target.Network == net.Network_UDP {
|
|
command = commandUDP
|
|
}
|
|
|
|
if _, err := buffer.Write(c.Account.Key); err != nil {
|
|
return err
|
|
}
|
|
if _, err := buffer.Write(crlf); err != nil {
|
|
return err
|
|
}
|
|
if err := buffer.WriteByte(command); err != nil {
|
|
return err
|
|
}
|
|
if err := addrParser.WriteAddressPort(&buffer, c.Target.Address, c.Target.Port); err != nil {
|
|
return err
|
|
}
|
|
if _, err := buffer.Write(crlf); err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err := c.Writer.Write(buffer.Bytes())
|
|
if err == nil {
|
|
c.headerSent = true
|
|
}
|
|
|
|
return err
|
|
}
|
|
|
|
// PacketWriter UDP Connection Writer Wrapper for trojan protocol
|
|
type PacketWriter struct {
|
|
io.Writer
|
|
Target net.Destination
|
|
}
|
|
|
|
// WriteMultiBuffer implements buf.Writer
|
|
func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
|
for _, b := range mb {
|
|
if b.IsEmpty() {
|
|
continue
|
|
}
|
|
if _, err := w.writePacket(b.Bytes(), w.Target); err != nil {
|
|
buf.ReleaseMulti(mb)
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// WriteMultiBufferWithMetadata writes udp packet with destination specified
|
|
func (w *PacketWriter) WriteMultiBufferWithMetadata(mb buf.MultiBuffer, dest net.Destination) error {
|
|
for _, b := range mb {
|
|
if b.IsEmpty() {
|
|
continue
|
|
}
|
|
if _, err := w.writePacket(b.Bytes(), dest); err != nil {
|
|
buf.ReleaseMulti(mb)
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (w *PacketWriter) WriteTo(payload []byte, addr gonet.Addr) (int, error) {
|
|
dest := net.DestinationFromAddr(addr)
|
|
|
|
return w.writePacket(payload, dest)
|
|
}
|
|
|
|
func (w *PacketWriter) writePacket(payload []byte, dest net.Destination) (int, error) { // nolint: unparam
|
|
var addrPortLen int32
|
|
switch dest.Address.Family() {
|
|
case net.AddressFamilyDomain:
|
|
if protocol.IsDomainTooLong(dest.Address.Domain()) {
|
|
return 0, newError("Super long domain is not supported: ", dest.Address.Domain())
|
|
}
|
|
addrPortLen = 1 + 1 + int32(len(dest.Address.Domain())) + 2
|
|
case net.AddressFamilyIPv4:
|
|
addrPortLen = 1 + 4 + 2
|
|
case net.AddressFamilyIPv6:
|
|
addrPortLen = 1 + 16 + 2
|
|
default:
|
|
panic("Unknown address type.")
|
|
}
|
|
|
|
length := len(payload)
|
|
lengthBuf := [2]byte{}
|
|
binary.BigEndian.PutUint16(lengthBuf[:], uint16(length))
|
|
|
|
buffer := buf.NewWithSize(addrPortLen + 2 + 2 + int32(length))
|
|
defer buffer.Release()
|
|
|
|
if err := addrParser.WriteAddressPort(buffer, dest.Address, dest.Port); err != nil {
|
|
return 0, err
|
|
}
|
|
if _, err := buffer.Write(lengthBuf[:]); err != nil {
|
|
return 0, err
|
|
}
|
|
if _, err := buffer.Write(crlf); err != nil {
|
|
return 0, err
|
|
}
|
|
if _, err := buffer.Write(payload); err != nil {
|
|
return 0, err
|
|
}
|
|
_, err := w.Write(buffer.Bytes())
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
return length, nil
|
|
}
|
|
|
|
// ConnReader is TCP Connection Reader Wrapper for trojan protocol
|
|
type ConnReader struct {
|
|
io.Reader
|
|
Target net.Destination
|
|
headerParsed bool
|
|
}
|
|
|
|
// ParseHeader parses the trojan protocol header
|
|
func (c *ConnReader) ParseHeader() error {
|
|
var crlf [2]byte
|
|
var command [1]byte
|
|
var hash [56]byte
|
|
if _, err := io.ReadFull(c.Reader, hash[:]); err != nil {
|
|
return newError("failed to read user hash").Base(err)
|
|
}
|
|
|
|
if _, err := io.ReadFull(c.Reader, crlf[:]); err != nil {
|
|
return newError("failed to read crlf").Base(err)
|
|
}
|
|
|
|
if _, err := io.ReadFull(c.Reader, command[:]); err != nil {
|
|
return newError("failed to read command").Base(err)
|
|
}
|
|
|
|
network := net.Network_TCP
|
|
if command[0] == commandUDP {
|
|
network = net.Network_UDP
|
|
}
|
|
|
|
addr, port, err := addrParser.ReadAddressPort(nil, c.Reader)
|
|
if err != nil {
|
|
return newError("failed to read address and port").Base(err)
|
|
}
|
|
c.Target = net.Destination{Network: network, Address: addr, Port: port}
|
|
|
|
if _, err := io.ReadFull(c.Reader, crlf[:]); err != nil {
|
|
return newError("failed to read crlf").Base(err)
|
|
}
|
|
|
|
c.headerParsed = true
|
|
return nil
|
|
}
|
|
|
|
// Read implements io.Reader
|
|
func (c *ConnReader) Read(p []byte) (int, error) {
|
|
if !c.headerParsed {
|
|
if err := c.ParseHeader(); err != nil {
|
|
return 0, err
|
|
}
|
|
}
|
|
|
|
return c.Reader.Read(p)
|
|
}
|
|
|
|
// ReadMultiBuffer implements buf.Reader
|
|
func (c *ConnReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
|
|
b := buf.New()
|
|
_, err := b.ReadFrom(c)
|
|
return buf.MultiBuffer{b}, err
|
|
}
|
|
|
|
// PacketPayload combines udp payload and destination
|
|
type PacketPayload struct {
|
|
Target net.Destination
|
|
Buffer buf.MultiBuffer
|
|
}
|
|
|
|
// PacketReader is UDP Connection Reader Wrapper for trojan protocol
|
|
type PacketReader struct {
|
|
io.Reader
|
|
}
|
|
|
|
// ReadMultiBuffer implements buf.Reader
|
|
func (r *PacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
|
|
p, err := r.ReadMultiBufferWithMetadata()
|
|
if p != nil {
|
|
return p.Buffer, err
|
|
}
|
|
return nil, err
|
|
}
|
|
|
|
// ReadMultiBufferWithMetadata reads udp packet with destination
|
|
func (r *PacketReader) ReadMultiBufferWithMetadata() (*PacketPayload, error) {
|
|
addr, port, err := addrParser.ReadAddressPort(nil, r)
|
|
if err != nil {
|
|
return nil, newError("failed to read address and port").Base(err)
|
|
}
|
|
|
|
var lengthBuf [2]byte
|
|
if _, err := io.ReadFull(r, lengthBuf[:]); err != nil {
|
|
return nil, newError("failed to read payload length").Base(err)
|
|
}
|
|
|
|
length := binary.BigEndian.Uint16(lengthBuf[:])
|
|
|
|
var crlf [2]byte
|
|
if _, err := io.ReadFull(r, crlf[:]); err != nil {
|
|
return nil, newError("failed to read crlf").Base(err)
|
|
}
|
|
|
|
dest := net.UDPDestination(addr, port)
|
|
|
|
b := buf.NewWithSize(int32(length))
|
|
_, err = b.ReadFullFrom(r, int32(length))
|
|
if err != nil {
|
|
return nil, newError("failed to read payload").Base(err)
|
|
}
|
|
|
|
return &PacketPayload{Target: dest, Buffer: buf.MultiBuffer{b}}, nil
|
|
}
|
|
|
|
type PacketConnectionReader struct {
|
|
reader *PacketReader
|
|
payload *PacketPayload
|
|
}
|
|
|
|
func (r *PacketConnectionReader) ReadFrom(p []byte) (n int, addr gonet.Addr, err error) {
|
|
if r.payload == nil || r.payload.Buffer.IsEmpty() {
|
|
r.payload, err = r.reader.ReadMultiBufferWithMetadata()
|
|
if err != nil {
|
|
return
|
|
}
|
|
}
|
|
|
|
addr = &gonet.UDPAddr{
|
|
IP: r.payload.Target.Address.IP(),
|
|
Port: int(r.payload.Target.Port),
|
|
}
|
|
|
|
r.payload.Buffer, n = buf.SplitFirstBytes(r.payload.Buffer, p)
|
|
|
|
return
|
|
}
|