Inheritance: AProtocolHeader
Exemple #1
0
        private static unsafe byte[] CreateSendMessageBuffer(IpHeader ipHeader, IcmpHeader icmpHeader, byte[] payload)
        {
            int icmpHeaderSize = sizeof(IcmpHeader);
            int offset         = 0;
            int packetSize     = ipHeader.TotalLength != 0 ? ipHeader.TotalLength : checked (icmpHeaderSize + payload.Length);

            byte[] result = new byte[packetSize];

            if (ipHeader.TotalLength != 0)
            {
                int ipHeaderSize = sizeof(IpHeader);
                new Span <byte>(&ipHeader, sizeof(IpHeader)).CopyTo(result);
                offset = ipHeaderSize;
            }

            //byte[] result = new byte[headerSize + payload.Length];
            Marshal.Copy(new IntPtr(&icmpHeader), result, offset, icmpHeaderSize);
            payload.CopyTo(result, offset + icmpHeaderSize);

            // offset now still points to beginning of ICMP header.
            ushort checksum = ComputeBufferChecksum(result.AsSpan(offset));

            // Jam the checksum into the buffer.
            result[offset + 2] = (byte)(checksum >> 8);
            result[offset + 3] = (byte)(checksum & (0xFF));

            return(result);
        }
Exemple #2
0
        private SocketConfig GetSocketConfig(IPAddress address, byte[] buffer, int timeout, PingOptions options)
        {
            SocketConfig config = new SocketConfig();

            config.EndPoint = new IPEndPoint(address, 0);
            config.Timeout  = timeout;
            config.Options  = options;

            config.IsIpv4       = address.AddressFamily == AddressFamily.InterNetwork;
            config.ProtocolType = config.IsIpv4 ? ProtocolType.Icmp : ProtocolType.IcmpV6;

            // Use a random value as the identifier. This doesn't need to be perfectly random
            // or very unpredictable, rather just good enough to avoid unexpected conflicts.
            Random rand = t_idGenerator ?? (t_idGenerator = new Random());

            config.Identifier = (ushort)rand.Next((int)ushort.MaxValue + 1);

            IcmpHeader header = new IcmpHeader()
            {
                Type           = config.IsIpv4 ? (byte)IcmpV4MessageType.EchoRequest : (byte)IcmpV6MessageType.EchoRequest,
                Code           = 0,
                HeaderChecksum = 0,
                Identifier     = config.Identifier,
                SequenceNumber = 0,
            };

            config.SendBuffer = CreateSendMessageBuffer(header, buffer);
            return(config);
        }
Exemple #3
0
            // ctor
            public IcmpEchoRequest(ref IcmpHeader hdr, byte[] !msgData)
            {
                header = hdr;

                // set the data
                data = new byte[msgData.Length];
                Array.Copy(msgData, 0, data, 0, msgData.Length);
            }
    private DateTime pingSentTime;         // Timestamp of when ping request was sent

    /// <summary>
    /// Base constructor that initializes the member variables to default values. It also
    /// creates the events used and initializes the async callback function.
    /// </summary>
    public RawSocketPing()
    {
        pingSocket         = null;
        pingTtl            = 8;
        pingPayloadLength  = 8;
        pingSequence       = 0;
        pingReceiveTimeout = 2000;
        destEndPoint       = new IPEndPoint(IPAddress.Loopback, 0);
        icmpHeader         = null;
    }
Exemple #5
0
        // construct an ICMP header from a packet
        public static bool ReadIcmpHeader(IBuffer !buf, out IcmpHeader hdr)
        {
            bool b;

            b  = buf.Read8(out hdr.type);
            b &= buf.Read8(out hdr.code);
            b &= buf.ReadNet16(out hdr.chksum);
            b &= buf.ReadNet16(out hdr.id);
            b &= buf.ReadNet16(out hdr.seq);
            return(b);
        }
Exemple #6
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);
        }
        public IcmpDisplayPacket(IpV4Header ipHeader, IcmpHeader icmpHeader)
        {
            Destination = ipHeader.DestinationAddress;
            //DestinationPort = udpHeader.DestinationPort;
            Source = ipHeader.SourceAddress;
            //SourcePort = udpHeader.SourcePort;
            Type  = ipHeader.ProtocolType;
            Flags = icmpHeader.Flags;
            StringBuilder retVal = new StringBuilder();

            AppendIcmp(icmpHeader, retVal);
            AppendIPInfo(ipHeader, retVal);
            Data = retVal.ToString();
        }
Exemple #8
0
        // write common ICMP header
        // (ignores the checksum field, notice that the checksum is
        //  calculated for the whole packet!)
        public static int WriteIcmpHeader(byte[] !pkt, int offset, ref IcmpHeader hdr)
        {
            int o = offset;

            pkt[o++] = hdr.type;
            pkt[o++] = hdr.code;
            pkt[o++] = 0;
            pkt[o++] = 0;
            pkt[o++] = (byte)(hdr.id >> 8);
            pkt[o++] = (byte)hdr.id;
            pkt[o++] = (byte)(hdr.seq >> 8);
            pkt[o++] = (byte)hdr.seq;

            return(o);
        }
Exemple #9
0
        private static unsafe byte[] CreateSendMessageBuffer(IcmpHeader header, byte[] payload)
        {
            int headerSize = sizeof(IcmpHeader);

            byte[] result = new byte[headerSize + payload.Length];
            Marshal.Copy(new IntPtr(&header), result, 0, headerSize);
            payload.CopyTo(result, headerSize);
            ushort checksum = ComputeBufferChecksum(result);

            // Jam the checksum into the buffer.
            result[2] = (byte)(checksum >> 8);
            result[3] = (byte)(checksum & (0xFF));

            return(result);
        }
Exemple #10
0
        public ManualResetEvent pingDoneEvent;             // Event to indicate all outstanding receives are done
                                                           //    this ping class can be disposed

        /// <summary>
        /// Base constructor that initializes the member variables to default values. It also
        /// creates the events used and initializes the async callback function.
        /// </summary>
        public RawSocketPing()
        {
            pingSocket              = null;
            pingFamily              = AddressFamily.InterNetwork;
            pingTtl                 = 8;
            pingPayloadLength       = 8;
            pingSequence            = 0;
            pingReceiveTimeout      = 4000;
            pingOutstandingReceives = 0;
            destEndPoint            = new IPEndPoint(IPAddress.Loopback, 0);
            protocolHeaderList      = new ArrayList();
            pingReceiveEvent        = new ManualResetEvent(false);
            pingDoneEvent           = new ManualResetEvent(false);
            receiveCallback         = new AsyncCallback(PingReceiveCallback);
            icmpHeader              = null;
            icmpv6Header            = null;
            icmpv6EchoRequestHeader = null;
        }
    /// <summary>
    /// This routine builds the appropriate ICMP echo packet depending on the
    /// protocol family requested.
    /// </summary>
    public void BuildPingPacket()
    {
        // Initialize the socket if it hasn't already been done

        if (pingSocket == null)
        {
            InitializeSocket();
        }
        // Create the ICMP header and initialize the members
        icmpHeader = new IcmpHeader()
        {
            Id = pingId, Sequence = pingSequence, Type = IcmpHeader.EchoRequestType, Code = IcmpHeader.EchoRequestCode
        };
        // Build the data payload of the ICMP echo request

        pingPayload = new byte[pingPayloadLength];
        for (int i = 0; i < pingPayload.Length; i++)
        {
            pingPayload[i] = (byte)'e';
        }
    }
            /// <summary>
            /// This routine creates an instance of the IcmpHeader class from a byte
            /// array that is a received IGMP packet. This is useful when a packet
            /// is received from the network and the header object needs to be
            /// constructed from those values.
            /// </summary>
            /// <param name="icmpPacket">Byte array containing the binary ICMP header</param>
            /// <param name="bytesCopied">Number of bytes used in header</param>
            /// <returns>Returns the IcmpHeader object created from the byte array</returns>
            static public IcmpHeader Create(byte[] icmpPacket, ref int bytesCopied)
            {
                IcmpHeader icmpHeader = new IcmpHeader();
                int        offset     = 0;

                // Make sure byte array is large enough to contain an ICMP header
                if (icmpPacket.Length < IcmpHeader.IcmpHeaderLength)
                {
                    return(null);
                }

                icmpHeader.icmpType     = icmpPacket[offset++];
                icmpHeader.icmpCode     = icmpPacket[offset++];
                icmpHeader.icmpChecksum = BitConverter.ToUInt16(icmpPacket, offset);
                offset                 += 2;
                icmpHeader.icmpId       = BitConverter.ToUInt16(icmpPacket, offset);
                offset                 += 2;
                icmpHeader.icmpSequence = BitConverter.ToUInt16(icmpPacket, offset);
                bytesCopied             = IcmpHeader.IcmpHeaderLength;
                return(icmpHeader);
            }
Exemple #13
0
        /// <summary>
        /// This routine builds the appropriate ICMP echo packet depending on the
        /// protocol family requested.
        /// </summary>
        public void BuildPingPacket()
        {
            // Initialize the socket if it hasn't already been done
            Console.WriteLine("Building the ping packet...");
            Console.WriteLine("Initializing the socket if not done yet...");

            if (pingSocket == null)
            {
                InitializeSocket();
            }

            // Clear any existing headers in the list
            Console.WriteLine("Clearing any existing headers in the list using Clear()...");
            protocolHeaderList.Clear();

            if (destEndPoint.AddressFamily == AddressFamily.InterNetwork)
            {
                // Create the ICMP header and initialize the members
                Console.WriteLine("Creating the ICMP header and initialize the members...");
                icmpHeader = new IcmpHeader();

                icmpHeader.Id       = pingId;
                icmpHeader.Sequence = pingSequence;
                icmpHeader.Type     = IcmpHeader.EchoRequestType;
                icmpHeader.Code     = IcmpHeader.EchoRequestCode;

                // Build the data payload of the ICMP echo request
                Console.WriteLine("Building the data payload of the ICMP echo request...");
                pingPayload = new byte[pingPayloadLength];

                for (int i = 0; i < pingPayload.Length; i++)
                {
                    pingPayload[i] = (byte)'e';
                }

                // Add ICMP header to the list of headers
                Console.WriteLine("Adding ICMP header to the list of headers using Add()...");
                protocolHeaderList.Add(icmpHeader);
            }
            else if (destEndPoint.AddressFamily == AddressFamily.InterNetworkV6)
            {
                Ipv6Header ipv6Header;     // Required for pseudo header checksum
                IPEndPoint localInterface;
                byte[]     localAddressBytes = new byte[28];

                Console.WriteLine("This part is for IPv6...");
                // An IPv6 header is required since the IPv6 protocol specifies that the
                //    pseudo header checksum needs to be calculated on ICMPv6 packets which
                //    requires the source and destination address that will appear in the
                //    IPv6 packet.
                ipv6Header = new Ipv6Header();

                // We definitely know the destination IPv6 address but the stack will
                //    choose the "appropriate" local v6 interface depending on the
                //    routing table which may be different than the address we bound
                //    the socket to. Because of this we will call the Winsock ioctl
                //    SIO_ROUTING_INTERFACE_QUERY which will return the local interface
                //    for a given destination address by querying the routing table.
                Console.WriteLine("Implementing the IOControl()...");
                pingSocket.IOControl(
                    WinsockIoctl.SIO_ROUTING_INTERFACE_QUERY,
                    SockaddrConvert.GetSockaddrBytes(destEndPoint),
                    localAddressBytes
                    );

                localInterface = SockaddrConvert.GetEndPoint(localAddressBytes);

                // Fill out the fields of the IPv6 header used in the pseudo-header checksum calculation
                Console.WriteLine("Filling out the IPv6 header fields...");
                ipv6Header.SourceAddress      = localInterface.Address;
                ipv6Header.DestinationAddress = destEndPoint.Address;
                ipv6Header.NextHeader         = 58; // IPPROTO_ICMP6

                // Initialize the ICMPv6 header
                Console.WriteLine("Initializing the ICMPv6 header...");
                icmpv6Header      = new Icmpv6Header(ipv6Header);
                icmpv6Header.Type = Icmpv6Header.Icmpv6EchoRequestType;
                icmpv6Header.Code = Icmpv6Header.Icmpv6EchoRequestCode;

                // Initialize the payload
                Console.WriteLine("Initializing the payload...");
                pingPayload = new byte[pingPayloadLength];

                for (int i = 0; i < pingPayload.Length; i++)
                {
                    pingPayload[i] = (byte)'e';
                }

                // Create the ICMPv6 echo request header
                Console.WriteLine("Creating the ICMPv6 echo request header...");
                icmpv6EchoRequestHeader    = new Icmpv6EchoRequest();
                icmpv6EchoRequestHeader.Id = pingId;

                // Add the headers to the protocol header list
                Console.WriteLine("Adding the headers to the protocol header list...");
                protocolHeaderList.Add(icmpv6Header);
                protocolHeaderList.Add(icmpv6EchoRequestHeader);
            }
        }
 private void AppendIcmp(IcmpHeader icmpHeader, StringBuilder retVal)
 {
     retVal.AppendFormat("[*ICMP* Header:{0}, ", icmpHeader.Header);
     retVal.AppendFormat("Code:{0},", icmpHeader.Code);
     retVal.AppendFormat("Type:{0}] ", icmpHeader.Type);
 }
Exemple #15
0
        private async Task <PingReply> SendIcmpEchoRequestOverRawSocket(IPAddress address, byte[] buffer, int timeout, PingOptions options)
        {
            EndPoint endPoint = new IPEndPoint(address, 0);

            bool         isIpv4       = address.AddressFamily == AddressFamily.InterNetwork;
            ProtocolType protocolType = isIpv4 ? ProtocolType.Icmp : ProtocolType.IcmpV6;
            // Use the current thread's ID as the identifier.
            ushort     identifier = (ushort)Environment.CurrentManagedThreadId;
            IcmpHeader header     = new IcmpHeader()
            {
                Type           = isIpv4 ? (byte)IcmpV4MessageType.EchoRequest : (byte)IcmpV6MessageType.EchoRequest,
                Code           = 0,
                HeaderChecksum = 0,
                Identifier     = identifier,
                SequenceNumber = 0,
            };

            byte[] sendBuffer = CreateSendMessageBuffer(header, buffer);

            using (Socket socket = new Socket(address.AddressFamily, SocketType.Raw, protocolType))
            {
                socket.ReceiveTimeout = timeout;
                socket.SendTimeout    = timeout;
                // Setting Socket.DontFragment and .Ttl is not supported on Unix, so ignore the PingOptions parameter.

                int ipHeaderLength = isIpv4 ? IpHeaderLengthInBytes : 0;
                await socket.SendToAsync(new ArraySegment <byte>(sendBuffer), SocketFlags.None, endPoint).ConfigureAwait(false);

                byte[] receiveBuffer = new byte[ipHeaderLength + IcmpHeaderLengthInBytes + buffer.Length];

                long      elapsed;
                Stopwatch sw = Stopwatch.StartNew();
                // Read from the socket in a loop. We may receive messages that are not echo replies, or that are not in response
                // to the echo request we just sent. We need to filter such messages out, and continue reading until our timeout.
                // For example, when pinging the local host, we need to filter out our own echo requests that the socket reads.
                while ((elapsed = sw.ElapsedMilliseconds) < timeout)
                {
                    Task <SocketReceiveFromResult> receiveTask = socket.ReceiveFromAsync(
                        new ArraySegment <byte>(receiveBuffer),
                        SocketFlags.None,
                        endPoint);
                    var  cts      = new CancellationTokenSource();
                    Task finished = await Task.WhenAny(receiveTask, Task.Delay(timeout - (int)elapsed, cts.Token)).ConfigureAwait(false);

                    cts.Cancel();
                    if (finished != receiveTask)
                    {
                        sw.Stop();
                        return(CreateTimedOutPingReply());
                    }

                    SocketReceiveFromResult receiveResult = receiveTask.GetAwaiter().GetResult();
                    int bytesReceived = receiveResult.ReceivedBytes;
                    if (bytesReceived - ipHeaderLength < IcmpHeaderLengthInBytes)
                    {
                        continue; // Not enough bytes to reconstruct IP header + ICMP header.
                    }

                    byte type, code;
                    unsafe
                    {
                        fixed(byte *bytesPtr = receiveBuffer)
                        {
                            int        icmpHeaderOffset = ipHeaderLength;
                            IcmpHeader receivedHeader   = *((IcmpHeader *)(bytesPtr + icmpHeaderOffset)); // Skip IP header.

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

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

                    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 = isIpv4
                                        ? IcmpV4MessageConstants.MapV4TypeToIPStatus(type, code)
                                        : IcmpV6MessageConstants.MapV6TypeToIPStatus(type, code);

                    return(new PingReply(address, options, status, roundTripTime, dataBuffer));
                }

                // We have exceeded our timeout duration, and no reply has been received.
                sw.Stop();
                return(CreateTimedOutPingReply());
            }
        }
Exemple #16
0
        private async Task<PingReply> SendIcmpEchoRequestOverRawSocket(IPAddress address, byte[] buffer, int timeout, PingOptions options)
        {
            EndPoint endPoint = new IPEndPoint(address, 0);

            bool isIpv4 = address.AddressFamily == AddressFamily.InterNetwork;
            ProtocolType protocolType = isIpv4 ? ProtocolType.Icmp : ProtocolType.IcmpV6;
            // Use the current thread's ID as the identifier.
            ushort identifier = (ushort)Environment.CurrentManagedThreadId;
            IcmpHeader header = new IcmpHeader()
            {
                Type = isIpv4 ? (byte)IcmpV4MessageType.EchoRequest : (byte)IcmpV6MessageType.EchoRequest,
                Code = 0,
                HeaderChecksum = 0,
                Identifier = identifier,
                SequenceNumber = 0,
            };

            byte[] sendBuffer = CreateSendMessageBuffer(header, buffer);

            using (Socket socket = new Socket(address.AddressFamily, SocketType.Raw, protocolType))
            {
                socket.ReceiveTimeout = timeout;
                socket.SendTimeout = timeout;
                // Setting Socket.DontFragment and .Ttl is not supported on Unix, so ignore the PingOptions parameter.

                int ipHeaderLength = isIpv4 ? IpHeaderLengthInBytes : 0;
                await socket.SendToAsync(new ArraySegment<byte>(sendBuffer), SocketFlags.None, endPoint).ConfigureAwait(false);
                byte[] receiveBuffer = new byte[ipHeaderLength + IcmpHeaderLengthInBytes + buffer.Length];

                long elapsed;
                Stopwatch sw = Stopwatch.StartNew();
                // Read from the socket in a loop. We may receive messages that are not echo replies, or that are not in response
                // to the echo request we just sent. We need to filter such messages out, and continue reading until our timeout.
                // For example, when pinging the local host, we need to filter out our own echo requests that the socket reads.
                while ((elapsed = sw.ElapsedMilliseconds) < timeout)
                {
                    Task<SocketReceiveFromResult> receiveTask = socket.ReceiveFromAsync(
                                                                    new ArraySegment<byte>(receiveBuffer),
                                                                    SocketFlags.None,
                                                                    endPoint);
                    var cts = new CancellationTokenSource();
                    Task finished = await Task.WhenAny(receiveTask, Task.Delay(timeout - (int)elapsed, cts.Token)).ConfigureAwait(false);
                    cts.Cancel();
                    if (finished != receiveTask)
                    {
                        sw.Stop();
                        return CreateTimedOutPingReply();
                    }

                    SocketReceiveFromResult receiveResult = receiveTask.GetAwaiter().GetResult();
                    int bytesReceived = receiveResult.ReceivedBytes;
                    if (bytesReceived - ipHeaderLength < IcmpHeaderLengthInBytes)
                    {
                        continue; // Not enough bytes to reconstruct IP header + ICMP header.
                    }

                    byte type, code;
                    unsafe
                    {
                        fixed (byte* bytesPtr = receiveBuffer)
                        {
                            int icmpHeaderOffset = ipHeaderLength;
                            IcmpHeader receivedHeader = *((IcmpHeader*)(bytesPtr + icmpHeaderOffset)); // Skip IP header.
                            type = receivedHeader.Type;
                            code = receivedHeader.Code;

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

                    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];
                    Array.Copy(receiveBuffer, dataOffset, dataBuffer, 0, dataBuffer.Length);

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

                    return new PingReply(address, options, status, roundTripTime, dataBuffer);
                }

                // We have exceeded our timeout duration, and no reply has been received.
                sw.Stop();
                return CreateTimedOutPingReply();
            }
        }
Exemple #17
0
        private static unsafe byte[] CreateSendMessageBuffer(IcmpHeader header, byte[] payload)
        {
            int headerSize = sizeof(IcmpHeader);
            byte[] result = new byte[headerSize + payload.Length];
            Marshal.Copy(new IntPtr(&header), result, 0, headerSize);
            payload.CopyTo(result, headerSize);
            ushort checksum = ComputeBufferChecksum(result);
            // Jam the checksum into the buffer.
            result[2] = (byte)(checksum >> 8);
            result[3] = (byte)(checksum & (0xFF));

            return result;
        }
Exemple #18
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);
        }
Exemple #19
0
    /// <summary>
    /// This routine creates an instance of the IcmpHeader class from a byte
    /// array that is a received IGMP packet. This is useful when a packet
    /// is received from the network and the header object needs to be
    /// constructed from those values.
    /// </summary>
    /// <param name="icmpPacket">Byte array containing the binary ICMP header</param>
    /// <param name="bytesCopied">Number of bytes used in header</param>
    /// <returns>Returns the IcmpHeader object created from the byte array</returns>
    public static IcmpHeader Create(byte[] icmpPacket, ref int bytesCopied)
    {
        IcmpHeader icmpHeader = new IcmpHeader();
        int offset = 0;

        // Make sure byte array is large enough to contain an ICMP header
        if (icmpPacket.Length < IcmpHeader.IcmpHeaderLength)
            return null;

        icmpHeader.icmpType = icmpPacket[offset++];
        icmpHeader.icmpCode = icmpPacket[offset++];
        icmpHeader.icmpChecksum = BitConverter.ToUInt16(icmpPacket, offset);
        offset += 2;
        icmpHeader.icmpId = BitConverter.ToUInt16(icmpPacket, offset);
        offset += 2;
        icmpHeader.icmpSequence = BitConverter.ToUInt16(icmpPacket, offset);
        bytesCopied = IcmpHeader.IcmpHeaderLength;
        return icmpHeader;
    }
        public static void WireguardTest()
        {
            var protocol = new Protocol(
                HandshakePattern.IK,
                CipherFunction.ChaChaPoly,
                HashFunction.Blake2s,
                PatternModifiers.Psk2
                );
            var buffer     = new byte[Protocol.MaxMessageLength];
            var buffer2    = new byte[Protocol.MaxMessageLength];
            int bufferRead = 0;

            using (var hs = protocol.Create(true,
                                            new ReadOnlySpan <byte>(Encoding.UTF8.GetBytes("WireGuard v1 zx2c4 [email protected]")),
                                            OurPrivate,
                                            TheirPublic,
                                            new byte[][] { Preshared }))
            {
                var now    = DateTimeOffset.UtcNow; //replace with Noda.Time?
                var tai64n = new byte[12];
                (4611686018427387914ul + (ulong)now.ToUnixTimeSeconds()).ToBigEndian(tai64n);
                ((uint)(now.Millisecond * 1e6)).ToBigEndian(tai64n, 8);

                var initiationPacket = new List <byte> {
                    1, 0, 0, 0
                };                                                              //type initiation
                initiationPacket.AddRange(((uint)28).ToLittleEndian());         //sender, random 4byte

                var(bytesWritten, _, _) = hs.WriteMessage(tai64n, buffer);
                initiationPacket.AddRange(buffer.Take(bytesWritten));           // should be 24byte, ephemeral, static, timestamp

                var hasher   = Blake2s.CreateIncrementalHasher(32);
                var hashThis = Encoding.UTF8.GetBytes("mac1----").Concat(TheirPublic).ToArray();
                hasher.Update(hashThis);
                var finishedHash = hasher.Finish();
                hasher   = Blake2s.CreateIncrementalHasher(16, finishedHash);
                hashThis = initiationPacket.ToArray();
                hasher.Update(hashThis);

                finishedHash = hasher.Finish();
                initiationPacket.AddRange(finishedHash);                        //mac1
                initiationPacket.AddRange(Enumerable.Repeat((byte)0, 16));      //mac2 = zeros if no cookie last received


                var socket         = new DatagramSocket();
                var responsePacket = new TaskCompletionSource <int>();
                var autoResetEvent = new AutoResetEvent(false);
                socket.MessageReceived += (sender, args) =>
                {
                    bufferRead = args.GetDataStream().AsStreamForRead().Read(buffer);
                    autoResetEvent.Set();
                };
                socket.ConnectAsync(new HostName("demo.wireguard.com"), "12913").AsTask().Wait();
                var streamWriter = new BinaryWriter(socket.OutputStream.AsStreamForWrite());
                streamWriter.Write(initiationPacket.ToArray());
                streamWriter.Flush();

                var successful = autoResetEvent.WaitOne(5000);
                if (!successful)
                {
                    return;
                }

                if (buffer[0] != 2)   //type init response
                {
                    return;           //"response packet type wrong: want %d, got %d"
                }
                if (bufferRead != 92) //always this length! for type=2
                {
                    return;           //"response packet too short: want %d, got %d"
                }
                if (buffer[1] != 0 || buffer[2] != 0 || buffer[3] != 0)
                {
                    return; //"response packet has non-zero reserved fields"
                }
                var theirIndex = buffer.LittleEndianToUInt32(4);
                var ourIndex   = buffer.LittleEndianToUInt32(8);
                if (ourIndex != 28)
                {
                    return; //log.Fatalf("response packet index wrong: want %d, got %d", 28, ourIndex)
                }
                var span = new Span <byte>(buffer);
                var(bytesRead, handshakeHash, transport) = hs.ReadMessage(span.Slice(12, 48),
                                                                          span.Slice(100)); //write on same buffer behind the received package (which
                if (bytesRead != 0)
                {
                    return; //"unexpected payload: %x"
                }
                var icmpHeader = new IcmpHeader()
                {
                    Type = 8, Id = 921, Sequence = 438
                };
                var pingMessage = icmpHeader.GetProtocolPacketBytes(Encoding.UTF8.GetBytes("WireGuard"));
                var pingHeader  = new Ipv4Header()
                {
                    Version            = 4, Length = 20, TotalLength = (ushort)(20 + pingMessage.Length),
                    Protocol           = 1, Ttl = 20,
                    SourceAddress      = new IPAddress(new byte[] { 10, 189, 129, 2 }),
                    DestinationAddress = new IPAddress(new byte[] { 10, 189, 129, 1 })
                }.GetProtocolPacketBytes(new byte[0]);


                span[0] = 4;
                span.Slice(1, 3).Assign((byte)0);
                theirIndex.ToLittleEndian(buffer, 4);
                0L.ToLittleEndian(buffer, 8);                                                        //this is the counter, little endian u64
                bytesWritten = transport.WriteMessage(
                    pingHeader.Concat(pingMessage).Concat(Enumerable.Repeat((byte)0, 11)).ToArray(), //pad message with 0 to make mod 16=0
                    span.Slice(16));

                //using (var streamWriter = new BinaryWriter(socket.OutputStream.AsStreamForWrite()))
                streamWriter.Write(span.Slice(0, 16 + bytesWritten).ToArray());
                streamWriter.Flush();
                successful = autoResetEvent.WaitOne(5000);
                if (!successful)
                {
                    return;
                }

                if (buffer[0] != 4)
                {
                    return;//"response packet type wrong: want %d, got %d"
                }
                if (buffer[1] != 0 || buffer[2] != 0 || buffer[3] != 0)
                {
                    return; //"response packet has non-zero reserved fields"
                }
                var replyPacket = buffer2.AsSpan(0, transport.ReadMessage(span.Slice(16, bufferRead - 16), buffer2));
                if (replyPacket.Length != 48)
                {
                    return;
                }

                var replyHeaderLen     = ((int)(replyPacket[0] & 0x0f)) << 2;
                var replyLen           = buffer2.BigEndianToUInt16(2);
                var our_index_received = buffer.LittleEndianToUInt32(4);
                if (our_index_received != 28)
                {
                    return;
                }
                var nonce = buffer2.LittleEndianToUInt64(8);
                //if (nonce != 0)//not parsed correctly?
                //    return;
                var replyMessage = IcmpHeader.Create(buffer2.AsSpan(replyHeaderLen, replyLen - replyHeaderLen).ToArray(), ref bytesRead);
                if (replyMessage.Type != 0 || replyMessage.Code != 0)
                {
                    return;
                }
                if (replyMessage.Id != 921 || replyMessage.Sequence != 438)
                {
                    return;
                }
                var replyPayload = Encoding.UTF8.GetString(buffer2.AsSpan(replyLen - replyHeaderLen + bytesRead, replyHeaderLen - bytesRead));
                if (replyPayload != "WireGuard") //trim necessary?
                {
                    return;
                }
            }
        }
Exemple #21
0
        /// <summary>
        /// This is the asynchronous callback that is fired when an async ReceiveFrom.
        /// An asynchronous ReceiveFrom is posted by calling BeginReceiveFrom. When this
        /// function is invoked, it calculates the elapsed time between when the ping
        /// packet was sent and when it was completed.
        /// </summary>
        /// <param name="ar">Asynchronous context for operation that completed</param>
        static void PingReceiveCallback(IAsyncResult ar)
        {
            RawSocketPing rawSock = (RawSocketPing)ar.AsyncState;
            TimeSpan      elapsedTime;
            int           bytesReceived = 0;
            ushort        receivedId    = 0;

            try
            {
                // Keep a count of how many async operations are outstanding -- one just completed
                //    so decrement the count.
                Interlocked.Decrement(ref rawSock.pingOutstandingReceives);

                // If we're done because ping is exiting and the socket has been closed,
                //    set the done event
                if (rawSock.pingSocket == null)
                {
                    if (rawSock.pingOutstandingReceives == 0)
                    {
                        rawSock.pingDoneEvent.Set();
                    }
                    return;
                }

                // Complete the receive op by calling EndReceiveFrom. This will return the number
                //    of bytes received as well as the source address of who sent this packet.
                bytesReceived = rawSock.pingSocket.EndReceiveFrom(ar, ref rawSock.castResponseEndPoint);

                // Calculate the elapsed time from when the ping request was sent and a response was
                //    received.
                elapsedTime = DateTime.Now - rawSock.pingSentTime;

                rawSock.responseEndPoint = (IPEndPoint)rawSock.castResponseEndPoint;

                // Here we unwrap the data received back into the respective protocol headers such
                //    that we can find the ICMP ID in the ICMP or ICMPv6 packet to verify that
                //    the echo response we received was really a response to our request.
                if (rawSock.pingSocket.AddressFamily == AddressFamily.InterNetwork)
                {
                    Ipv4Header v4Header;
                    IcmpHeader icmpv4Header;
                    byte[]     pktIcmp;
                    int        offset = 0;

                    // Remember, raw IPv4 sockets will return the IPv4 header along with all
                    //    subsequent protocol headers
                    v4Header = Ipv4Header.Create(rawSock.receiveBuffer, ref offset);
                    pktIcmp  = new byte[bytesReceived - offset];
                    Array.Copy(rawSock.receiveBuffer, offset, pktIcmp, 0, pktIcmp.Length);
                    icmpv4Header = IcmpHeader.Create(pktIcmp, ref offset);

                    /*Console.WriteLine("Icmp.Id = {0}; Icmp.Sequence = {1}",
                     *  icmpv4Header.Id,
                     *  icmpv4Header.Sequence
                     *  );*/

                    receivedId = icmpv4Header.Id;
                }
                else if (rawSock.pingSocket.AddressFamily == AddressFamily.InterNetworkV6)
                {
                    Icmpv6Header      icmp6Header;
                    Icmpv6EchoRequest echoHeader;
                    byte[]            pktEchoRequest;
                    int offset = 0;

                    // For IPv6 raw sockets, the IPv6 header is never returned along with the
                    //    data received -- the received data always starts with the header
                    //    following the IPv6 header.
                    icmp6Header    = Icmpv6Header.Create(rawSock.receiveBuffer, ref offset);
                    pktEchoRequest = new byte[bytesReceived - offset];
                    Array.Copy(rawSock.receiveBuffer, offset, pktEchoRequest, 0, pktEchoRequest.Length);
                    echoHeader = Icmpv6EchoRequest.Create(pktEchoRequest, ref offset);

                    /*Console.WriteLine("Icmpv6.Id = {0}; Icmp.Sequence = {1}",
                     *  echoHeader.Id,
                     *  echoHeader.Sequence
                     *  );*/

                    receivedId = echoHeader.Id;
                }

                if (receivedId == rawSock.pingId)
                {
                    string elapsedString;

                    // Print out the usual statistics for ping
                    if (elapsedTime.Milliseconds < 1)
                    {
                        elapsedString = "<1";
                    }
                    else
                    {
                        elapsedString = "=" + elapsedTime.Milliseconds.ToString();
                    }

                    Console.WriteLine("Reply from {0}: byte={1} time{2}ms TTL={3} ",
                                      rawSock.responseEndPoint.Address.ToString(),
                                      bytesReceived,
                                      elapsedString,
                                      rawSock.pingTtl
                                      );
                }

                // Post another async receive if the count indicates for us to do so.
                if (rawSock.pingCount > 0)
                {
                    rawSock.pingSocket.BeginReceiveFrom(
                        rawSock.receiveBuffer,
                        0,
                        rawSock.receiveBuffer.Length,
                        SocketFlags.None,
                        ref rawSock.castResponseEndPoint,
                        rawSock.receiveCallback,
                        rawSock
                        );

                    // Keep track of outstanding async operations
                    Interlocked.Increment(ref rawSock.pingOutstandingReceives);
                }
                else
                {
                    // If we're done then set the done event
                    if (rawSock.pingOutstandingReceives == 0)
                    {
                        rawSock.pingDoneEvent.Set();
                    }
                }
                // If this is indeed the response to our echo request then signal the main thread
                //    that we received the response so it can send additional echo requests if
                //    necessary. This is done after another async ReceiveFrom is already posted.
                if (receivedId == rawSock.pingId)
                {
                    rawSock.pingReceiveEvent.Set();
                }
            }
            catch (SocketException err)
            {
                Console.WriteLine("Socket error occurred in async callback: {0}", err.Message);
            }
        }
Exemple #22
0
        /// <summary>
        /// This function parses the incoming packets and extracts the data based upon
        /// the protocol being carried by the IP datagram.
        /// </summary>
        /// <param name="byteData">Incoming bytes</param>
        /// <param name="nReceived">The number of bytes received</param>
        private IPDisplayPacket GetDisplayPacket(IpV4Header ipHeader)
        {
            IPDisplayPacket retVal;

            // Since all protocol packets are encapsulated in the IP datagram
            // so we start by parsing the IP header and see what protocol data
            // is being carried by it.
            // Now according to the protocol being carried by the IP datagram we parse
            // the data field of the datagram.
            switch (ipHeader.ProtocolType)
            {
            case Protocol.TCP:
            {
                TcpHeader tcpHeader = new TcpHeader(ipHeader.Data, ipHeader.MessageLength);
                retVal = new TCPDisplayPacket(ipHeader, tcpHeader);
            }
            break;

            case Protocol.UDP:
            {
                UdpHeader udpHeader = new UdpHeader(ipHeader.Data, (int)ipHeader.MessageLength);
                retVal = new UDPDisplayPacket(ipHeader, udpHeader);
            }
            break;

            case Protocol.ICMP:
            {
                IcmpHeader icmpHeader = new IcmpHeader(ipHeader.Data, (int)ipHeader.MessageLength);
                retVal = new IcmpDisplayPacket(ipHeader, icmpHeader);
            }
            break;

            case Protocol.IGMP:
            {
                IgmpHeader igmpHeader = new IgmpHeader(ipHeader.Data, (int)ipHeader.MessageLength);
                retVal = new IgmpDisplayPacket(ipHeader, igmpHeader);
            }
            break;

            case Protocol.DCCP:
            {
                DCCPHeader icmpHeader = new DCCPHeader(ipHeader.Data, (int)ipHeader.MessageLength);
                retVal = new DCCPDisplayPacket(ipHeader, icmpHeader);
            }
            break;

            case Protocol.EIGRP:
            {
                EIGRPHeader icmpHeader = new EIGRPHeader(ipHeader.Data, (int)ipHeader.MessageLength);
                retVal = new EIGRPDisplayPacket(ipHeader, icmpHeader);
            }
            break;

            case Protocol.GREs:
            {
                GREHeader icmpHeader = new GREHeader(ipHeader.Data, (int)ipHeader.MessageLength);
                retVal = new GREDisplayPacket(ipHeader, icmpHeader);
            }
            break;

            case Protocol.OSPF:
            {
                OSPFHeader icmpHeader = new OSPFHeader(ipHeader.Data, (int)ipHeader.MessageLength);
                retVal = new OSPFDisplayPacket(ipHeader, icmpHeader);
            }
            break;

            default:
            case Protocol.Unknown:
                retVal = new IPDisplayPacket(ipHeader);
                break;
            }
            return(retVal);
        }