socket.getaddrinfo fails if network started offline - python

I'm having a problem with a Python script which should check if the user is connected to a wifi network with a captive portal. Specifically, the script is long-running, attempting to connect to example.org every 60 seconds.
The problem is that if the network starts offline (meaning the wifi isn't connected at the start of the script), socket.getaddrinfo will always fail with the error "Name or service not known", even once the wifi is connected, until the Python script is restarted. (This isn't a DNS thing -- all requests fail.)
Because both urllib and requests use sockets, it's totally impossible to download an example page once Python gets into this state.
Is there a way around this or a way to reset sockets so it works properly once the network fails?
To be clear, here's a repro:
Disconnect wifi
Run an interactive Python session
import urllib and urllib.open("http://stackoverflow.com/") -- fails as expected
Reconnect wifi
urllib.open("http://example.com/")
Expected: Returned HTML from example.com
Actual: socket.gaierror: [Errno -2] Name or service not known

If you're not connected to an access point when running the script, and don't have an IP address assigned to your device socket.getaddrinfo will fail. Maybe it's still connecting when you run the script. The domain name cannot be resolved because you are not connected to the network, thus no DNS.
Does it fail when you're actually connected to the network? Does curl http://icanhazip.com work at the point when the script fails? Or if you run ifconfig does your device have an IP? (I'm assuming you're on a *nix box).

Related

Keep alive mechanism for ssh over ssh in Paramiko

I'm using Paramiko interactive shell (invoke_shell() method) for opening session between my local host and remote host and sending commands to it.
Sometimes I need to open from my remote host an ssh connection to another remote host (this is like a bridge or SSH via SSH from local host to remote_host_2 via remote_host_1).
For better understanding this is a picture how it should behave:
| local host | -(1)-> | remote host | -(2)-> | destination host |
1: is open using invoke_shell() paramiko method so it will create some paramiko.Channel obj.
2: is open using Linux command i.e. ssh remote_user#remote_ip
This is done this way because sometimes I have no direct connection to destination host and in case you are opening it via remote host then user decision should be made (entering another password, answering yes/no on some questions etc..)
Now my question is regarding keeping my connection alive.
I read on keep_alive mechanism that paramiko has but it doesn't do what I want because paramiko knows my connection ends in remote_host and not in destination host so in case destination host is dead I will not receive any notification regarding it and commands execution will fail.
The only solution that came to my mind is sending empty command on this channel (\n) and trying to read the output from the channel before executing the desirable command on it. but this means that I can affect my channel on one hand and my command execution time is now twice longer.
Now my question is, is there another way to perform this connection so this keep alive mechanism will work?
p.s. I read that there exists some ServerAliveInterval=30 flag that can help me to keep my ssh interactive connection alive but I don't understand how can I use it to validate it doesn't became dead.
The correct way is to implement the jump using port forwarding.
See Connecting to a server via another server using Paramiko
Then you will have a complete control over both connections and you will be able to use native Paramiko features to keep the connection alive and to check its status.

Can't connect to my google cloud VM instance through tcp using python

Situation
I wrote a simple program in python. It's a simple socket chatting program. In my program, the client just connect to an address (ip, port) and send a message, while at this time the server is ready and receives the message and prints it. I can assure the program is correct, since I tried on my computer.
I have a VM instance on Google Cloud Platform, which I can operate through ssh, a simple way provided by google cloud. I can make sure the server is working.
Problem
I start a simple tcp server, python program on my google cloud server. Then I start my client program on my computer. But I get this error:
ConnectionRefusedError: [WinError 10061] No connection could be made because the target machine actively refused it
or equivalently in Chinese:
ConnectionRefusedError: [WinError 10061] 由于目标计算机积极拒绝,无法连接。
How do I solve this problem and connect to my google cloud server?
I guess maybe the firewall refused my computer's connection, but have no idea how to solve it.
This error means that your program is not listening on 0.0.0.0 port XYZ.
Check to see if your program is instead listening on localhost. If it is change to 0.0.0.0 which means all available networks. localhost means do not listen on any network interfaces and only accept connections from inside the computer.
Then double check the port number.
To see if you have something listening run this command (Linux): netstat -at
Look for a line with your port XYZ.
When you start your program, make sure that it does not error when creating the listener. If you are trying to use a port number below 1024, you will need to lauch the program with root privileges.
The TCP connection is being refused because the GCP Firewall is indeed blocking it. Therefore, you must create a firewall rule that opens the TCP port for Ingress connections.
By navigating to Firewall rules in the VPC network section of the GCP Console, you can create firewall rules or update existing ones.
One approach is to tag your GCE instance, and when creating the firewall rule, set the target to be this tag, and as for 'Source filters', the IP of the machine you're attempting to establish the connection from, or simply allow all IPs to connect with 0.0.0.0/0 as the source. Remember to specify the TCP port that needs to be opened.

Python TCP Sockets Not Working [Repost]

A week back I posted this, and about 2 weeks back I posted this, both pertaining to an ever evolving issue with my Python sockets. I've also asked a question on the Wireshark Stack Exchange, and even after all 3 posts, I haven't been able to reach any conclusion. So heres the problem:
When I start up IDLE, it returns an error: IDLE Subprocess: socket error: No connection could be made because the target machine actively refused it and then I press ok on the dialogue boxes and it closes it out. But the issue isn't only limited to IDLE.
Any TCP ports I try to connect to via the Python socket module will fail. For example, if I run a server and a client (server first, of course, and both have the current IP of my computer and the port 45002) locally on my computer it returns: [Errno 10061] No connection could be made because the target machine actively refused it. So someone on an earlier post told me that running both the programs locally on a Windows machine will not work because it doesn't have a loopback interface (although when I look at my network interfaces via CMD, Loopback interface is listed for some reason). So then I went ahead and put the server on the computer with the issue, and the client on another computer on the network. It returns: [Errno 10060] A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond. But for some reason, if I run the server on the other computer and then run the client on the computer with the issue, the server and client actually connect, and then the server fails claiming: [Errno 10057] A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied, even though I made sure to include a .connect(addr) in the client program. Sorry if this is getting confusing, but it's going to get a bit more complicated than this.
After this mess of running servers/clients on different computers, per request of another answerer on an early post, I installed Wireshark and began looking for packets being sent on the ports I am using. The results were a little weird. When I run the server on the computer with the issue, and the client on the other computer, Wireshark catches absolutely no packets on the port of the server, and the client fails with the errno 10060, as I said earlier. If I run the server from the other computer and the client from the computer with the issue, Wireshark catches some ordinary SYNs and ACKs. I only get an RST when I end the Python.exe process (this info is really only important to people who are good with Wireshark/networking, it's really only extra info).
I've also tried capturing packets from the IDLE program with Wireshark after I pinpointed the range of ports that it tends to use. When I start it up, no packets on any port in the range. Again, this is really just extra info to any of you who may be able to make something of it.
Again, sorry for the confusion, but I must go on.
And now, the issue that brought all this up. The problem that really caused me to ask myself "Hmm... Why is Python not working correctly?", my Twisted server was not able to import the reactor module returning the errno 10061. If you don't use/know of Twisted, all that's really needed to understand the problem is that, to import the reactor module, Twisted has to setup a Python TCP port, which is not working.
This issue has left me (and presumably everyone who's read it) scratching their head. I am sure that the ports I am using are not used. I'm sure the IP addresses are correct and matching. I am sure that there is no firewall blocking the connections, since I have tried running the programs without a firewall on with no luck. I am running a Wireless Windows 64bit laptop.
Heres my client program, and here's my server program, if they help at all.
Any suggestions, ideas, or answers are welcomed. At this point, any at all. Thanks.
P.S. If there is any info I can provide, or anything I can do to help find the solution to this issue, please tell. Also, I know this question is barely a programming one, so if there is somewhere else I am supposed to put this, please say and I'll move it over.
EDIT: Seems like I solved one piece of the puzzle. I can now connect a client on the computer with the issue to the computer with no issue, but not the other way around (running the client on the good computer, and running server on the broken one). I had to switch servSock.recv(buff) to cliSock.recv(buff) on the server side.

python paramiko module socket.error, errno 10060

It seems the socket connection through paramiko (v1.10.0) is not stable.
I have two computers. The python code is on the PC one. The connection sometime is successful and sometime is not (Same code). When the PC paramiko code fails (socket.error, 10060), I use my Mac via terminal ssh login the server and everything is fine.
I use set_missing_host_key_policy in the code. But the Mac has the key I guess. I typed yes when login at the first time.
If the unstable connection is caused by the hotkey, how do I get the host key? From the server or somewhere in my local folder (win7)?
Try switching off Windows firewall. It's a network error, it should not be because of SSH key problems.
Error Code 10060: Connection timeout
Background: The gateway could not receive a timely response from the website you are trying to access. This might indicate that the network is congested, or that the website is experiencing technical difficulties.

How do I setup a python, telnet proxy for a device on a different network over SSH?

Overview:
I have a device sitting on a local network to a computer that is sitting on an outside network. I would like to create a software program that allows me to seamlessly connect to the device from a computer on a different network. For purposes of this question, I've created a picture to help describe the network flow. What I need help with is what python packages I would need to develop the solution for this problem.
Details:
I have a computer MYPC (IP address 192.168.0.168) that is attached to the internet running through a proxy server (ROUTER1). I have full control over MYPC's environment, which is running Linux.
I have a second computer SOMESERVER (IP address 192.168.1.168) that is attached to the internet running through a proxy server (ROUTER2). In addition, SOMESERVER (IP address 10.0.0.159) is also attached to a local network (LOCAL). SOMESERVER is running windows. I have very limited control with SOMESERVER: I am able to send an executable to SOMESERVER that can run once before it is removed. I do not know the internet/world IP address of the ROUTER2 initially.
I have a device (DEVICE1) attached to SOMESERVER through LOCAL (IP address: 10.0.0.157).
I have another device (DEVICE2) attached to SOMESERVER through LOCAL (IP address: 10.0.0.158). DEVICE(x) runs linux. I have python on DEVICE(x) and I could install a pure python package if I needed to. However, I do not have the ability to compile for DEVICE(x).
I can connect between SOMESERVER and MYPC through the internet using SSH over ROUTER1 and ROUTER2. I can connect between SOMESERVER and DEVICE1 through the local network (LOCAL) using Telnet. I can connect between SOMESERVER and DEVICE2 through the local network (LOCAL) using Telnet.
I want to send a program to SOMESERVER that allows me seamless access over SSH and Telnet to DEVICE1 and DEVICE2 from MYPC. In addition, I want that program to be running python.
Here's a picture that helps explain the above problem:
Solution:
What I think I want is as follows. I need help with the details and what packages I might need to make it happen.
Part 1: The Dial Home Client and Server
Create a "dial home" server program (DIAL_HOME_SERVER) for MYPC which listens for any one dialing home and then will "dial into" any SOMESERVER that "dials home" using SSH.
Create a "dial home" client program (DIAL_HOME_CLIENT) for SOMESERVER which is downloaded as part of a package
Part 2: The Proxy Server
Create a ssh to telnet proxy server program (PROXY_SERVER) for SOMESERVER which listens for connections from MYPC and funnels them into a telnet connection to DEVICE(x).
Thanks to Greg Hewgill, it sounds like I can use Paramiko to pull together the PROXY_SERVER code on SOMESERVER. It appears that Paramiko also requires PyCryto, and the Windows binary for it can be found here.
Future Robustness
At a future date, the telnet connection will be replaced with an SSH client (dropbox on DEVICE(x)).
In Closing
I think the above will allow MYPC to connect "seamlessly", but the details of how to put together these programs is unknown to me. I already know how to package up a python program using Innosetup and/or py2exe. What I'd love to see is links pointing to different pieces of the solution so I can pull it all together. And then I can post it.
Thanks in advance!
I have to admit that I didn't quite follow all of your description, especially the "dial home" client/server part. However, your diagram seems sufficient for understanding.
Set up port forwarding on "router2" that forwards the incoming SSH port to your Windows server.
Write a Python program (you will probably find paramiko helpful) that runs on your Windows server, listens for SSH connections, and opens a telnet connection to one of your devices on the back end.
That seems sufficient to me. If you've got weird restrictions on the Windows server about only being able to run an executable once before it is deleted, that seems like another problem to solve that doesn't really relate to this tunnelling problem.

Categories