Search code examples
c#linuxprocessstdout

Read standard output from tcpdump using c#


I have read several question on how to read the standard output from a process such as these ones:

  1. https://stackoverflow.com/a/285841/637142

  2. https://stackoverflow.com/a/9730455/637142

and all of them work great. But for some reason when using it against tcpdump it does not work.

When I run this on Linux I get this output:

~ /usr/bin/tcpdump -n
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
16:34:36.190659 IP 192.168.157.221.56683 > 8.8.8.8.53: 29151+ A? google.com. (28)
16:34:36.190665 IP 192.168.157.221.56683 > 8.8.8.8.53: 39646+ AAAA? google.com. (28)
16:34:36.219305 IP 8.8.8.8.53 > 192.168.157.221.56683: 29151 1/0/0 A 142.250.64.206 (44)
16:34:40.891435 ARP, Request who-has 192.168.157.221 (00:15:5d:fb:8f:dd) tell 192.168.144.1, length 28
... etc

Now on C# this is what am I doing hoping to do the same thing:

var process = new Process();
process.StartInfo = new ProcessStartInfo()
{
    UseShellExecute = false,
    FileName = "/usr/bin/tcpdump",
    Arguments = "-n",
    RedirectStandardOutput = true,
    RedirectStandardError = true,
    CreateNoWindow = true,
};
process.OutputDataReceived += (a, b) =>
{
    if (b.Data is null) return;
    Console.WriteLine(b.Data); // <--- trying to hit this line
};
process.ErrorDataReceived += (a, b) =>
{
    if (b.Data is null) return;
    Console.WriteLine(b.Data);
};
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();

await process.WaitForExitAsync();

Why is it that when I run that I get no output? If I run on another terminal the command /usr/bin/tcpdump -n I see output but not on the c# application why?

I have also tried a synchronous attempt:

var process = new Process();
process.StartInfo = new ProcessStartInfo()
{
    UseShellExecute = false,
    FileName = "/usr/bin/tcpdump",
    Arguments = "-n",
    RedirectStandardOutput = true,
    CreateNoWindow = true,
};
process.Start();

while (process.HasExited == false)
{
    Span<char> buf = new char[1024].AsSpan();
    var i = process.StandardOutput.Read(buf);
    if (i > 0)
    {
        var str = new string(buf); // I never hit this line
        Console.WriteLine(str);
    }
}

If I run both programs at the same time one works (top) and the other does not (c#):

enter image description here

As you can see from the output both programs are listening on interface eth0 they both show the same output. But for some reason the c# one does not capture any traffic.


Solution

  • This answer solved my problem: https://unix.stackexchange.com/a/16484/281179

    I needed to pass the argument -l for buffered. In other works this is how my c# code looks like now:

    process.StartInfo = new ProcessStartInfo()
    {
        UseShellExecute = false,
        FileName = "/usr/bin/tcpdump",
        Arguments = "-l -n", // <--------- append -l flag
        RedirectStandardOutput = true,
        RedirectStandardError = true,
        CreateNoWindow = true,
    };
    // ... etc