How to close ssh connections opened via script - bash

I use the following script to open a ssh tunnel to a bunch servers always varying between mysql, redis and ssh ports.
I am doing this while being in the company vpn, but I had the same problem back in the days, when you worked in the office.
Usually I start the script and use the opened connection with other tools like SequelPro or PhpStorm to connect to webserver or databases. Ideally it would just run until I don't need it any more and then I would exit the jumpserver and the connections should close. That is fine as long as I don't loose the connection and get kicked out of the jumpserver.
#!/bin/sh
username="my-user"
jumpServer="my.bastionserver.net"
hosts=("my.awsserver1.com" "my.awsserver2.com" "my.awsserver3.com")
destMysqlPort=3306
destSshPort=22
destRedisPort=6379
x=10001
y=10002
z=10003
for i in "${hosts[#]}"; do
:
server=$i
sshTunnel="$sshTunnel -L $x:$server:$destMysqlPort -L $y:$server:$destSshPort -L $y:$server:$destRedisPort"
echo "Server: $server -- MYSQL: $x -- SSH: $y-- Redis: $z"
x=$((x + 3))
y=$((y + 3))
z=$((z + 3))
done
if [ -z "$sshTunnel" ]
then
echo "ssh tunnels are empty"
else
ssh $sshTunnel $username#$jumpServer -i ~/.ssh/aws
fi
the output is as follows:
$ ./awstunnel.sh
Server: my.awsserver1.com -- MYSQL: 10001 -- SSH: 10002-- Redis: 10003
Server: my.awsserver1.com -- MYSQL: 10004 -- SSH: 10005-- Redis: 10006
Server: my.awsserver1.com -- MYSQL: 10007 -- SSH: 10008-- Redis: 10009
[...]
When I try to connect again via this script I get the messages that the address is already in use:
bind [127.0.0.1]:10002: Address already in use
channel_setup_fwd_listener_tcpip: cannot listen to port: 10002
bind [127.0.0.1]:10005: Address already in use
channel_setup_fwd_listener_tcpip: cannot listen to port: 10005
[...]
How can I change the script so that I can start it again right away and don't have to wait for quite some time until the connection via this tunnel really closes?
I work from a Mac and the jumpserver is a Linux server, where I should not change settings.

Just like this, a little hint:
To get the PID of the last executed command you have to type:
echo "$!"
So, what you can do is just store the PID after each ssh login command like this for example:
#Store the pid of the last command in a variable named sshPid:
sshPid=$!
and when you are done just kill the corresponding PID with:
kill ${sshPid}
Tell me if that worked for you :p
Bguess

Related

Why netcat port forwarding can just receive one time connection?

I have one http server open 8000 port like next:
orange#orange:~$ python -m SimpleHTTPServer
Serving HTTP on 0.0.0.0 port 8000 ...
As known to all, there are several versions netcat, but for some reasons, I can just use next versions:
root#orange:~# busybox nc
BusyBox v1.27.2 (Ubuntu 1:1.27.2-2ubuntu3.2) multi-call binary.
Usage: nc [-iN] [-wN] [-l] [-p PORT] [-f FILE|IPADDR PORT] [-e PROG]
Open a pipe to IP:PORT or FILE
-l Listen mode, for inbound connects
(use -ll with -e for persistent server)
-p PORT Local port
-w SEC Connect timeout
-i SEC Delay interval for lines sent
-f FILE Use file (ala /dev/ttyS0) instead of network
-e PROG Run PROG after connect
This means only above parameters should be used.
I did next:
root#orange:~# rm -f /tmp/backpipe && mkfifo /tmp/backpipe && cat /tmp/backpipe | busybox nc 127.0.0.1 8000 | busybox nc -l -p 80 > /tmp/backpipe
The aim is: when user visit http://127.0.0.1:80, it will automactically forward to http://127.0.0.1:8000, so the contents of python simplehttpserver will returned to user.
Finally, I launch test client:
orange#orange:~$ wget http://127.0.0.1
--2019-06-26 22:47:25-- http://127.0.0.1/
Connecting to 127.0.0.1:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 1378 (1.3K) [text/html]
Saving to: ‘index.html’
index.html 100%
[==============================================>] 1.35K --.-KB/s in 0s
2019-06-26 22:47:25 (505 MB/s) - ‘index.html’ saved [1378/1378]
Above all ok, but back to the port forward command, I found it had been exit, so it nolonger receive the second time connect.
So, my question is, with above busybox netcat, how can I make this port forward command not exit after the first connection.
NOTE: I don't want the solution with for-loop, I just want to find the way to do port forward with above netcat, meanwhile it will continue serve after the first connection.
You may have been using an older version of busybox. Current versions come with the -lk flag, which allows you to persist the server beyond just a single connection.
In order to accomplish what you wanted, you can do something like this:
busybox nc -lk -p 80 -e busybox nc localhost 8000

Script to check if SSH service in Docker is up

My docker container has two services: a web service and a SSH server.
The SSH server is openssh-server and I need to run the command docker exec -it my-container sudo service ssh restart from outside the container to start the SSH server.
However, the command doesn't succeed all the time. Every time I need to manually check if the SSH server is up in the container using the command: ssh root#localhost:
1) If the SSH server fails to start, the result is ssh_exchange_identification: Connection closed by remote host
2) Otherwise, it asks for the password. (Which indicates that the SSH server is up)
Since I have to deploy multiple containers at the same time, it is unrealistic to check every container manually. Therefore, I want to retry the docker exec -it my-container sudo service ssh restart command automatically if the SSH serve fails to start. But I am not sure how to write the bash script to achieve this. It basically should work like this:
while (ssh_server_fails_to_start):
docker exec -it my-container sudo service ssh restart
Any comments or ideas are appreciated. Thanks in advance!
If the sshd is up an running, it will accept connections on its certain port. Otherwise, the connection attempt will fail.
If you run the following command:
ssh -o PasswordAuthentication=No root#localhost true
This will fail in either way, but the output will be different. In the case that the server is running and accepting connections, the explicit switch-off of password authentication will make it fail with this message:
Permission denied (publickey,password).
Otherwise it will print out a message like this:
ssh: connect to host localhost port 22: Connection refused
So I propose to scan the error message for a hint like this:
if ssh -o PasswordAuthentication=No root#localhost true \
|& grep -q "Connection refused"
then
echo "No server reachable!"
else
echo "Server reachable."
fi
So you could write your script like this:
while ssh -o PasswordAuthentication=No root#localhost true \
|& grep -q "Connection refused"
do
docker exec -it my-container sudo service ssh restart
done
You might want to add some sleep delays to avoid hurried restarts. Maybe the ssh server just needs some time to accept connections after being restarted.
To test the ssh connection, we can use sshpass package to provide a password in the command line.
while : ; do
docker exec -it my-container sudo service ssh restart
sleep 5s
sshpass -p 'root' ssh -q root#localhost -p 2222 exit
if [ $? == 0 ]; then
echo "SSH server is running."
break
fi
echo "SSH server is not running. Restarting..."
done

User-level command shell change for accessing remote machine with paramiko

I use some code connecting with remote machine with use of paramiko library. The connection is established over tunnelling ssh connection bound to one of the localhost ports. The default shell on the remote machine is tcsh, but my code requires it to run bash. I have tested the sshing some simple commands and it works fine.
$ ssh localhost -p 2222 'echo $0'
tcsh
To change the login shell I have added to my .tcshrc file following two lines:
setenv SHELL /bin/bash
exec /bin/bash --login
The following thing works:
$ ssh localhost -p 2222
[user#remote ~]$ echo $0
/bin/bash
But not the following:
$ ssh localhost -p 2222 'echo $0'
which gives no response. The same for the connections with paramiko established by the code I want to use.
At the moment I am limited only to user-level solutions and would rather not play with the paramiko-using-code itself. Is there anything else I could try here?

Expect: How can I open a telnet session from an ssh session?

I want to write a script that automatically connects me via SSH to a given IP, and after that opens a telnet session from where it just connected.
My expect code till now:
# $1 = ssh root#111.111.111.111
# $2 = password
# $3 = telnet 123.123.123.123 10023
(expect -c "
set timeout 20
spawn $1
expect {
\"Password:\" { send \"$2\r\" }
timeout { send_error \"\nTimeout!\n\"; exit 1; }
}
spawn $3
interact
" )
My problem is that I cannot spawn the telnet in the ssh session, the script is just "telnetting" from my home directory. Maybe there is a way with session ids, but I could not find helpful information.
Would be nice if someone of you could suggest some solution or workaround,
thanks in advance and please excuse my bad English skills :)
Edit:
What helped with my problem, was:
(expect -c "
set timeout 20
spawn ssh root#server telnet server2
expect {
\"Password:\" { send \"$2\r\" }
timeout { send_error \"\nTimeout!\n\"; exit 1; }
}
interact
" )
I'd have a bit of a different approach for you, easier maybe.
As I understand it:
You want to SSH into a server of yours and from there telnet to another place
Did you consider using key based authentication with SSH ?
For this approach you would add your identity key to .ssh/authorized_keys on the remote server.
Here is an example which uses expect from command line, connects to a SSH server using a key file and from there connects to a mailserver and sends "HELO test"
Tested it on my servers, works
expect -c 'expect "\n" {eval spawn ssh -i identity_file my.sshserver.com telnet mail.anotherserver.com 25; expect "SMTP" {send "HELO test\r\n"};interact}'
you can also add a timeout option to ssh (-oConnectTimeout)
It will connect to the server and call the telnet command, so you would have an open SSH session which has telnet already connected.
The script waits for an initial ENTER from you to start.
As you also asked for a Workaround, here is one: You can use ssh port forwarding
ssh -f -N -n root#111.111.111.111 -L 10024:123.123.123.123:10023
[wait for connecting]
telnet localhost 10024
Here, ssh will open a connection and go into background. the local ssh client will listen on port 10024 and redirect all traffic to 123.123.123.123 port 10023. As long as this ssh instance is running, you can open and use telnet sessions (From the initial location).

Google Apps Script JDBC connection problem

I have problem to connect to any mysql database using jdbc connector in google apps scripts, I'm using tutorial code:
var conn = Jdbc.getConnection("jdbc:mysql://host(or ip):3306/database", "username", "password");
But in each case ( I've tested 4 different databases on 4 different host names) i get the same error:
Failed to establish a database connection. Check connection string, username and password. (line 2)
I'm looking for some help, I have no idea what could be the problem ;-(
ps. usernames/passwords are ok.
pps. In each database remote access is working ( I've tested by using telnet).
Since your issue was Remote access to a MySQL Database I will post some related documentation so that future viewers like TonyMiao will have a avenue to fix their own related issues.
Step # 1: Login Using SSH (if server is outside your data center)
First, login over ssh to remote MySQL database server. You may need to login to your MySQL server as the root user:
ssh user#server1.cyberciti.biz
login as the root using su or sudo
su
or use sudo
sudo -i
OR directly login as root user if allowed:
ssh root#server1.cyberciti.biz
Step # 2: Edit the my.cnf file
Once connected you need to edit the MySQL server configuration file my.cnf using a text editor such as vi:
If you are using Debian/Ubuntu Linux file is located at /etc/mysql/my.cnf location.
If you are using Red Hat Linux/Fedora/Centos Linux file is located at /etc/my.cnf location.
If you are using FreeBSD you need to create a file /var/db/mysql/my.cnf location.
Edit the /etc/my.cnf, run:
# vi /etc/my.cnf
Step # 3: Once file opened, locate line that read as follows
[mysqld]
Make sure line skip-networking is commented (or remove line) and add following line
bind-address=YOUR-SERVER-IP
For example, if your MySQL server IP is 65.55.55.2 then entire block should be look like as follows:
[mysqld]
user = mysql
pid-file = /var/run/mysqld/mysqld.pid
socket = /var/run/mysqld/mysqld.sock
port = 3306
basedir = /usr
datadir = /var/lib/mysql
tmpdir = /tmp
language = /usr/share/mysql/English
bind-address = 65.55.55.2
# skip-networking
....
..
....
Where,
bind-address: IP address to bind to.
skip-networking : Don’t listen for TCP/IP connections at all. All
interaction with mysqld must be made via Unix sockets. This option is
highly recommended for systems where only local requests are allowed.
Since you need to allow remote connection this line should be removed
from my.cnf or put it in comment state.
Step# 4 Save and Close the file
If you are using Debian / Ubuntu Linux, type the following command to restart the mysql server:
# /etc/init.d/mysql restart
OR
# systemctl restart mysql
If you are using RHEL / CentOS / Fedora / Scientific Linux, type the following command to restart the mysql server:
# /etc/init.d/mysqld restart
OR
# systemctl restart mysqld
If you are using FreeBSD, type the following command to restart the mysql server:
# /usr/local/etc/rc.d/mysql-server restart
OR
# service mysql-server restart
Step # 5 Grant access to remote IP address
Connect to mysql server:
$ mysql -u root -p mysql
GRANT ACCESS TO A NEW DATABASE
If you want to add a new database called foo for user bar and remote IP 202.54.10.20 then you need to type the following commands at mysql> prompt:
mysql> CREATE DATABASE foo;
mysql> GRANT ALL ON foo.* TO bar#'202.54.10.20' IDENTIFIED BY 'PASSWORD';
HOW DO I GRANT ACCESS TO AN EXISTING DATABASE?
Let us assume that you are always making connection from remote IP called 202.54.10.20 for database called webdb for user webadmin, To grant access to this IP address type the following command At mysql> prompt for existing database, enter:
mysql> update db set Host='202.54.10.20' where Db='webdb';
mysql> update user set Host='202.54.10.20' where user='webadmin';
Step # 6: Logout of MySQL
Type exit command to logout mysql:
mysql> exit
Step # 7: Open port 3306
You need to open TCP port 3306 using iptables or BSD pf firewall.
A SAMPLE IPTABLES RULE TO OPEN LINUX IPTABLES FIREWALL
/sbin/iptables -A INPUT -i eth0 -p tcp --destination-port 3306 -j ACCEPT
OR only allow remote connection from your web server located at 10.5.1.3:
/sbin/iptables -A INPUT -i eth0 -s 10.5.1.3 -p tcp --destination-port 3306 -j ACCEPT
OR only allow remote connection from your lan subnet 192.168.1.0/24:
/sbin/iptables -A INPUT -i eth0 -s 192.168.1.0/24 -p tcp --destination-port 3306 -j ACCEPT
Finally save all rules (RHEL / CentOS specific command):
# service iptables save
A SAMPLE FREEBSD / OPENBSD / NETBSD PF FIREWALL RULE ( /ETC/PF.CONF)
Use the following to open port # 3306 on a BSD based systems:
pass in on $ext_if proto tcp from any to any port 3306
OR allow only access from your web server located at 10.5.1.3:
pass in on $ext_if proto tcp from 10.5.1.3 to any port 3306 flags S/SA synproxy state
Step # 8: Test it
From your remote system or your desktop type the following command:
$ mysql -u webadmin -h 65.55.55.2 -p
Where,
-u webadmin: webadmin is MySQL username
-h IP or hostname: 65.55.55.2 is MySQL server IP address or hostname (FQDN)
-p : Prompt for password
You can also use the telnet or nc command to connect to port 3306 for testing purpose:
$ echo X | telnet -e X 65.55.55.2 3306
OR
$ nc -z -w1 65.55.55.2 3306
Sample outputs:
Connection to 65.55.55.2 3306 port [tcp/mysql] succeeded!
Resource information: Click Here!

Resources