-
Notifications
You must be signed in to change notification settings - Fork 0
/
IcmpHeader.cs
180 lines (150 loc) · 5.71 KB
/
IcmpHeader.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
using System;
using Microsoft.SPOT;
using System.Net;
using System.Net.Sockets;
using System.Collections;
namespace NetduinoPlusApplication1
{
/// <summary>
/// The ICMP protocol header used with the IPv4 protocol.
/// </summary>
class IcmpHeader
{
private ushort icmpChecksum; // Checksum of ICMP header and payload
private ushort icmpId; // Message ID
private ushort icmpSequence; // ICMP sequence number
static public byte EchoRequestType = 8; // ICMP echo request
static public byte EchoRequestCode = 0; // ICMP echo request code
static public byte EchoReplyType = 0; // ICMP echo reply
static public byte EchoReplyCode = 0; // ICMP echo reply code
static public int IcmpHeaderLength = 8; // Length of ICMP header
/// <summary>
/// Default constructor for ICMP packet
/// </summary>
public IcmpHeader()
{
Type = 0;
Code = 0;
icmpChecksum = 0;
icmpId = 0;
icmpSequence = 0;
}
/// <summary>
/// ICMP message type.
/// </summary>
public byte Type { get; set; }
/// <summary>
/// ICMP message code.
/// </summary>
public byte Code { get; set; }
/// <summary>
/// Checksum of ICMP packet and payload. Performs the necessary byte order conversion.
/// </summary>
public ushort Checksum
{
get
{
return (ushort)NetworkHostConverter.NetworkToHostOrder((short)icmpChecksum);
}
set
{
icmpChecksum = (ushort)NetworkHostConverter.HostToNetworkOrder((short)value);
}
}
/// <summary>
/// ICMP message ID. Used to uniquely identify the source of the ICMP packet.
/// Performs the necessary byte order conversion.
/// </summary>
public ushort Id
{
get
{
return (ushort)NetworkHostConverter.NetworkToHostOrder((short)icmpId);
}
set
{
icmpId = (ushort)NetworkHostConverter.HostToNetworkOrder((short)value);
}
}
/// <summary>
/// ICMP sequence number. As each ICMP message is sent the sequence should be incremented.
/// Performs the necessary byte order conversion.
/// </summary>
public ushort Sequence
{
get
{
return (ushort)NetworkHostConverter.NetworkToHostOrder((short)icmpSequence);
}
set
{
icmpSequence = (ushort)NetworkHostConverter.HostToNetworkOrder((short)value);
}
}
/// <summary>
/// This routine builds the ICMP packet suitable for sending on a raw socket.
/// It builds the ICMP packet and payload into a byte array and computes
/// the checksum.
/// </summary>
/// <param name="payLoad">Data payload of the ICMP packet</param>
/// <returns>Byte array representing the ICMP packet and payload</returns>
public byte[] GetProtocolPacketBytes(byte[] payLoad)
{
byte[] icmpPacket,
byteValue;
int offset = 0;
icmpPacket = new byte[IcmpHeaderLength + payLoad.Length];
icmpPacket[offset++] = Type;
icmpPacket[offset++] = Code;
icmpPacket[offset++] = 0; // Zero out the checksum until the packet is assembled
icmpPacket[offset++] = 0;
byteValue = BitConverter.GetBytes(icmpId);
Array.Copy(byteValue, 0, icmpPacket, offset, byteValue.Length);
offset += byteValue.Length;
byteValue = BitConverter.GetBytes(icmpSequence);
Array.Copy(byteValue, 0, icmpPacket, offset, byteValue.Length);
offset += byteValue.Length;
if (payLoad.Length > 0)
{
Array.Copy(payLoad, 0, icmpPacket, offset, payLoad.Length);
offset += payLoad.Length;
}
// Compute the checksum over the entire packet
Checksum = ComputeChecksum(icmpPacket);
// Put the checksum back into the packet
byteValue = BitConverter.GetBytes(icmpChecksum);
Array.Copy(byteValue, 0, icmpPacket, 2, byteValue.Length);
return icmpPacket;
}
public byte[] BuildPacket(ushort pingID, byte[] payLoad)
{
IcmpHeader protocolHeader = new IcmpHeader() { Id = pingID, Sequence = 0, Type = IcmpHeader.EchoRequestType, Code = IcmpHeader.EchoRequestCode }; ;
payLoad = protocolHeader.GetProtocolPacketBytes(payLoad);
return payLoad;
}
static public ushort ComputeChecksum(byte[] payLoad)
{
uint xsum = 0;
ushort shortval = 0,
hiword = 0,
loword = 0;
// Sum up the 16-bits
for (int i = 0; i < payLoad.Length / 2; i++)
{
hiword = (ushort)(((ushort)payLoad[i * 2]) << 8);
loword = (ushort)payLoad[(i * 2) + 1];
shortval = (ushort)(hiword | loword);
xsum = xsum + (uint)shortval;
}
// Pad if necessary
if ((payLoad.Length % 2) != 0)
{
xsum += (uint)payLoad[payLoad.Length - 1];
}
xsum = ((xsum >> 16) + (xsum & 0xFFFF));
xsum = (xsum + (xsum >> 16));
shortval = (ushort)(~xsum);
return shortval;
}
}
}