Catch sshtunnel exception with Python - python

I have a python code that brings up an SSH connection to remote server to further forward telnet traffic to several routers hidden behind this server, in order to remote manage those. The code is the following:
def sshStart(self):
try:
self.sshServer = SSHTunnelForwarder(
(SRVR_IP, SRVR_PORT),
ssh_username = SRVR_USER[0],
ssh_password = SRVR_USER[1],
remote_bind_address = (self.systemIP, 23),
local_bind_address = ("127.0.0.1", self.localPort)
)
self.sshServer.start()
except:
fncPrintConsole(self.strConn + "Error SSH Tunnel")
self.quit()
def routerLogin(self):
try:
self.tn = telnetlib.Telnet("127.0.0.1",self.localPort)
except:
fncPrintConsole(self.strConn + "No route to host!")
self.quit()
This is working very nice. Indeed, I can easily manage several routers with this code, provided that there is networking towards the far-end router.
The problem arises when the remote router (in other words, the combination of 127.0.0.1:self.localPort -> self.systemIP, 23) is not reachable because of something (timeout, no routing available, etc ... ).
In such a case, I get the following error:
2017-07-24 10:38:57,409| ERROR | Could not establish connection from ('127.0.0.1', 50000) to remote side of the tunnel
2017-07-24 10:38:57,448| ERROR | Secsh channel 0 open FAILED: Network is unreachable: Connect failed
Even though the error is correct (there actually is no reachability to the remote router) I cannot catch that error: the python program gets stuck there for ever and I cannot exit it properly (i.e.: if error -> quit() )
Do you have any clue on how to accomplish this?
Thanks!
Lucas

So, the issue of catching the exception was solved at a later stage within the code.
After triggering the telnet connection ...
def routerLogin(self):
try:
self.tn = telnetlib.Telnet("127.0.0.1",self.localPort)
except:
fncPrintConsole(self.strConn + "No route to host!")
self.quit()
... I do expect some string before going on.
i = self.tn.expect(PROMPT_LOGIN, TIME_LOGIN)
For some reason I thought that including try | except when creating the tn connection was enough. But no, I kept on receiving the SSH error mentioned.
Wrapping the tn.expect with try|except did the trick. So now I have...
try:
i = self.tn.expect(PROMPT_LOGIN, TIME_LOGIN)
except:
quit()
... and in the case of reachability problems I can catch it up there.
Don't know if this is the more elegant / right way of doing it but at least is working ...
Thanks!
Lucas

Related

Is there any way to test the weblogic admin connecting URL (t3/t3s) before connecting to it

I'm using following command to connect to weblgic using WLST,
java weblogic.wlst core.py
inside core.py I'm calling following command to connect to the weblogic admin. but some times the service url becomes unresponsive And my script hangs occasionally due to this. Is there any way to give a timeout to this connect() method or any other method to implement a timeout functionality?. Appreciate if someone can shed some light on this. Thanks.
connect(username,password,t3://:)
in earlier WebLogic versions they have provided following functionality(to ping), but they have removed it after 12.2*
java weblogic.Admin -url t3://localhost:7001 -username weblogic -password weblog
ic ping 3 100
This is a very common situation, where you can use Python's socket module to check that the Admin port is opened or not with the following function.
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
AdminIP = '192.168.33.10'
result = sock.connect_ex((AdminIP,7001))
if result == 0:
print "AdminPort is open you can connect"
else:
print "Admin Port is not yet open"
sock.close()
add your logic accordingly, HTH!

AWS Lambda timed out error for checking if a port is open on a DNS name

I have a very basic Python code that checks if an array of ports are open on a load balancer DNS. So, I am using the conventional SOCKET to check it. When I tried executing the code on my local machine, it was running good and giving the expected output. When I tried to deploy the same logic over Lambda, I am getting a timed out error.
My local code:
import socket
DNS = ['loadbalancer-dns.elb.amazonaws.com']
PORT = [8099,9087,10041,10004,5001,3001,4001,10010,8085,9050,8088,8081,10041,8086,8072,10025,20026,10006,9098,9099,10005,8070]
for iDNS in DNS:
for iport in PORT:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
output = sock.connect_ex((iDNS,iport))
if output == 0:
print(f'Port {iport} is open on {iDNS}')
else:
print(f'Port {iport} is closed on {iDNS}')
sock.close()
My Lambda function code:
import json
import boto3
import socket
PORT = [8099,9087]
DNS = ['loadbalancer-dns.elb.amazonaws.com']
def lambda_handler(event, context):
try:
for iDNS in DNS:
for iport in PORT:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
output = sock.connect_ex((iDNS,iport))
if output == 0:
print(f'Port {iport} is open on {iDNS}')
else:
print(f'Port {iport} is closed on {iDNS}')
sock.close()
except:
print('Task timed out')
My Python version in Lambda is Python 3.8 and my Timeout value is set to 1 minute 30 seconds.
Found the reason to the problem. My loadbalancer is an internal load balancer that serves the applications running in Private subnets. There has been a VPN configured to my VPC. So after attaching the VPC to my Lambda function, it worked.
Timeout errors can be attributed to several issues.
Insufficient processing power. While your code on the first glance isn't very heavy, it still is of O(N2) complexity. In case you expand it in future, keep this in mind. This is solved by allocating more memory to the function, which will also allocate more CPU proportionally.
Function just needs more time. Can be related to 1st point. You can try using more detailed logging to see where the operation was just before the timeout.
Networking problems (most likely). You can use socket timeout to force error on the resource which is unreachable. This can show you that there is some sort of AWS "firewall" block between lambda and the endpoint (security group, NACL etc)

Checking ip:port is open on remote host

I have a list of servers and ip:ports (external addressses) and i need to check if each server can connect to those addresses.
Looping through the file and trying to open an sshtunnel and doing connect as below
tunnel=sshtunnel.SSHTunnelForwarder(
ssh_host=host,
ssh_port=22,
ssh_username=ssh_username,
ssh_pkey=privkey,
remote_bind_address=(addr_ip, int(addr_port)),
local_bind_address=('0.0.0.0', 10022)
#,logger=sshtunnel.create_logger(loglevel=10)
)
tunnel.start()
# use socket
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
res = s.connect(('localhost', 10022))
print(res)
#s.connect((addr_ip, int(addr_port)))
s.close()
except socket.error as err:
print('socket err:')
print(err)
finally:
s.close()
time.sleep(2)
tunnel.stop()
When i do this though, the response is always 0 (i.e. the sock can connect to the local bind) even if the remote is incorrect - however sshtunnelforwarder throws
ERROR | Secsh channel 0 open FAILED: Network is unreachable: Connect failed
ERROR | Could not establish connection from ('127.0.0.1', 10022) to remote side of the tunnel
How do I make my socket command check if the remote_bind_address is available?
I tried to do use telnetlib, but get a similar issue
the code is effectively the same with the socket block replaced with
tn=telnetlib.Telnet()
tn.open('localhost',10022)
tn.close()
Im relatively new to all this, so still learning. If there is a better way to achieve what i need to do please let me know.
Thanks
Set the attribute skip_tunnel_checkup to False to enable checking of the remote side availability (it's disabled by default for backwards compatibility):
tunnel.skip_tunnel_checkup = False
Adding this before starting the tunnel checks the remote side is up on start and throws an exception which can be handled.
Removed my socket code.
I haven't tried that, but there's the tunnel_is_up attribute of the SSH tunnel class, which according to the documentation:
Describe whether or not the other side of the tunnel was reported to be up (and we must close it) or not (skip shutting down that tunnel)
Example of its content (it's a dictionary):
{('127.0.0.1', 55550): True, # this tunnel is up
('127.0.0.1', 55551): False} # this one isn't
So you shouldn't need to make an explicit connection yourself.
Note: you may need to set the attribute skip_tunnel_checkup to False (which is True by default for backwards compatibility) first before setting up the tunnel, otherwise tunnel_is_up may always report True:
When skip_tunnel_checkup is disabled or the local bind is a UNIX socket, the value will always be True
So the code may look like:
tunnel=sshtunnel.SSHTunnelForwarder(
# ...
)
tunnel.skip_tunnel_checkup = False
tunnel.start()
# tunnel.tunnel_is_up should be populated with actual tunnel status(es) now
In the code you posted, you're setting up a tunnel and then just opening a socket to the local endpoint of the tunnel, which is apparently open no matter what state the tunnel is in, so it always connects successfully.
Another approach would be to actually try to establish an SSH connection through the tunnel, but that's the paramiko.SSHclient alternative you're mentioning in a comment I guess.

Grab banner of different ports with python

I'm working on a script that grabs the banner from common ports of a host. I'm using sockets to make the connection but I'm facing some issues. Here is the code:
try:
connsocket = socket(AF_INET, SOCK_STREAM)
connsocket.settimeout( 5 )
connsocket.connect((ip, port))
connsocket.send("HEAD / HTTP/1.0")
results = connsocket.recv(400)
connsocket.close()
return str(results)
except:
print '[ERROR]Failed to connect or Connection timed out'
The are two major issues:
First time I run the script to a host all the banners are retrieved correctly except port 80 which exits with the timeout
The second problem is that when I relaunch the script to the same host there is no response from any port.
I suspect that the second issue is due to the connection is still open and the script fails retying to connect. With the first issue I have no idea why it's not working.
Any idea?
Regards.

connection refused from server unit I reset client machine

Below is the code I am running within a service. For the most part the script runs fine for days/weeks until the script hiccups and crashes. I am not so worried about the crashing part as I can resolve the cause from the error logs an patch appropriately. The issue I am facing is that sometimes when the service restarts and tries to connect to the server again, it gets a (10061, 'Connection refused') error, so that the service is unable to start up again. The bizarre part is that there is no python processes running when connections are being refused. IE no process with image name "pythonw.exe" or "pythonservice.exe." It should be noted that I am unable to connect to the server with any other machine as well until I reset computer which runs the client script. The client machine is running python 2.7 on a windows server 2003 OS. It should also be noted that the server is coded on a piece of hardware of which I do not have access to the code.
try:
EthernetConfig = ConfigParser()
EthernetConfig.read('Ethernet.conf')
HOST = EthernetConfig.get("TCP_SERVER", "HOST").strip()
PORT = EthernetConfig.getint("TCP_SERVER", "PORT")
lp = LineParser()
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
reader = s.makefile("rb")
while(self.run == True):
line = reader.readline()
if line:
line = line.strip()
lp.parse(line)
except:
servicemanager.LogErrorMsg(traceback.format_exc()) # if error print it to event log
s.shutdown(2)
s.close()
os._exit(-1)
Connection refused is an error meaning that the program on the other side of the connection is not accepting your connection attempt. Most probably it hasn't noticed you crashing, and hasn't closed its connection.
What you can do is simply sleep a little while (30-60 seconds) and try again, and do this in a loop and hope the other end notices that the connection in broken so it can accept new connections again.
Turns out that Network Admin had the port closed that I was trying to connect to. It is open for one IP which belongs to the server. Problem is that the server has two network cards with two separate IP's. Issue is now resolved.

Categories