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