1+ import argparse
2+ import threading
3+
4+ # Import the PortScanner class from the scanner module
5+ from scanner import PortScanner
6+
7+
8+ def main ():
9+ """
10+ Main function to run the port scanner application.
11+ It handles command-line argument parsing, initializes the scanner,
12+ and starts the scanning process.
13+ """
14+
15+ # 1. Argument Parsing Setup
16+ # --------------------------------------------------------------------------
17+ # Create an ArgumentParser object. This object will hold all the information
18+ # needed to parse the command line into Python data types.
19+ # The 'description' argument provides a brief help message shown when
20+ # you runs the script with -h or --help.
21+ parser = argparse .ArgumentParser (description = "A multi-threaded TCP Port Scanner Tool" )
22+
23+ # Add arguments that the script will accept from the command line.
24+
25+ # --target / -t: Specifies the host (IP address or hostname) to scan.
26+ # 'type=str' ensures the input is treated as a string.
27+ # 'default="localhost"' sets a default value if the argument is not provided.
28+ # 'help' provides a description for the argument in the help message.
29+ parser .add_argument (
30+ "-t" , "--target" , type = str , default = "localhost" ,
31+ help = "Target host to scan (e.g., 'example.com' or '192.168.1.1'). Defaults to 'localhost'."
32+ )
33+
34+ # --start-port / -sp: Defines the starting port for the scan range.
35+ # 'type=int' ensures the input is an integer.
36+ parser .add_argument (
37+ "-sp" , "--start-port" , type = int , default = 1 ,
38+ help = "Starting port for the scan range. Defaults to 1."
39+ )
40+
41+ # --end-port / -ep: Defines the ending port for the scan range.
42+ # 'type=int' ensures the input is an integer.
43+ parser .add_argument (
44+ "-ep" , "--end-port" , type = int , default = 1024 ,
45+ help = "Ending port for the scan range (inclusive). Defaults to 1024."
46+ )
47+
48+ # --max-connections / -mc: Limits the number of concurrent connections (threads).
49+ # This prevents overwhelming the target or the scanning machine.
50+ # 'type=int' for an integer value.
51+ parser .add_argument (
52+ "-mc" , "--max-connections" , type = int , default = 100 ,
53+ help = "The maximum number of concurrent connections (threads) to use during scanning. Defaults to 100."
54+ )
55+
56+ # --verbose / -v: Enables verbose output, showing status for all ports.
57+ # 'action='store_true'' means this argument is a boolean flag. If it's present
58+ # on the command line, args.verbose will be True; otherwise, False.
59+ parser .add_argument (
60+ "-v" , "--verbose" , action = 'store_true' ,
61+ help = "Enable verbose output. Prints the status of every port (open, closed, or filtered) as it's scanned."
62+ )
63+
64+ # --output / -o: Specifies an output file for scan results.
65+ # 'type=str': Expects a string value (the filename).
66+ # 'nargs='?'': This is crucial. It means the argument is optional.
67+ # - If `-o filename.txt` is given, args.output will be "filename.txt".
68+ # - If just `-o` is given (without a filename), `const` value is used.
69+ # 'const='auto_generate'': The value assigned to `args.output` if `-o` is present
70+ # but no value is provided (e.g., `python main.py -o`).
71+ # 'default=None': The value assigned to `args.output` if `-o` is not present at all.
72+ parser .add_argument (
73+ "-o" , "--output" , type = str , nargs = '?' , const = 'auto_generate' , default = None ,
74+ help = "Specify an output file to save results (e.g., results.txt). If just '-o' is used without a filename, a timestamped file will be created automatically in a 'port-scanner_results' directory."
75+ )
76+
77+ # Parse the arguments provided by you from the command line.
78+ args = parser .parse_args ()
79+
80+ # 2. PortScanner Initialization
81+ # --------------------------------------------------------------------------
82+ # Create an instance of the PortScanner class.
83+ # Pass the parsed target host, verbose flag, and output file path to its constructor.
84+ # The PortScanner will resolve the hostname to an IP address during its initialization.
85+ scanner = PortScanner (args .target , args .verbose , args .output )
86+
87+ # Check if the target host was successfully resolved to an IP address.
88+ # The resolve_host method in PortScanner returns an empty string if resolution fails.
89+ if not scanner .target_ip :
90+ print ("[!] Exiting: Target host could not be resolved. Please check the hostname or IP address." )
91+ return # Exit the script if the target is invalid.
92+
93+ # 3. Configure Scanner Parameters
94+ # --------------------------------------------------------------------------
95+ # Set the port range and maximum concurrent connections based on the parsed arguments.
96+ # These properties are set directly on the scanner instance.
97+ scanner .start_port = args .start_port
98+ scanner .end_port = args .end_port
99+ scanner .max_connections = args .max_connections
100+
101+ # Crucial: Re-initialize the semaphore in the scanner.
102+ # The semaphore is responsible for limiting concurrent threads.
103+ # It must be re-initialized here because 'max_connections' might have been
104+ # changed by the command-line argument, overriding its default value set in __init__.
105+ scanner .scan_semaphore = threading .Semaphore (scanner .max_connections )
106+
107+ # 4. Start the Scan
108+ # --------------------------------------------------------------------------
109+ # Call the scan_range method to begin the port scanning process.
110+ # This method orchestrates the creation of threads and manages the scan.
111+ scanner .scan_range ()
112+
113+
114+ # 5. Script Entry Point
115+ # --------------------------------------------------------------------------
116+ # This block ensures that the main() function is called only when the script
117+ # is executed directly (not when it's imported as a module into another script).
118+ if __name__ == "__main__" :
119+ main ()
0 commit comments