ravahn / machina

Network capture library for realtime TCP/IP decoding from a windows application. Includes an extension library to support FFXIV data capture.
GNU General Public License v3.0
206 stars 76 forks source link

RawSocket mode stops reporting any data when a TCP listener is opened #14

Closed anna-is-cute closed 3 years ago

anna-is-cute commented 3 years ago

I can replicate this using ACT and Teamcraft, but this happens for any process. I included two test programs that can be used to replicate this behaviour.

When using Machina in RawSocket mode, if the process being listened to opens a TCP listener and listens for incoming connections, Machina will stop reporting any data at all.

using Machina;
using System;
using System.Linq;

namespace TestMachinaPacketListener {
    class Program {
        static void Main(string[] args) {
            TCPNetworkMonitor monitor = new TCPNetworkMonitor();
            monitor.ProcessID = uint.Parse(args[0]);
            // change this to WinPCap and it will work as expected
            monitor.MonitorType = TCPNetworkMonitor.NetworkMonitorType.RawSocket;
            monitor.DataReceived = (string connection, byte[] data) => DataReceived(connection, data);
            monitor.Start();
            Console.ReadLine();
            monitor.Stop();
        }

        private static void DataReceived(string conn, byte[] data) {
            Console.WriteLine(conn);
            Console.WriteLine(string.Join("", data.Select(b => b.ToString("x2"))));
            Console.WriteLine();
        }
    }
}
using System;
using System.Diagnostics;
using System.Net;
using System.Net.Http;
using System.Net.Sockets;
using System.Threading.Tasks;

namespace PeriodicDownloader {
    class Program {
        static void Main(string[] args) {
            Console.WriteLine(Process.GetCurrentProcess().Id);

            using var client = new HttpClient();
            Task.Run(async () => {
                while (true) {
                    string data = await client.GetStringAsync("https://duckduckgo.com/");
                    Console.WriteLine(data.Substring(0, 20));
                    await Task.Delay(1_000);
                }
            });

            Console.ReadLine();

            var listener = new TcpListener(IPAddress.Parse("0.0.0.0"), 12345);
            listener.Start();

            Task.Run(async () => {
                await listener.AcceptTcpClientAsync();
            });

            Console.ReadLine();
        }
    }
}

Run the periodic downloader and it will output its PID. Run the other program with the PID as the first argument. You will see it reports the download every second. Press enter to start the listener in the downloader and the other program will become silent.

ravahn commented 3 years ago

Apologies for the late reply. You provided an excellent repro sample, thank you. This was fixed in NetworkStructs branch on Jan 12. I just re-tested and confirmed it happens with the master branch, but not with NetworkStructs branch. I finished refactoring in that branch recently, and plan to merge it to Master branch soon. A new Nuget package will be published.

There are a few breaking changes when this happens, which I will include in the release notes.

The underlying problem was that my code was identifying listening connections as originating from IP 0.0.0.0, which doesn't translate to a valid interface. This raised a runtime error, which exited the polling thread loop. The fix is to just exclude adding a new socket listening for this connection.