/// <summary> /// Display ICMP packet that have been sent /// </summary> public static void RequestPacket(ICMP packet, String address, int index) { if (!Display.ShowOutput) { return; } // Show shortened info if (Short) { Console.Write(REQUEST_MSG_SHORT, address); } else { Console.Write(REQUEST_MSG, address, index, packet.GetBytes().Length); } // Print coloured type PacketType(packet); Console.Write(REQUEST_CODE_TXT, packet.code); // Display timestamp if (ShowTimeStamp) { Console.Write(TIMESTAMP_LAYOUT, DateTime.Now.ToString("HH:mm:ss")); } // End line Console.WriteLine(); }
/// <summary> /// Display ICMP packet that have been sent /// </summary> public static void RequestPacket(ICMP packet, string address, int index) { if (!Configuration.ShowOutput || !Configuration.ShowRequests) { return; } // Show shortened info if (Configuration.Short) { Console.Write(ProgramStrings.REQUEST_MSG_SHORT, address); } else { Console.Write(ProgramStrings.REQUEST_MSG, address, index, packet.GetBytes().Length); } // Print coloured type PacketType(packet); Console.Write(ProgramStrings.REQUEST_CODE_TXT, packet.Code); // Display timestamp if (Configuration.ShowFullTimeStamp) { Console.Write(ProgramStrings.TIMESTAMP_LAYOUT, DateTime.Now.ToString(CultureInfo.CurrentCulture)); } else if (Configuration.ShowFullTimeStampUTC) { Console.Write(ProgramStrings.TIMESTAMP_LAYOUT, DateTime.UtcNow.ToString(CultureInfo.CurrentCulture)); } else if (Configuration.ShowTimeStamp) { Console.Write(ProgramStrings.TIMESTAMP_LAYOUT, DateTime.Now.ToString("HH:mm:ss")); } else if (Configuration.ShowtimeStampUTC) { Console.Write(ProgramStrings.TIMESTAMP_LAYOUT, DateTime.UtcNow.ToString("HH:mm:ss")); } // End line Console.WriteLine(); }
/// <summary> /// Core ICMP sending method (used by all other functions) /// Takes a set of attributes, performs operation and returns a set of results. /// /// Works specifically by creating a raw socket, creating a ICMP object and /// other socket properties (timeouts, interval etc) using the /// inputted properties (attrs), then performs ICMP operation /// before cleaning up and returning results. /// /// NOTE: There is a weird hack here, The set of PingAttributes used are /// those provided in the parameter as opposed to the ones stored /// in this class (Ping.Attributes) (similar case with PingResults). /// This is due to some functions (flood, scan) requiring to be run on seperate threads /// and needing us to pass specific attributes directly to the object /// trust me it works (I think..) /// </summary> /// <param name="attrs">Properties of pings to be sent</param> /// <returns>Set of ping results</returns> private PingResults SendICMP(PingAttributes attrs) { IPEndPoint iep = null; EndPoint ep = null; IPAddress ipAddr = null; ICMP packet = new ICMP(); Socket sock = null; byte[] receiveBuffer = new byte[attrs.RecieveBufferSize]; // Ipv4Header.length + IcmpHeader.length + attrs.recievebuffersize int bytesRead, packetSize, index = 1; // Convert to IPAddress ipAddr = IPAddress.Parse(attrs.Address); // Setup endpoint iep = new IPEndPoint(ipAddr, 0); ep = (EndPoint)iep; // Setup raw socket sock = CreateRawSocket(ipAddr.AddressFamily); // Set socket options sock.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, attrs.Timeout); // Socket timeout sock.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.IpTimeToLive, attrs.Ttl); sock.DontFragment = attrs.DontFragment; // Create packet message payload byte[] payload; if (attrs.Size != -1) { payload = Helper.GenerateByteArray(attrs.Size); } else { payload = Encoding.ASCII.GetBytes(attrs.Message); } // Construct our ICMP packet packet.type = attrs.Type; packet.code = attrs.Code; Buffer.BlockCopy(BitConverter.GetBytes(sessionId), 0, packet.message, 0, 2); // Add identifier to ICMP message Buffer.BlockCopy(payload, 0, packet.message, 4, payload.Length); // Add text into ICMP message packet.messageSize = payload.Length + 4; packetSize = packet.messageSize + 4; // Sending loop while (attrs.Continous ? true : index <= attrs.Count) { // Exit loop if cancel event is set if (cancelEvent.WaitOne(0)) { break; } else { IsRunning = true; } // Include sequence number in ping message ushort sequenceNum = (ushort)index; Buffer.BlockCopy(BitConverter.GetBytes(sequenceNum), 0, packet.message, 2, 2); // Fill ICMP message field if (attrs.RandomMsg) { payload = Encoding.ASCII.GetBytes(Helper.RandomString()); Buffer.BlockCopy(payload, 0, packet.message, 4, payload.Length); } // Update packet checksum packet.checksum = 0; UInt16 chksm = packet.GetChecksum(); packet.checksum = chksm; try { // Show request packet if (Display.ShowRequests) { Display.RequestPacket(packet, Display.UseInputtedAddress | Display.UseResolvedAddress ? attrs.Host : attrs.Address, index); } // If there were extra responses from a prior request, ignore them while (sock.Available != 0) { bytesRead = sock.ReceiveFrom(receiveBuffer, ref ep); } // Send ping request sock.SendTo(packet.GetBytes(), packetSize, SocketFlags.None, iep); // Packet size = message field + 4 header bytes long requestTimestamp = Stopwatch.GetTimestamp(); try { Results.Sent++; } catch (OverflowException) { Results.HasOverflowed = true; } if (debug) { // Induce random wait for debugging Random rnd = new Random(); Thread.Sleep(rnd.Next(700)); if (rnd.Next(20) == 1) { throw new SocketException(); } } ICMP response; TimeSpan replyTime; do { // Wait for response bytesRead = sock.ReceiveFrom(receiveBuffer, ref ep); replyTime = new TimeSpan(Helper.StopwatchToTimeSpanTicks(Stopwatch.GetTimestamp() - requestTimestamp)); // Store reply packet response = new ICMP(receiveBuffer, bytesRead); // Ignore unexpected echo responses if (packet.type == 8 && response.type == 0) { ushort responseSessionId = BitConverter.ToUInt16(response.message, 0); ushort responseSequenceNum = BitConverter.ToUInt16(response.message, 2); if (responseSessionId != sessionId || responseSequenceNum != sequenceNum) { if (replyTime.TotalMilliseconds >= attrs.Timeout) { throw new SocketException(); } response = null; } } } while (response == null); // Display reply packet if (Display.ShowReplies) { PowerPing.Display.ReplyPacket(response, Display.UseInputtedAddress | Display.UseResolvedAddress ? attrs.Host : ep.ToString(), index, replyTime, bytesRead); } // Store response info try { Results.Received++; } catch (OverflowException) { Results.HasOverflowed = true; } Results.CountPacketType(response.type); Results.SaveResponseTime(replyTime.TotalMilliseconds); if (attrs.BeepLevel == 2) { try { Console.Beep(); } catch (Exception) { } // Silently continue if Console.Beep errors } } catch (IOException) { if (Display.ShowOutput) { PowerPing.Display.Error("General transmit error"); } Results.SaveResponseTime(-1); try { Results.Lost++; } catch (OverflowException) { Results.HasOverflowed = true; } } catch (SocketException) { PowerPing.Display.Timeout(index); if (attrs.BeepLevel == 1) { try { Console.Beep(); } catch (Exception) { Results.HasOverflowed = true; } } Results.SaveResponseTime(-1); try { Results.Lost++; } catch (OverflowException) { Results.HasOverflowed = true; } } catch (Exception) { if (Display.ShowOutput) { PowerPing.Display.Error("General error occured"); } Results.SaveResponseTime(-1); try { Results.Lost++; } catch (OverflowException) { Results.HasOverflowed = true; } } finally { // Increment seq and wait for interval index++; // Wait for set interval before sending again cancelEvent.WaitOne(attrs.Interval); // Generate random interval when RandomTimings flag is set if (attrs.RandomTiming) { attrs.Interval = Helper.RandomInt(5000, 100000); } } // Stop sending if flag is set if (!IsRunning) { break; } } // Clean up IsRunning = false; sock.Close(); return(Results); }
private void SendPacket() { byte[] receiveBuffer = new byte[m_PingAttributes.ReceiveBufferSize]; // Ipv4Header.length + IcmpHeader.length + attrs.recievebuffersize int bytesRead = 0; // Sending loop for (int index = 1; m_PingAttributes.Continous || index <= m_PingAttributes.Count; index++) { if (index != 1) { // Wait for set interval before sending again or cancel if requested if (m_CancellationToken.WaitHandle.WaitOne(m_PingAttributes.Interval)) { break; } // Generate random interval when RandomTiming flag is set if (m_PingAttributes.RandomTiming) { m_PingAttributes.Interval = Helper.RandomInt(5000, 100000); } } // Update packet before sending UpdatePacketSequenceNumber(index); if (m_PingAttributes.RandomMessage) { UpdatePacketMessage(Encoding.ASCII.GetBytes(Helper.RandomString())); } UpdatePacketChecksum(); try { // Show request packet if (Display.ShowRequests) { Display.RequestPacket(m_Packet, Display.UseInputtedAddress | Display.UseResolvedAddress ? m_PingAttributes.InputtedAddress : m_PingAttributes.ResolvedAddress, index); } // If there were extra responses from a prior request, ignore them while (m_Socket.Available != 0) { bytesRead = m_Socket.Receive(receiveBuffer); } // Send ping request m_Socket.SendTo(m_Packet.GetBytes(), m_PacketSize, SocketFlags.None, m_RemoteEndpoint); // Packet size = message field + 4 header bytes long requestTimestamp = Stopwatch.GetTimestamp(); m_PingResults.IncrementSentPackets(); // Just for artifically testing higher ping response times if (m_Debug) { Random rnd = new Random(); Thread.Sleep(rnd.Next(10, 400)); if (rnd.Next(3) == 1) { throw new SocketException(); } } // Try and recieve a packet ICMP response = null; EndPoint responseEP = m_RemoteEndpoint; TimeSpan replyTime = TimeSpan.Zero; ReceivePacket(ref response, ref responseEP, ref replyTime, ref bytesRead, requestTimestamp); if (Display.ShowReplies) { // Determine what form the response address is going to be displayed in string responseAddress = responseEP.ToString(); if (Display.UseResolvedAddress) { // Returned address normally have port at the end (eg 8.8.8.8:0) so we need to remove that before trying to query the DNS string responseIP = responseEP.ToString().Split(':')[0]; // Resolve the ip and store as the response address responseAddress = Helper.RunWithCancellationToken(() => Lookup.QueryHost(responseIP), m_CancellationToken); } else if (Display.UseInputtedAddress) { responseAddress = m_PingAttributes.InputtedAddress; } Display.ReplyPacket(response, responseAddress, index, replyTime, bytesRead); } // Store response info m_PingResults.IncrementReceivedPackets(); m_PingResults.CountPacketType(response.Type); m_PingResults.SaveResponseTime(replyTime.TotalMilliseconds); if (m_PingAttributes.BeepMode == 2) { try { Console.Beep(); } catch (Exception) { } // Silently continue if Console.Beep errors } } catch (IOException) { if (Display.ShowOutput) { Display.Error("General transmit error"); } m_PingResults.SaveResponseTime(-1); m_PingResults.IncrementLostPackets(); } catch (SocketException) { Display.Timeout(index); if (m_PingAttributes.BeepMode == 1) { try { Console.Beep(); } catch (Exception) { } } m_PingResults.SaveResponseTime(-1); m_PingResults.IncrementLostPackets(); } catch (OperationCanceledException) { m_PingResults.ScanWasCanceled = true; break; } catch (Exception) { if (Display.ShowOutput) { Display.Error("General error occured"); } m_PingResults.SaveResponseTime(-1); m_PingResults.IncrementLostPackets(); } // Run callback (if provided) to notify of updated results OnPingResultsUpdateCallback?.Invoke(m_PingResults); } }
private PingResults SendICMP(PingAttributes attrs, Action <PingResults> resultsUpdateCallback = null) { PingResults results = new PingResults(); ICMP packet = new ICMP(); byte[] receiveBuffer = new byte[attrs.RecieveBufferSize]; // Ipv4Header.length + IcmpHeader.length + attrs.recievebuffersize int bytesRead, packetSize; // Convert to IPAddress IPAddress ipAddr = IPAddress.Parse(attrs.Address); // Setup endpoint IPEndPoint iep = new IPEndPoint(ipAddr, 0); // Setup raw socket Socket sock = CreateRawSocket(ipAddr.AddressFamily); // Helper function to set receive timeout (only if it's changing) int appliedReceiveTimeout = 0; void SetReceiveTimeout(int receiveTimeout) { if (receiveTimeout != appliedReceiveTimeout) { sock.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, receiveTimeout); appliedReceiveTimeout = receiveTimeout; } } // Set socket options sock.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.IpTimeToLive, attrs.Ttl); sock.DontFragment = attrs.DontFragment; sock.ReceiveBufferSize = attrs.RecieveBufferSize; // Create packet message payload byte[] payload; if (attrs.Size != -1) { payload = Helper.GenerateByteArray(attrs.Size); } else { payload = Encoding.ASCII.GetBytes(attrs.Message); } // Construct our ICMP packet packet.Type = attrs.Type; packet.Code = attrs.Code; Buffer.BlockCopy(BitConverter.GetBytes(m_SessionId), 0, packet.Message, 0, 2); // Add identifier to ICMP message Buffer.BlockCopy(payload, 0, packet.Message, 4, payload.Length); // Add text into ICMP message packet.MessageSize = payload.Length + 4; packetSize = packet.MessageSize + 4; // Sending loop for (int index = 1; attrs.Continous || index <= attrs.Count; index++) { if (index != 1) { // Wait for set interval before sending again or cancel if requested if (m_CancellationToken.WaitHandle.WaitOne(attrs.Interval)) { break; } // Generate random interval when RandomTimings flag is set if (attrs.RandomTiming) { attrs.Interval = Helper.RandomInt(5000, 100000); } } // Include sequence number in ping message ushort sequenceNum = (ushort)index; Buffer.BlockCopy(BitConverter.GetBytes(sequenceNum), 0, packet.Message, 2, 2); // Fill ICMP message field if (attrs.RandomMsg) { payload = Encoding.ASCII.GetBytes(Helper.RandomString()); Buffer.BlockCopy(payload, 0, packet.Message, 4, payload.Length); } // Update packet checksum packet.Checksum = 0; UInt16 chksm = packet.GetChecksum(); packet.Checksum = chksm; try { // Show request packet if (Display.ShowRequests) { Display.RequestPacket(packet, Display.UseInputtedAddress | Display.UseResolvedAddress ? attrs.InputtedAddress : attrs.Address, index); } // If there were extra responses from a prior request, ignore them while (sock.Available != 0) { bytesRead = sock.Receive(receiveBuffer); } // Send ping request sock.SendTo(packet.GetBytes(), packetSize, SocketFlags.None, iep); // Packet size = message field + 4 header bytes long requestTimestamp = Stopwatch.GetTimestamp(); try { results.Sent++; } catch (OverflowException) { results.HasOverflowed = true; } if (m_Debug) { // Induce random wait for debugging Random rnd = new Random(); Thread.Sleep(scale);//rnd.Next(scale));//1500)); //Thread.Sleep(rnd.Next(100)); if (inverting) { scale -= 5; } else { scale += 5; } if (scale > 1100) { inverting = true; } else if (scale == 10) { inverting = false; } //if (rnd.Next(20) == 1) { throw new SocketException(); } } ICMP response; EndPoint responseEP = iep; TimeSpan replyTime = TimeSpan.Zero; do { // Cancel if requested m_CancellationToken.ThrowIfCancellationRequested(); // Set receive timeout, limited to 250ms so we don't block very long without checking for // cancellation. If the requested ping timeout is longer, we will wait some more in subsequent // loop iterations until the requested ping timeout is reached. int remainingTimeout = (int)Math.Ceiling(attrs.Timeout - replyTime.TotalMilliseconds); if (remainingTimeout <= 0) { throw new SocketException(); } SetReceiveTimeout(Math.Min(remainingTimeout, 250)); // Wait for response try { bytesRead = sock.ReceiveFrom(receiveBuffer, ref responseEP); } catch (SocketException) { bytesRead = 0; } replyTime = new TimeSpan(Helper.StopwatchToTimeSpanTicks(Stopwatch.GetTimestamp() - requestTimestamp)); if (bytesRead == 0) { response = null; } else { // Store reply packet response = new ICMP(receiveBuffer, bytesRead); // If we sent an echo and receive a response with a different identifier or sequence // number, ignore it (it could correspond to an older request that timed out) if (packet.Type == 8 && response.Type == 0) { ushort responseSessionId = BitConverter.ToUInt16(response.Message, 0); ushort responseSequenceNum = BitConverter.ToUInt16(response.Message, 2); if (responseSessionId != m_SessionId || responseSequenceNum != sequenceNum) { response = null; } } } } while (response == null); // Display reply packet if (Display.ShowReplies) { Display.ReplyPacket(response, Display.UseInputtedAddress | Display.UseResolvedAddress ? attrs.InputtedAddress : responseEP.ToString(), index, replyTime, bytesRead); } // Store response info try { results.Received++; } catch (OverflowException) { results.HasOverflowed = true; } results.CountPacketType(response.Type); results.SaveResponseTime(replyTime.TotalMilliseconds); if (attrs.BeepLevel == 2) { try { Console.Beep(); } catch (Exception) { } // Silently continue if Console.Beep errors } } catch (IOException) { if (Display.ShowOutput) { Display.Error("General transmit error"); } results.SaveResponseTime(-1); try { results.Lost++; } catch (OverflowException) { results.HasOverflowed = true; } } catch (SocketException) { Display.Timeout(index); if (attrs.BeepLevel == 1) { try { Console.Beep(); } catch (Exception) { results.HasOverflowed = true; } } results.SaveResponseTime(-1); try { results.Lost++; } catch (OverflowException) { results.HasOverflowed = true; } } catch (OperationCanceledException) { results.ScanWasCanceled = true; break; } catch (Exception) { if (Display.ShowOutput) { Display.Error("General error occured"); } results.SaveResponseTime(-1); try { results.Lost++; } catch (OverflowException) { results.HasOverflowed = true; } } // Run callback (if provided) to notify of updated results resultsUpdateCallback?.Invoke(results); } // Clean up sock.Close(); return(results); }