Пример #1
0
        public static async Task <IEnumerable <IPAddress> > GetFullRoute(string adr)
        {
            var ret = new List <IPAddress>();

            using (var pong = new Ping())
            {
                var       po     = new PingOptions(1, true);
                PingReply?r      = null;
                var       buffer = new byte[buffer_size];
                for (var i = 0; i < buffer.Length; i++)
                {
                    buffer[i] = 0;
                }
                for (var i = 1; i < max_hops; i++)
                {
                    if (r != null && r.Status != IPStatus.TimedOut)
                    {
                        po.Ttl = i;
                    }
                    r = await pong.SendPingAsync(adr, ping_timeout, buffer, po).ConfigureAwait(false);

                    if (r.Status == IPStatus.TtlExpired)
                    {
                        ret.Add(r.Address);
                    }
                    else
                    {
                        break;
                    }
                }
            }
            ret.Add(IPAddress.Parse(adr));
            return(ret);
        }
Пример #2
0
        private bool TryGetPingReply(
            SocketConfig socketConfig, byte[] receiveBuffer, int bytesReceived, Stopwatch sw, ref int ipHeaderLength,
            [NotNullWhen(true)] out PingReply?reply)
        {
            byte type, code;

            reply = null;

            if (socketConfig.IsIpv4)
            {
                // Determine actual size of IP header
                byte ihl = (byte)(receiveBuffer[0] & 0x0f); // Internet Header Length
                ipHeaderLength = 4 * ihl;
                if (bytesReceived - ipHeaderLength < IcmpHeaderLengthInBytes)
                {
                    return(false); // Not enough bytes to reconstruct actual IP header + ICMP header.
                }
            }

            int icmpHeaderOffset = ipHeaderLength;

            // Skip IP header.
            IcmpHeader receivedHeader = MemoryMarshal.Read <IcmpHeader>(receiveBuffer.AsSpan(icmpHeaderOffset));

            type = receivedHeader.Type;
            code = receivedHeader.Code;

            if (socketConfig.Identifier != receivedHeader.Identifier ||
                type == (byte)IcmpV4MessageType.EchoRequest ||
                type == (byte)IcmpV6MessageType.EchoRequest)    // Echo Request, ignore
            {
                return(false);
            }

            sw.Stop();
            long roundTripTime = sw.ElapsedMilliseconds;
            int  dataOffset    = ipHeaderLength + IcmpHeaderLengthInBytes;

            // We want to return a buffer with the actual data we sent out, not including the header data.
            byte[] dataBuffer = new byte[bytesReceived - dataOffset];
            Buffer.BlockCopy(receiveBuffer, dataOffset, dataBuffer, 0, dataBuffer.Length);

            IPStatus status = socketConfig.IsIpv4
                ? IcmpV4MessageConstants.MapV4TypeToIPStatus(type, code)
                : IcmpV6MessageConstants.MapV6TypeToIPStatus(type, code);

            IPAddress address = ((IPEndPoint)socketConfig.EndPoint).Address;

            reply = new PingReply(address, socketConfig.Options, status, roundTripTime, dataBuffer);
            return(true);
        }
Пример #3
0
        private async Task <(PCStatus, string)> GetStatusAsync()
        {
            PingReply?pingReply = null;

            try
            {
                if (!Uri.TryCreate(BaseAddress, UriKind.Absolute, out var baseAddressUri))
                {
                    return(PCStatus.Offline, $"Invalid URI : '{BaseAddress}'");
                }
                if (IPAddress.TryParse(baseAddressUri.Host, out var baseIpAddress))
                {
                    try
                    {
                        pingReply = pinger.Send(baseIpAddress);
                    }
                    catch (PingException ex)
                    {
                        pingReply = null;
                    }
                }

                if (pingReply != null && pingReply.Status != IPStatus.Success)
                {
                    return(PCStatus.Offline, null);
                }
                var res = await ValidatePin();

                if (res)
                {
                    return(PCStatus.ValidPIN, null);
                }
                else
                {
                    return(PCStatus.ServerOnline, null);
                }
            }
            catch (Exception ex)
            {
                var message = ex is OperationCanceledException?null: $"{ex.GetType().Name}{Environment.NewLine}{ex.Message}{Environment.NewLine}{ex.StackTrace}";
                if (pingReply == null)
                {
                    return(PCStatus.Offline, message);
                }
                else
                {
                    return(PCStatus.DeviceOnline, message);
                }
            }
        }
Пример #4
0
        private static bool TryParseTtlExceeded(string stdout, out PingReply?reply)
        {
            reply = null;
            if (!stdout.Contains("Time to live exceeded", StringComparison.Ordinal))
            {
                return(false);
            }

            // look for address in "From 172.21.64.1 icmp_seq=1 Time to live exceeded"
            int       addressStart  = stdout.IndexOf("From ", StringComparison.Ordinal) + 5;
            int       addressLength = stdout.IndexOf(' ', Math.Max(addressStart, 0)) - addressStart;
            IPAddress?address;

            if (addressStart < 5 || addressLength <= 0 || !IPAddress.TryParse(stdout.AsSpan(addressStart, addressLength), out address))
            {
                // failed to parse source address (which in case of TTL is different than the original
                // destination address), fallback to all 0
                address = new IPAddress(0);
            }

            reply = CreatePingReply(IPStatus.TimeExceeded, address);
            return(true);
        }
 internal PingCompletedEventArgs(PingReply?reply, Exception?error, bool cancelled, object?userToken) : base(error, cancelled, userToken)
 {
     Reply = reply;
 }
Пример #6
0
        private void ProcessMTUSize(string targetNameOrAddress)
        {
            PingReply?reply, replyResult = null;

            if (!TryResolveNameOrAddress(targetNameOrAddress, out string resolvedTargetName, out IPAddress? targetAddress))
            {
                if (Quiet.IsPresent)
                {
                    WriteObject(-1);
                }

                return;
            }

            // Caution! Algorithm is sensitive to changing boundary values.
            int HighMTUSize    = 10000;
            int CurrentMTUSize = 1473;
            int LowMTUSize     = targetAddress.AddressFamily == AddressFamily.InterNetworkV6 ? 1280 : 68;
            int timeout        = TimeoutSeconds * 1000;

            try
            {
                PingOptions pingOptions = new PingOptions(MaxHops, true);
                int         retry       = 1;

                while (LowMTUSize < (HighMTUSize - 1))
                {
                    byte[] buffer = GetSendBuffer(CurrentMTUSize);

                    WriteDebug(StringUtil.Format(
                                   "LowMTUSize: {0}, CurrentMTUSize: {1}, HighMTUSize: {2}",
                                   LowMTUSize,
                                   CurrentMTUSize,
                                   HighMTUSize));

                    reply = SendCancellablePing(targetAddress, timeout, buffer, pingOptions);

                    if (reply.Status == IPStatus.PacketTooBig || reply.Status == IPStatus.TimedOut)
                    {
                        HighMTUSize = CurrentMTUSize;
                        retry       = 1;
                    }
                    else if (reply.Status == IPStatus.Success)
                    {
                        LowMTUSize  = CurrentMTUSize;
                        replyResult = reply;
                        retry       = 1;
                    }
                    else
                    {
                        // If the host didn't reply, try again up to the 'Count' value.
                        if (retry >= Count)
                        {
                            string message = StringUtil.Format(
                                TestConnectionResources.NoPingResult,
                                targetAddress,
                                reply.Status.ToString());
                            Exception   pingException = new PingException(message);
                            ErrorRecord errorRecord   = new ErrorRecord(
                                pingException,
                                TestConnectionExceptionId,
                                ErrorCategory.ResourceUnavailable,
                                targetAddress);
                            WriteError(errorRecord);
                            return;
                        }
                        else
                        {
                            retry++;
                            continue;
                        }
                    }

                    CurrentMTUSize = (LowMTUSize + HighMTUSize) / 2;

                    // Prevent DoS attack.
                    Thread.Sleep(100);
                }
            }
            catch (PingException ex)
            {
                string      message       = StringUtil.Format(TestConnectionResources.NoPingResult, targetAddress, ex.Message);
                Exception   pingException = new PingException(message, ex.InnerException);
                ErrorRecord errorRecord   = new ErrorRecord(
                    pingException,
                    TestConnectionExceptionId,
                    ErrorCategory.ResourceUnavailable,
                    targetAddress);
                WriteError(errorRecord);
                return;
            }

            if (Quiet.IsPresent)
            {
                WriteObject(CurrentMTUSize);
            }
            else
            {
                WriteObject(new PingMtuStatus(
                                Source,
                                resolvedTargetName,
                                replyResult ?? throw new ArgumentNullException(nameof(replyResult)),
                                CurrentMTUSize));
            }
        }
Пример #7
0
        private bool TryGetPingReply(
            SocketConfig socketConfig, byte[] receiveBuffer, int bytesReceived, Stopwatch sw, ref int ipHeaderLength,
            [NotNullWhen(true)] out PingReply?reply)
        {
            byte type, code;

            reply = null;

            if (socketConfig.IsIpv4)
            {
                // Determine actual size of IP header
                byte ihl = (byte)(receiveBuffer[0] & 0x0f); // Internet Header Length
                ipHeaderLength = 4 * ihl;
                if (bytesReceived - ipHeaderLength < IcmpHeaderLengthInBytes)
                {
                    return(false); // Not enough bytes to reconstruct actual IP header + ICMP header.
                }
            }

            int icmpHeaderOffset = ipHeaderLength;
            int dataOffset       = ipHeaderLength + IcmpHeaderLengthInBytes;

            // Skip IP header.
            IcmpHeader receivedHeader = MemoryMarshal.Read <IcmpHeader>(receiveBuffer.AsSpan(icmpHeaderOffset));
            ushort     identifier     = 0;

            type = receivedHeader.Type;
            code = receivedHeader.Code;

            // Validate the ICMP header and get the identifier
            if (socketConfig.IsIpv4)
            {
                if (type == (byte)IcmpV4MessageType.EchoReply)
                {
                    // Reply packet has the identifier in the ICMP header.
                    identifier = receivedHeader.Identifier;
                }
                else if (type == (byte)IcmpV4MessageType.DestinationUnreachable ||
                         type == (byte)IcmpV4MessageType.TimeExceeded ||
                         type == (byte)IcmpV4MessageType.ParameterProblemBadIPHeader ||
                         type == (byte)IcmpV4MessageType.SourceQuench ||
                         type == (byte)IcmpV4MessageType.RedirectMessage)
                {
                    // Original IP+ICMP request is in the payload. Read the ICMP header from
                    // the payload to get identifier.

                    if (dataOffset + MinIpHeaderLengthInBytes + IcmpHeaderLengthInBytes > bytesReceived)
                    {
                        return(false);
                    }

                    byte ihl = (byte)(receiveBuffer[dataOffset] & 0x0f); // Internet Header Length
                    int  payloadIpHeaderLength = 4 * ihl;

                    if (bytesReceived - dataOffset - payloadIpHeaderLength < IcmpHeaderLengthInBytes)
                    {
                        return(false); // Not enough bytes to reconstruct actual IP header + ICMP header.
                    }

                    IcmpHeader originalRequestHeader = MemoryMarshal.Read <IcmpHeader>(receiveBuffer.AsSpan(dataOffset + payloadIpHeaderLength));
                    identifier = originalRequestHeader.Identifier;

                    // Update the date offset to point past the payload IP+ICMP headers. While the specification
                    // doesn't indicate there should be any additional data the reality is that we often get the
                    // original packet data back.
                    dataOffset += payloadIpHeaderLength + IcmpHeaderLengthInBytes;
                }
                else
                {
                    return(false);
                }
            }
            else
            {
                if (type == (byte)IcmpV6MessageType.EchoReply)
                {
                    // Reply packet has the identifier in the ICMP header.
                    identifier = receivedHeader.Identifier;
                }
                else if (type == (byte)IcmpV6MessageType.DestinationUnreachable ||
                         type == (byte)IcmpV6MessageType.TimeExceeded ||
                         type == (byte)IcmpV6MessageType.ParameterProblem ||
                         type == (byte)IcmpV6MessageType.PacketTooBig)
                {
                    // Original IP+ICMP request is in the payload. Read the ICMP header from
                    // the payload to get identifier.

                    if (bytesReceived - dataOffset < IpV6HeaderLengthInBytes + IcmpHeaderLengthInBytes)
                    {
                        return(false); // Not enough bytes to reconstruct actual IP header + ICMP header.
                    }

                    IcmpHeader originalRequestHeader = MemoryMarshal.Read <IcmpHeader>(receiveBuffer.AsSpan(dataOffset + IpV6HeaderLengthInBytes));
                    identifier = originalRequestHeader.Identifier;

                    // Update the date offset to point past the payload IP+ICMP headers. While the specification
                    // doesn't indicate there should be any additional data the reality is that we often get the
                    // original packet data back.
                    dataOffset += IpV6HeaderLengthInBytes + IcmpHeaderLengthInBytes;
                }
                else
                {
                    return(false);
                }
            }

            if (socketConfig.Identifier != identifier)
            {
                return(false);
            }

            sw.Stop();
            long roundTripTime = sw.ElapsedMilliseconds;

            // We want to return a buffer with the actual data we sent out, not including the header data.
            byte[] dataBuffer = new byte[bytesReceived - dataOffset];
            Buffer.BlockCopy(receiveBuffer, dataOffset, dataBuffer, 0, dataBuffer.Length);

            IPStatus status = socketConfig.IsIpv4
                ? IcmpV4MessageConstants.MapV4TypeToIPStatus(type, code)
                : IcmpV6MessageConstants.MapV6TypeToIPStatus(type, code);

            IPAddress address = ((IPEndPoint)socketConfig.EndPoint).Address;

            reply = new PingReply(address, socketConfig.Options, status, roundTripTime, dataBuffer);
            return(true);
        }