How do I test if there is a server open on a port with python?

Tom picture Tom · Jan 1, 2013 · Viewed 20.4k times · Source

Ok, so I did the following, figuring it would raise an exception if it could not connect:

>>> s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>>> s.settimeout(0.2)
>>> s.connect(("thisdomaiyndontexistduhh.com", 80))

But no exception was raised. How do I test if there is a server open on a port with Python's socket module? Thanks!

Answer

selbie picture selbie · Jan 2, 2013

Here's why the code above never fails.

My ISP (Frontier) configures DNS such that for any domain that does not exist, it will return "198.105.251.114". As such, they actually have a web server listening on port 80 at that address to display some garbage/spam search results. Change your host to use 8.8.8.8 (Google server) for DNS and your code above will likely work.

Given that these sorts of "captive networks" are common, the first thing your code should do is determine if it is on such a network. Hence, the right thing to do is call socket.gethostbyname("thisdomaiyndontexistduhh.com"). If it actually returns a value, then you know you are behind such a DNS server. As such, then do a gethostbyname call on the server you want to probe. If it returns the same DNS address, you know the server doesn't exist. Otherwise, proceed with the connect call to finish the test.

Update: I've been learning Python over the holidays, so I used this problem as excuse to practice. Here's my code:

import socket

def DoesServiceExist(host, port):
    captive_dns_addr = ""
    host_addr = ""

    try:
        captive_dns_addr = socket.gethostbyname("BlahThisDomaynDontExist22.com")
    except:
        pass

    try:
        host_addr = socket.gethostbyname(host)

        if (captive_dns_addr == host_addr):
            return False

        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.settimeout(1)
        s.connect((host, port))
        s.close()
    except:
        return False

    return True