Skip to content

Instantly share code, notes, and snippets.

@curipha
Created May 23, 2017 12:19
Show Gist options
  • Save curipha/0e440f74b1e0421f727bedb534267f3b to your computer and use it in GitHub Desktop.
Save curipha/0e440f74b1e0421f727bedb534267f3b to your computer and use it in GitHub Desktop.
Simple port scanner written in Ruby
#!/usr/bin/env ruby
require 'socket'
require 'timeout'
require 'thread'
$stdout.sync = true
DEBUG = false # Debug mode
PARALLEL = 120 # Number of port scanning thread
TIMEOUT = 5 # Timeout in sec.
DATEFORMAT = '%Y-%m-%d %H:%M:%S.%4N'
#DATEFORMAT = '%H:%M:%S.%4N'
$mutex = Mutex.new # Giant lock ;p
$threads = Array.new # All threads
def msg(str, type = 'MSG')
return '[' + Time.now.strftime(DATEFORMAT) + '] [' + type.strip + '] ' + str.strip
end
def dbg(str)
if DEBUG
$threads << Thread.new do
$mutex.synchronize do
warn msg(str, 'DEBUG')
end
end
end
end
def err(str)
abort msg(str, 'ERROR')
end
def scan(host = '127.0.0.1', port = 80)
begin
Timeout.timeout(TIMEOUT) do
TCPSocket.open(host, port)
end
rescue Timeout::Error, Errno::ETIMEDOUT
return :STEALTH
rescue Errno::ECONNREFUSED
return :CLOSE
rescue
return :FAIL
end
return :OPEN
end
def report(result)
puts 'Ports (except for CLOSE):'
cnt = 0
result.each_pair do |p, r|
case r
when :OPEN, :STEALTH, :FAIL
puts "#{'%5d' % p} : #{r}"
cnt += 1
end
end
if cnt < 1
puts ' No data for output.'
end
end
case ARGV[0]
when nil
host = '127.0.0.1'
when '-h', '-?', '--help', '--version'
puts <<MAN
$ ./#{File.basename(__FILE__)} [ host [ start_port [ end_port ] ] ]
Examples:
./#{File.basename(__FILE__)} ... Scan 127.0.0.1, port 1 - 65535
./#{File.basename(__FILE__)} 203.0.113.1 ... Scan 203.0.113.1, port 1 - 65535
./#{File.basename(__FILE__)} 203.0.113.1 80 ... Scan 203.0.113.1, port 80
./#{File.basename(__FILE__)} 203.0.113.1 20 500 ... Scan 203.0.113.1, port 20 - 500
MAN
exit
else
host = ARGV[0].strip
end
if ARGV[1].nil?
s_port = 1
e_port = 65535
else
s_port = ARGV[1].to_i
if ARGV[2].nil?
e_port = s_port
else
e_port = ARGV[2].to_i
end
end
if s_port < 1 || s_port > 65535
err 'Start port must be between 1 and 65535.'
end
if e_port < 1 || e_port > 65535
err 'End port must be between 1 and 65535.'
end
result = Hash.new # Result
queue = Queue.new # Work Queue
s_port.upto(e_port) do |p|
result[p] = nil
q = { 'host' => host, 'port' => p }
queue.push q
end
begin
dbg "Starting to scan... [ #{host} ]"
# Create worker threaeds
PARALLEL.times do
$threads << Thread.new do
while ! queue.empty?
w = queue.pop
dbg "Scanning Port #{w['port']} ..."
r = scan(w['host'], w['port'])
result[w['port']] = r
end
end
end
$threads.each do |t|
t.join
end
rescue Interrupt
dbg 'Interrupt.'
dbg "Please take a moment to finish all working threads (Max = #{TIMEOUT}sec.)."
queue.clear
$threads.each do |t|
t.join
end
ensure
dbg 'Finish!!'
report(result)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment