PDA

View Full Version : Python and threads


GnuVince
09-27-2002, 07:00 PM
Anyone can tell me what modifications I should make to this port scanner so that it is threaded?


#!/usr/bin/env python

from socket import *
import sys

try:
host = sys.argv[1]
maxport = int(sys.argv[2]) + 1

for port in xrange(1, maxport):
s = socket(AF_INET, SOCK_STREAM)
try:
s.connect((host, port))
print "Port %d is open" % port
except error:
continue
except IndexError:
print "Usage: %s <ip address> <max port>" % sys.argv[0]
except ValueError:
print "Port must be a valid integer"
except Exception, e:
print e


Threading seems to be a complicated concept and there still aren't any good book (at least as good as Ruby Programming (www.rubycentral.com/book/)) available online for Python.

nex
09-27-2002, 08:07 PM
Threads are actually rather simple in Python if you use the threading module. You just extend the Thread class and override the run() method (see the docs for more details). Also, if you override the __init__ method, you have to call the one in Thread yourself.

This works:

[EDIT] fixed code :rolleyes:

#!/usr/bin/env python

from threading import Thread
from socket import *
import sys

class ScanThread(Thread):
def __init__(self, host, port):
self.host = host
self.port = port
Thread.__init__(self)

def run(self):
try:
s = socket(AF_INET, SOCK_STREAM)
s.connect((self.host, self.port))
print "Port %d is open" % self.port
s.close()
except error:
return

try:
host = sys.argv[1]
maxport = int(sys.argv[2]) + 1

for port in xrange(1, maxport):
newscanthread = ScanThread(host, port)
newscanthread.start()

except IndexError:
print "Usage: %s <ip address> <max port>" % sys.argv[0]
except ValueError:
print "Port must be a valid integer"
except Exception, e:
print e

If you're scanning thousands of ports you may want to limit how many threads you have running. You can use an Event object and have threads set it when they finish. Something like this would work:

#!/usr/bin/env python

from threading import Thread, Event, activeCount
from socket import *
import sys

MAX_THREADS = 100

class ScanThread(Thread):
def __init__(self, host, port, event):
self.host = host
self.port = port
self.event = event
Thread.__init__(self)

def run(self):
try:
s = socket(AF_INET, SOCK_STREAM)
s.connect((self.host, self.port))
print "Port %d is open" % self.port
s.close()
except error:
pass

self.event.set()
return

try:
host = sys.argv[1]
maxport = int(sys.argv[2]) + 1
event = Event()

for port in xrange(1, maxport):
if ( activeCount() > MAX_THREADS ): # if too many threads are running
event.clear()
event.wait() # wait for one to finish
newscanthread = ScanThread(host, port, event)
newscanthread.start()

except IndexError:
print "Usage: %s <ip address> <max port>" % sys.argv[0]
except ValueError:
print "Port must be a valid integer"
except Exception, e:
print e

Really all that you need to know is hiding in the docs for threads, but python.org is being mean right now so I can't find an exact link.

GnuVince
09-27-2002, 09:52 PM
Hum... none of the examples you gave worked with me :(

GnuVince
09-27-2002, 10:24 PM
I got it working:


#!/usr/bin/env python

import socket
import sys
from threading import Thread

class Scanner(Thread):
portList = []
def __init__(self, host, port):
Thread.__init__(self)
self.host = host
self.port = port

def run(self):
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((self.host, self.port))
s.close()
self.__class__.portList.append(self.port)
except socket.error:
return


if __name__ == '__main__':
if len(sys.argv) != 3:
print "Usage: %s <host> <max port to reach>" % sys.argv[0]
sys.exit(1)

threadList = []
portList = Scanner.portList
host = sys.argv[1]
maxport = int(sys.argv[2]) + 1

for port in xrange(1, maxport):
scan = Scanner(host, port)
scan.start()
threadList.append(scan)

for scan in threadList:
scan.join()

portList.sort()

for port in portList:
print "Port %d is open" % port


For people interested, here's the Ruby code:


#!/usr/bin/env ruby

require 'socket'

trap "INT" do
puts "\nScan interrupted"
exit 0
end

if $0 == __FILE__
if ARGV.size < 2
puts "Usage: #{$0} <host> <highest port to scan>"
exit 1
end

threads = []
host = ARGV[0]
h_port = Integer(ARGV[1])

for port in 1..h_port
threads << Thread.new(port) { |myPage|
begin
t = TCPSocket.new(host, myPage)
puts "Port #{myPage} is open"
t.close
rescue Errno::ECONNREFUSED
next
end
}
end

threads.each { |aThread| aThread.join }
end

nex
09-27-2002, 10:35 PM
Err, oops. Mine uses the global values of host and port instead of self.host and self.port. I tested on localhost and it was too fast to really be apparent. At least you got the idea though (?) :)

GnuVince
09-27-2002, 11:46 PM
About the whole subclassing thing, yeah.

Halide
09-28-2002, 12:38 AM
it worked for me when i tried www.tribes-universe.com ?