5
\$\begingroup\$

this is my code for watching IP packets. I am doing project for my self because I want to learn how this things works.

This is my IP Packet class:

public class IPPacket
{

    private IPHeader _ipHeader;
    private TCPHeader _tcpHeader;
    private UDPHeader _udpHeader;

    public IPPacket(IPHeader ipHeader, TCPHeader tcpHeader, UDPHeader udpHeader)
    {
        _ipHeader = ipHeader;
        _tcpHeader = tcpHeader;
        _udpHeader = udpHeader;
    }

    public static IPPacket ParseData(byte[] bytes)
    {

        var ipHeader = new IPHeader(bytes);
        UDPHeader udpHeader = null;
        TCPHeader tcpHeader = null;

        switch (ipHeader.Protocol)
        {
            case System.Net.Sockets.ProtocolType.Tcp:
                tcpHeader = new TCPHeader(ipHeader.Data);
                break;

            case System.Net.Sockets.ProtocolType.Udp:
                udpHeader = new UDPHeader(ipHeader.Data);
                break;
            default:
                if (Debugger.IsAttached) Debugger.Break();
                break;
        }

        return new IPPacket(ipHeader, tcpHeader, udpHeader);

    }

}

IP Header class:

// 0                   1                   2                   3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//|Version|  IHL  |Type of Service|       Total Length            |
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//|     Identification            |  Flags | Fragment offset      |
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//|Time to live | Protocol        |         Header checksum       | 
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//|                         Source IP address                     |
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//|                     Destination IP address                    |
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//|                     Options                     | Padding     |
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

public class IPHeader
{
    public byte Version { get; set; }
    public ushort IHL { get; set; }
    public byte DifferentiatedServices { get; set; }
    public ushort TotalLength { get; set; }
    public ushort Identification { get; set; }
    public Flags Flags { get; set; }
    public ushort FragmentOffset { get; set; }
    public byte TimeToLive { get; set; }
    public ProtocolType Protocol { get; set; }
    public string HeaderChecksum { get; set; }
    public IPAddress SourceIPAddress { get; set; }
    public IPAddress DestinationIPAddress { get; set; }
    public byte[] Data { get; set; }

    public IPHeader(byte[] bytes)
    {
        Version = (byte)((bytes[0] >> 4) & 0x0F); //0000XXXX & 0000FFFF
        IHL = (ushort)((bytes[0] & 0x0F) * 4);
        DifferentiatedServices = bytes[1];
        TotalLength = (ushort)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(bytes, 2));
        Identification = (ushort)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(bytes, 4));
        Flags = new Flags(bytes[6]);
        FragmentOffset = (ushort)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(bytes, 6) << 3);
        TimeToLive = bytes[8];
        Protocol = (ProtocolType)bytes[9];
        HeaderChecksum = string.Format("0x{0:x2}", IPAddress.NetworkToHostOrder(BitConverter.ToInt16(bytes, 10)));
        SourceIPAddress = new IPAddress(BitConverter.ToInt32(bytes, 12));
        DestinationIPAddress = new IPAddress(BitConverter.ToInt32(bytes, 16));
        Data = new byte[TotalLength - IHL];
        Array.Copy(bytes, IHL, Data, 0, TotalLength - IHL);
    }
}

public class Flags
{
    public bool Reserved { get; set; }
    public bool DontFragment { get; set; }
    public bool MoreFragments { get; set; }

    public Flags(byte flags)
    {
        Reserved = Convert.ToBoolean((flags >> 7) & 0x01);
        DontFragment = Convert.ToBoolean((flags >> 6) & 0x01);
        MoreFragments = Convert.ToBoolean((flags >> 5) & 0x01);
    }
}

TCP Header class:

// 0                   1                   2                   3   
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//|          Source Port          |       Destination Port        |
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//|                        Sequence Number                        |
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//|                    Acknowledgment Number                      |
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//|  Data |           |U|A|P|R|S|F|                               |
//| Offset| Reserved  |R|C|S|S|Y|I|            Window             |
//|       |           |G|K|H|T|N|N|                               |
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//|           Checksum            |         Urgent Pointer        |
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//|                    Options                    |    Padding    |
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//|                             data                              |
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

public class TCPHeader
{
    public ushort SourcePort { get; set; }
    public ushort DestinationPort { get; set; }
    public uint SequenceNumber { get; set; }
    public uint AcknowledgmentNumber { get; set; }
    public byte DataOffset { get; set; }
    public byte Reserved { get; set; }
    public ControlBits ControlBits { get; set; }
    public ushort Window { get; set; }
    public string Checksum { get; set; }
    public ushort UrgentPointer { get; set; }
    public byte[] Data { get; set; }

    public TCPHeader(byte[] bytes)
    {
        SourcePort = (ushort)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(bytes, 0));
        DestinationPort = (ushort)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(bytes, 2));
        SequenceNumber = (uint)IPAddress.NetworkToHostOrder(BitConverter.ToInt32(bytes, 4));
        AcknowledgmentNumber = (uint)IPAddress.NetworkToHostOrder(BitConverter.ToInt32(bytes, 8));
        DataOffset = (byte)((bytes[9] >> 4) & 0x0F);
        Reserved = 0;
        ControlBits = new ControlBits(bytes[13]);
        Window = (ushort)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(bytes, 14));
        Checksum = string.Format("0x{0:x2}", (ushort)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(bytes, 16)));
        UrgentPointer = (ushort)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(bytes, 18));
        Data = new byte[bytes.Length - 20];
        Array.Copy(bytes, 20, Data, 0, bytes.Length - 20);
    }
}

public class ControlBits
{
    public bool URG { get; set; }
    public bool ACK { get; set; }
    public bool PSH { get; set; }
    public bool RST { get; set; }
    public bool SYN { get; set; }
    public bool FIN { get; set; }

    public ControlBits(byte controlBits)
    {
        URG = Convert.ToBoolean(controlBits >> 5 & 0x01);
        ACK = Convert.ToBoolean(controlBits >> 4 & 0x01);
        PSH = Convert.ToBoolean(controlBits >> 3 & 0x01);
        RST = Convert.ToBoolean(controlBits >> 2 & 0x01);
        SYN = Convert.ToBoolean(controlBits >> 1 & 0x01);
        FIN = Convert.ToBoolean(controlBits  & 0x01);
    }
}

UDP Header class:

// 0      7 8     15 16    23 24    31  
//+--------+--------+--------+--------+ 
//|     Source      |   Destination   | 
//|      Port       |      Port       | 
//+--------+--------+--------+--------+ 
//|                 |                 | 
//|     Length      |    Checksum     | 
//+--------+--------+--------+--------+ 
//|                                     
//|          data octets...
//+---------------- ...                 

public class UDPHeader
{
    public ushort SourcePort { get; set; }
    public ushort DestinationPort { get; set; }
    public ushort Length { get; set; }
    public ushort Checksum { get; set; }
    public byte[] Data { get; set; }

    public UDPHeader(byte[] bytes)
    {
        SourcePort = (ushort)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(bytes, 0));
        DestinationPort = (ushort)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(bytes, 2));
        Length = (ushort)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(bytes, 4));
        Checksum = (ushort)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(bytes, 6));
        Data = new byte[Length - 8];
        Array.Copy(bytes, 8, Data, 0, Length - 8);
    }
}

Can you give some advice what seems bad code practice? And one more thing how would be best to define TCP and UDP header inside IP packet, because one packet can have TCP header second can have UDP header.

\$\endgroup\$
1

2 Answers 2

2
\$\begingroup\$

I would rename IPPacket to PacketParser, and then create an IPacketParser interface that defines the parse method, but make it a regular method, not static.

Then, I would create a TcpPacketParser class and a UdpPacketParser class, which would eliminate the need for your switch logic within the parse method, thus there would be no need to return the IPPacket object. It's good to reduce cyclomatic complexity.

You'll probably want some way to access the parsed data, but I'm not sure what your use cases would be.

\$\endgroup\$
1
  • \$\begingroup\$ But this parse methods from TcpPacketParser and UdpPacketParser should return TCPHeader or UDPHeader object or should be void method? \$\endgroup\$
    – TJacken
    Commented Nov 25, 2019 at 21:08
1
\$\begingroup\$

I improved my code and now I made console application for tracking IP packets. I tracked IP packets with Wireshark and got same result.

IPPacket class now contains IPHeader and ProtocolHeader data. UDPHeader and TCPHeader class inherit abstract ProtocolHeader class, I added method ParseProtocolData which return UDPHeader or TCPHeader depending on protocol type inside IP header.

public class IPPacket
{

    private IPHeader ipHeader;
    private ProtocolHeader protocolHeader;

    public IPPacket(IPHeader ipHeader, ProtocolHeader protocolHeader)
    {
        this.ipHeader = ipHeader;
        this.protocolHeader = protocolHeader;
    }

    public static IPPacket ParseData(byte[] bytes)
    {

        var ipHeader = new IPHeader(bytes);
        var protocolHeader = ParseProtocolData(ipHeader.Data, ipHeader.Protocol);

        return new IPPacket(ipHeader, protocolHeader);
    }

    public static ProtocolHeader ParseProtocolData(byte[] bytes, ProtocolType protocolType)
    {
        switch (protocolType)
        {
            case ProtocolType.Tcp:
                return new TCPHeader(bytes);
            case ProtocolType.Udp:
                return new UDPHeader(bytes);
            default:
                return null;
        }
    }

    public override string ToString()
    {
        return $"---------------------- IP Packet ---------------------- \n" +
               $"{this.ipHeader.ToString()} \n" +
               $"{this.protocolHeader.ToString()} \n" +
               $"-------------------------------------------------------";
    }

}

IPheader class:

// 0                   1                   2                   3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//|Version|  IHL  |Type of Service|       Total Length            |
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//|     Identification            |  Flags | Fragment offset      |
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//|Time to live | Protocol        |         Header checksum       | 
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//|                         Source IP address                     |
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//|                     Destination IP address                    |
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//|                     Options                     | Padding     |
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
public class IPHeader
{
    public byte Version { get; set; }
    public ushort IHL { get; set; }
    public byte DifferentiatedServices { get; set; }
    public ushort TotalLength { get; set; }
    public ushort Identification { get; set; }
    public Flags Flags { get; set; }
    public ushort FragmentOffset { get; set; }
    public byte TimeToLive { get; set; }
    public ProtocolType Protocol { get; set; }
    public string HeaderChecksum { get; set; }
    public IPAddress SourceIPAddress { get; set; }
    public IPAddress DestinationIPAddress { get; set; }
    public byte[] Data { get; set; }

    public IPHeader(byte[] bytes)
    {
        Version = (byte)((bytes[0] >> 4) & 0x0F); //0000XXXX & 0000FFFF
        IHL = (ushort)((bytes[0] & 0x0F) * 4);
        DifferentiatedServices = bytes[1];
        TotalLength = (ushort)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(bytes, 2));
        Identification = (ushort)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(bytes, 4));
        Flags = new Flags(bytes[6]);
        FragmentOffset = (ushort)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(bytes, 6) << 3);
        TimeToLive = bytes[8];
        Protocol = (ProtocolType)bytes[9];
        HeaderChecksum = string.Format("0x{0:x2}", IPAddress.NetworkToHostOrder(BitConverter.ToInt16(bytes, 10)));
        SourceIPAddress = new IPAddress(BitConverter.ToUInt32(bytes, 12));
        DestinationIPAddress = new IPAddress(BitConverter.ToUInt32(bytes, 16));
        Data = new byte[TotalLength - IHL];
        Array.Copy(bytes, IHL, Data, 0, TotalLength - IHL);
    }

    public override string ToString()
    {
        return $"Version: {Version} \n" +
               $"Header Length: {IHL} \n" +
               $"Differentiated services: {DifferentiatedServices} \n" +
               $"Total length: {TotalLength} \n" +
               $"Identification: {string.Format("0x{0:x2}", Identification)} ({Identification}) \n" +
               $"Flags: {Flags} \n" +
               $"Fragment offset: {FragmentOffset} \n" +
               $"Time to live: {TimeToLive} \n" +
               $"Protocol : {Protocol} \n" +
               $"Header checksum: {HeaderChecksum} \n" +
               $"Source IP address: {SourceIPAddress} \n" +
               $"Destination IP address: {DestinationIPAddress}";
    }
}

public class Flags
{
    public bool Reserved { get; set; }
    public bool DontFragment { get; set; }
    public bool MoreFragments { get; set; }

    public Flags(byte flags)
    {
        Reserved = Convert.ToBoolean((flags >> 7) & 0x01);
        DontFragment = Convert.ToBoolean((flags >> 6) & 0x01);
        MoreFragments = Convert.ToBoolean((flags >> 5) & 0x01);
    }

    public override string ToString()
    {
        return $"\n" +
               $"   -- Reserved: {(Reserved ? "Set" : "Not set")} \n" +
               $"   -- Dont fragment: {(DontFragment ? "Set" : "Not set")} \n" +
               $"   -- More fragments: {(MoreFragments ? "Set" : "Not set")}";

    }
}

I made abstract class ProtocolHeader because IP packet can contain TCP or UDP segment depends on Protocol Type inside IPheader.

public abstract class ProtocolHeader
{
    public uint SourcePort { get; set; }
    public uint DestinationPort { get; set; }
}

TCP Header class:

// 0                   1                   2                   3   
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//|          Source Port          |       Destination Port        |
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//|                        Sequence Number                        |
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//|                    Acknowledgment Number                      |
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//|  Data |           |U|A|P|R|S|F|                               |
//| Offset| Reserved  |R|C|S|S|Y|I|            Window             |
//|       |           |G|K|H|T|N|N|                               |
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//|           Checksum            |         Urgent Pointer        |
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//|                    Options                    |    Padding    |
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//|                             data                              |
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

public class TCPHeader : ProtocolHeader
{
    public uint SequenceNumber { get; set; }
    public uint AcknowledgmentNumber { get; set; }
    public byte DataOffset { get; set; }
    public byte Reserved { get; set; }
    public ControlBits ControlBits { get; set; }
    public ushort Window { get; set; }
    public string Checksum { get; set; }
    public ushort UrgentPointer { get; set; }
    public byte[] Data { get; set; }

    public TCPHeader(byte[] bytes)
    {
        SourcePort = (ushort)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(bytes, 0));
        DestinationPort = (ushort)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(bytes, 2));
        SequenceNumber = (uint)IPAddress.NetworkToHostOrder(BitConverter.ToInt32(bytes, 4));
        AcknowledgmentNumber = (uint)IPAddress.NetworkToHostOrder(BitConverter.ToInt32(bytes, 8));
        DataOffset = (byte)((bytes[9] >> 4) & 0x0F);
        Reserved = 0;
        ControlBits = new ControlBits(bytes[13]);
        Window = (ushort)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(bytes, 14));
        Checksum = string.Format("0x{0:x2}", (ushort)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(bytes, 16)));
        UrgentPointer = (ushort)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(bytes, 18));
        Data = new byte[bytes.Length - 20];
        Array.Copy(bytes, 20, Data, 0, bytes.Length - 20);
    }

    public override string ToString()
    {
        return $"   Transmision control protocol \n" +
               $"   -- Source port: {SourcePort} \n" +
               $"   -- Destination port: {DestinationPort} \n" +
               $"   -- Sequence number: {SequenceNumber} \n" +
               $"   -- Acknowledgment number: {AcknowledgmentNumber} \n" +
               $"   -- Dataoffset: {DataOffset} \n" +
               $"   -- Reserved: {Reserved} \n" +
               $"   -- Control bits: {ControlBits} \n" +
               $"   -- Window: {Window} \n" +
               $"   -- Checksum: {Checksum} \n" +
               $"   -- Urgent pointer: {UrgentPointer}";
    }
}

public class ControlBits
{
    public bool URG { get; set; }
    public bool ACK { get; set; }
    public bool PSH { get; set; }
    public bool RST { get; set; }
    public bool SYN { get; set; }
    public bool FIN { get; set; }

    public ControlBits(byte controlBits)
    {
        URG = Convert.ToBoolean(controlBits >> 5 & 0x01);
        ACK = Convert.ToBoolean(controlBits >> 4 & 0x01);
        PSH = Convert.ToBoolean(controlBits >> 3 & 0x01);
        RST = Convert.ToBoolean(controlBits >> 2 & 0x01);
        SYN = Convert.ToBoolean(controlBits >> 1 & 0x01);
        FIN = Convert.ToBoolean(controlBits  & 0x01);
    }

    public override string ToString()
    {
        return $"URG: {URG} \n" +
               $"ACK: {ACK} \n" +
               $"PSH: {PSH} \n" +
               $"RST: {RST} \n" +
               $"SYN: {SYN} \n" +
               $"FIN: {FIN}";
    }
}

UDPHeader class:

// 0      7 8     15 16    23 24    31  
//+--------+--------+--------+--------+ 
//|     Source      |   Destination   | 
//|      Port       |      Port       | 
//+--------+--------+--------+--------+ 
//|                 |                 | 
//|     Length      |    Checksum     | 
//+--------+--------+--------+--------+ 
//|                                     
//|          data octets...
//+---------------- ...                 

public class UDPHeader : ProtocolHeader
{
    public ushort Length { get; set; }
    public ushort Checksum { get; set; }
    public byte[] Data { get; set; }

    public UDPHeader(byte[] bytes)
    {
        SourcePort = (ushort)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(bytes, 0));
        DestinationPort = (ushort)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(bytes, 2));
        Length = (ushort)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(bytes, 4));
        Checksum = (ushort)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(bytes, 6));
        Data = new byte[bytes.Length - 8];
        Array.Copy(bytes, 8, Data, 0, bytes.Length - 8);
    }

    public override string ToString()
    {
        return $"   User datagram protocol \n" +
               $"   -- Source port: {SourcePort} \n" + 
               $"   -- Destination port: {DestinationPort} \n" +
               $"   -- Length: {Length} \n" +
               $"   -- Checksum: {Checksum} \n" +
               $"   -- Data: {ASCIIEncoding.ASCII.GetString(Data)}";
    }
}

Implementation of main method:

class Program
{
    private static Socket socket;
    private static byte[] buffer = new byte[4096];
    static void Main(string[] args)
    {

        try
        {

            if(!NetworkInterface.GetIsNetworkAvailable())
            {
                Console.WriteLine("Network is not available.");
            }
            else
            {
                var address = NetworkInterface.GetAllNetworkInterfaces()
                                              .AsEnumerable()
                                              .Where(i => (i.NetworkInterfaceType == NetworkInterfaceType.Wireless80211 ||
                                                           i.NetworkInterfaceType == NetworkInterfaceType.Ethernet) && 
                                                           i.OperationalStatus == OperationalStatus.Up)
                                              .SelectMany(i => i.GetIPProperties().UnicastAddresses)
                                              .Where(a => a.Address.AddressFamily == AddressFamily.InterNetwork)
                                              .Select(a => a.Address.ToString())
                                              .ToList();
                int counter = 0;

                if(address != null)
                {
                    Console.WriteLine("Please choose address for tracking IP packets: (Enter address number.)");
                }

                foreach (var addr in address)
                {
                    Console.WriteLine($"Number [{counter}] Addres: {addr}");
                    counter++;
                }

                int.TryParse(Console.ReadLine(), out counter);

                socket = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.IP);

                socket.Bind(new IPEndPoint(IPAddress.Parse(address[counter]), 0));
                socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.HeaderIncluded, true);

                byte[] byTrue = new byte[4] { 1, 0, 0, 0 };
                byte[] byOut = new byte[4];

                socket.IOControl(IOControlCode.ReceiveAll, byTrue, byOut);

                socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(OnRecieve), null);

            }

            Console.ReadLine();

        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }

    }

    public static void OnRecieve(IAsyncResult ar)
    {

        try
        {

            int recv = socket.EndReceive(ar);
            byte[] buf = new byte[recv];

            Array.Copy(buffer, buf, recv);

            IPPacket ipPacket = IPPacket.ParseData(buf);

            Console.WriteLine(ipPacket.ToString());

            socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(OnRecieve), null);

        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }

    }
}

Could you give me advice now after I improved my code and gave whole picture how tracking program should work?

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.