How to bind a Python socket to a specific domain? - python

I have a Heroku application that has a domain moarcatz.tk. It listens for non-HTTP requests using Python's socket.
The documenatation states that if I bind a socket to an empty string as an IP address, it will listen on all available interfaces. I kept getting empty requests from various IP addresses, so I assume that setting the socket to only listen for connections to moarcatz.tk would fix the problem. But I don't know how to bind a socket to a domain name.
I tried 'moarcatz.tk' and gethostbyname('moarcatz.tk'), but both give me this error:
OSError: [Errno 99] Cannot assign requested address
What's up with that?

You can't control this via your code, but you can control this via Heroku.
Heroku has a pretty nifty DNS CNAME tool you can use to ensure your app ONLY listens to incoming requests for specific domains -- it's part of the core Heroku platform.
What you do is this:
heroku domains:add www.moarcatz.tk
Then, go to your DNS provider for moarcatz.tk and add a CNAME record for:
www <heroku-app-name>.herokuapp.com
This will do two things:
Point your DNS to Heroku.
Make Heroku filter the incoming traffic and ALLOW it for that specific domain.

Related

Cannot bind to external IP address of google compute engine VM instance

I am trying to test a simple client-server setup between my laptop and my google compute engine instance using python. The setup works fine between 2 laptops. But when I run the server program in my VM instance I get the following error after calling the bind command: "socket.error: [Errno 99] Cannot assign requested address"
I am trying to bind to the external IP address so I can receive data from an external device.
Here is the code snippet
import socket
s = socket.socket()
port = 12345
s.bind(('xxx.xxx.xxx.xxx',port))
Can anyone please tell me why I can't bind to the external IP address. I have tried to find the answer in Google's docs and via online searches but to no avail. I am new to this and don't really even know what info to post that would help in troubleshooting. Thanks in advance.
Here are my firewall rules
Google Cloud's networking has a distinction between internal and external IP addresses. In particular, a GCE VM won't actually have an interface with the externally visible IP address -- the cloud infrastructure handles the translation outside of the instance.
You need to bind to the internal IP address for your instance, and GCP's networking infrastructure will take care of the routing for you, assuming such routing is allowed by your VPC firewall configuration.
Note: As provided, your current firewall configuration does not have a rule that will allow ingress on the 12345 port and you will need to add this and ensure it applies to this particular instance (either via a target tag which is applied to the instance, or by applying the rule to all targets in your network)
You might also consider using 0.0.0.0 (or INADDR_ANY) which in python is just the empty string. So this should also work for you (again, assuming the correct firewall configuration):
import socket
s = socket.socket()
port = 12345
s.bind(('',port))

Python Flask with STUN

I'm developing a simple Flask based server that can communicate with peer applications (other similar servers) on internet. The application can be behind a NAT. So I'm trying to resolve the external IP and port through a stun server by using pystun.
import stun
nat_type,external_ip,external_port=stun.get_ip_info()
The port returned is 54320. Problem is when I try http://external_ip:54320 the request is not reaching the Flask app. http://external_ip:5000 is also not working, 5000 being the internal port used (I know this should not work, but tried it anyways). There are no firewalls. I have run Flask with host="0.0.0.0".
to add.. i dont want to do explicit port mapping in the router.. is there a way flask can listen to a port that is accessible from external addresses and figure out external port through stun?
It is very difficult to host a server behind a NAT without doing an explicit port mapping. The NAT is also acting as a firewall. The node behind the NAT can make outbound TCP connections, but the NAT will block any inbound connections.
STUN doesn't help here because it only helps nodes behind NATs discover their own port mappings. To allow connection to be established after STUN, you typically have to do a hole punching step, which involves both endpoints simultaneously trying to connect to each other.
The one idea you could try is to use UPNP, which is a protocol that many NATs support for dynamically creating port mappings. There's some opens source libraries that might work.
But the easier solution is to just configure your NAT to have an explicitly port mapping. (e.g. port 50000 maps to your PC's internal IP address at a specific port).

Why host http server needs to specify the IP on which it is hosting?

I am hosting a http server on Python using BaseHTTPServer module.
I want to understand why it's required to specify the IP on which you are hosting the http server, like 127.0.0.1/192.168.0.1 or whatever. [might be a general http server concept, and not specific to Python]
Why can't it be like anybody who knows the IP of the machine could connect to the http server?
I face problems in case when my http server is connected to two networks at the same time, and I want to serve the http server on both the networks. And often my IP changes on-the-fly when I switch from hotspot mode on the http server machine, to connecting to another wifi router.
You must specify the IP address of the server, mainly because the underlying system calls for listening on a socket requires it. At a lower level you declare what pair (IP address, port) you want to use, listen on it and accept incoming connexions.
Another reason is that professional grade server often have multiple network interfaces and multiple IP addresses, and some services only need to listen on some interface addresses.
Hopefully, there are special addresses:
localhost or 127.0.0.1 is the loopback address, only accessible from local machine. It is currently used for tests of local services
0.0.0.0 (any) is a special address used to declare that you want to listen to all the local interfaces. I think that it is what you want here.
Try running it on 0.0.0.0, this accepts connections from all interfaces. Explicitly specifying the IP is a good practice in general (load balancing, caching servers, security, internal netwrok-only micro services, etc), but judging by your story this is not a production server, but some internal LAN application.

difference between finding ip address by python an cmd

I wrote this code for finding google ip in python
import socket
print socket.gethostbyname('google.com')
.
.
173.194.39.0
but if we use command prompt and ping command for finding google ip result is:216.58.208.36
why there is difference between two results?
Both of those IP addresses resolve to Google.com. We can verify this from the command line with the unix whois command.
$ whois 216.58.208.36
NetRange: 216.58.192.0 - 216.58.223.255
CIDR: 216.58.192.0/19
NetName: GOOGLE
$ whois 173.194.39.0
NetRange: 173.194.0.0 - 173.194.255.255
CIDR: 173.194.0.0/16
NetName: GOOGLE
I ran into this same issue and the cause was that the first command that required an IP address was using a cached DNS entry (because the DNS entry's time to live (TTL) hadn't expired yet) and then by the time the second command was issued the TTL had expired on the cached entry so a new DNS request was made for the domain therefore grabbing a new IP address from the DNS server which happened to be different because the domain had a lot of IP addresses just like Google.com.
Python just relies on the Operating System's DNS resolver (or whatever daemon is running) and as far as I know the socket module doesn't give you the ability to clear the DNS cache before it tries to resolve an address. If you want more control over this functionality you can use DNSPython or something similar. If you are using a daemon for DNS on your operating system (like on Linux, for example) then usually restarting the daemon will force a flush of DNS cache and you find both addresses to the be same (unless you run into the timing issue as described above with the TTL's expiring).
Hostnames are translated to IP addresses through something called a DNS server. When you type a name into a web browser or use a program such as ping, the hostname that you provide (google.com) eventually reaches an authoritative DNS server for that domain-separate from the server that you correspond with for the actual content.
google.com has multiple different servers that can respond to data requests. Depending on the implementation of the different programs you are using to generate the request and other factors such as the network traffic at the time that you make the request, multiple requests from the same host may be directed to different servers by the authoritative DNS server. This is accomplished by returning different IP addresses to your machine.
FWIW, both ping and socket.gethostbyname() for google.com resolve to 216.58.217.14 on my machine, running OS X Yosemite.

Twisted: how-to bind a server to a specified IP address?

I want to have a twisted service (started via twistd) which listens to TCP/POST request on a specified port on a specified IP address. By now I have a twisted application which listens to port 8040 on localhost. It is running fine, but I want it to only listen to a certain IP address, say 10.0.0.78.
How-to manage that? This is a snippet of my code:
application = service.Application('SMS_Inbound')
smsInbound = resource.Resource()
smsInbound.putChild('75sms_inbound',ReceiveSMS(application))
smsInboundServer = internet.TCPServer(8001, webserver.Site(smsInbound))
smsInboundServer.setName("SMS Handling")
smsInboundServer.setServiceParent(application)
What you're looking for is the interface argument to twisted.application.internet.TCPServer:
smsInboundServer = internet.TCPServer(8001, webserver.Site(smsInbound),
interface='10.0.0.78')
(Which it inherits from reactor.listenTCP(), since all the t.a.i.*Server classes really just forward to reactor.listenXXX for the appropriate protocol.)

Categories