<commit_before>﻿// Copyright (c) CodesInChaos
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using log4net;
using PacketDotNet;
using SharpPcap;
using SharpPcap.WinPcap;

namespace NetworkSniffer
{
    // Only works when WinPcap is installed
    public class IpSnifferWinPcap : IpSniffer
    {
        private static readonly ILog Logger = LogManager.GetLogger
            (MethodBase.GetCurrentMethod().DeclaringType);

        private readonly string _filter;
        private WinPcapDeviceList _devices;
        private volatile uint _droppedPackets;
        private volatile uint _interfaceDroppedPackets;

        public IpSnifferWinPcap(string filter)
        {
            _filter = filter;
        }

        public IEnumerable<string> Status()
        {
            return _devices.Select(device =>
                $"Device {device.LinkType} {(device.Opened ? "Open" : "Closed")} {device.LastError}\r\n{device}");
        }

        public int? BufferSize { get; set; }

        protected override void SetEnabled(bool value)
        {
            if (value)
                Start();
            else
                Finish();
        }

        private static bool IsInteresting(WinPcapDevice device)
        {
            return true;
        }

        private void Start()
        {
            Debug.Assert(_devices == null);
            _devices = WinPcapDeviceList.New();
            var interestingDevices = _devices.Where(IsInteresting);
            foreach (var device in interestingDevices)
            {
                device.OnPacketArrival += device_OnPacketArrival;
                device.Open(DeviceMode.Promiscuous, 1000);
                device.Filter = _filter;
                if (BufferSize != null)
                {
                    try
                    {
                        device.KernelBufferSize = (uint) BufferSize.Value;
                    }
                    catch (Exception e)
                    {
                        Logger.Warn($"Failed to set KernelBufferSize to {BufferSize.Value} on {device.Name}. {e.Message}");
                    }
                }
                device.StartCapture();
            }
        }

        private void Finish()
        {
            Debug.Assert(_devices != null);
            foreach (var device in _devices.Where(device => device.Opened))
            {
                device.StopCapture();
                device.Close();
            }
            _devices = null;
        }

        public event Action<string> Warning;

        protected virtual void OnWarning(string obj)
        {
            Action<string> handler = Warning;
            if (handler != null) handler(obj);
        }

        void device_OnPacketArrival(object sender, CaptureEventArgs e)
        {
            var linkPacket = Packet.ParsePacket(e.Packet.LinkLayerType, e.Packet.Data);

            var ipPacket = linkPacket.PayloadPacket as IpPacket;
            if (ipPacket == null)
                return;

            var ipData = ipPacket.BytesHighPerformance;
            var ipData2 = new ArraySegment<byte>(ipData.Bytes, ipData.Offset, ipData.Length);

            OnPacketReceived(ipData2);

            var device = (WinPcapDevice)sender;
            if (device.Statistics.DroppedPackets != _droppedPackets || device.Statistics.InterfaceDroppedPackets != _interfaceDroppedPackets)
            {
                _droppedPackets = device.Statistics.DroppedPackets;
                _interfaceDroppedPackets = device.Statistics.InterfaceDroppedPackets;<commit_msg>Fix packet parsing error if npcap loopback adapter installed. Add support for proxy/vpn via npcap loopback adapter. (More efficient alternative to raw sockets)<commit_after>﻿// Copyright (c) CodesInChaos
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using log4net;
using PacketDotNet;
using PacketDotNet.Utils;
using SharpPcap;
using SharpPcap.WinPcap;

namespace NetworkSniffer
{
    // Only works when WinPcap is installed
    public class IpSnifferWinPcap : IpSniffer
    {
        private static readonly ILog Logger = LogManager.GetLogger
            (MethodBase.GetCurrentMethod().DeclaringType);

        private readonly string _filter;
        private WinPcapDeviceList _devices;
        private volatile uint _droppedPackets;
        private volatile uint _interfaceDroppedPackets;

        public IpSnifferWinPcap(string filter)
        {
            _filter = filter;
        }

        public IEnumerable<string> Status()
        {
            return _devices.Select(device =>
                $"Device {device.LinkType} {(device.Opened ? "Open" : "Closed")} {device.LastError}\r\n{device}");
        }

        public int? BufferSize { get; set; }

        protected override void SetEnabled(bool value)
        {
            if (value)
                Start();
            else
                Finish();
        }

        private static bool IsInteresting(WinPcapDevice device)
        {
            return true;
        }

        private void Start()
        {
            Debug.Assert(_devices == null);
            _devices = WinPcapDeviceList.New();
            var interestingDevices = _devices.Where(IsInteresting);
            foreach (var device in interestingDevices)
            {
                device.OnPacketArrival += device_OnPacketArrival;
                device.Open(DeviceMode.Promiscuous, 1000);
                device.Filter = _filter;
                if (BufferSize != null)
                {
                    try
                    {
                        device.KernelBufferSize = (uint) BufferSize.Value;
                    }
                    catch (Exception e)
                    {
                        Logger.Warn($"Failed to set KernelBufferSize to {BufferSize.Value} on {device.Name}. {e.Message}");
                    }
                }
                device.StartCapture();
            }
        }

        private void Finish()
        {
            Debug.Assert(_devices != null);
            foreach (var device in _devices.Where(device => device.Opened))
            {
                device.StopCapture();
                device.Close();
            }
            _devices = null;
        }

        public event Action<string> Warning;

        protected virtual void OnWarning(string obj)
        {
            Action<string> handler = Warning;
            if (handler != null) handler(obj);
        }

        void device_OnPacketArrival(object sender, CaptureEventArgs e)
        {
            IPv4Packet ipPacket;
            if (e.Packet.LinkLayerType != LinkLayers.Null)
            {
                var linkPacket = Packet.ParsePacket(e.Packet.LinkLayerType, e.Packet.Data);
                ipPacket = linkPacket.PayloadPacket as IPv4Packet;
            }
            else
            {
                ipPacket = new IPv4Packet(new ByteArraySegment(e.Packet.Data, 4, e.Packet.Data.Length - 4));
            }
            if (ipPacket == null)
                return;

            var ipData = ipPacket.BytesHighPerformance;
            var ipData2 = new ArraySegment<byte>(ipData.Bytes, ipData.Offset, ipData.Length);

            OnPacketReceived(ipData2);

            var device = (WinPcapDevice)sender;
            if (device.Statistics.DroppedPackets != _droppedPackets || device.Statistics.InterfaceDroppedPackets != _interfaceDroppedPackets)
            {
                _droppedPackets = device.Statistics.DroppedPackets;
                _interfaceDroppedPackets = device.Statistics.InterfaceDroppedPackets;
{'fraction_non_alphanumeric': 0.0794576099353694, 'fraction_numerical': 0.002407806361677861, 'mean_word_length': 1.7440890125173854, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5917036', 'n_tokens_mistral': 2064, 'n_tokens_neox': 1937, 'n_words': 479}