-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpayload_ipv4.go
180 lines (134 loc) · 4.49 KB
/
payload_ipv4.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
package exu
import (
"encoding/binary"
"errors"
"net"
)
// IPv4Packet represents the structure of an IPv4 packet
type IPv4Packet struct {
Header IPv4Header // IPv4 header
Payload []byte // Payload data
}
// MarshalBinary converts the IPv4Packet struct to its binary representation
func (p *IPv4Packet) MarshalBinary() ([]byte, error) {
headerBytes, err := p.Header.MarshalBinary()
if err != nil {
return nil, err
}
// Combine header and payload
packetBytes := append(headerBytes, p.Payload...)
return packetBytes, nil
}
func (p *IPv4Packet) EtherType() EtherType {
return EtherTypeIPv4
}
// UnmarshalBinary converts the binary representation to an IPv4Packet struct
func (p *IPv4Packet) UnmarshalBinary(data []byte) error {
// Minimum size for a valid IPv4 packet is the size of the header (20 bytes)
if len(data) < 20 {
return errors.New("ipv4 packet must be at least 20 bytes")
}
// Unmarshal header
if err := p.Header.UnmarshalBinary(data[:20]); err != nil {
return err
}
// Set payload
p.Payload = data[20:]
return nil
}
type IPv4Protocol uint8
const (
IPv4ProtocolICMP IPv4Protocol = 1
IPv4ProtocolTCP IPv4Protocol = 6
IPv4ProtocolUDP IPv4Protocol = 17
)
// IPv4Header represents the structure of an IPv4 header
type IPv4Header struct {
Version uint8 // 4-bit IP version
IHL uint8 // 4-bit Internet Header Length (IHL)
TOS uint8 // 8-bit Type of Service (TOS)
TotalLength uint16 // 16-bit Total Length
ID uint16 // 16-bit Identification
FlagsFragment uint16 // 3-bit Flags and 13-bit Fragment Offset
TTL uint8 // 8-bit Time to Live (TTL)
Protocol IPv4Protocol // 8-bit Protocol
HeaderChecksum uint16 // 16-bit Header Checksum
SourceIP net.IP // 32-bit Source IP Address
DestinationIP net.IP // 32-bit Destination IP Address
}
// MarshalBinary converts the IPv4Header struct to its binary representation
func (header *IPv4Header) MarshalBinary() ([]byte, error) {
b := make([]byte, 20) // IPv4 header length is 20 bytes
// Version and IHL (Internet Header Length)
b[0] = (header.Version << 4) | (header.IHL & 0x0F)
// Type of Service (TOS)
b[1] = header.TOS
// Total Length
binary.BigEndian.PutUint16(b[2:4], header.TotalLength)
// Identification
binary.BigEndian.PutUint16(b[4:6], header.ID)
// Flags and Fragment Offset
binary.BigEndian.PutUint16(b[6:8], header.FlagsFragment)
// Time to Live (TTL)
b[8] = header.TTL
// Protocol
b[9] = byte(header.Protocol)
// Header Checksum
binary.BigEndian.PutUint16(b[10:12], header.HeaderChecksum)
// Source IP Address
copy(b[12:16], header.SourceIP.To4())
// Destination IP Address
copy(b[16:20], header.DestinationIP.To4())
return b, nil
}
// UnmarshalBinary converts the binary representation to an IPv4Header struct
func (header *IPv4Header) UnmarshalBinary(data []byte) error {
if len(data) < 20 {
return errors.New("ipv4 header must be at least 20 bytes")
}
// Version and IHL (Internet Header Length)
header.Version = data[0] >> 4
header.IHL = data[0] & 0x0F
// Type of Service (TOS)
header.TOS = data[1]
// Total Length
header.TotalLength = binary.BigEndian.Uint16(data[2:4])
// Identification
header.ID = binary.BigEndian.Uint16(data[4:6])
// Flags and Fragment Offset
header.FlagsFragment = binary.BigEndian.Uint16(data[6:8])
// Time to Live (TTL)
header.TTL = data[8]
// Protocol
header.Protocol = IPv4Protocol(data[9])
// Header Checksum
header.HeaderChecksum = binary.BigEndian.Uint16(data[10:12])
// Source IP Address
header.SourceIP = data[12:16]
// Destination IP Address
header.DestinationIP = data[16:20]
return nil
}
// CalculateChecksum calculates the header checksum for an IPv4 header
func (header *IPv4Header) CalculateChecksum() uint16 {
// Save the current checksum value
oldChecksum := header.HeaderChecksum
// Set the checksum field to 0
header.HeaderChecksum = 0
// Convert the header to a byte slice
headerBytes, _ := header.MarshalBinary()
// Initialize the checksum
checksum := uint32(0)
// Iterate over 16-bit words in the header
for i := 0; i < len(headerBytes); i += 2 {
checksum += uint32(binary.BigEndian.Uint16(headerBytes[i : i+2]))
}
// Fold the carry into the checksum
checksum = (checksum >> 16) + (checksum & 0xffff)
checksum += checksum >> 16
// Take the one's complement
checksum = ^checksum
// Set the header checksum back to its original value
header.HeaderChecksum = oldChecksum
return uint16(checksum)
}