-
Notifications
You must be signed in to change notification settings - Fork 51
/
helpers.go
167 lines (123 loc) · 4.18 KB
/
helpers.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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
package packet
import (
"bytes"
"encoding/binary"
"encoding/hex"
"fmt"
"strconv"
"golang.org/x/net/ipv4"
)
// Helpher functions for the package, mainly for debugging and validation
// They are not used by the main package
// VerifyIPChecksum returns true if the IP header checksum is correct
// for this packet, false otherwise. Note that the checksum is not
// modified.
func (p *Packet) VerifyIPChecksum() bool {
sum := p.computeIPChecksum()
return sum == p.ipChecksum
}
// UpdateIPChecksum computes the IP header checksum and updates the
// packet with the value.
func (p *Packet) UpdateIPChecksum() {
p.ipChecksum = p.computeIPChecksum()
binary.BigEndian.PutUint16(p.Buffer[ipChecksumPos:ipChecksumPos+2], p.ipChecksum)
}
// VerifyTCPChecksum returns true if the TCP header checksum is correct
// for this packet, false otherwise. Note that the checksum is not
// modified.
func (p *Packet) VerifyTCPChecksum() bool {
sum := p.computeTCPChecksum()
return sum == p.TCPChecksum
}
// UpdateTCPChecksum computes the TCP header checksum and updates the
// packet with the value.
func (p *Packet) UpdateTCPChecksum() {
p.TCPChecksum = p.computeTCPChecksum()
binary.BigEndian.PutUint16(p.Buffer[TCPChecksumPos:TCPChecksumPos+2], p.TCPChecksum)
}
// String returns a string representation of fields contained in this packet.
func (p *Packet) String() string {
var buf bytes.Buffer
buf.WriteString("(error)")
header, err := ipv4.ParseHeader(p.Buffer)
if err == nil {
buf.Reset()
buf.WriteString(header.String())
buf.WriteString(" srcport=")
buf.WriteString(strconv.Itoa(int(p.SourcePort)))
buf.WriteString(" dstport=")
buf.WriteString(strconv.Itoa(int(p.DestinationPort)))
buf.WriteString(" tcpcksum=")
buf.WriteString(fmt.Sprintf("0x%0x", p.TCPChecksum))
buf.WriteString(" data")
buf.WriteString(hex.EncodeToString(p.GetBytes()))
}
return buf.String()
}
// Computes the IP header checksum. The packet is not modified.
func (p *Packet) computeIPChecksum() uint16 {
// IP packet checksum is computed with the checksum value set to zero
binary.BigEndian.PutUint16(p.Buffer[ipChecksumPos:ipChecksumPos+2], uint16(0))
// Compute checksum, over IP header only
sum := checksum(p.Buffer[0 : p.ipHeaderLen*4])
// Restore the previous checksum (whether correct or not, as this function doesn't change it)
binary.BigEndian.PutUint16(p.Buffer[ipChecksumPos:ipChecksumPos+2], p.ipChecksum)
return sum
}
// Computes the TCP header checksum. The packet is not modified.
func (p *Packet) computeTCPChecksum() uint16 {
var pseudoHeaderLen uint16 = 12
tcpSize := uint16(len(p.Buffer)) - p.l4BeginPos
bufLen := pseudoHeaderLen + tcpSize
buf := make([]byte, bufLen)
// Construct the pseudo-header for TCP checksum computation:
// bytes 0-3: Source IP address
copy(buf[0:4], p.Buffer[ipSourceAddrPos:ipSourceAddrPos+4])
// bytes 4-7: Destination IP address
copy(buf[4:8], p.Buffer[ipDestAddrPos:ipDestAddrPos+4])
// byte 8: Constant zero
buf[8] = 0
// byte 9: Protocol (6==TCP)
buf[9] = 6
// bytes 10,11: TCP buffer size (real header + payload)
binary.BigEndian.PutUint16(buf[10:12], tcpSize+uint16(len(p.tcpData)+len(p.tcpOptions)))
// bytes 12+: The TCP buffer (real header + payload)
copy(buf[12:], p.Buffer[p.l4BeginPos:])
// Set current checksum to zero (in buf, not changing packet)
buf[pseudoHeaderLen+16] = 0
buf[pseudoHeaderLen+17] = 0
buf = append(buf, p.tcpOptions...)
buf = append(buf, p.tcpData...)
return checksum(buf)
}
// incCsum16 implements rfc1624, equation 3.
func incCsum16(start, old, new uint16) uint16 {
start = start ^ 0xffff
old = old ^ 0xffff
csum := uint32(start) + uint32(old) + uint32(new)
for (csum >> 16) > 0 {
csum = (csum & 0xffff) + ((csum >> 16) & 0xffff)
}
csum = csum ^ 0xffff
return uint16(csum)
}
// Computes a sum of 16 bit numbers
func checksumDelta(buf []byte) uint16 {
sum := uint32(0)
for ; len(buf) >= 2; buf = buf[2:] {
sum += uint32(buf[0])<<8 | uint32(buf[1])
}
if len(buf) > 0 {
sum += uint32(buf[0]) << 8
}
for sum > 0xffff {
sum = (sum >> 16) + (sum & 0xffff)
}
return uint16(sum)
}
// Computes a checksum over the given slice.
func checksum(buf []byte) uint16 {
sum := checksumDelta(buf)
csum := ^sum
return csum
}