/
IPPacket.cs
299 lines (271 loc) · 10.6 KB
/
IPPacket.cs
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
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
/*
* PROJECT: Aura Operating System Development
* CONTENT: IPv4 Packet
* PROGRAMMERS: Valentin Charbonnier <valentinbreiz@gmail.com>
* Port of Cosmos Code.
*/
using System;
using Cosmos.HAL;
using Cosmos.HAL.Network;
using Cosmos.System.Network.ARP;
using Cosmos.System.Network.IPv4.TCP;
using Cosmos.System.Network.IPv4.UDP;
using Cosmos.System.Network.IPv4.UDP.DHCP;
namespace Cosmos.System.Network.IPv4
{
/// <summary>
/// IPPacket class. See also: <seealso cref="EthernetPacket"/>.
/// </summary>
public class IPPacket : EthernetPacket
{
protected byte ipHeaderLength;
private static ushort sNextFragmentID;
/// <summary>
/// IPv4 handler.
/// </summary>
/// <param name="packetData">Packet data.</param>
/// <exception cref="sys.ArgumentOutOfRangeException">Thrown on fatal error (contact support).</exception>
/// <exception cref="sys.IO.IOException">Thrown on IO error.</exception>
/// <exception cref="sys.ArgumentException">Thrown on fatal error (contact support).</exception>
/// <exception cref="sys.OverflowException">Thrown if packetData array length is greater than Int32.MaxValue.</exception>
internal static void IPv4Handler(byte[] packetData)
{
var ip_packet = new IPPacket(packetData);
if (ip_packet.SourceIP == null)
{
Global.mDebugger.Send("SourceIP null in IPv4Handler!");
}
ARPCache.Update(ip_packet.SourceIP, ip_packet.SourceMAC);
if ((NetworkStack.AddressMap.ContainsKey(ip_packet.DestinationIP.Hash) == true) ||
(ip_packet.DestinationIP.address[3] == 255))
{
switch (ip_packet.Protocol)
{
case 1:
ICMPPacket.ICMPHandler(packetData);
break;
case 6:
TCPPacket.TCPHandler(packetData);
break;
case 17:
UDPPacket.UDPHandler(packetData);
break;
}
}
else if (NetworkStack.MACMap.ContainsKey(ip_packet.DestinationMAC.Hash))
{
DHCPPacket.DHCPHandler(packetData);
}
}
/// <summary>
/// Get next IP fragment ID.
/// </summary>
public static ushort NextIPFragmentID => sNextFragmentID++;
/// <summary>
/// Create new instance of the <see cref="IPPacket"/> class.
/// </summary>
internal IPPacket()
{
}
/// <summary>
/// Create new instance of the <see cref="IPPacket"/> class.
/// </summary>
/// <param name="rawData">Raw data.</param>
public IPPacket(byte[] rawData)
: base(rawData)
{
}
/// <summary>
/// Init IPPacket fields.
/// </summary>
/// <exception cref="sys.ArgumentException">Thrown if RawData is invalid or null.</exception>
protected override void InitFields()
{
base.InitFields();
IPVersion = (byte)((RawData[14] & 0xF0) >> 4);
ipHeaderLength = (byte)(RawData[14] & 0x0F);
TypeOfService = RawData[15];
IPLength = (ushort)((RawData[16] << 8) | RawData[17]);
FragmentID = (ushort)((RawData[18] << 8) | RawData[19]);
IPFlags = (byte)((RawData[20] & 0xE0) >> 5);
FragmentOffset = (ushort)(((RawData[20] & 0x1F) << 8) | RawData[21]);
TTL = RawData[22];
Protocol = RawData[23];
IPCRC = (ushort)((RawData[24] << 8) | RawData[25]);
SourceIP = new Address(RawData, 26);
DestinationIP = new Address(RawData, 30);
DataOffset = (ushort)(14 + HeaderLength);
}
/// <summary>
/// Create new instance of the <see cref="IPPacket"/> class.
/// </summary>
/// <param name="dataLength">Data length.</param>
/// <param name="protocol">Protocol.</param>
/// <param name="source">Source address.</param>
/// <param name="dest">Destionation address.</param>
/// <param name="Flags">Flags.</param>
protected IPPacket(ushort dataLength, byte protocol, Address source, Address dest, byte Flags)
: this(MACAddress.None, MACAddress.None, dataLength, protocol, source, dest, Flags)
{ }
/// <summary>
/// Create new instance of the <see cref="IPPacket"/> class.
/// </summary>
/// <param name="dataLength">Data length.</param>
/// <param name="protocol">Protocol.</param>
/// <param name="source">Source address.</param>
/// <param name="dest">Destionation address.</param>
/// <param name="Flags">Flags.</param>
/// /// <param name="broadcast">Mac address</param>
protected IPPacket(ushort dataLength, byte protocol, Address source, Address dest, byte Flags, MACAddress broadcast)
: this(MACAddress.None, broadcast, dataLength, protocol, source, dest, Flags)
{ }
/// <summary>
/// Create new instance of the <see cref="IPPacket"/> class.
/// </summary>
/// <param name="srcMAC">Source MAC address.</param>
/// <param name="destMAC">Destination MAC address.</param>
/// <param name="dataLength">Data length.</param>
/// <param name="protocol">Protocol.</param>
/// <param name="source">Source address.</param>
/// <param name="dest">Destionation address.</param>
/// <param name="Flags">Flags.</param>
/// <exception cref="sys.ArgumentException">Thrown if RawData is invalid or null.</exception>
public IPPacket(MACAddress srcMAC, MACAddress destMAC, ushort dataLength, byte protocol,
Address source, Address dest, byte Flags)
: base(destMAC, srcMAC, 0x0800, dataLength + 14 + 20)
{
RawData[14] = 0x45;
RawData[15] = 0;
IPLength = (ushort)(dataLength + 20);
ipHeaderLength = 5;
RawData[16] = (byte)((IPLength >> 8) & 0xFF);
RawData[17] = (byte)((IPLength >> 0) & 0xFF);
FragmentID = NextIPFragmentID;
RawData[18] = (byte)((FragmentID >> 8) & 0xFF);
RawData[19] = (byte)((FragmentID >> 0) & 0xFF);
RawData[20] = Flags;
RawData[21] = 0x00;
RawData[22] = 0x80;
RawData[23] = protocol;
RawData[24] = 0x00;
RawData[25] = 0x00;
for (int b = 0; b < 4; b++)
{
RawData[26 + b] = source.address[b];
RawData[30 + b] = dest.address[b];
}
IPCRC = CalcIPCRC(20);
RawData[24] = (byte)((IPCRC >> 8) & 0xFF);
RawData[25] = (byte)((IPCRC >> 0) & 0xFF);
InitFields();
}
/// <summary>
/// Calcutale CRC.
/// </summary>
/// <param name="offset">Offset.</param>
/// <param name="length">Length.</param>
/// <returns></returns>
protected ushort CalcOcCRC(ushort offset, ushort length) => CalcOcCRC(RawData, offset, length);
/// <summary>
/// Calcutale CRC.
/// </summary>
/// <param name="buffer">Buffer.</param>
/// <param name="offset">Offset.</param>
/// <param name="length">Length.</param>
/// <returns>ushort value.</returns>
protected static ushort CalcOcCRC(byte[] buffer, ushort offset, int length)
{
return (ushort)~SumShortValues(buffer, offset, length);
}
protected static ushort SumShortValues(byte[] buffer, int offset, int length)
{
uint chksum = 0;
int end = offset + (length & ~1);
int i = offset;
while (i != end)
{
chksum += (uint)((((ushort)buffer[i++]) << 8) + (ushort)buffer[i++]);
}
if (i != offset + length)
{
chksum += (uint)(((ushort)buffer[i]) << 8);
}
chksum = (chksum & 0xFFFF) + (chksum >> 16);
chksum = (chksum & 0xFFFF) + (chksum >> 16);
return (ushort)chksum;
}
/// <summary>
/// Calcutale CRC.
/// </summary>
/// <param name="headerLength">Header length.</param>
/// <returns>ushort value.</returns>
protected ushort CalcIPCRC(ushort headerLength)
{
return CalcOcCRC(14, headerLength);
}
/// <summary>
/// Get IP version.
/// </summary>
internal byte IPVersion { get; private set; }
/// <summary>
/// Get header length.
/// </summary>
internal ushort HeaderLength => (ushort)(ipHeaderLength * 4);
/// <summary>
/// Get type of service.
/// </summary>
internal byte TypeOfService { get; private set; }
/// <summary>
/// Get IP length.
/// </summary>
internal ushort IPLength { get; private set; }
/// <summary>
/// Get fragment ID.
/// </summary>
internal ushort FragmentID { get; private set; }
/// <summary>
/// Get flags.
/// </summary>
internal byte IPFlags { get; private set; }
/// <summary>
/// Get fragment offset.
/// </summary>
internal ushort FragmentOffset { get; private set; }
/// <summary>
/// Get TTL.
/// </summary>
internal byte TTL { get; private set; }
/// <summary>
/// Get protocol.
/// </summary>
internal byte Protocol { get; private set; }
/// <summary>
/// Get IPCRC.
/// </summary>
internal ushort IPCRC { get; private set; }
/// <summary>
/// Get source IP.
/// </summary>
internal Address SourceIP { get; private set; }
/// <summary>
/// Get destination IP.
/// </summary>
internal Address DestinationIP { get; private set; }
/// <summary>
/// Get data offset.
/// </summary>
internal ushort DataOffset { get; private set; }
/// <summary>
/// Get data length.
/// </summary>
internal ushort DataLength => (ushort)(IPLength - HeaderLength);
/// <summary>
/// To string.
/// </summary>
/// <returns>string value.</returns>
public override string ToString()
{
return "IP Packet Src=" + SourceIP + ", Dest=" + DestinationIP + ", Protocol=" + Protocol + ", TTL=" + TTL + ", DataLen=" + DataLength;
}
}
}