github.com/ipfans/trojan-go@v0.11.0/tunnel/trojan/packet.go (about) 1 package trojan 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "io" 7 "io/ioutil" 8 "net" 9 10 "github.com/ipfans/trojan-go/common" 11 "github.com/ipfans/trojan-go/log" 12 "github.com/ipfans/trojan-go/tunnel" 13 ) 14 15 type PacketConn struct { 16 tunnel.Conn 17 } 18 19 func (c *PacketConn) ReadFrom(payload []byte) (int, net.Addr, error) { 20 return c.ReadWithMetadata(payload) 21 } 22 23 func (c *PacketConn) WriteTo(payload []byte, addr net.Addr) (int, error) { 24 address, err := tunnel.NewAddressFromAddr("udp", addr.String()) 25 if err != nil { 26 return 0, err 27 } 28 m := &tunnel.Metadata{ 29 Address: address, 30 } 31 return c.WriteWithMetadata(payload, m) 32 } 33 34 func (c *PacketConn) WriteWithMetadata(payload []byte, metadata *tunnel.Metadata) (int, error) { 35 packet := make([]byte, 0, MaxPacketSize) 36 w := bytes.NewBuffer(packet) 37 metadata.Address.WriteTo(w) 38 39 length := len(payload) 40 lengthBuf := [2]byte{} 41 crlf := [2]byte{0x0d, 0x0a} 42 43 binary.BigEndian.PutUint16(lengthBuf[:], uint16(length)) 44 w.Write(lengthBuf[:]) 45 w.Write(crlf[:]) 46 w.Write(payload) 47 48 _, err := c.Conn.Write(w.Bytes()) 49 50 log.Debug("udp packet remote", c.RemoteAddr(), "metadata", metadata, "size", length) 51 return len(payload), err 52 } 53 54 func (c *PacketConn) ReadWithMetadata(payload []byte) (int, *tunnel.Metadata, error) { 55 addr := &tunnel.Address{ 56 NetworkType: "udp", 57 } 58 if err := addr.ReadFrom(c.Conn); err != nil { 59 return 0, nil, common.NewError("failed to parse udp packet addr").Base(err) 60 } 61 lengthBuf := [2]byte{} 62 if _, err := io.ReadFull(c.Conn, lengthBuf[:]); err != nil { 63 return 0, nil, common.NewError("failed to read length") 64 } 65 length := int(binary.BigEndian.Uint16(lengthBuf[:])) 66 67 crlf := [2]byte{} 68 if _, err := io.ReadFull(c.Conn, crlf[:]); err != nil { 69 return 0, nil, common.NewError("failed to read crlf") 70 } 71 72 if len(payload) < length || length > MaxPacketSize { 73 io.CopyN(ioutil.Discard, c.Conn, int64(length)) // drain the rest of the packet 74 return 0, nil, common.NewError("incoming packet size is too large") 75 } 76 77 if _, err := io.ReadFull(c.Conn, payload[:length]); err != nil { 78 return 0, nil, common.NewError("failed to read payload") 79 } 80 81 log.Debug("udp packet from", c.RemoteAddr(), "metadata", addr.String(), "size", length) 82 return length, &tunnel.Metadata{ 83 Address: addr, 84 }, nil 85 }