我尝试使用C#实现基于udp数据包的ping。我们的想法是将udp数据包发送到错误的端口并获取ICMP数据包,以防止端口无法访问错误。并且,在发送udp数据包和接收icmp数据包之间经过的时间是ping时间。我这样做:
// Start building the headers
//Console.WriteLine("Building the packet header...");
int messageSize = 64;
byte[] builtPacket, payLoad = new byte[messageSize];
UdpHeader udpPacket = new UdpHeader();
ArrayList headerList = new ArrayList();
Socket rawSocket = null;
SocketOptionLevel socketLevel;
// Initialize the payload
//Console.WriteLine("Initialize the payload...");
for (int i = 0; i < payLoad.Length; i++)
payLoad[i] = (byte)'0';
// Fill out the UDP header first
//Console.WriteLine("Filling out the UDP header...");
udpPacket.SourcePort = 33434;
udpPacket.DestinationPort = 33434;
udpPacket.Length = (ushort)(UdpHeader.UdpHeaderLength + messageSize);
udpPacket.Checksum = 0;
Ipv4Header ipv4Packet = new Ipv4Header();
// Build the IPv4 header
//Console.WriteLine("Building the IPv4 header...");
ipv4Packet.Version = 4;
ipv4Packet.Protocol = (byte)ProtocolType.Udp;
ipv4Packet.Ttl = 30;
ipv4Packet.Offset = 0;
ipv4Packet.Length = (byte)Ipv4Header.Ipv4HeaderLength;
ipv4Packet.TotalLength = (ushort)Convert.ToUInt16(Ipv4Header.Ipv4HeaderLength + UdpHeader.UdpHeaderLength + messageSize);
ipv4Packet.SourceAddress = sourceAddress;
ipv4Packet.DestinationAddress = destAddress;
// Set the IPv4 header in the UDP header since it is required to calculate the
// pseudo header checksum
//Console.WriteLine("Setting the IPv4 header for pseudo header checksum...");
udpPacket.ipv4PacketHeader = ipv4Packet;
// Add IPv4 header to list of headers -- headers should be added in th order
// they appear in the packet (i.e. IP first then UDP)
//Console.WriteLine("Adding the IPv4 header to the list of header, encapsulating packet...");
headerList.Add(ipv4Packet);
socketLevel = SocketOptionLevel.IP;
// Add the UDP header to list of headers after the IP header has been added
//Console.WriteLine("Adding the UDP header to the list of header, after IP header...");
headerList.Add(udpPacket);
// Convert the header classes into the binary on-the-wire representation
//Console.WriteLine("Converting the header classes into the binary...");
builtPacket = udpPacket.BuildPacket(headerList, payLoad);
// Create the raw socket for this packet
//Console.WriteLine("Creating the raw socket using Socket()...");
rawSocket = new Socket(sourceAddress.AddressFamily, SocketType.Raw, ProtocolType.Udp);
// Bind the socket to the interface specified
//Console.WriteLine("Binding the socket to the specified interface using Bind()...");
IPAddress bindAddress = IPAddress.Any;
rawSocket.Bind(new IPEndPoint(bindAddress, 0));
// Set the HeaderIncluded option since we include the IP header
//Console.WriteLine("Setting the HeaderIncluded option for IP header...");
rawSocket.SetSocketOption(socketLevel, SocketOptionName.HeaderIncluded, 1);
rawSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 1000);
Stopwatch timer = new Stopwatch();
try {
for (int i = 0; i < 5; i++) {
timer.Reset();
timer.Start();
int rc = rawSocket.SendTo(builtPacket, new IPEndPoint(destAddress, 0));
Console.WriteLine("Sent {0} bytes to {1}", rc, destAddress);
Socket icmpListener = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.Icmp);
icmpListener.Bind(new IPEndPoint(sourceAddress, 0));
icmpListener.IOControl(IOControlCode.ReceiveAll, new byte[] { 1, 0, 0, 0 }, new byte[] { 1, 0, 0, 0 });
icmpListener.Shutdown(SocketShutdown.Send);
byte[] buffer = new byte[4096];
EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
try {
int bytesRead = icmpListener.ReceiveFrom(buffer, ref remoteEndPoint);
timer.Stop();
Console.WriteLine("Recieved " + bytesRead + " bytes from " + destAddress + " in " + timer.ElapsedMilliseconds + "ms\n");
}
catch {
Console.WriteLine("Server is not responding!");
}
finally {
icmpListener.Close();
}
}
}
catch (SocketException err) {
Console.WriteLine("Socket error occurred: {0}", err.Message);
}
finally {
rawSocket.Close();
}
它不时有效。问题是有些网站发给我一个icmp数据包而有些没有。实际上起初他们也没有发送然后我用Windows ping ping它们并跟踪traceroute它们。并改变了端口号,它起作用了。但并不适合所有人。我只能ping google.com和另外一个网站,但其他人不会发回icmp数据包。与我尝试ping的本地网络计算机相同的情况。我发送了udp数据包,但没有得到icmp。
我用wireshark来观看飞行的数据包。
我在这里做错了什么?