/// <summary> /// Runs the traceroute using UDP over IP version 4. /// </summary> /// <param name="localEndPoint">The local end point.</param> /// <param name="remoteEndPoint">The remote end point.</param> /// <param name="socket">The sending socket.</param> /// <param name="cancel">The cancellation token.</param> /// <param name="result">The result.</param> /// <param name="algorithm">The multipath algorithm.</param> private void RunUdpv4(IPEndPoint localEndPoint, IPEndPoint remoteEndPoint, Socket socket, CancellationToken cancel, MultipathTracerouteResult result, MultipathAlgorithm algorithm) { // The request type. MultipathTracerouteResult.RequestType requestType = MultipathTracerouteResult.RequestType.None; if ((this.settings.Algorithm & MultipathAlgorithm.UdpType & MultipathAlgorithm.UdpIdentification) != 0) { // Set the request type. requestType = requestType | MultipathTracerouteResult.RequestType.UdpIdentification; } if ((this.settings.Algorithm & MultipathAlgorithm.UdpType & MultipathAlgorithm.UdpChecksum) != 0) { // Set the request type. requestType = requestType | MultipathTracerouteResult.RequestType.UdpChecksum; } if ((this.settings.Algorithm & MultipathAlgorithm.UdpTest) != 0) { // Set the request type. requestType = MultipathTracerouteResult.RequestType.UdpBoth; } // Set the packet processing delegate lock (this.syncProcess) { if ((requestType & MultipathTracerouteResult.RequestType.UdpIdentification) != 0) this.processPacket = this.ProcessPacketUdpIdentification; else this.processPacket = this.ProcessPacketUdpChecksum; } // The data payload. byte[] data = new byte[this.settings.DataLength]; for (int index = 2; index < data.Length; index++) { data[index] = (byte)((index - 2) & 0xFF); } // Create an UDP packet. ProtoPacketUdp packetUdp = new ProtoPacketUdp(0, 0, data); // Create an IP version 4 packet. ProtoPacketIp packetIp = new ProtoPacketIp(localEndPoint.Address, remoteEndPoint.Address, packetUdp); packetIp.DifferentiatedServices = 0x80; // Begin the UDP measurements. result.Callback(MultipathTracerouteState.StateType.BeginAlgorithm, algorithm); // For each attempt. for (byte attempt = 0; attempt < settings.AttemptsPerFlow; attempt++) { // For each flow. for (byte flow = 0; flow < result.Flows.Length; flow++) { // Call the start flow handler. result.Callback(MultipathTracerouteState.StateType.BeginFlow, flow); // Set the UDP packet source port. packetUdp.SourcePort = result.Flows[flow].UdpSourcePort; // Set the UDP packet destination port. packetUdp.DestinationPort = result.Flows[flow].UdpDestinationPort; for (byte retry = 0; (retry < this.settings.MaximumRetries) && (!result.IsUdpDataComplete(flow, attempt)); retry++) { // If the retry is greater than zero, wait a random time. if (retry > 0) { // Wait before beginning the next attempt. Thread.Sleep(this.settings.RetryDelay); } // For each time-to-live. for (byte ttl = this.settings.MinimumHops; ttl <= this.settings.MaximumHops; ttl++) { // If the response was received for this flow, TTL and attempt, skip. if (result.IsUdpDataResponseReceived(flow, ttl, attempt)) continue; // Call the begin time-to-live. result.Callback(MultipathTracerouteState.StateType.BeginTtl, ttl); // Set the packet TTL. packetIp.TimeToLive = ttl; if ((requestType & MultipathTracerouteResult.RequestType.UdpIdentification) != 0) { // Set the packet identification. packetIp.Identification = (ushort)((ttl << 8) | attempt); } if ((requestType & MultipathTracerouteResult.RequestType.UdpChecksum) != 0) { // Compute the UDP data to set the checksum. ushort checksum = (ushort)((ttl << 8) | attempt); int checksumDiff = (ushort)(~checksum & 0xFFFF) + ProtoPacket.ChecksumOneComplement16Bit(data, 2, data.Length - 2, packetUdp.SourcePort, packetUdp.DestinationPort, packetUdp.Length, (ushort)((packetIp.SourceAddressBytes[0] << 8) | packetIp.SourceAddressBytes[1]), (ushort)((packetIp.SourceAddressBytes[2] << 8) | packetIp.SourceAddressBytes[3]), (ushort)((packetIp.DestinationAddressBytes[0] << 8) | packetIp.DestinationAddressBytes[1]), (ushort)((packetIp.DestinationAddressBytes[2] << 8) | packetIp.DestinationAddressBytes[3]), packetIp.Protocol, packetUdp.Length); checksumDiff = ((checksumDiff >> 16) + (checksumDiff & 0xFFFF)) & 0xFFFF; // Set the data checksum difference. data[0] = (byte)(checksumDiff >> 8); data[1] = (byte)(checksumDiff & 0xFF); } // Write the packet to the buffer. packetIp.Write(bufferSend, 0); try { // Send a packet. socket.SendTo(bufferSend, (int)packetIp.Length, SocketFlags.None, remoteEndPoint); // Add the request. MultipathTracerouteResult.RequestState state = result.AddRequest(MultipathTracerouteResult.RequestType.Udp, flow, ttl, attempt, TimeSpan.FromMilliseconds(this.settings.HopTimeout)); // Set the data. result.UdpDataRequestSent(flow, ttl, attempt, state.Timestamp); } catch { } // Call the end time-to-live. result.Callback(MultipathTracerouteState.StateType.EndTtl, ttl); } } // Call the end flow handler. result.Callback(MultipathTracerouteState.StateType.EndFlow, flow); // Wait before beginning the next attempt. Thread.Sleep(this.settings.AttemptDelay); } } // Wait for the result to complete. result.Wait.WaitOne(); // Process the result statistics. result.ProcessStatistics(MultipathTracerouteResult.ResultAlgorithm.Udp); // End the UDP measurements. result.Callback(MultipathTracerouteState.StateType.EndAlgorithm, algorithm); // Clear the packet processing delegate. lock (this.syncProcess) { this.processPacket = null; } }
/// <summary> /// Runs the traceroute using ICMP version 4. /// </summary> /// <param name="localEndPoint">The local end point.</param> /// <param name="remoteEndPoint">The remote end point.</param> /// <param name="socket">The sending socket.</param> /// <param name="cancel">The cancellation token.</param> /// <param name="result">The result.</param> private void RunIcmpv4(IPEndPoint localEndPoint, IPEndPoint remoteEndPoint, Socket socket, CancellationToken cancel, MultipathTracerouteResult result) { // Set the packet processing delegate. lock (this.syncProcess) { this.processPacket = this.ProcessPacketIcmp; } // The data payload. byte[] data = new byte[this.settings.DataLength]; for (int index = 2; index < data.Length; index++) { data[index] = (byte)((index - 2) & 0xFF); } // Create an ICMP echo request packet. ProtoPacketIcmpEchoRequest packetIcmpEchoRequest = new ProtoPacketIcmpEchoRequest(0, 0, data); // Create an IP traceroute option. //ProtoPacketIpOptionTraceroute packetIpOptionTraceroute = new ProtoPacketIpOptionTraceroute(0, 0, 0, localEndPoint.Address); // Create an IP record route option. //ProtoPacketIpOptionRecordRoute packetIpOptionRecordRoute = new ProtoPacketIpOptionRecordRoute(ProtoPacketIpOptionRecordRoute.maxSize); // Create an IP version 4 packet. ProtoPacketIp packetIp = new ProtoPacketIp(localEndPoint.Address, remoteEndPoint.Address, packetIcmpEchoRequest); // Begin the ICMP measurements. result.Callback(MultipathTracerouteState.StateType.BeginAlgorithm, MultipathAlgorithm.Icmp); // For each attempt. for (byte attempt = 0; attempt < settings.AttemptsPerFlow; attempt++) { // For each flow. for (byte flow = 0; flow < result.Flows.Length; flow++) { // Call the start flow handler. result.Callback(MultipathTracerouteState.StateType.BeginFlow, flow); // Set the ICMP packet identifier. packetIcmpEchoRequest.Identifier = result.Flows[flow].IcmpId; for (byte retry = 0; (retry < this.settings.MaximumRetries) && (!result.IsIcmpDataComplete(flow, attempt)); retry++) { // If the retry is greater than zero, wait a random time. if (retry > 0) { // Wait before beginning the next attempt. Thread.Sleep(this.settings.RetryDelay); } // For each time-to-live. for (byte ttl = this.settings.MinimumHops; ttl <= this.settings.MaximumHops; ttl++) { // If the response was received for this flow, TTL and attempt, skip. if (result.IsIcmpDataResponseReceived(flow, ttl, attempt)) continue; // Call the begin time-to-live. result.Callback(MultipathTracerouteState.StateType.BeginTtl, ttl); // Set the packet TTL. packetIp.TimeToLive = ttl; // Set the ICMP packet sequence number. packetIcmpEchoRequest.Sequence = (ushort)((ttl << 8) | attempt); // Compute the ICMP data to set the checksum. int checksumDiff = (ushort)(~result.Flows[flow].IcmpChecksum & 0xFFFF) + ProtoPacket.ChecksumOneComplement16Bit(data, 2, data.Length - 2, (ushort)((packetIcmpEchoRequest.Type << 8) | packetIcmpEchoRequest.Code), packetIcmpEchoRequest.Identifier, packetIcmpEchoRequest.Sequence); checksumDiff = ((checksumDiff >> 16) + (checksumDiff & 0xFFFF)) & 0xFFFF; // Set the data checksum difference. data[0] = (byte)(checksumDiff >> 8); data[1] = (byte)(checksumDiff & 0xFF); // Write the packet to the buffer. packetIp.Write(bufferSend, 0); try { // Send a packet. socket.SendTo(bufferSend, (int)packetIp.Length, SocketFlags.None, remoteEndPoint); // Add the request. MultipathTracerouteResult.RequestState state = result.AddRequest(MultipathTracerouteResult.RequestType.Icmp, flow, ttl, attempt, TimeSpan.FromMilliseconds(this.settings.HopTimeout)); // Set the data. result.IcmpDataRequestSent(flow, ttl, attempt, state.Timestamp); } catch { } // Call the end time-to-live. result.Callback(MultipathTracerouteState.StateType.EndTtl, ttl); } } // Call the end flow handler. result.Callback(MultipathTracerouteState.StateType.EndFlow, flow); // Wait before beginning the next attempt. Thread.Sleep(this.settings.AttemptDelay); } } // Wait for the result to complete. result.Wait.WaitOne(); // Process the result statistics. result.ProcessStatistics(MultipathTracerouteResult.ResultAlgorithm.Icmp); // End the ICMP measurements. result.Callback(MultipathTracerouteState.StateType.EndAlgorithm, MultipathAlgorithm.Icmp); // Clear the packet processing delegate. lock (this.syncProcess) { this.processPacket = null; } }