예제 #1
0
        private unsafe byte[] ConstructIP6Packet(
            byte ipversion,
            ushort trafficclass,
            uint flowlabel,
            ulong source_address1,
            ulong source_address2,
            ulong destination_address1,
            ulong destination_address2,
            byte[] data
            )
        {
            int size = (data?.Length ?? 0);

            if (size % 8 != 0)
            {
                size += 8 - (size % 8);
            }
            byte[] ret = new byte[size + sizeof(IPv6Header)];

            IPv6Header header = new IPv6Header();
            ushort     temp   = Utility.htons((ushort)((ipversion << 4) + trafficclass));

            header.version_ltc     = (byte)(temp >> 8);
            header.htc_lfl         = (byte)((temp & 0xff) + (flowlabel >> 8));
            header.flow_label      = (ushort)(flowlabel & 0xff);
            header.payload_length  = Utility.htons((ushort)(size / 8));
            header.next_header     = 0;
            header.hop_limit       = 60;
            header.source_address1 = Utility.htonq(source_address1);
            header.source_address2 = Utility.htonq(source_address2);
            header.dest_address1   = Utility.htonq(destination_address1);
            header.dest_address2   = Utility.htonq(destination_address2);

            // todo: what about custom headers?

            IntPtr ptr = IntPtr.Zero;

            try
            {
                ptr = Marshal.AllocHGlobal(sizeof(IPv6Header));
                Marshal.StructureToPtr(header, ptr, true);
                Marshal.Copy(ptr, ret, 0, sizeof(IPv6Header));
            }
            finally
            {
                if (ptr != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(ptr);
                }
            }
            if ((data?.Length ?? 0) > 0)
            {
                Array.Copy(data, 0, ret, sizeof(IPv6Header), data.Length);
            }

            return(ret);
        }
예제 #2
0
        async void SendTask()
        {
            while (true)
            {
                if (sendbuf.Count > 0)
                {
                    var payload = sendbuf.Dequeue();

                    GREHeader outhead = new GREHeader {
                        flags_ver = 0, protocol = payload.Type
                    };

                    //TODO: callback to print packet now? maybe another task?
                    switch (payload.Type)
                    {
                    case 0x86dd:
                        var v6outHeader = IPv6Header.FromBytes(payload.Data, 0);
                        Console.WriteLine($"Type: {v6outHeader.nextHeader} Payload: {v6outHeader.payloadLen} From: {v6outHeader.source} To: {v6outHeader.dest}");
                        break;

                    case 0x0800:
                        var v4outHeader = IPv4Header.FromBytes(payload.Data, 0);
                        Console.WriteLine($"Type: {v4outHeader.protocol} Size: {v4outHeader.totalLen} From: {v4outHeader.source} To: {v4outHeader.dest}");
                        break;

                    case 0x88B5:    // code for private experimentation
                        Console.WriteLine($"FCP");
                        break;

                    default:
                        Console.WriteLine($"GRE Invalid Type: 0x{payload.Type:x4} {payload.Data.Length} bytes");
                        break;
                    }

                    var packet = new List <ArraySegment <byte> > {
                        new ArraySegment <byte>(outhead.ToBytes()),
                        new ArraySegment <byte>(payload.Data)
                    };

                    await Task.Factory.FromAsync(
                        (callback, state) =>
                        gresock.BeginSend(packet, SocketFlags.None,
                                          callback, state)
                        ,
                        gresock.EndSend, null);
                }
                else
                {
                    //TODO: better way to wait for new packets?
                    await Task.Delay(1);
                }
            }
        }
예제 #3
0
        PackedFrame packet_to_circuit(byte[] buffer, int startAt, int size)
        {
            var frame = new List <VarInt>();

            frame.Add(1);                    // firstsignal = 1 we start at the beginning of the map...
            frame.Add(((size + 3) / 4) + 2); // sigcount = enough signals to hold all the bytes plus two for feathernet header...

            frame.Add(0);                    // grey = broadcast / placeholder for feathernet dest
            frame.Add(1);                    // white = 1 to mark feathernet map

            int i;

            for (i = startAt; i < startAt + size; i += 4)
            {
                Int32 nextword = ((buffer[i] << 24) | (buffer[i + 1] << 16) | (buffer[i + 2] << 8) | (buffer[i + 3]));
                // clear tail bytes if last word...
                if ((startAt + size) - i < 4)
                {
                    nextword = (Int32)(nextword & (0xffffffff << ((4 - ((startAt + size) - i)) * 8)));
                }

                frame.Add(nextword);
            }

            // add a world-id to be consistent with other clusterio traffic
            VarInt srcid = ID;



            var    head = IPv6Header.FromBytes(buffer, startAt);
            var    ipdest = head.dest;
            VarInt dstid, featherdst;

            if (ipdest.IsIPv6Multicast)
            {
                dstid      = 0xffffffff;
                featherdst = 0;
            }
            else
            {
                var ipdestbytes = ipdest.GetAddressBytes();
                dstid      = ((ipdestbytes[8] << 24) | (ipdestbytes[9] << 16) | (ipdestbytes[10] << 8) | (ipdestbytes[11]));
                featherdst = ((ipdestbytes[12] << 24) | (ipdestbytes[13] << 16) | (ipdestbytes[14] << 8) | (ipdestbytes[15]));
            }

            frame[2] = featherdst;

            return(new PackedFrame(dstid, srcid, frame, Feathernet_0_16));
        }
예제 #4
0
        static void Main(string[] args)
        {
            Console.CancelKeyPress += delegate { _running = false; };

            // open handle
            using (var handle = Diversion.WinDivertOpen("true", WinDivertLayer.Network, 100, 0))
            {
                if (handle.IsInvalid)
                {
                    Console.WriteLine("Unable to open handle. Error: " + Marshal.GetLastWin32Error());
                    return;
                }

                // prepare headers
                var ipHeader     = new IPHeader();
                var ipv6Header   = new IPv6Header();
                var icmpHeader   = new ICMPHeader();
                var icmpv6Header = new ICMPv6Header();
                var tcpHeader    = new TCPHeader();
                var udpHeader    = new UDPHeader();

                var    address = new Address();
                byte[] buffer  = new byte[65535];

                uint receiveLength = 0;
                uint sendLength    = 0;

                string processName;
                uint   pid = 0;

                // loop
                while (_running)
                {
                    pid = 0;
                }
                receiveLength = 0;
                sendLength    = 0;

                fixed(byte *data = buffer)
                {
                    Diversion.WinDivertHelperParsePacket(data, receiveLength, ipHeader, ipv6Header, icmpHeader,
                                                         icmpv6Header, tcpHeader, udpHeader, null, null);
                }
            }
        }
예제 #5
0
        void ReceivedBytes(byte[] rcvbuf)
        {
            // convert to signals and OnRecieve()
            switch (rcvbuf[0] >> 4)
            {
            case 4:
                var v4Header = IPv4Header.FromBytes(rcvbuf, 0);
                if (v4Header.protocol != 47)
                {
                    break;                              // only GRE... this should be handled by socket, but just to be sure...
                }
                if (v4Header.headLen != 5)
                {
                    break;                            // don't currently handle any options
                }
                var GRE4Header = GREHeader.FromBytes(rcvbuf, (v4Header.headLen * 4));
                if (GRE4Header.flags_ver != 0)
                {
                    break;                                // don't support any GRE flags, version is always 0
                }
                // convert inner to json for clusterio and submit... for now we only have v6 inner
                switch (GRE4Header.protocol)
                {
                case 0x86dd:
                    var v6inHeader = IPv6Header.FromBytes(rcvbuf, ((v4Header.headLen + 1) * 4));
                    Console.WriteLine($"Type: {v6inHeader.nextHeader} Payload: {v6inHeader.payloadLen} From: {v6inHeader.source} To: {v6inHeader.dest}");
                    if (v6inHeader.payloadLen + 40 <= ((Feathernet_0_16.Count - 2) * 4))
                    {
                        if (v6inHeader.nextHeader == 44)
                        {
                            Console.WriteLine("Fragmented packet dropped");
                        }
                        else
                        {
                            var circpacket = packet_to_circuit(rcvbuf, ((v4Header.headLen + 1) * 4), v6inHeader.totalLen).Unpack();
                            circpacket.origin = this;
                            OnReceive?.Invoke(circpacket);
                        }
                    }
                    else
                    {
                        Console.WriteLine("Too large");
                    }


                    break;

                default:
                    break;
                }

                break;

            case 6:
                var v6Header   = IPv6Header.FromBytes(rcvbuf, 0);
                var GRE6Header = GREHeader.FromBytes(rcvbuf, 40);

                break;

            default:
                break;
            }
        }
예제 #6
0
 /// <summary>
 /// Sets the flow label value.
 /// </summary>
 /// <param name="hdr">
 /// The ipv6 header.
 /// </param>
 /// <param name="val">
 /// The value.
 /// </param>
 public static void IPv6Header_SET_FLOWLABEL(IPv6Header hdr, uint val)
 {
     //hdr.FlowLabel0 = (uint)(val >> 16);
     //hdr.FlowLabel1 = (ushort)val;
 }
예제 #7
0
 /// <summary>
 /// Sets the traffic class value.
 /// </summary>
 /// <param name="hdr">
 /// The ipv6 header.
 /// </param>
 /// <param name="val">
 /// The value.
 /// </param>
 public static void IPv6Header_SET_TRAFFICCLASS(IPv6Header hdr, byte val)
 {
     hdr.TrafficClass0 = (byte)(val >> 4);
     hdr.TrafficClass1 = val;
 }
예제 #8
0
 /// <summary>
 /// Gets the flow label value.
 /// </summary>
 /// <param name="hdr">
 /// The ipv6 header.
 /// </param>
 /// <returns>
 /// The flow label value.
 /// </returns>
 public static uint IPv6Header_GET_FLOWLABEL(IPv6Header hdr)
 {
     return((hdr.FlowLabel0 << 16) | hdr.FlowLabel1);
 }
예제 #9
0
 /// <summary>
 /// Gets the traffic class value.
 /// </summary>
 /// <param name="hdr">
 /// The ipv6 header.
 /// </param>
 /// <returns>
 /// The traffic class value.
 /// </returns>
 public static uint IPv6Header_GET_TRAFFICCLASS(IPv6Header hdr)
 {
     return((byte)((hdr.TrafficClass0 << 4) | (byte)hdr.TrafficClass1));
 }
예제 #10
0
        static void Main(string[] args)
        {

            // This is not really like the netdump example in the native WinDivert examples. Since we are 
            // pulling the names of processes behind packet flows, we need to fully intercept/divert packets,
            // make the process query, then reinject. If we just sniff, the process will either be closed or
            // no longer bound to the local port the packet is associated with, and the process query will
            // be hit or miss (probably fail). So, by fully diverting rather than sniffing, we force
            // the process to hang open waiting for the packet while we check the process identity, then
            // hand the packet over untouched.
            //
            // Ideally you do not want to be querying the process on every single packet. Rather, you would
            // create a stucture that keeps track of a network flow, identify the process (protocol, whatever
            // else) one time, then only re-check when the flow has ended and a new flow has begun. This is
            // just for basic demonstration though, so we don't create and track any flows.
            //
            // Note also that the process identification is still not 100%. Many system processes run under
            // PID 4. I'm not satisfied with just getting SYSTEM for these processes, and I'd like to
            // ideally be able to identify exactly which processes they are. Still working on that.

            Console.WindowWidth = Console.LargestWindowWidth;

            bool running = true;

            Console.CancelKeyPress += delegate {
                running = false;
            };

            Diversion diversion;

            string filter = "true";

            try
            {   
                diversion = Diversion.Open(filter, DivertLayer.Network, 100, 0);
            }
            catch(Exception e)
            {
                Console.WriteLine(e.Message);
                return;
            }

            if(!diversion.Handle.Valid)
            {
                Console.WriteLine("Failed to open divert handle with error {0}", System.Runtime.InteropServices.Marshal.GetLastWin32Error());
                return;
            }

            IPHeader ipHeader = new IPHeader();
            IPv6Header ipv6Header = new IPv6Header();
            ICMPHeader icmpHeader = new ICMPHeader();
            ICMPv6Header icmpv6Header = new ICMPv6Header();
            TCPHeader tcpHeader = new TCPHeader();
            UDPHeader udpHeader = new UDPHeader();

            Address address = new Address();

            byte[] buffer = new byte[65535];

            uint receiveLength = 0;
            uint sendLength = 0;

            string processName;

            uint pid = 0;

            while (running)
            {
                pid = 0;

                receiveLength = 0;
                sendLength = 0;

                if (!diversion.Receive(buffer, address, ref receiveLength))
                {
                    Console.WriteLine("Failed to receive packet with error {0}", System.Runtime.InteropServices.Marshal.GetLastWin32Error());
                    continue;
                }

                diversion.ParsePacket(buffer, receiveLength, ipHeader, ipv6Header, icmpHeader, icmpv6Header, tcpHeader, udpHeader);

                if (ipHeader.Valid && tcpHeader.Valid)
                {                    
                    Diversion.GetPacketProcess(address, tcpHeader, ipHeader, ref pid, out processName);

                    if (processName.Equals("SYSTEM", StringComparison.OrdinalIgnoreCase))
                    {
                        Console.WriteLine("ERROR {0} and PID is {1}", System.Runtime.InteropServices.Marshal.GetLastWin32Error(), pid);
                    }

                    Console.WriteLine(
                        "{0} IPv4 TCP packet captured destined for {1}:{2} from {3}:{4} {5}.", 
                        address.Direction == DivertDirection.Inbound ? "Inbound" : "Outbound", 
                        ipHeader.DestinationAddress.ToString(), tcpHeader.DestinationPort.ToString(), 
                        ipHeader.SourceAddress.ToString(), tcpHeader.SourcePort.ToString(),
                        address.Direction == DivertDirection.Inbound ? string.Format("to process {0}", processName) : string.Format("from process {0}", processName)
                        );

                    Console.WriteLine(string.Format("ack: {0}, syn: {1}, len: {2}, seq: {3}", tcpHeader.Ack, tcpHeader.Syn, ipHeader.Length, tcpHeader.SequenceNumber));
                }
                else if(ipHeader.Valid && udpHeader.Valid)
                {
                    Diversion.GetPacketProcess(address, udpHeader, ipHeader, ref pid, out processName);

                    if (processName.Equals("SYSTEM", StringComparison.OrdinalIgnoreCase))
                    {
                        Console.WriteLine("ERROR {0} and PID is {1}", System.Runtime.InteropServices.Marshal.GetLastWin32Error(), pid);
                    }

                    Console.WriteLine(
                        "{0} IPv4 UDP packet captured destined for {1}:{2} from {3}:{4} {5}.",
                        address.Direction == DivertDirection.Inbound ? "Inbound" : "Outbound",
                        ipHeader.DestinationAddress.ToString(), tcpHeader.DestinationPort.ToString(),
                        ipHeader.SourceAddress.ToString(), tcpHeader.SourcePort.ToString(),
                        address.Direction == DivertDirection.Inbound ? string.Format("to process {0}", processName) : string.Format("from process {0}", processName)
                        );                   
                }
                else if(ipv6Header.Valid && tcpHeader.Valid)
                {
                    Diversion.GetPacketProcess(address, tcpHeader, ipv6Header, ref pid, out processName);

                    if (processName.Equals("SYSTEM", StringComparison.OrdinalIgnoreCase))
                    {
                        Console.WriteLine("ERROR {0} and PID is {1}", System.Runtime.InteropServices.Marshal.GetLastWin32Error(), pid);
                    }

                    Console.WriteLine(
                        "{0} IPv6 TCP packet captured destined for {1}:{2} from {3}:{4} {5}.",
                        address.Direction == DivertDirection.Inbound ? "Inbound" : "Outbound",
                        ipHeader.DestinationAddress.ToString(), tcpHeader.DestinationPort.ToString(),
                        ipHeader.SourceAddress.ToString(), tcpHeader.SourcePort.ToString(),
                        address.Direction == DivertDirection.Inbound ? string.Format("to process {0}", processName) : string.Format("from process {0}", processName)
                        );

                    Console.WriteLine(string.Format("ack: {0}, syn: {1}, len: {2}, seq: {3}", tcpHeader.Ack, tcpHeader.Syn, ipv6Header.Length, tcpHeader.SequenceNumber));
                }
                else if (ipv6Header.Valid && udpHeader.Valid)
                {
                    Diversion.GetPacketProcess(address, udpHeader, ipv6Header, ref pid, out processName);

                    if (processName.Equals("SYSTEM", StringComparison.OrdinalIgnoreCase))
                    {
                        Console.WriteLine("ERROR {0} and PID is {1}", System.Runtime.InteropServices.Marshal.GetLastWin32Error(), pid);
                    }

                    Console.WriteLine(
                        "{0} IPv6 UDP packet captured destined for {1}:{2} from {3}:{4} {5}.",
                        address.Direction == DivertDirection.Inbound ? "Inbound" : "Outbound",
                        ipHeader.DestinationAddress.ToString(), tcpHeader.DestinationPort.ToString(),
                        ipHeader.SourceAddress.ToString(), tcpHeader.SourcePort.ToString(),
                        address.Direction == DivertDirection.Inbound ? string.Format("to process {0}", processName) : string.Format("from process {0}", processName)
                        );                   
                }

                if(address.Direction == DivertDirection.Outbound)
                {
                    diversion.CalculateChecksums(buffer, receiveLength, 0);
                }

                diversion.SendAsync(buffer, receiveLength, address, ref sendLength);
            }

            diversion.Close();
        }
예제 #11
0
        public void ParseNetworkPacket(PacketRawInfo args)
        {
            IPHeader           ipHeader          = null;
            IPv6Header         ipv6Header        = null;
            EthernetHeader     ethernetHeader    = null;
            EthernetPacketType ethernetPackeType = EthernetPacketType.IpV4;

            PacketInfo packetInfo = new PacketInfo();

            packetInfo.protocolE = PacketType.UNKNOWN;
            packetInfo.count     = 1;

            if (args.linkLayer == LinkLayers.Ethernet)
            {
                ethernetHeader = new EthernetHeader(args.data, args.size);

                ethernetPackeType             = ethernetHeader.EtherType;
                packetInfo.hardwareSource     = ethernetHeader.SourceMac;
                packetInfo.harwareDestination = ethernetHeader.DestinationMac;
                packetInfo.protocol           = ((Protocol)ethernetHeader.EtherType).ToString();
                if (ethernetHeader.EtherType == EthernetPacketType.IpV4)
                {
                    args.data = ethernetHeader.Payload;
                    args.size = ethernetHeader.Payload.Length;
                }
            }
            else
            {
                packetInfo.protocol = Protocol.Iplt.ToString();
            }
            switch (ethernetPackeType)
            {
            case EthernetPacketType.IpV4:
                ipHeader = new IPHeader(args.data, args.size);
                packetInfo.ipDestination = ipHeader.DestinationAddress.ToString();
                packetInfo.ipSource      = ipHeader.SourceAddress.ToString();
                packetInfo.size          = ipHeader.MessageLength;
                if (packetInfo.ipSource == incomingIP)
                {
                    packetInfo.incoming = true;
                }
                Statistics.AddToIPPacketsStats(packetInfo.size, packetInfo.incoming);
                break;

            case EthernetPacketType.IpV6:
                ipv6Header = new IPv6Header(args.data, args.size);
                packetInfo.ipDestination = ipv6Header.DestinationAddress.ToString();
                packetInfo.ipSource      = ipv6Header.SourceAddress.ToString();
                if (packetInfo.ipSource == incomingIP)
                {
                    packetInfo.incoming = true;
                }
                Statistics.AddToIPPacketsStats(packetInfo.size, packetInfo.incoming);
                break;

            case EthernetPacketType.Arp:
                ARPHeader arpHeader = new ARPHeader(ethernetHeader.Payload, ethernetHeader.Payload.Length);
                packetInfo.ipDestination = arpHeader.TPA;
                packetInfo.ipSource      = arpHeader.SPA;
                packetInfo.desription    = arpHeader.Description;
                if (packetInfo.ipSource == incomingIP)
                {
                    packetInfo.incoming = true;
                }
                packetInfo.size      = arpHeader.Size;
                packetInfo.protocol  = "ARP";
                packetInfo.protocolE = PacketType.ARP;
                Statistics.AddToARPPacketsStats(packetInfo.size, packetInfo.incoming);
                break;

            case EthernetPacketType.WakeOnLan:

                break;

            default:
                packetInfo.desription = "неизвестный Ethernet протокол";
                break;
            }

            if (ipHeader != null)
            {
                switch (ipHeader.ProtocolType)
                {
                case Protocol.Udp:
                    NetworkShow.Network.Packets.UDPHeader udpheader = new UDPHeader(ipHeader.Data, ipHeader.Data.Length);
                    packetInfo.portDestination = udpheader.DestinationPort;
                    packetInfo.portSource      = udpheader.SourcePort;
                    packetInfo.size            = udpheader.Length;
                    packetInfo.protocol        = "UDP";
                    packetInfo.protocolE       = PacketType.UDP;
                    packetInfo.active          = "T";
                    Statistics.AddToUDPPacketsStats(packetInfo.size, packetInfo.incoming);
                    break;

                case Protocol.Tcp:
                    NetworkShow.Network.Packets.TCPHeader tcpheader = new TCPHeader(ipHeader.Data, ipHeader.Data.Length);
                    packetInfo.portDestination = tcpheader.DestinationPort;
                    packetInfo.portSource      = tcpheader.SourcePort;
                    packetInfo.size            = tcpheader.MessageLength + tcpheader.HeaderLength;
                    packetInfo.active          = "T";
                    packetInfo.protocol        = "TCP";
                    packetInfo.protocolE       = PacketType.TCP;
                    Statistics.AddToTCPPacketsStats(packetInfo.size, packetInfo.incoming);
                    break;

                case Protocol.InternetControlMessageProtocol:
                    NetworkShow.Network.Packets.ICMPHeader icmpheader = new ICMPHeader(ipHeader.Data, ipHeader.Data.Length);
                    packetInfo.desription = icmpheader.Type.ToString();
                    packetInfo.size       = icmpheader.Size;
                    packetInfo.protocol   = "ICMP";
                    packetInfo.protocolE  = PacketType.ICMP;
                    Statistics.AddToICMPPacketsStats(packetInfo.size, packetInfo.incoming);
                    break;

                case Protocol.InternetGroupManagementProtocol:
                    NetworkShow.Network.Packets.IGMPHeader igmpheader = new IGMPHeader(ipHeader.Data, ipHeader.Data.Length);
                    packetInfo.desription = igmpheader.GroupAddress + " " + igmpheader.Type + " " + igmpheader.Version;
                    packetInfo.size       = igmpheader.Size;
                    packetInfo.protocol   = "IGMP";
                    packetInfo.protocolE  = PacketType.IGMP;
                    Statistics.AddToIGMPPacketsStats(packetInfo.size, packetInfo.incoming);
                    break;

                default:
                    packetInfo.desription = "неизвестный IP протокол";
                    packetInfo.protocol   = ipHeader.ProtocolType.ToString();
                    packetInfo.protocolE  = PacketType.UNKNOWN;
                    packetInfo.size       = ipHeader.MessageLength;
                    break;
                }
            }
            //PacketsInfo.AddToQueue(packetInfo);
            int pos = -1;

            if ((packetInfo.protocol == "TCP") || (packetInfo.protocol == "UDP"))
            {
                //pos = FindConnection(packetInfo);
                pos = FindConnection(packetInfo);
                if (pos >= 0)
                {
                    packetInfo = UpdateConnection(pos, packetInfo);
                    UpdateInfoEvent(packetInfo.protocol);
                    db.UpdateConnection(packetInfo.pos, packetInfo);
                }
                else
                {
                    packetInfo.pos = db.SaveNewPacket(packetInfo);
                    AddConnection(packetInfo);
                    ChangeRowsCountEvent(packetInfo.protocolE, packetInfo.pos, packetInfo.portSource, packetInfo.portSource);
                }
            }
            else
            {
                int position = db.SaveNewPacket(packetInfo);
                ChangeRowsCountEvent(packetInfo.protocolE, position, packetInfo.portSource, packetInfo.portSource);
            }
        }
예제 #12
0
        static void Main(string[] args)
        {
            // This is not really like the netdump example in the native WinDivert examples. Since we are
            // pulling the names of processes behind packet flows, we need to fully intercept/divert packets,
            // make the process query, then reinject. If we just sniff, the process will either be closed or
            // no longer bound to the local port the packet is associated with, and the process query will
            // be hit or miss (probably fail). So, by fully diverting rather than sniffing, we force
            // the process to hang open waiting for the packet while we check the process identity, then
            // hand the packet over untouched.
            //
            // Ideally you do not want to be querying the process on every single packet. Rather, you would
            // create a stucture that keeps track of a network flow, identify the process (protocol, whatever
            // else) one time, then only re-check when the flow has ended and a new flow has begun. This is
            // just for basic demonstration though, so we don't create and track any flows.
            //
            // Note also that the process identification is still not 100%. Many system processes run under
            // PID 4. I'm not satisfied with just getting SYSTEM for these processes, and I'd like to
            // ideally be able to identify exactly which processes they are. Still working on that.

            Console.WindowWidth = Console.LargestWindowWidth;

            bool running = true;

            Console.CancelKeyPress += delegate {
                running = false;
            };

            Diversion diversion;

            string filter = "true";

            try
            {
                diversion = Diversion.Open(filter, DivertLayer.Network, 100, 0);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                return;
            }

            if (!diversion.Handle.Valid)
            {
                Console.WriteLine("Failed to open divert handle with error {0}", System.Runtime.InteropServices.Marshal.GetLastWin32Error());
                return;
            }

            IPHeader     ipHeader     = new IPHeader();
            IPv6Header   ipv6Header   = new IPv6Header();
            ICMPHeader   icmpHeader   = new ICMPHeader();
            ICMPv6Header icmpv6Header = new ICMPv6Header();
            TCPHeader    tcpHeader    = new TCPHeader();
            UDPHeader    udpHeader    = new UDPHeader();

            Address address = new Address();

            byte[] buffer = new byte[65535];

            uint receiveLength = 0;
            uint sendLength    = 0;

            string processName;

            uint pid = 0;

            while (running)
            {
                pid = 0;

                receiveLength = 0;
                sendLength    = 0;

                if (!diversion.Receive(buffer, address, ref receiveLength))
                {
                    Console.WriteLine("Failed to receive packet with error {0}", System.Runtime.InteropServices.Marshal.GetLastWin32Error());
                    continue;
                }

                diversion.ParsePacket(buffer, receiveLength, ipHeader, ipv6Header, icmpHeader, icmpv6Header, tcpHeader, udpHeader);

                if (ipHeader.Valid && tcpHeader.Valid)
                {
                    Diversion.GetPacketProcess(address, tcpHeader, ipHeader, ref pid, out processName);

                    if (processName.Equals("SYSTEM", StringComparison.OrdinalIgnoreCase))
                    {
                        Console.WriteLine("ERROR {0} and PID is {1}", System.Runtime.InteropServices.Marshal.GetLastWin32Error(), pid);
                    }

                    Console.WriteLine(
                        "{0} IPv4 TCP packet captured destined for {1}:{2} from {3}:{4} {5}.",
                        address.Direction == DivertDirection.Inbound ? "Inbound" : "Outbound",
                        ipHeader.DestinationAddress.ToString(), tcpHeader.DestinationPort.ToString(),
                        ipHeader.SourceAddress.ToString(), tcpHeader.SourcePort.ToString(),
                        address.Direction == DivertDirection.Inbound ? string.Format("to process {0}", processName) : string.Format("from process {0}", processName)
                        );

                    Console.WriteLine(string.Format("ack: {0}, syn: {1}, len: {2}, seq: {3}", tcpHeader.Ack, tcpHeader.Syn, ipHeader.Length, tcpHeader.SequenceNumber));
                }
                else if (ipHeader.Valid && udpHeader.Valid)
                {
                    Diversion.GetPacketProcess(address, udpHeader, ipHeader, ref pid, out processName);

                    if (processName.Equals("SYSTEM", StringComparison.OrdinalIgnoreCase))
                    {
                        Console.WriteLine("ERROR {0} and PID is {1}", System.Runtime.InteropServices.Marshal.GetLastWin32Error(), pid);
                    }

                    Console.WriteLine(
                        "{0} IPv4 UDP packet captured destined for {1}:{2} from {3}:{4} {5}.",
                        address.Direction == DivertDirection.Inbound ? "Inbound" : "Outbound",
                        ipHeader.DestinationAddress.ToString(), tcpHeader.DestinationPort.ToString(),
                        ipHeader.SourceAddress.ToString(), tcpHeader.SourcePort.ToString(),
                        address.Direction == DivertDirection.Inbound ? string.Format("to process {0}", processName) : string.Format("from process {0}", processName)
                        );
                }
                else if (ipv6Header.Valid && tcpHeader.Valid)
                {
                    Diversion.GetPacketProcess(address, tcpHeader, ipv6Header, ref pid, out processName);

                    if (processName.Equals("SYSTEM", StringComparison.OrdinalIgnoreCase))
                    {
                        Console.WriteLine("ERROR {0} and PID is {1}", System.Runtime.InteropServices.Marshal.GetLastWin32Error(), pid);
                    }

                    Console.WriteLine(
                        "{0} IPv6 TCP packet captured destined for {1}:{2} from {3}:{4} {5}.",
                        address.Direction == DivertDirection.Inbound ? "Inbound" : "Outbound",
                        ipHeader.DestinationAddress.ToString(), tcpHeader.DestinationPort.ToString(),
                        ipHeader.SourceAddress.ToString(), tcpHeader.SourcePort.ToString(),
                        address.Direction == DivertDirection.Inbound ? string.Format("to process {0}", processName) : string.Format("from process {0}", processName)
                        );

                    Console.WriteLine(string.Format("ack: {0}, syn: {1}, len: {2}, seq: {3}", tcpHeader.Ack, tcpHeader.Syn, ipv6Header.Length, tcpHeader.SequenceNumber));
                }
                else if (ipv6Header.Valid && udpHeader.Valid)
                {
                    Diversion.GetPacketProcess(address, udpHeader, ipv6Header, ref pid, out processName);

                    if (processName.Equals("SYSTEM", StringComparison.OrdinalIgnoreCase))
                    {
                        Console.WriteLine("ERROR {0} and PID is {1}", System.Runtime.InteropServices.Marshal.GetLastWin32Error(), pid);
                    }

                    Console.WriteLine(
                        "{0} IPv6 UDP packet captured destined for {1}:{2} from {3}:{4} {5}.",
                        address.Direction == DivertDirection.Inbound ? "Inbound" : "Outbound",
                        ipHeader.DestinationAddress.ToString(), tcpHeader.DestinationPort.ToString(),
                        ipHeader.SourceAddress.ToString(), tcpHeader.SourcePort.ToString(),
                        address.Direction == DivertDirection.Inbound ? string.Format("to process {0}", processName) : string.Format("from process {0}", processName)
                        );
                }

                if (address.Direction == DivertDirection.Outbound)
                {
                    diversion.CalculateChecksums(buffer, receiveLength, 0);
                }

                diversion.SendAsync(buffer, receiveLength, address, ref sendLength);
            }

            diversion.Close();
        }