Read standard output from tcpdump using c# - c#

I have read several question on how to read the standard output from a process such as these ones:
https://stackoverflow.com/a/285841/637142
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#):
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.

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

Related

I get a can't execute binary file error when running a bash command from C#

I've created a Discord Bot with which you can interact (running on a Raspberry Pi with a default Raspberry Pi OS). I also added a command to execute a shell command. My code:
ProcessStartInfo inf = new()
{
CreateNoWindow = true,
RedirectStandardError = true,
RedirectStandardOutput = true,
RedirectStandardInput = true,
FileName = "/bin/bash",
Arguments = command,
};
if (Process.Start(inf) is Process cmd)
{
string ret = "Output: " + await cmd.StandardOutput.ReadToEndAsync();
ret += "\nError Output: " + await cmd.StandardError.ReadToEndAsync();
await Program.Log(ret);
return ret;
}
When I set command to "echo Hello, World!" I just get the error
/usr/bin/echo: /usr/bin/echo: cannot execute binary file
from the StandardOutput.
What am I doing wrong?
You have to pass -c parameter to bash if you want execute something through it
ProcessStartInfo inf = new()
{
CreateNoWindow = true,
RedirectStandardError = true,
RedirectStandardOutput = true,
RedirectStandardInput = true,
FileName = "/bin/bash",
Arguments = $"-c \"{command}\""
};
if (Process.Start(inf) is Process cmd)
{
string ret = "Output: " + await cmd.StandardOutput.ReadToEndAsync();
ret += "\nError Output: " + await cmd.StandardError.ReadToEndAsync();
await Program.Log(ret);
return ret;
}

Exectute a Linux Shell command from ASP.NET Core 3 app

My question is literally, how do I execute a Shell command from my application. There is a similar Post, but that shows how to execute a script file and requires the path to that file.
var process = new Process()
{
StartInfo = new ProcessStartInfo
{
FileName = command, // Path required here
Arguments = args,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true,
}
};
process.Start();
Why I want to pass the command as a string?
Because I want to interpolate it. Otherwise, I would have to create a script, with some input parameters. Since I'm not that good with Shell, I prefer the easy way.
Assume you want to run echo hello in bash, then
Process process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "bash",
RedirectStandardInput = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false
}
};
process.Start();
await process.StandardInput.WriteLineAsync("echo hello");
var output = await process.StandardOutput.ReadLineAsync();
Console.WriteLine(output);

Send Python Output to File from C#

I want to get the output and error messages after running a python script from C#. The output works, however if there's an error in the python script the output returns as "" and I can't get the error. The error displays correctly if the python script is run from Windows shell.
As a workaround I'd like to output from the python script to a txt file and then read the text file in C#. The below works in shell to write for the file mylog.log.
python c:\temp\text.py 2>&1 | tee -filePath mylog.log
If I run the code below in C# no mylog.log file is created.
public string RunFile(string fileName)
{
fileName = #"c:\temp\text.py 2>&1 | tee -filePath c:\temp\myLog.log";
Process p = new Process();
p.StartInfo = new ProcessStartInfo(#"python", fileName)
{
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true,
WorkingDirectory = #"c:\temp"
};
p.Start();
p.WaitForExit();
string output = p.StandardOutput.ReadToEnd();
return output;
}
Thanks for the comments. I've just enabled redirect of the error and am reading the error in C#.
Process p = new Process();
p.StartInfo = new ProcessStartInfo(#"python", fileName)
{
RedirectStandardError = true,
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true,
WorkingDirectory = #"c:\temp"
};
p.Start();
p.WaitForExit();
string output = p.StandardOutput.ReadToEnd();
string error = p.StandardError.ReadToEnd();

can not get out put from pg_dump.exe command line

i'm developing an application to get backup from my postgreSQL database with C#.
i,m using code below to execute and get out put from pg_dump.exe.
ProcessStartInfo startinfo = new ProcessStartInfo
{
FileName = "\"C:\\Program Files (x86)\\pgAdmin III\\1.16\\pg_dump.exe\"",
Arguments = "--host XXX.XXX.XXX.XXX --port 5432 --username \"USERNAME\" --no-password --format plain --verbose --file \"D:\\MYBACKUP.backup\" \"MYDBNAME\"",
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
};
Process proc = new Process();
proc.StartInfo = startinfo;
proc.Start();
while (!proc.StandardOutput.EndOfStream)
{
var r = proc.StandardOutput.ReadLine();
}
proc.WaitForExit();
Console.WriteLine(proc.ExitCode);
Console.ReadLine();
but proc.StandardOutput.ReadLine always returns null!!!
i try to put pg_dump.exe output to a file with command propt like this:
C:\Program Files (x86)\pgAdmin III\1.16>pg_dump.exe > d:\log.txt
but again log.txt is empty!!
thanks in advance.
Replace RedirectStandardOutput with RedirectStandardError.
My working code is:
ProcessStartInfo startinfo = new ProcessStartInfo
{
FileName = "Path to pg_dump.exe",
Arguments = "Arguments",
UseShellExecute = false,
RedirectStandardError = true,
CreateNoWindow = true
};
using (Process process = Process.Start(startinfo))
{
using (StreamReader reader = process.StandardError)
{
StreamWriter sw = new StreamWriter(#"C:\log.txt");
sw.WriteLine(reader.ReadToEnd());
sw.Close();
}
}

Running / spawning commands vs files in c#

I can in C# do the following:
var pSpawn = new Process
{
StartInfo = { WorkingDirectory = #"C:\temp", FileName = fileToRun, CreateNoWindow = true }
};
pSpawn.Start();
and this works fine.... however I am wondering if there is a way to run a command (ie: "dir /b") without having to encapsulate it in a batch file?
Just start the cmd.exe and pass the arguments required
var pSpawn = new Process
{
StartInfo =
{
WorkingDirectory = #"C:\temp",
FileName = "cmd.exe",
Arguments ="/K dir /b" }
};
pSpawn.Start();
I have added the parameter /K to leave the command window open so, it is possible to see the output of the command dir.
Of course I think that you are really interested to catch the output of the command.
In this case you could work with something like this:
StringBuilder sb = new StringBuilder();
var pSpawn = new Process
{
StartInfo =
{
WorkingDirectory = #"C:\temp",
FileName = "cmd.exe",
Arguments ="/c dir /b",
CreateNoWindow = true,
RedirectStandardOutput = true,
RedirectStandardInput = true,
UseShellExecute = false
}
};
pSpawn.OutputDataReceived += (sender, args) => sb.AppendLine(args.Data);
pSpawn.Start();
pSpawn.BeginOutputReadLine();
pSpawn.WaitForExit();
Console.WriteLine(sb.ToString());
You can call something like this:
ProcessStartInfo info = new ProcessStartInfo("cmd.exe");
info.Arguments = "/c dir /b";
Process.Start(info);

Categories