Port Scanner in Python

Python is a great tool to do some socket operations. I have written a piece of code by which I can scan a port range.
It is very basic and missing bunch of checks as aim is the simplicity here.

#!/usr/bin/python

import socket,sys

try:
  sys.argv[3]
except:
  print "Usage: port_scanner.py [hostname|IP] [port_start] [port_end]"
  sys.exit()

host = sys.argv[1]
start_port = int(sys.argv[2])
end_port = int(sys.argv[3])

#CREATE SOCKET
try:
  s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
except socket.error,err_msg:
  print 'Socket creation failed. Error code: '+ str(err_msg[0]) + ' Error mesage: ' + err_msg[1]
  sys.exit()

#RESOLVE HOSTNAME
try:
  remote_ip = socket.gethostbyname(host)

except socket.error,error_msg:
  print 'ERROR:'
  print error_msg
  sys.exit()

#ITERATE PORT RANGE
end_port+=1
for port in range(start_port,end_port):
  try:
    s.connect((remote_ip,port))
    print 'port ' + str(port) + ' open'

    s.close()
    s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
  except socket.error:
    pass

You can run the script in the following way by which you scan ports between 1 and 1024:

$ ./port_scanner.py remotehost.com 1 1024
port 80 open
port 443 open

However I need to give some more info in here. If you send a TCP SYN segment to a closed port, normal behavior is to send a TCP RST segment back to the source. Under normal circumstances script runs through the port range and knocks every port on the remote destination. If a TCP RST is received, socket is closed and script knocks the other port in the list but what if you don’t receive any TCP RST back? For example there is a firewall in between and you can’t even knock some ports. Then what happens?  In this case Linux kernel does 5 TCP SYN by default according to my ubuntu sysctl settings;

$ sysctl -a | grep tcp_syn_retries
net.ipv4.tcp_syn_retries = 5

This is a terrible setting which causes lots of delay in every port knock. That is why to speed up test I decrease this retry value to 1 temporarily

# sysctl net.ipv4.tcp_syn_retries=1
net.ipv4.tcp_syn_retries = 1

Actually I wanted to set my own retry scheme via python but it seems it isn’t possible to manipulate kernel’s behavior on this.  In python there is a “setsockopt” method of socket by which you can send certain options but no related option I could find in socket manual of Linux. There may be a way but I don’t know it yet.

When you run the test,  you can check the SYN requests with the following tcpdump command, you can have a better picture of what the script is doing;

#tcpdump -nni any host remotehost.com and 'tcp[tcpflags] & tcp-syn!=0'

About: rtoodtoo

Genco has worked for more than 10 years as a Network/Support Engineer. He is also interested in Python, Linux, Security and SD-WAN, currently lives in the Netherlands and works as a Network Support Engineer at Tesla Inc. // JNCIE-SEC #223 / RHCE / PCNSE


You have a feedback?

This site uses Akismet to reduce spam. Learn how your comment data is processed.