/
helpers.go
190 lines (142 loc) · 4.76 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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
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)
}
// UpdateTCPFlags
func (p *Packet) updateTCPFlags(tcpFlags uint8) {
p.Buffer[tcpFlagsOffsetPos] = tcpFlags
}
// ConvertAcktoFinAck function removes the data from the packet
// It is called only if the packet is Ack or Psh/Ack
// converts psh/ack to fin/ack packet.
func (p *Packet) ConvertAcktoFinAck() error {
var tcpFlags uint8
tcpFlags = tcpFlags | TCPFinMask
tcpFlags = tcpFlags | TCPAckMask
p.updateTCPFlags(tcpFlags)
p.TCPFlags = tcpFlags
if err := p.TCPDataDetach(0); err != nil {
return fmt.Errorf("ack packet in wrong format")
}
p.DropDetachedBytes()
return nil
}
// 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
}