forked from yinghuocho/gotun2socks
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ip.go
103 lines (90 loc) · 2.08 KB
/
ip.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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
package gotun2socks
import (
"log"
"net"
"github.com/yinghuocho/gotun2socks/internal/packet"
)
type ipPacket struct {
ip *packet.IPv4
mtuBuf []byte
wire []byte
}
var (
frags = make(map[uint16]*ipPacket)
)
func procFragment(ip *packet.IPv4, raw []byte) (bool, *packet.IPv4, []byte) {
exist, ok := frags[ip.Id]
if !ok {
if ip.Flags&0x1 == 0 {
return false, nil, nil
}
// first
log.Printf("first fragment of IPID %d", ip.Id)
dup := make([]byte, len(raw))
copy(dup, raw)
clone := &packet.IPv4{}
packet.ParseIPv4(dup, clone)
frags[ip.Id] = &ipPacket{
ip: clone,
wire: dup,
}
return false, clone, dup
} else {
exist.wire = append(exist.wire, ip.Payload...)
packet.ParseIPv4(exist.wire, exist.ip)
last := false
if ip.Flags&0x1 == 0 {
log.Printf("last fragment of IPID %d", ip.Id)
last = true
} else {
log.Printf("continue fragment of IPID %d", ip.Id)
}
return last, exist.ip, exist.wire
}
}
func genFragments(first *packet.IPv4, offset uint16, data []byte) []*ipPacket {
var ret []*ipPacket
for {
frag := packet.NewIPv4()
frag.Version = 4
frag.Id = first.Id
frag.SrcIP = make(net.IP, len(first.SrcIP))
copy(frag.SrcIP, first.SrcIP)
frag.DstIP = make(net.IP, len(first.DstIP))
copy(frag.DstIP, first.DstIP)
frag.TTL = first.TTL
frag.Protocol = first.Protocol
frag.FragOffset = offset
if len(data) <= MTU-20 {
frag.Payload = data
} else {
frag.Flags = 1
offset += (MTU - 20) / 8
frag.Payload = data[:MTU-20]
data = data[MTU-20:]
}
pkt := &ipPacket{ip: frag}
pkt.mtuBuf = newBuffer()
payloadL := len(frag.Payload)
payloadStart := MTU - payloadL
if payloadL != 0 {
copy(pkt.mtuBuf[payloadStart:], frag.Payload)
}
ipHL := frag.HeaderLength()
ipStart := payloadStart - ipHL
frag.Serialize(pkt.mtuBuf[ipStart:payloadStart], payloadL)
pkt.wire = pkt.mtuBuf[ipStart:]
ret = append(ret, pkt)
if frag.Flags == 0 {
return ret
}
}
}
func releaseIPPacket(pkt *ipPacket) {
packet.ReleaseIPv4(pkt.ip)
if pkt.mtuBuf != nil {
releaseBuffer(pkt.mtuBuf)
}
pkt.mtuBuf = nil
pkt.wire = nil
}