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.
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
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 ?
vBulletin® v3.7.0, Copyright ©2000-2009, Jelsoft Enterprises Ltd.