glider/proxy/trojan/packet.go
2020-04-12 15:27:20 +08:00

76 lines
1.7 KiB
Go

// https://trojan-gfw.github.io/trojan/protocol
// If the connection is a UDP ASSOCIATE, then each UDP packet has the following format:
// +------+----------+----------+--------+---------+----------+
// | ATYP | DST.ADDR | DST.PORT | Length | CRLF | Payload |
// +------+----------+----------+--------+---------+----------+
// | 1 | Variable | 2 | 2 | X'0D0A' | Variable |
// +------+----------+----------+--------+---------+----------+
package trojan
import (
"bytes"
"encoding/binary"
"errors"
"io"
"net"
"github.com/nadoo/glider/common/conn"
"github.com/nadoo/glider/common/socks"
)
// PktConn .
type PktConn struct {
net.Conn
tgtAddr socks.Addr
}
func NewPktConn(c net.Conn, tgtAddr socks.Addr) *PktConn {
pc := &PktConn{
Conn: c,
tgtAddr: tgtAddr,
}
return pc
}
func (pc *PktConn) ReadFrom(b []byte) (int, net.Addr, error) {
// ATYP, DST.ADDR, DST.PORT
_, err := socks.ReadAddr(pc.Conn)
if err != nil {
return 0, nil, err
}
// Length
if _, err = io.ReadFull(pc.Conn, b[:2]); err != nil {
return 0, nil, err
}
length := int(binary.BigEndian.Uint16(b[:2]))
if length > conn.UDPBufSize {
return 0, nil, errors.New("packet invalid")
}
// CRLF
if _, err = io.ReadFull(pc.Conn, b[:2]); err != nil {
return 0, nil, err
}
// Payload
n, err := io.ReadFull(pc.Conn, b[:length])
if err != nil {
return 0, nil, err
}
// TODO: check the addr in return value, it's a fake packetConn so the addr is not valid
return n, nil, err
}
func (pc *PktConn) WriteTo(b []byte, addr net.Addr) (int, error) {
var buf bytes.Buffer
buf.Write(pc.tgtAddr)
binary.Write(&buf, binary.BigEndian, uint16(len(b)))
buf.WriteString("\r\n")
buf.Write(b)
return pc.Write(buf.Bytes())
}