A Server Behind A Router [closed] - python

Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 10 years ago.
Improve this question
I'm trying to set up a server behind a router, and I've been able to reduce it to the following problem:
I use:
Siemens SL2-141 Router.
Windows 7 64-bits with Python 2.7.
I run:
server.py:
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind((IP, 8080))
sock.listen(1)
sock.accept()
print 'success'
sock.close()
client.py:
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((IP, 8080))
sock.close()
When IP = '127.0.0.1' it works.
I set up a static IP:
> Network And Sharing Center > Change Adaper Settings > Local Area Connection
> Properties > Internet Protocol Version 4 (TCP/IPv4) > Properties
> Use The Following IP Address:
IP Address: 10.0.0.200
Subnet Mask: 255.0.0.0
Default Gateway: 10.0.0.138
> Use The Following DNS Server Addresses:
Preferred DNS Server: 10.0.0.138
Alternate DNS Server: - - - -
And when IP = '10.0.0.200' it works.
I set up port forwarding on my router:
> http://10.0.0.138/
> Username: Admin
> Password: Admin
> Advanced > Virtual Server > Port Forwarding > Add:
User Defined: Test
From Internal Host IP Address: ALL
Forward to Internal Host IP Address: 10.0.0.200
Protocol: TCP
External Packet Port Start: 8080
External Packet Port End: 8080
Forward To Internal Host Port Start: 8080
Forward To Internal Host Port End: 8080
> Apply (and reboot router, just in case).
To my understanding, if I leave the server IP '10.0.0.200' and set the client IP to my public IP it should work, but it doesn't work ("no connection could be made because the target machine actively refused it").
I tried doing the same thing with an Apache server and the result was similar: browsing localhost worked, browsing the static IP worked, but browsing the public IP didn't work (port 80 gave me the router setup page, and port 8080 just couldn't connect).
Final notes:
I turned off my firewall.
I checked that the port is open (http://www.canyouseeme.org/) and it is.
I checked that the server is listening (netstat -na | find /i "8080") and it does.
Any ideas what's the problem?

To my understanding, if I leave the server IP '10.0.0.200' and set the client IP to my public IP it should work, but it doesn't work.
That's right, if the client is on an external network. On the local network if you use your public address it may or may not work depending on if your router implements NAT reflection (if not it will drop the packets). You should use the your local (private) IP address on your local network. Many routers allow you to configure DNS records for local resources (that override records from the DNS server, implementing a type of "Split DNS"). That way you can use one DNS name to get the correct address.
If you're problem is with a connection from a client on the external network, it sounds like somehow your NAT router is not port forwarding. I don't have your model of router, but I see this line:
From Internal Host IP Address: ALL
And wonder if you have to allow From External.
Also are you sure this rule is enabled? (I only ask because the last time I had a problem like this I had created the forwarding rule correctly but it wasn't enabled.)
If you're still stuck, try removing the rule and re-test if the port looks open to http://www.canyouseeme.org/. I would also re-test when NOT running your server program (to test if the external port scan is misleading, which can happen).
Finally, when you write:
I turned off my firewall.
Do you mean Windows Firewall? You'll want to double check that too because Windows Firewall can allow local connections while blocking remote connections.

Related

How can I make my client and server IPv6 compatible? (Flutter, Python, Nginx)

I have a mobile app that sends location information to database. The server (Tavu.io) is Ubuntu based and uses Nginx. The problem is that when I try to connect to the server using IPv6 address, the data is not transferred. The application should work in IPv6 network only. UDP protocol should be used.
In the nginx.conf, there are path to files included that contain:
listen 80 default_server;
listen [::]:80 default_server;
netstat -pnltu shows that "tcp" and "tcp6" have LISTEN. But, there is only "udp", and no "udp6" which I assume it should be. There is no LISTEN on "udp".
My Python socket is like this:
self.connection = db.connect_to_database()
self.status = True
self.udp = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)
self.udp.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
self.udp.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
self.udp.bind(('', 50943))
And the mobile client (Dart/Flutter):
static String serverIP = '[ipv4 address hardcoded]';
static Future<RawDatagramSocket> rDgS =
RawDatagramSocket.bind(InternetAddress.anyIPv4, 50943);
rDgS.then(
(RawDatagramSocket udpSocket) {
udpSocket.writeEventsEnabled = true;
List<int> data = utf8.encode(message);
udpSocket.send(data, InternetAddress(serverIP), 50943);
},
);
That above code works at that state as intended, but when is use hardcoded IPv6 address and change to .anyIPv6, the sent data is not reaching the server. No error is shown on the VSCode console though. The reason the IP addresses are hard coded because I don't have the hostname for the server and giving server name to nginx.conf was not working. Is there a workaround to this issue to have client to connect to server while in IPv6-only network?
I have changed the settings on nginx and attempted multiple times this application on IPv6-only network but the data (location and username) are not sent to database.

Run flask file on wlan1 instead of wlan0

I have a raspberry pi, a flask server, a flask client, and two different networks.
when I connect a wifi adapter to the raspberry pi I can see that I have a new interface called "wlan1" is there a way to run a the server for example on "wlan0" and the client on "wlan1".
what I'm trying to do is run the server on a different network than the client (while both of them are on the pi).
Server:
For the server part, you need to "bind" the listening socket to the IP address of wlan0.
Find the IP address of wlan0 using ifconfig wlan0 or ip addr show dev wlan0 (e.g. 192.168.0.2)
Bind the Flask server to that IP address using app.run(host='192.168.0.2', port=80)
If you bind to 0.0.0.0, it will be reachable from all network devices.
Client:
A little bit more involved, take a look at how "routing tables" work for the theory.
Find out the IP address of the server that your client will connect to (e.g. 93.184.216.34)
Find out the IP address of the default gateway on the interface wlan1, for example with ip route (look for "default via dev wlan1"), e.g. "default via 192.168.1.1 dev wlan1"
Add a route to that IP address via the gateway and interface, using route add 93.184.216.34 gw 192.168.1.1 dev wlan1
Note that the routing table will affect all programs on the raspberry pi, not just your client application.

Python OpenSSL Specify DNS Server

Has anyone found a way to specify a DNS server for OpenSSL connections on a Linux OS? We have internal and external DNS servers and I am building a monitor for SSL certificate usage. I need the ability to specify a DNS server to be used on hostname connections. It works just fine against the internal DNS, but I am having difficulty finding a way to tie in a DNS server. I am fairly new to changing networks through Python and am not sure where to begin. Is it possible to do this through the dns.resolver module's nameservers function?
This looks like a viable solution for Windows, but I am hoping to find something similar for Linux.
How to Change DNS Servers Programmatically in Windows?
Below is my code that works against the default DNS host.
def readCerts(self,host,port,cast):
"""readCerts prompts terminal for username.
Attributes:
host: Host or IP of SSL connection
port: Port of SSL connection
cast: Format of returned results (JSON currently only structure supported)
Response:
Returns certificate attributes in specified format
"""
sslContext = SSL.Context(SSL.SSLv23_METHOD)
apiSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sslConnection = SSL.Connection(sslContext,apiSocket)
try:
sslConnection.connect((host,port))
except Exception as e:
raise e
else:
#Block the socket
sslConnection.setblocking(1)
#Set the hostname field for servers that support SNI. Format must be in bytestring.
sslConnection.set_tlsext_host_name(host.encode('utf-8'))
try:
sslConnection.do_handshake()
except:
pass
else:
#print "handshake succeeded"
sslConnection.close()
if cast.upper()=='JSON':
attributes = self._FormatJSON(sslConnection.get_peer_cert_chain())
return attributes

Unable to change DNS resolver to localhost

I configured my windows machine's DNS server to 127.0.0.1 and on localhost I created a basic python server:
from socket import *
serverPort = 53
serverSocket = socket(AF_INET, SOCK_DGRAM)
serverSocket.bind(('127.0.0.1', serverPort))
print "The server is ready to receive on port: {}".format(serverPort)
while 1:
try:
message, clientAddress = serverSocket.recvfrom(512)
except:
continue
print clientAddress, message
modifiedMessage = "127.0.0.1"
serverSocket.sendto(modifiedMessage, clientAddress)
PS :I know that DNS is a binary protocol and sending ASCII text won't do any good, but I am not trying to make a resolver, I am trying to see with transperancy that how the former works.
When I srarted the server, I am greated with the following output:
(('127.0.0.1', 53945), '.\x9c\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x03www\x06google\x03com\x00\x00\x01\x00\x01')
(('127.0.0.1', 53945), '.\x9c\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x03www\x06google\x03com\x00\x00\x01\x00\x01')
(('127.0.0.1', 53945), '.\x9c\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x03www\x06google\x03com\x00\x00\x01\x00\x01')
(('127.0.0.1', 61362), '\xefc\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x03www\x06google\x03com\x00\x00\x01\x00\x01')
(('127.0.0.1', 50065), '\xb5\xfc\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x06google\x03com\x00\x00\x01\x00\x01')
(('127.0.0.1', 61362), '\xefc\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x03www\x06google\x03com\x00\x00\x01\x00\x01')
(('127.0.0.1', 61362), '\xefc\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x03www\x06google\x03com\x00\x00\x01\x00\x01')
(('127.0.0.1', 52718), '\xc7\x15\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x05tiles\x08services\x07mozilla\x03com\x00\x00\x01\x00\x01')
But unlike as I enticipated, I am still able to open websites. And Wireshark told me that I am making connection to 8.8.8.8(IDK how?).
I tried flushing the DNS cashe from my machine, nada.
What am I missing?
PPS: If I remove the try/catch clause I get this error(a few seconds after the execution of the program):
error: [Errno 10054] An existing connection was forcibly closed by the remote host
You probably have configured Googles 8.8.8.8 as a fallback DNS server.
And since you are destroying the DNS answers, whoever is receiving these broken answers is falling back to the secondary server. The whole path of DNS queries on a typical UN*X machine is quite complicated and the whole system is usually quite robust.

How to ssh over HTTP proxy in Python Paramiko?

I am adapting a Python script to be OS independent and run on Windows. I have changed its ssh system calls to calls to paramiko functions. I am stuck with the issue of http proxy authentication. In Unix (actually Cygwin) environment I would use ~/.ssh/config
Host *
ProxyCommand corkscrew http-proxy.example.com 8080 %h %p
Is there a way to obtain the same using paramiko (or the Python ssh module) either using or not using corkscrew? This post seems to suggest that, but I don't know how.
Note: I am behind a firewall that allows me to use only port 80. I need to control Amazon ec2 instances so I configured the sshd server on those machines to listen to port 80. Everything is working fine in my cygwin+corkscrew prototype, but I would like to have a Python script that works without Cygwin.
You can use any pre-established session to paramiko via the sock parameter in SSHClient.connect(hostname,username,password,...,sock).
Below is a code-snippet that tunnels SSH via HTTP-Proxy-Tunnel (HTTP-CONNECT). At first the connection to the proxy is established and the proxy is instructed to connect to localhost:22. The result is a TCP tunnel over the established session that is usually used to tunnel SSL but can be used for any tcp based protocol.
This scenario works with a default installation of tinyproxy with Allow <yourIP> and ConnectPort 22 being set in /etc/tinyproxy.conf. The proxy and the sshd are running on the same host in my example but all you need is any proxy that allows you to CONNECT to your ssh port. Usually this is restricted to port 443 (hint: if you make your sshd listen on 443 this will work with most of the public proxies even thought I do not recommend to do this for interop and security reasons). If this ultimately allows you to bypass your firewall depends on what kind of firewall is employed. If there's no DPI/SSL-Interception features involved, you should be fine. If there's SSL-Interception involved you could still try to tunnel it via ssl or as part of HTTP payload :)
import paramiko
import socket
import logging
logging.basicConfig(loglevel=logging.DEBUG)
LOG = logging.getLogger("xxx")
def http_proxy_tunnel_connect(proxy, target,timeout=None):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(timeout)
sock.connect(proxy)
LOG.debug("connected")
cmd_connect = "CONNECT %s:%d HTTP/1.1\r\n\r\n"%target
LOG.debug("--> %s"%repr(cmd_connect))
sock.sendall(cmd_connect)
response = []
sock.settimeout(2) # quick hack - replace this with something better performing.
try:
# in worst case this loop will take 2 seconds if not response was received (sock.timeout)
while True:
chunk = sock.recv(1024)
if not chunk: # if something goes wrong
break
response.append(chunk)
if "\r\n\r\n" in chunk: # we do not want to read too far ;)
break
except socket.error, se:
if "timed out" not in se:
response=[se]
response = ''.join(response)
LOG.debug("<-- %s"%repr(response))
if not "200 connection established" in response.lower():
raise Exception("Unable to establish HTTP-Tunnel: %s"%repr(response))
return sock
if __name__=="__main__":
LOG.setLevel(logging.DEBUG)
LOG.debug("--start--")
sock = http_proxy_tunnel_connect(proxy=("192.168.139.128",8888),
target=("192.168.139.128",22),
timeout=50)
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname="192.168.139.128",sock=sock, username="xxxx", password="xxxxx")
print "#> whoami \n%s"% ssh.exec_command("whoami")[1].read()
output:
DEBUG:xxx:--start--
DEBUG:xxx:connected
DEBUG:xxx:--> 'CONNECT 192.168.139.128:22 HTTP/1.1\r\n\r\n'
DEBUG:xxx:<-- 'HTTP/1.0 200 Connection established\r\nProxy-agent: tinyproxy/1.8.3\r\n\r\n'
#> whoami
root
here are some other resources on how to tunnel through proxies. Just do whatever is needed to establish your tunnel and pass the socket to SSHClient.connect(...,sock)
There's paraproxy, which implements proxy support for Paramiko.
The post you linked to suggets that Paramiko can operate over an arbitrary socket, but that doesn't appear to be the case. In fact, paraproxy works by completing replacing specific methods inside paramiko, since the existing code simply calls socket.socket() to obtain a socket and does not offer any way of hooking in a proxy.

Categories

Resources