Sam1916
Sam1916

Reputation: 11

How to convert a script(Capture Packets and save it to log file) into Window Service?

I want to write a window service for keep capturing the network traffic and save the packets info into a log file, but I can't start it.
"Error 1064: An exception occurred in the service when handling the control request."
References:
Capturing And Parsing Packets
Save Output to Log
Create Window Service

Here's the code for Windows Service(failed):

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
using CapturingAndParsingPackets;
using PacketDotNet;
using SharpPcap;

namespace CaptureService
{
    public partial class Service1 : ServiceBase
    {
        private static bool _stopCapturing;
        string path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);//Get the desktop path
        string filename = DateTime.Now.ToString("yyyy-MM-dd--HH-mm-ss");//Use date to name the file

        public Service1()
        {
            InitializeComponent();
            var devices = CaptureDeviceList.Instance; //Get the local devices
            if (devices.Count < 1)
            {
                OnStop();
                return;
            }
        }

        protected override void OnStart(string[] args)
        {
            var devices = CaptureDeviceList.Instance; //Get the local devices
            //set output type
            var defaultOutputType = StringOutputType.Normal;
            var outputTypeValues = Enum.GetValues(typeof(StringOutputType));
            StringOutputType selectedOutputType = defaultOutputType;
            int userSelectedOutputType;
            userSelectedOutputType = 3;
            selectedOutputType = (StringOutputType)userSelectedOutputType;
            //read local device
            var device = devices[3];
            //read packets
            var readTimeoutMilliseconds = 1000;
            device.Open(DeviceModes.Promiscuous, readTimeoutMilliseconds);
            //set filter
            string filter = "host 192.168.0.212";
            device.Filter = filter;

            
            PacketCapture e;
            var status = device.GetNextPacket(out e);

            var rawCapture = e.GetPacket();

            // use PacketDotNet to parse this packet and print out
            // its high level information
            var p = Packet.ParsePacket(rawCapture.GetLinkLayers(), rawCapture.Data);

            // Create a log file to desktop and write the log into the log file
            using (StreamWriter w = File.AppendText(path + "\\" + filename + ".log"))
            {
                Log(p.ToString(selectedOutputType) + p.PrintHex(), w);
            }
            
            device.Close();
        }

        public static void Log(string logMessage, TextWriter txtWriter)
        {
            try
            {
                txtWriter.Write("\r\nLog Entry : ");
                txtWriter.WriteLine("{0} {1}", DateTime.Now.ToLongTimeString(),
                    DateTime.Now.ToLongDateString());
                txtWriter.WriteLine();
                txtWriter.WriteLine(logMessage);
                txtWriter.WriteLine("============================================================================================================");
            }
            catch (Exception)
            {
            }
        }
        protected override void OnStop()
        {
            using (StreamWriter w = File.AppendText(path + "\\" + filename + ".log"))
            {
                Log("Service is stopped at " + DateTime.Now, w);
            }
        }
    }
}

And Here is the script for just running it in VS(works fine):

using System;
using PacketDotNet;
using SharpPcap;
using System.IO;
using System.Reflection;
using log4net;
using log4net.Config;

namespace CapturingAndParsingPackets
{
    class MainClass
    {
        // used to stop the capture loop
        private static bool _stopCapturing;

        public static void Main(string[] args)
        {
            // Print SharpPcap version
            var ver = SharpPcap.Pcap.SharpPcapVersion;
            Console.WriteLine("PacketDotNet example using SharpPcap {0}", ver);

            // Retrieve the device list
            var devices = CaptureDeviceList.Instance;

            // If no devices were found print an error
            if (devices.Count < 1)
            {
                Console.WriteLine("No devices were found on this machine");
                return;
            }

            Console.WriteLine();
            Console.WriteLine("The following devices are available on this machine:");
            Console.WriteLine("----------------------------------------------------");
            Console.WriteLine();

            var i = 0;

            // Print out the devices
            foreach (var dev in devices)
            {
                /* Description */
                Console.WriteLine("{0}) {1} {2}", i, dev.Name, dev.Description);
                i++;
            }

            Console.WriteLine();
            Console.Write("-- Please choose a device to capture: ");


            Console.WriteLine();
            Console.WriteLine("Output Verbosity Options");
            Console.WriteLine("----------------------------------------------------");
            Console.WriteLine();
            var defaultOutputType = StringOutputType.Normal;
            var outputTypeValues = Enum.GetValues(typeof(StringOutputType));
            foreach (StringOutputType outputType in outputTypeValues)
            {
                Console.Write("{0} - {1}", (int)outputType, outputType);
                if (outputType == defaultOutputType)
                {
                    Console.Write(" (default)");
                }

                Console.WriteLine("");
            }

            Console.WriteLine();
            Console.Write("-- Please choose a verbosity (or press enter for the default): ");
            StringOutputType selectedOutputType = defaultOutputType;
            int userSelectedOutputType;
            //Fixed
            userSelectedOutputType = 3;
            selectedOutputType = (StringOutputType)userSelectedOutputType;


            // Register a cancel handler that lets us break out of our capture loop
            Console.CancelKeyPress += HandleCancelKeyPress;

            //Fixed
            var device = devices[3];

            // Open the device for capturing
            var readTimeoutMilliseconds = 1000;
            device.Open(DeviceModes.Promiscuous, readTimeoutMilliseconds);
            //filter host 192.168.0.212
            //or you can set it to "filter = 'ip'; " for default 
            string filter = "host 192.168.0.212";
            device.Filter = filter;


            Console.WriteLine();
            Console.WriteLine("-- Listening on {0}, hit 'ctrl-c' to stop...",
                              device.Name);

            while (_stopCapturing == false)
            {
                PacketCapture e;
                var status = device.GetNextPacket(out e);

                // null packets can be returned in the case where
                // the GetNextRawPacket() timed out, we should just attempt
                // to retrieve another packet by looping the while() again
                if (status != GetPacketStatus.PacketRead)
                {
                    // go back to the start of the while()
                    continue;
                }

                var rawCapture = e.GetPacket();

                // use PacketDotNet to parse this packet and print out
                // its high level information
                var p = Packet.ParsePacket(rawCapture.GetLinkLayers(), rawCapture.Data);



                Console.WriteLine(p.ToString(selectedOutputType) + p.PrintHex());
                Console.WriteLine("============================================================================================================");
                using (StreamWriter w = File.AppendText("networkTraffic.log"))
                {
                    Log(p.ToString(selectedOutputType), w);
                    Log(p.PrintHex(), w);
                }
            }

            Console.WriteLine("-- Capture stopped");

            // Print out the device statistics
            Console.WriteLine(device.Statistics.ToString());


            // Close the pcap device
            device.Close();
        }

        static void Log(string logMessage, TextWriter txtWriter)
        {
            try
            {
                txtWriter.Write("\r\nLog Entry : ");
                txtWriter.WriteLine("{0} {1}", DateTime.Now.ToLongTimeString(),
                    DateTime.Now.ToLongDateString());
                txtWriter.WriteLine();
                txtWriter.WriteLine(logMessage);
                txtWriter.WriteLine("============================================================================================================");
            }
            catch (Exception)
            {
            }
        }



        static void HandleCancelKeyPress(object sender, ConsoleCancelEventArgs e)
        {
            Console.WriteLine("-- Stopping capture");
            _stopCapturing = true;

            // tell the handler that we are taking care of shutting down, don't
            // shut us down after we return because we need to do just a little
            // bit more processing to close the open capture device etc
            e.Cancel = true;
        }
    }
}

The error that shows in Event Viewer(1064):

Application: CaptureTrafficService.exe
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.IO.FileNotFoundException
   at CaptureTrafficService.Service1.OnStart(System.String[])
   at System.ServiceProcess.ServiceBase.ServiceQueuedMainCallback(System.Object)
   at System.ServiceProcess.ServiceBase.Run(System.ServiceProcess.ServiceBase[])
   at CaptureTrafficService.Program.Main()

Service cannot be started. System.IO.FileNotFoundException: Could not load file or assembly 'netstandard, Version=2.1.0.0, Culture=neutral, PublicKeyToken=cc7b1xxxxxxxxxxx' or one of its dependencies. The system cannot find the file specified.
File name: 'netstandard, Version=2.1.0.0, Culture=neutral, PublicKeyToken=cc7b1xxxxxxxxxxx'
   at CaptureTrafficService.Service1.OnStart(String[] args)
   at System.ServiceProcess.ServiceBase.ServiceQueuedMainCallback(Object state)

After I remove the while loop in OnStart method, It shows up another error(1053):

Application: CaptureTrafficService.exe
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.IO.FileNotFoundException

Exception Info: System.IO.FileNotFoundException
   at CaptureService.Service1..ctor()
   at CaptureService.Program.Main()

Upvotes: 0

Views: 234

Answers (2)

Sam1916
Sam1916

Reputation: 11

There are too many unnecessary references that may affect each other in the solution so that it will return a lot of errors & warnings when building it. Just add them one by one if it is necessary, rebuild it when you added a new reference(for checking the compatibility) and not just copying all of them to the solution.

Too many unnecessary references(Before)

Just add the references you need(After)

Here's the code that works with windows service:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
using SharpPcap;
using PacketDotNet;

namespace Capture
{
    public partial class Capture : ServiceBase
    {
        Timer timer = new Timer();
        public Capture()
        {
            InitializeComponent();
        }

        protected override void OnStart(string[] args)
        {
            Log("Service started at " + DateTime.Now);
            timer.Elapsed += new ElapsedEventHandler(OnElapsedTime);
            //timer.Interval = 5000;
            timer.Enabled = true;
        }

        protected override void OnStop()
        {
            Log("Service is stopped at " + DateTime.Now);
        }
        private void OnElapsedTime(object source, ElapsedEventArgs e)
        {
            var devices = CaptureDeviceList.Instance;
            //set output type
            var defaultOutputType = StringOutputType.Normal;
            StringOutputType selectedOutputType = defaultOutputType;
            int userSelectedOutputType;
            userSelectedOutputType = ? ;//? = 0-3
            selectedOutputType = (StringOutputType)userSelectedOutputType;
            //read local device
            var device = devices[?];//? is mean num 0-4 or more(depends on your device)
            //read packets
            var readTimeoutMilliseconds = 1000;
            device.Open(DeviceModes.Promiscuous, readTimeoutMilliseconds);
            PacketCapture d;
            var status = device.GetNextPacket(out d);
            var rawCapture = d.GetPacket();
            var p = Packet.ParsePacket(rawCapture.LinkLayerType, rawCapture.Data);
            Log(p.ToString(selectedOutputType) +p.PrintHex());//write to log file
            device.Close();
        }

        public static void Log(string logMessage)
        {
            string path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);+ "\\Logs" ;
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }
            string filepath =Environment.GetFolderPath(Environment.SpecialFolder.Desktop); + "\\Logs\\ServiceLog_" +
                DateTime.Now.Date.ToShortDateString().Replace('/','_') + ".log";
            
            using (StreamWriter sw = File.AppendText(filepath))
            {
                sw.WriteLine(logMessage);
                sw.WriteLine("============================================================================================================");
            }
            
        }


    }
}

Upvotes: 0

fym
fym

Reputation: 41

The answer by @Sam1916 might lessen the frustration of FileNotFoundException.

The "System.IO.FileNotFoundException" caught my attention - but missing info on what files.

As Windows services run in "their own context" the files referenced (Through "using") might not exists in a readable directory, hench "FileNotFoundException"

Is the logfile placed in a directory where your service credentials are allowed to write?

Upvotes: 0

Related Questions