Reputation: 2755
If I have a Twisted server, how can I find its public-facing IP address?
Take this trivial echo server example:
from twisted.internet import protocol, reactor, endpoints
class Echo(protocol.Protocol):
def dataReceived(self, data):
self.transport.write(data)
class EchoFactory(protocol.Factory):
def buildProtocol(self, addr):
return Echo()
server_endpoint = endpoints.serverFromString(reactor, "tcp:1234")
listening_port_deferred = server_endpoint.listen(EchoFactory())
reactor.run()
I was expecting something like server_endpoint.getHost()
, but I can't see that TCP4ServerEndpoint
offers anything useful.
By adding the following lines before reactor.run()
, we can see that the server is listening on all interfaces (0.0.0.0):
def print_host(listening_port):
print("listening_port.getHost():", listening_port.getHost())
listening_port_deferred.addCallback(print_host)
It outputs listening_port.getHost(): IPv4Address(type='TCP', host='0.0.0.0', port=1234)
. But that doesn't help us with the IP address of the network interface of the server.
We can get the IP address of the client by adding the following as the first line of buildProtocol():
print("Client's address:", addr.host)
But that only gives us the client's address.
How should I get the server's IP address?
Upvotes: 1
Views: 944
Reputation: 48335
Twisted will tell you the address you've bound the server to using just the method you found, getHost
on the listening port. Unfortunately, it has the big limitation that you found which is that when the server is listening on all local addresses (INADDR_ANY
) it gives you 0.0.0.0
(the canonical IPv4 dotted-quad representation of INADDR_ANY
).
When this happens, you have to go outside of Twisted. I've found the netifaces package to be pretty good for this. From the docs:
>>> netifaces.interfaces()
['lo0', 'gif0', 'stf0', 'en0', 'en1', 'fw0']
>>> >>> addrs = netifaces.ifaddresses('lo0')
>>> addrs[netifaces.AF_INET]
[{'peer': '127.0.0.1', 'netmask': '255.0.0.0', 'addr': '127.0.0.1'}]
By combining this information with the observation that 0.0.0.0
means "all local addresses" you can figure out what local addresses the server will accept connections on.
Upvotes: 1
Reputation: 2755
Thanks to notorious's comment, I realised that the server's IP address is available only once a client connects. However, as Jean-Paul points out, this IP address isn't necessarily public-facing and may well be behind a NATing router.
To obtain the server's IP address for a given connection, we can use the getHost()
method from the transport
attribute of the Protocol
class. This is documented in the ITransport
interface.
For example, if we add the following method into the Echo
protocol class in the original question, each time a client connects, the server will print out the IP address that was used.
def connectionMade(self):
print("IP address of host given connection:", self.transport.getHost())
So, for example, if you connect from the same machine on which the server is running, you will see:
IP address of host given connection: IPv4Address(type='TCP', host='127.0.0.1', port=1234)
However, if you connect from another machine on the same network, you might see:
IP address of host given connection: IPv4Address(type='TCP', host='192.168.5.103', port=1234)
Upvotes: 1