Infosec Project: Python Port Scanner Failing Test

Greetings,

All tests, bar one, pass for my port scanner implementation. The failing test output:

======================================================================
FAIL: test_port_scanner_verbose_ip_no_hostname_returned_single_port (test_module.UnitTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/runner/fcc-port-scanner/test_module.py", line 28, in test_port_scanner_verbose_ip_no_hostname_returned_single_port
    self.assertEqual(actual, expected, "Expected 'Open ports for 104.26.10.78\nPORT     SERVICE\n443      https'")
AssertionError: 'Open ports for 104.26.10.78\nPORT     SERVICE' != 'Open ports for 104.26.10.78\nPORT     SERVICE\n443      https'
  Open ports for 104.26.10.78
- PORT     SERVICE+ PORT     SERVICE
?                 +
+ 443      https : Expected 'Open ports for 104.26.10.78
PORT     SERVICE
443      https'

----------------------------------------------------------------------
Ran 8 tests in 45.682s

FAILED (failures=1)

The test is expecting a successful connection to the host using the supplied IPv4 address, and finding that port 443 is open. However a connection using an IPv4 address is not possible. A browser visit using this address reveals the following message:

cf_no_direct_ip_access

It would appear then, the test, as currently implemented, will not pass.

Advice as to how to move forward here would be appreciated.

Perhaps that was just a lone glitch? I’ve just run tests on my implementation and haven’t got any issues with that test. If the issue still persists maybe there’s something else wonky. In such case could you paste link to your repl.it?

Greetings sanity,

Many thanks for your response.

I performed several tests with curl and netcat to ascertain port 443 on host 104.26.10.78 is accessible. For example, the following netcat invocation:

port=443; \
nc -zw 2 104.26.10.78 ${port} &> /dev/null \
&& echo Port ${port} open \
|| echo Port ${port} closed

Port 443 open

indicated the port was open, as did the output from following curl invocation:

curl -Ikv 'https://104.26.10.78'

* Rebuilt URL to: https://104.26.10.78/
*   Trying 104.26.10.78...
* TCP_NODELAY set
* Connected to 104.26.10.78 (104.26.10.78) port 443 (#0)
*
<SNIP>

Further analysis revealed that a failing ‘socket.gethostbyaddr’ call was always returning a void result because it was not handling the possibility of an ip address not resolving to a host name:

    if is_strictly_ipv4_format(target):
        try:
            hostname, _, listipv4 = socket.gethostbyaddr(target)
            hostipv4 = listipv4[0]
        except:
            # Return void results
            if not verbose: return open_ports
            return generate_report('', target, open_ports, ports_and_services)

This is something I failed to anticipate (it can be confirmed via a reverse DNS lookup using the dig command - it fails to return a host name):

dig -x 104.26.10.78 +short

Problem was solved by altering the above-posted code to force a port scan:

    if is_strictly_ipv4_format(target):
        try:
            hostname, _, listipv4 = socket.gethostbyaddr(target)
            hostipv4 = listipv4[0]
        except:
            # Force port scan
            for port in range(port_range[0], port_range[1] + 1):
                # Record only successful connection
                if is_port_open(target, port, timeout):
                    open_ports.append(port)

            # Return results; will either be void, or contain port information
            if not verbose: return open_ports
            return generate_report('', target, open_ports, ports_and_services)

It would seem that overthinking the input validation contributed to this oversight.

Again, thank you for your response.

1 Like