I am writing a program with c# and .net core 3.1 which connecting to a UPS (Uninterruptible power supply) via Telnet connection. For Telnet connection I use codes from Quick tool : A minimalistic Telnet library - CodeProject .
//create a new telnet connection to hostname "gobelijn" on port "23"
TelnetConnection tc = new TelnetConnection("gobelijn", 23);
//login with user "root",password "rootpassword", using a timeout of 100ms,
//and show server output
string s = tc.Login("root", "rootpassword",100);
Console.Write(s);
// server output should end with "$" or ">", otherwise the connection failed
string prompt = s.TrimEnd();
prompt = s.Substring(prompt.Length -1,1);
if (prompt != "$" && prompt != ">" )
throw new Exception("Connection failed");
prompt = "";
// while connected
while (tc.IsConnected && prompt.Trim() != "exit" )
{
// display server output
Console.Write(tc.Read());
// send client input to server
prompt = Console.ReadLine();
tc.WriteLine(prompt);
// display server output
Console.Write(tc.Read());
}
Console.WriteLine("***DISCONNECTED");
Console.ReadLine();
It worked for some simple one line-many parameter commands; like Settime [YYMMDD-HHmmss] that set time of the device. But When I want to execute a command like nsave that save changes in the device, command prompt of Telnet becomes like this:
>>nsave
Are you sure? (y/n)
I want to send y but I can’t.
Besides that, after each command I execute exit command to disconnect Telnet connection, but in this scenario (nsave) the connection will remain open and my program cannot connect to Telnet to execute further commands.
How can I include yes or other inputs in similar conditions?
Related
I am trying to automatically create an SSH connection for a program that uses an SSH tunnel to update a local database from a remote PostgreSQL server. Up to this time, I have been manually opening a tunnel with PuTTY (including local port forwarding instructions with the -L command). I want to use ssh.net to automatically open the port when the program is run. Once the connection is made, the program uses Entity Framework Core to access the remote database.
When I open the SSH connection with PuTTY, the program runs fine. This is the PuTTY command:
//plink.exe -i "C:\Users\user.name\Desktop\host_private_key.ppk" -L 6544:111.22.33.66:6543 -N user#address.io -pw *PASSWORD*"
(login details removed for privacy)
This is the ssh.net code that I have trying to open the same connection:
public void MakeSSHTunnel()
{
string password = "password";
// path of RSA private key in openSSH format:
string privateKeyPath = "C:/Users/user.name/.ssh/id_rsa";
try
{
// creates variable to transmit RSA private key + passphrase to server via SSH.NET, openSSH compatible.
var privateKeyFile = new PrivateKeyFile(privateKeyPath, password);
string serverAddress = "address.io";
string user = "user";
// allows for the remote port forwarding options required by the server
using (var client = new SshClient(serverAddress, user, privateKeyFile))
{
client.Connect();
var tunnel = new ForwardedPortLocal(6544, "111.22.33.66", 6543);
client.AddForwardedPort(tunnel);
// testing weather the connection has been successful:
if (client.IsConnected)
{
Console.WriteLine("OPENTUNNEL.CS: Connection to {0} successful.", serverAddress);
state = "Open";
}
else
{
Console.WriteLine("Connection to {0} failed.");
state = "Closed";
}
tunnel.Exception += delegate (object sender, ExceptionEventArgs e)
{
Console.WriteLine(e.Exception.ToString());
};
tunnel.Start();
Program.RunBackup();
// ... closes the port ... //
tunnel.Stop();
client.Disconnect();
}
}
catch (UnauthorizedAccessException e)
{
Console.WriteLine(e);
}
}
I am confused since in the above, the if (client.IsConnected) returns true.
The error seems to be occurring when the Entity Framework Core OnConfiguring() method passes details of the connection with its optionsBuilder:
optionsBuilder.UseNpgsql($"Host=127.0.0.1;Port=6544;Database=user;Username=user;Password=databasePassworh;CommandTimeout=300;Timeout=300;SSL Mode=Require;Trust Server Certificate=true;Convert Infinity DateTime=true");
The errors that are arising are:
NpgsqlException: Exception while connecting
and:
ExtendedSocketException: No connection could be made because the target machine actively refused it. 127.0.0.1:6544
I have double checked all passwords, and read through all the SSH.NET documentation and code examples, and left all the previously working (via PuTTY) code untouched.
If anyone can see what I'm doing wrong, I would be grateful. C#, SSH.NET and port forwarding are new to me, please tell me where I'm being an idiot.
This code is now working. I believe the problem was that in line:
var tunnel = new ForwardedPortLocal(6544, "111.22.33.66", 6543);
the 'bound port' did not include an address. I had seen examples where this was undefined, and had followed these. On stepping through the code, I noticed that the field was blank, and decided to try 127.0.0.1. This is now successfully connecting to the database. It works with:
var tunnel = new ForwardedPortLocal("127.0.0.1", 6544, "111.22.33.66", 6543);
Thanks for looking into this and for your contributions.
I am doing SSH to a Linux machine and again from there want to SSH to another Linux machine to carry out few Perforce tasks.
using (SshClient ssh = new SshClient("ip address","username", "pwd"))
{
ssh.Connect();
command = ssh.CreateCommand("ssh hostname");
result = command.Execute();
Console.WriteLine(result);
}
Where the ssh hostname is a password less ssh. How can I control the second SSH session and pass commands to it?
Even explored the CreateShell function, but seems like it is not suggested for automation.
In general, trying to automate ssh command is a bad design.
You better use a port forwarding (aka SSH tunnel) to implement the "hop".
var firstClient =
new SshClient(firstHostName, firstUserName, firstPassword);
firstClient.Connect();
var port = new ForwardedPortLocal("127.0.0.1", secondHostName, 22);
firstClient.AddForwardedPort(port);
port.Start();
var secondClient =
new SshClient(port.BoundHost, (int)port.BoundPort, secondUserName, secondPassword);
secondClient.Connect();
var command = secondClient.CreateCommand("ls");
var result = command.Execute();
Console.WriteLine(result);
There are some cases, when automating the ssh is acceptable (while still not ideal). E.g. because there's an authentication to the second host set up on the first one. I.e. there might be private key in the .ssh folder and you are not allowed to transfer that key to your client machine.
Even then, try talking to the system Administrator to find a better solution. The private key is still accessible using the credentials contained in your application, so it's not protected any better, had the private key itself been contained directly in the application.
Anyway, ssh can accept a command on its command line, like:
command = ssh.CreateCommand("ssh hostname command");
result = command.Execute();
Console.WriteLine(result);
I'm using the SSH.NET library to execute a command on a (Red Hat) server - something like this:
var response = string.Empty;
using (var client = new SshClient("<host>", "<username>", "<password>"))
{
client.Connect();
var cmd = client.CreateCommand("<some command>");
response = cmd.Execute();
client.Disconnect();
}
I't works great - except that I have to use a jumphost...
This is normally done by connecting to the jumphost and execute a 'ssh' command to connect to another server:
ssh <user>#<server>
You are then asked for a password before you get connected. You are now connected to the other server - which is ended by the 'exit' command.
Can this be achieved in SSH.NET (or another C# library) ?
I have tried using the 'RunCommand' which returns:
Pseudo-terminal will not be allocated because stdin is not a terminal.
I want to run command and get the result on remote computer which has Linux operating system. I am using ssh .net library to connect by C# code. I can connect and run some commands that it doesn't need to use "sudo" before. but I don't know How to run commands which need to be run by sudo, because after run -for instance- "sudo iptables -L -n" I should enter password and I don't know How to enter password after execute this command.
This is my code :
private void connectingToLinuxHost(string ip, string username, string password, int port)
{
SshCommandLineRunner ssh = new SshCommandLineRunner(ip, username, password, port);
ssh.Connect();
string output1 = ssh.ExecuteCommand("ls");
ssh.ExecuteCommand("sudo iptables -L -n");
Thread.Sleep(1000);
string output2 = ssh.ExecuteCommand(password);
ssh.ExecuteCommand("sudo iptables -L -n \n");
Thread.Sleep(1000);
string output3 = ssh.ExecuteCommand(password);
}
when this function run, I can connect to remote pc successfully, output1 has correct value, but output2 and output3 are empty. actually it is obvious that after sudo command it is needed to enter password.
I have read most question about ssh .net. some similar question has retain unanswered.
SSH .NET : freeze upon sudo su - user2
( he or she didnt know the password but I know I dont know how to enter it via code)
How to su with SSH.Net?
(I used create shell method but i couldn't understand what is for and like this question I got "Last login: ..." output.)
The most secure way to do it, as already mentioned by a comment, is to use CreateShellStream and just write the password directly to the stream after running the sudo command. The password gets sent just as if you had been using an interactive terminal. This might not be a convenient solution, though, if you don't want to be locked into using an endless stream for the rest of what you want to do. Example:
var promptRegex = new Regex(#"\][#$>]"); // regular expression for matching terminal prompt
var modes = new Dictionary<Renci.SshNet.Common.TerminalModes, uint>();
using (var stream = ssh.CreateShellStream("xterm", 255, 50, 800, 600, 1024, modes))
{
stream.Write("sudo iptables -L -n\n");
stream.Expect("password");
stream.Write("mypassword\n");
var output = stream.Expect(promptRegex);
}
The downside is that your output will include junk you don't really want: control characters, prompts, and everything else that gets sent over the stream.
If you want to avoid using a shell stream then you may be able to (depending on security settings) provide a password via stdin. THIS IS INSECURE because commands get logged in various places and you might be revealing your password to other users with root access. If you're the only user, or if you don't care that everybody else can see your password, then this might be more convenient for you.
Example:
using (var cmd = ssh.RunCommand("echo -e 'mypassword\n' | sudo -S iptables -L -n"))
{
if (cmd.ExitStatus == 0)
Console.WriteLine(cmd.Result);
else
Console.WriteLine(cmd.Error);
}
Finally, it's also possible to have a script print your password to stdin. This way your password won't get logged along with the rest of the command line; but this still isn't much more secure since anyone with root access could potentially read the script and see the password:
using (var cmd = ssh.RunCommand("~/printpasswd.sh | sudo -S iptables -L -n"))
{
if (cmd.ExitStatus == 0)
Console.WriteLine(cmd.Result);
else
Console.WriteLine(cmd.Error);
}
and inside printpasswd.sh:
#!/bin/bash
echo -e 'mypassword\n'
You can use the same bash command with Renci library and install in the server "sshpass" package. In this case you can use:
SshClient client = new SsClient(IP_server, username, password);
client.Connect();
var commandToSend = client.CreateCommand("sshpass -p \"password\" sudo iptables -L");
commandToSend.Execute();
string response = commandToSend:Result.ToString();
Console.WriteLine("Response: " + response);
This is the situation. I have a Windows machine and a Linux machine. There is a shared drive between these two machines (which is mapped to Q:). I am trying to figure out how to create an SSH session at the Q: drive (shared drive) from C#. I am trying to use the SharpSsh library to do this.
This is what I have so far, however, it is giving me an error:
try
{
ssh = new SshStream(host, username, password);
Console.WriteLine("OK ({0}/{1})", ssh.Cipher, ssh.Mac);
Console.WriteLine("Server version={0}, Client version={1}", ssh.ServerVersion, ssh.ClientVersion);
Console.WriteLine("-Use the 'exit' command to disconnect.");
Console.WriteLine();
//Sets the end of response character
ssh.Prompt = "#";
//Remove terminal emulation characters
ssh.RemoveTerminalEmulationCharacters = true;
//Reads the initial response from the SSH stream
Console.Write(ssh.ReadResponse()); // Blocking here
while (true)
{
string command = Console.ReadLine();
if (command.ToLower().Equals("exit"))
break;
//Write command to the SSH stream
ssh.Write(command);
//Read response from the SSH stream
Console.Write(ssh.ReadResponse());
}
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
if(ssh != null)
{
ssh.Close();
}
I have added the Tamir.SharpSSH.dll as a reference to the project, and I am using it in the project. There are two other dll's that are included with SharpSSH, do I need to add them as well to the references? The examples I have seen only have the Tamir.SharpSSH.dll as a reference.
I am not sure how to initiate the connection in the correct location, and how to submit commands properly to the ssh.
UPDATE
I realized I needed to close the SSH connection before ending the program. The error does not exist anymore, however, I am still not getting any information from my "ls" command.
UPDATE
I updated the code with what I have now. It seems like the ssh.ReadResponse() is blocking, which leads me to believe the server is not responding. Is that correct?