Automating Netcat file transfer from C# application - Windows & Raspberry Pi - c#

I am trying to receive a file through Netcat from a Linux based server (Raspberry Pi).
On the sender side (Raspberry Pi) I run a small Python script, that just packs up some files and sends them into the pipeline. This works great, and has been tested a lot.
On the receiver side (Windows 8.1 Pro), I use Netcat to turn the incoming stream into a file. If I do this by hand in cmd.exe, it works great:
nc -l -p <port> > C:\file.gz
My file arrives as planned.
However when I try to automate this process on the receiver side with a C# script (.Net 4.5), the file simply doesn't arrive. My code looks like this:
public void StartListeningToNetcat()
{
Process ncProcess = new Process();
ncProcess.StartInfo.UseShellExecute = false;
ncProcess.StartInfo.CreateNoWindow = false;
ncProcess.StartInfo.RedirectStandardOutput = true;
ncProcess.StartInfo.RedirectStandardInput = true;
ncProcess.StartInfo.FileName = "cmd.exe";
ncProcess.StartInfo.Arguments = #"C:\...\nc -l -p <port> > C:\file.gz";
ncProcess.Start();
}
I am aware, that running nc through cmd.exe is a detour, but calling netcat directly like this:
ncProcess.StartInfo.FileName = "C:\...\nc.exe";
ncProcess.StartInfo.Arguments = #"-l -p <port> > C:\file.gz";
...returns the error: ">: forward host lookup failed: h_errno 11001: HOST_NOT_FOUND". Anyway, I wouldn't mind ignoring this error and going for the "inelegant" way to call cmd.exe.
Assuming that it could be a security measure by windows to not allow applications to write incoming files on my hard drive I tried turning of my firewall and using:
ncProcess.StartInfo.Verb = "runas";
with no success.
Could somebody point me in the right direction?

I was just able to resolve this issue myself:
Instead of executing "cmd.exe" with the arguments to run netcat, or calling Netcat itself, I create a batch file upfront, which I can later call in my C# script.
public void StartListenToNetcat()
{
string batchPath = CreateNetcatBatchFile();
Process.Start(batchPath);
}
public string CreateNetcatBatchFile()
{
Streamwriter w = new StreamWriter("C:\runNC.bat");
w.WriteLine("C:\...\nc -l -p 22 > C:\file.gz");
w.Close();
return "C:\runNC.bat";
}
Still I don't actually understand the necessity of this detour. Comments for clarifaction would be greatly appreciated.

Related

Why would reading a certifcate in a server.js started by a process cause the process to terminate?

I have a process which, on start, runs a node.js server. Trying to add HTTPS to the server results in the process which the server is attached to terminating. What could be causing this?
The process is started by a service written in C#. The process is then attached onto by the server.js. I've tried debugging the service to see which path of execution leads to the process being terminated by I couldn't track it down. Removing the lines form server.js that read the certificates results in the process not being terminated. However, I can't work out why that would be the case.
To read the certificates:
var privatekey = fs.readFileSync("xxx.pem", "utf8");
var certificate = fs.readFileSync("xxx.cert", "utf8");
var credentials = { key: privatekey, cert: certificate };
The setup of the Process:
var nodePath = GetNodePath();
// Get the path to the web files
var serverPath = ".\\server\\server.js";
// Create the process arguments
ProcessStartInfo info = new ProcessStartInfo();
info.WorkingDirectory = Path.GetDirectoryName( Assembly.GetExecutingAssembly().Location );
info.CreateNoWindow = true;
info.UseShellExecute = false;
info.FileName = nodePath;
info.EnvironmentVariables.Add( "NODE_ENV", "production" );
info.Arguments = $"{serverPath} --max-old-space=200";
I have an event handler for the exit of the process which is mostly below:
private static void webProcess_Exited( object sender, EventArgs e )
{
// Make sure we haven't restarted more than 10 times
if ( restartCount > 5 )
{
var message = "The xxx web service is being shut down due to the nodejs process expectantly terminating too many times.";
// Log to the event log
ShutdownService();
}
else
{
var message = "The nodejs process was expectantly terminated, restarting the process in 5 seconds.";
// Log to the event log
Thread.Sleep( 5000 );
//Starts the process/node.js server again
Start();
}
}
Starting server.js reading the certificates works fine. Removing the lines reading the certificate and running the service also works fine. But, for some reason, when reading the certificates and starting the node.js server through the service, it terminates/starts before terminating for good, as above.
Would anyone what could be causing this? Or suggest ways to troubleshoot this further?
Investigating the comment by #FrankerZ , I found that moving the certificate file from the directory the server.js is held to where the process assembly is fixed my issue. The reason the process terminated is, I assume, the working directory was set in the c# service to be where the assembly is (one level above the server.js). However, the certificate files were stored in the level below (alongside server.js). Thus, when I read the certificates, it is attempting to read them from the directory above where they actually are, resulting in the process terminating.

C# - Command runs from command prompt but not from service

I have a C# (ASP Core) service running on Windows Server 2012 R2 that executes Newman test suites via the command line. The command the service executes works perfectly when run directly in the command prompt, but is not working from the service. To add insult to injury, the very same command DOES work from the service running locally on my dev machine (Windows 10 Pro). I am certain I am running the same command in all instances, as the service outputs the CLI's StandardOutput into a file, the contents of which I paste straight into the command prompt.
EDIT: The service is hosted on IIS.
The error I receive:
module.js:471
throw err;
^
Error: Cannot find module 'C:\Users\MyName\AppData\Roaming\npm\node_modules\newman\bin\newman.js'
at Function.Module._resolveFilename (module.js:469:15)
at Function.Module._load (module.js:417:25)
at Module.runMain (module.js:604:10)
at run (bootstrap_node.js:393:7)
at startup (bootstrap_node.js:150:9)
at bootstrap_node.js:508:3
The command I'm running (all paths are the same in every instance):
"C:\Program Files\NodeJS\node.exe" C:\Users\MyName\AppData\Roaming\npm\node_modules\newman\bin\newman.js run https://api.getpostman.com/collections/MyCollectionURI -r cli,junit --reporter-junit-export D:\TestHarnessServiceLogs\XML\{FilenameFromDatetime}.xml -e https://api.getpostman.com/environments/MyEnvironmentURI --disable-unicode
C# to build and run command:
//Build over multiple lines to make it vaguely readable, then string replace away the newlines so it runs as one command
string runTestCmd = $#"{_nodeExecutablePath}
{_newmanDotJsFile} run
{collectionPath}
-r cli,junit
--reporter-junit-export {_junitReportPathWithFilename}
-e {environmentPath}
--disable-unicode"
.Replace(Environment.NewLine, " ")
.Replace("\t", "");
File.WriteAllText(#"D:\TestHarnessServiceLogs\Command.txt", runTestCmd);
//Launch hidden CLI
using (Process p = new Process())
{
p.StartInfo.FileName = #"C:\Windows\System32\cmd.exe";
p.StartInfo.RedirectStandardInput = true;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.UseShellExecute = false;
p.StartInfo.Arguments = _nodeVarsBatPath;
p.Start();
//Execute commands
using (StreamWriter sw = p.StandardInput)
{
if (sw.BaseStream.CanWrite)
{
sw.WriteLine(runTestCmd);
}
}
//Parse the various outputs
output = p.StandardOutput.ReadToEnd();
error = p.StandardError.ReadToEnd();
exitCode = p.ExitCode.ToString(); //Always returns 0, think this is because it evaluates success of creating the process, not what happens inside it
File.WriteAllText(#"D:\TestHarnessServiceLogs\output.txt", output);
File.WriteAllText(#"D:\TestHarnessServiceLogs\error.txt", error);
File.WriteAllText(#"D:\TestHarnessServiceLogs\exitCode.txt", exitCode);
}
Newman is installed globally in both environments, and some relevant AppSettings below (names modified slightly for brevity):
"_newmanDotJsFile": "C:\\Users\\MyName\\AppData\\Roaming\\npm\\node_modules\\newman\\bin\\newman.js",
"_nodeVarsBatPath": "\"C:\\Program Files\\NodeJS\\nodevars.bat\"",
"_nodeExecutablePath": "\"C:\\Program Files\\NodeJS\\node.exe\"",
How can an identical command find the newman module and run fine from the CLI but not from the service?
EDIT: The user the service is running under couldn't access the file, having done that I now get the following (obviously permissions based) error instead, think I know where this is going...:
fs.js:994
binding.lstat(pathModule._makeLong(path), statValues);
^
Error: EPERM: operation not permitted, lstat 'C:\Users\MyName'
at Error (native)
at Object.fs.lstatSync (fs.js:994:11)
at Object.realpathSync (fs.js:1676:21)
at toRealPath (module.js:133:13)
at Function.Module._findPath (module.js:181:22)
at Function.Module._resolveFilename (module.js:467:25)
at Function.Module._load (module.js:417:25)
at Module.runMain (module.js:604:10)
at run (bootstrap_node.js:393:7)
at startup (bootstrap_node.js:150:9)
EDIT 2: Created a new user for the service to run under, installed newman for that user and gave it the right permissions (didn't seem clever to give Network Service access to my profile) - all is now working!
It sounds like the service doesn't run as your user? Perhaps that's why it doesn't find the file in that location you specified.

Issue Seperate Arguments to Exe in one construct

I'm currently trying to pipe multiple parameters to the adb.exe file in the google sdk. an example of my inputs are:
adb shell getprop ro.build.version.release
adb shell getprop ro.product.brand
which are outputting correct from my application. Though, the problem is I want to populate a list view of information, the problem that i'm currently encountering though, is the method to pipe commands to get desired output. I've currently got:
var proc = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "Resources/adb.exe",
Arguments = "devices",
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
}
};
proc.Start();
string Output = proc.StandardOutput.ReadToEnd().ToString();
This currently returns as expected, but i'm wishing to get multiple results from piping something like:
Arguments = "devices ro.build.version.release ro.product.brand"
This provides no avail, even when piping directly into command prompt.
adb shell getprop devices ro.build.version.release ro.product.brand
empty, I have come around with a (assumingly) load heavy solution, which is to move the initialization of the executional into it's own function to be called multiple times. See code below:
public string GetInfo(string CommandArg)
{
var proc = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "Resources/adb.exe",
Arguments = CommandArg,
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
}
};
proc.Start();
return proc.StandardOutput.ReadToEnd().ToString();
}
public void SetDefineInformation()
{
AndroidVersion = decimal.Parse(GetInfo("ro.build.version.release"));
DeviceModel = GetInfo("ro.product.device");
...
}
To me, this seems like a load heavy task with constantly opening a single executable for it to close then re-open until the task is complete. Is there an overall work around, which might allow one to pipe multiple parameters to an executional and get the desired results?
adb can start a shell so you could create the shell with adb shell then redirect stdin and stdout to write to it directly
No measurable performance gain would come from the "optimization" you are proposing. The adb code is pretty efficient. The overhead it introduces is very minimal. Specially in the client part. Most of the delay comes from waiting for the device's response anyway.
So stop overcomplicating things and just run multiple adb shell sessions. If loading the adb binary bothers you so much - just use sockets to talk to the adb server directly. Take a look at the Mad Bee library code to see how to do it in c#. Or just use the library.
As for optimizing querying multiple system properties - just use adb shell getprop command to pull all properties at once.

How to use Process.Start() or equivalent with Mono on a Mac and pass in arguments

I am trying to write some c# code to start a browser using Process.Start(app,args); where apps is the path to the browser e.g. /Applications/Google Chrome.app/Contents/MacOS/Google Chrome and the args are --no-default-browser-check
If i do, which works on Windows and on Linux
Process.Start("/Applications/Google Chrome.app/Contents/MacOS/Google Chrome","--no-first-run");
I get
open: unrecognized option `--no-first-run'
Usage: open [-e] [-t] [-f] [-W] [-n] [-g] [-h] [-b <bundle identifier>] [-a <application>] [filenames]
Help: Open opens files from a shell.
By default, opens each file using the default application for that file.
If the file is in the form of a URL, the file will be opened as a URL.
Options:
-a Opens with the specified application.
-b Opens with the specified application bundle identifier.
-e Opens with TextEdit.
-t Opens with default text editor.
-f Reads input from standard input and opens with TextEdit.
-W, --wait-apps Blocks until the used applications are closed (even if they were already running).
-n, --new Open a new instance of the application even if one is already running.
-g, --background Does not bring the application to the foreground.
-h, --header Searches header file locations for headers matching the given filenames, and opens them.
I have also tried Monobjc to try run the code with
// spin up the objective-c runtime
ObjectiveCRuntime.LoadFramework("Cocoa");
ObjectiveCRuntime.Initialize();
NSAutoreleasePool pool = new NSAutoreleasePool();
// Create our process
NSTask task = new NSTask();
NSPipe standardOut = new NSPipe();
task.StandardOutput = standardOut;
task.LaunchPath = #"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome";
// add some arguments
NSString argumentString = new NSString("--no-first-run");
NSArray arguments = NSArray.ArrayWithObject(argumentString);
task.Arguments = arguments;
// We should have liftoff
task.Launch();
// Parse the output and display it to the console
NSData output = standardOut.FileHandleForReading.ReadDataToEndOfFile;
NSString outString = new NSString(output,NSStringEncoding.NSUTF8StringEncoding);
Console.WriteLine(outString);
// Dipose our objects, gotta love reference counting
pool.Release();
But when I run my code using NUnit it causes NUnit to blow up.
I suspect that this is a bug but can't prove it. I appreciate any and all help!
To make Process.Start use exec directly instead of using the OS' mechanism for opening files, you must set UseShellExecute to false. This is also true on Linux and Windows.
Process.Start(new ProcessStartInfo (
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
"--no-first-run")
{ UseShellExecute = false });
Note that you can also use 'open' for your use case, to run the Chrome app bundle properly. Use the '-a' argument to force it to run a specific app, the '-n' argument to open a new instance, and '--args' to pass in arguments:
Process.Start(new ProcessStartInfo (
"open",
"-a '/Applications/Google Chrome.app' -n --args --no-first-run")
{ UseShellExecute = false });
Looks like Process uses the open command line utility to launch.
You should avoid calling the executable directly. If the application is already running, this would launch a second instance of it instead of activating the already running instance. That's probably not what you want, and not all applications can handle this anyway.
With open, the syntax to launch Chrome would be
open -a Chrome
I don't know how the Process class works on MacOS X, but I assume that the parameters should be similar.
Note, if you just want to open a web page, you should not specify the executable; instead, just pass the URL, so that it will be opened in the user's default browser. This is valid for any platform.
Process.Start("http://www.google.com");
Have you tried something like concatenating the parameters into the process name instead of passing it separated?
var processName = "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome";
var args = "--no-default-browser-check";
Process.Start(String.Format("{0} {1}", processName, args));
Why dont you try something like this:
Process P = new Process();
P.StartInfo.FileName = "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome";
P.StartInfo.Arguments = "--no-default-browser-check";
P.UseShellExecute = false;
P.Start();

C#: Query FlexLM License Manager

Does anyone have any experience querying FlexLM? (At a minimum) I need to be able to tell if a license is available for a particular application. Previously this was done by checking what processes were running, but if I can somehow query FlexLM, that would be more elegant!
I've done this recently. I needed to query FlexLM license servers, and discover what licenses were outstanding/available. I didn't find a reasonable API for this, so I instead just launched lmutil, asked it to query the server, and parsed laboriously through the textual results. A pain, but it worked, and really didn't take that long to put together.
Find your copy of lmutil.exe, and run it with either the -a or -i switch, depending on the data you want to gather. Pass it the server and port you wish you query, with the -c switch. Yes, you will need to know the port the FlexLM daemon's running on. There's a standard port, but there's nothing forcing it to run on that port only.
Since I needed to run this regularly, and I needed to query thousands of daemons, I drove lmutil from an application - something like:
string portAtHost = "1708#my.server.com";
string args = String.Format("lmstat -c {0} -a -i", portAtHost);
ProcessStartInfo info = new ProcessStartInfo(#"lmutil.exe", args);
info.WindowStyle = ProcessWindowStyle.Hidden;
info.UseShellExecute = false;
info.RedirectStandardOutput = true;
using (Process p = Process.Start(info))
{
string output = p.StandardOutput.ReadToEnd();
// standard output must be read first; wait max 5 minutes
if (p.WaitForExit(300000))
{
p.WaitForExit(); // per MSDN guidance: Process.WaitForExit Method
}
else
{
// kill the lmstat instance and move on
log.Warn("lmstat did not exit within timeout period; killing");
p.Kill();
p.WaitForExit(); // Process.Kill() is asynchronous; wait for forced quit
}
File.WriteAllText("c:\file.lmout", output);
}
...then you need to parse through the results. Depending what you're looking for, this could be as simple as splitting the result lines over space characters.

Categories