Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Flask>=1.1.0
34 changes: 22 additions & 12 deletions src/ipscanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,33 @@
import json
import os
from multi.scanner_thread import split_processing
try:
from utils.path_utils import get_absolute_path
except Exception:
def get_absolute_path(relative_path):
dir = os.path.dirname(os.path.abspath(__file__))
split_path = relative_path.split("/")
return os.path.join(dir, *split_path)

# Ask for input
net1 = raw_input('Enter the IP address: ')
try:
net1 = raw_input('Enter the IP address: ')
except NameError:
net1 = input('Enter the IP address: ')
net2 = net1.split('.')
a = '.'
net3 = net2[0] + a + net2[1] + a + net2[2] + a

# Print a nice banner with information on which host we are about to scan
print "-" * 60
print "Please wait, scanning IP address....", net3+"XXX"
print "-" * 60
print("-" * 60)
print("Please wait, scanning IP address....", net3+"XXX")
print("-" * 60)

# Resolves the relative path to absolute path
# [BUG]: https://github.com/vinitshahdeo/PortScanner/issues/19


def get_absolute_path(relative_path):
dir = os.path.dirname(os.path.abspath(__file__))
split_path = relative_path.split("/")
absolute_path = os.path.join(dir, *split_path)
return absolute_path
"""get_absolute_path now imported from utils.path_utils (fallback defined above)."""


# Check what time the scan started
Expand Down Expand Up @@ -63,11 +69,15 @@ def scan(addr):


def run1(ips, range_low, range_high):
for ip in xrange(range_low, range_high):
try:
iterator = xrange
except NameError:
iterator = range
for ip in iterator(range_low, range_high):
addr = net3+str(ip)
# gets full address
if (scan(addr)):
print addr + " is live\n"
print(addr + " is live\n")


# calling function from scanner_thread.py for multithreading
Expand All @@ -77,4 +87,4 @@ def run1(ips, range_low, range_high):
# Calculates the difference of time, to see how long it took to run the script
total = td2-td1
# Printing the information to screen
print "Scanning completed in ", total
print("Scanning completed in ", total)
42 changes: 25 additions & 17 deletions src/mainScanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,18 @@
import json
import os
import threading
import __builtin__
try:
import __builtin__ as builtins
except ImportError:
import builtins
from multi.scanner_thread import split_processing
try:
from utils.path_utils import get_absolute_path
except Exception:
def get_absolute_path(relative_path):
dir = os.path.dirname(os.path.abspath(__file__))
split_path = relative_path.split("/")
return os.path.join(dir, *split_path)
import logging
from flask import Flask, render_template, request, redirect, url_for

Expand Down Expand Up @@ -37,17 +47,13 @@ def input():
return EnvironmentError

# Print a nice banner with information on which host we are about to scan
print "-" * 60
print "Please wait, scanning remote host....", remoteServerIP
print "-" * 60
print("-" * 60)
print("Please wait, scanning remote host....", remoteServerIP)
print("-" * 60)

# Resolves the relative path to absolute path
# [BUG]: https://github.com/vinitshahdeo/PortScanner/issues/19
def get_absolute_path(relative_path):
dir = os.path.dirname(os.path.abspath(__file__))
split_path = relative_path.split("/")
absolute_path = os.path.join(dir, *split_path)
return absolute_path
# get_absolute_path now provided by shared utils (see utils/path_utils.py)

# Check what time the scan started
t1 = datetime.now()
Expand All @@ -56,14 +62,16 @@ def get_absolute_path(relative_path):
try:
with open(get_absolute_path('../config.json')) as config_file:
config = json.load(config_file)
print get_absolute_path('../config.json')
print(get_absolute_path('../config.json'))
# defining number of threads running concurrently
CONST_NUM_THREADS = int(config['thread']['count'])

except IOError:
print("config.json file not found")
print("config.json file not found; falling back to thread count = 8")
CONST_NUM_THREADS = 8
except ValueError:
print("Kindly check the json file for appropriateness of range")
print("Kindly check the json file for appropriateness of range; using thread count = 8")
CONST_NUM_THREADS = 8

ports = list(range(range_low, range_high, 1))
# scanning the port only in range of (range_low, range_high)
Expand All @@ -76,20 +84,20 @@ def scan(ports, range_low, range_high):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
result = sock.connect_ex((remoteServerIP, port))
if result == 0:
print "Port {}: Open".format(port)
print("Port {}:\t Open".format(port))
portnum.append("Port "+str(port))
sock.close()

except KeyboardInterrupt:
print "You pressed Ctrl+C"
print("You pressed Ctrl+C")
sys.exit()

except socket.gaierror:
print 'Hostname could not be resolved. Exiting'
print('Hostname could not be resolved. Exiting')
sys.exit()

except socket.error:
print "Couldn't connect to server"
print("Couldn't connect to server")
sys.exit()

# calling function from scanner_thread.py for multithreading
Expand All @@ -102,7 +110,7 @@ def scan(ports, range_low, range_high):
total = t2 - t1

# Printing the information to screen
print 'Scanning Completed in: ', total
print('Scanning Completed in: ', total)
return render_template('index.html', portnum=portnum, host=remoteServerIP, range_low=range_low, range_high=range_high, total=total)


Expand Down
125 changes: 80 additions & 45 deletions src/scanner.py
Original file line number Diff line number Diff line change
@@ -1,35 +1,69 @@
#!/usr/bin/env python
from __future__ import print_function
"""Multithreaded port scanner.

Refactored to add optional CLI arguments for non-interactive usage and to
centralize path resolution logic. Backwards compatible with previous
interactive prompt behaviour.

Author: Basuki (Hacktoberfest 2025 contribution)
"""
import socket
import subprocess
import sys
from datetime import datetime
import json
import os
import threading
import __builtin__
import argparse
try:
import __builtin__ as builtins
except ImportError:
import builtins
from multi.scanner_thread import split_processing
try:
# Local util for resolving paths (new shared helper)
from utils.path_utils import get_absolute_path
except Exception: # pragma: no cover - fallback for legacy environments
import os
def get_absolute_path(relative_path):
base_dir = os.path.dirname(os.path.abspath(__file__))
split_path = relative_path.split("/")
return os.path.join(base_dir, *split_path)

exc = getattr(builtins, "IOError", IOError)

# Clear the screen (best-effort; works on *nix). Silently ignore on Windows.
try:
subprocess.call('clear', shell=True)
except Exception:
pass

parser = argparse.ArgumentParser(description="Simple multithreaded port scanner")
parser.add_argument('-H', '--host', help='Remote host to scan (e.g. localhost)')
parser.add_argument('-l', '--low', type=int, help='Override low port (inclusive)')
parser.add_argument('-u', '--high', type=int, help='Override high port (exclusive)')
parser.add_argument('-t', '--threads', type=int, help='Override number of threads')
parser.add_argument('--no-banner', action='store_true', help='Suppress banner output')
args = parser.parse_args()

# Ask for input only if host not provided via CLI
if args.host:
remoteServer = args.host
else:
try:
remoteServer = raw_input("Enter a remote host to scan: ")
except NameError:
remoteServer = input("Enter a remote host to scan: ")

exc = getattr(__builtin__, "IOError", "FileNotFoundError")

# Clear the screen
subprocess.call('clear', shell=True)

# Ask for input
remoteServer = raw_input("Enter a remote host to scan: ")
remoteServerIP = socket.gethostbyname(remoteServer)

# Print a nice banner with information on which host we are about to scan
print "-" * 60
print "Please wait, scanning remote host....", remoteServerIP
print "-" * 60
try:
remoteServerIP = socket.gethostbyname(remoteServer)
except socket.gaierror:
print('Hostname could not be resolved. Exiting')
sys.exit(1)

# Resolves the relative path to absolute path
# [BUG]: https://github.com/vinitshahdeo/PortScanner/issues/19
def get_absolute_path(relative_path):
dir = os.path.dirname(os.path.abspath(__file__))
split_path = relative_path.split("/")
absolute_path = os.path.join(dir, *split_path)
return absolute_path
if not args.no_banner:
print("-" * 60)
print("Please wait, scanning remote host....", remoteServerIP)
print("-" * 60)

# Check what time the scan started
t1 = datetime.now()
Expand All @@ -38,50 +72,51 @@ def get_absolute_path(relative_path):
try:
with open(get_absolute_path('../config.json')) as config_file:
config = json.load(config_file)
print get_absolute_path('../config.json')
range_high = int(config['range']['high'])
range_low = int(config['range']['low'])
# defining number of threads running concurrently
CONST_NUM_THREADS = int(config['thread']['count'])

except IOError:
print("config.json file not found")
print("config.json file not found; using defaults 1-1024 with 8 threads")
range_low, range_high, CONST_NUM_THREADS = 1, 1024, 8
except ValueError:
print("Kindly check the json file for appropriateness of range")
print("Invalid values in config.json; using safe defaults 1-1024 with 8 threads")
range_low, range_high, CONST_NUM_THREADS = 1, 1024, 8

# CLI overrides
if args.low is not None:
range_low = args.low
if args.high is not None:
range_high = args.high
if args.threads is not None and args.threads > 0:
CONST_NUM_THREADS = args.threads

if range_low >= range_high:
print('Error: low port must be < high port')
sys.exit(2)

ports = list(range(range_low, range_high, 1))
# scanning the port only in range of (range_low, range_high)

def scan(ports, range_low, range_high):
def scan(ports, start_port, end_port):
try:
for port in range(range_low, range_high):
for port in range(start_port, end_port):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(0.5)
result = sock.connect_ex((remoteServerIP, port))
if result == 0:
print "Port {}: Open".format(port)
print("Port {}:\t Open".format(port))
sock.close()

except KeyboardInterrupt:
print "You pressed Ctrl+C"
print("You pressed Ctrl+C")
sys.exit()

except socket.gaierror:
print 'Hostname could not be resolved. Exiting'
sys.exit()

except socket.error:
print "Couldn't connect to server"
print("Couldn't connect to server")
sys.exit()


# calling function from scanner_thread.py for multithreading
split_processing(ports, CONST_NUM_THREADS, scan, range_low, range_high)

# Checking the time again
t2 = datetime.now()

# Calculates the difference of time, to see how long it took to run the script
total = t2 - t1
print('Scanning Completed in: ', total)

# Printing the information to screen
print 'Scanning Completed in: ', total
36 changes: 36 additions & 0 deletions src/utils/path_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"""Utility helpers for path resolution.

Centralizes logic for converting a relative path (using forward slashes) to
an absolute path rooted at the current file's directory. This logic was
previously duplicated across multiple scanner scripts.

Author: Basuki (Hacktoberfest 2025 contribution)
"""

from __future__ import absolute_import
import os


def get_absolute_path(relative_path):
"""Return absolute path for a project-relative path.

The existing code split relative paths using '/'. This keeps backward
compatibility while supporting Windows paths by joining components with
``os.path.join``.

Args:
relative_path (str): A relative path using '/' as separator.

Returns:
str: The absolute, normalized path.
"""
base_dir = os.path.dirname(os.path.abspath(__file__)) # .../src/utils
# Move up one directory to stay consistent with prior implementations
# which anchored at the script's directory (scanner.py etc.). Those
# scripts live under src/, so we go to their parent with dirname.
src_dir = os.path.dirname(base_dir)
split_path = relative_path.split("/")
return os.path.normpath(os.path.join(src_dir, *split_path))


__all__ = ["get_absolute_path"]