aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/results.py52
-rw-r--r--lib/scanner.py85
-rw-r--r--lib/util.py4
-rw-r--r--lib/worker.py38
4 files changed, 179 insertions, 0 deletions
diff --git a/lib/results.py b/lib/results.py
new file mode 100644
index 0000000..1565c4b
--- /dev/null
+++ b/lib/results.py
@@ -0,0 +1,52 @@
+from threading import Lock
+from lib.util import Colored
+from lib.scanner import PortState
+from ch1p import telegram_notify
+
+
+class Results:
+ def __init__(self):
+ self.warnings = []
+ self.mutex = Lock()
+
+ def add(self, worker):
+ host = worker.get_host()
+ with self.mutex:
+ if not worker.done:
+ print(f'{Colored.RED}{worker.name}: scanning failed{Colored.END}')
+ return
+
+ if worker.name != host:
+ print(f'{worker.name} ({host}):')
+ else:
+ print(f'{host}:')
+
+ opened = []
+ results = worker.get_results()
+ for port, state in results:
+ if state != PortState.OPEN:
+ continue
+
+ opened.append(port)
+ if not worker.is_expected(port):
+ self.warnings.append(f'<b>{worker.name}</b> ({host}): port {port} is open')
+ print(f' {Colored.RED}{port} opened{Colored.END}')
+ else:
+ print(f' {Colored.GREEN}{port} opened{Colored.END}')
+
+ if worker.opened:
+ for port in worker.opened:
+ if port not in opened:
+ self.warnings.append(
+ f'<b>{worker.name}</b> ({host}): port {port} is NOT open')
+ print(f' {Colored.RED}{port} not opened{Colored.END}')
+ print()
+
+ def has_warnings(self):
+ return len(self.warnings) > 0
+
+ def notify(self, chat_id=None, token=None):
+ text = '<b>❗️Attention!</b>\n\n'
+ text += '\n'.join(self.warnings)
+
+ telegram_notify(text, parse_mode='html', chat_id=chat_id, token=token)
diff --git a/lib/scanner.py b/lib/scanner.py
new file mode 100644
index 0000000..f78e4f6
--- /dev/null
+++ b/lib/scanner.py
@@ -0,0 +1,85 @@
+import struct
+import socket
+import threading
+import queue
+import logging
+
+from enum import Enum, auto
+
+logger = logging.getLogger(__name__)
+
+
+class PortState(Enum):
+ OPEN = auto()
+ CLOSED = auto()
+ FILTERED = auto()
+
+
+class TCPScanner:
+ def __init__(self, host, ports, timeout=5):
+ self.host = host
+ self.ports = ports
+ self.timeout = timeout
+ self.results = []
+ self.q = queue.SimpleQueue()
+ self.failed = False
+
+ def scan(self, num_threads=5):
+ for port in self.ports:
+ self.q.put(port)
+
+ threads = []
+ for i in range(num_threads):
+ t = threading.Thread(target=self.run)
+ t.start()
+ threads.append(t)
+
+ for t in threads:
+ t.join()
+
+ def run(self):
+ while True:
+ if self.failed:
+ break
+
+ try:
+ port = self.q.get(block=False)
+ except queue.Empty:
+ break
+
+ try:
+ self._scan(port)
+ except Exception as e:
+ logger.exception(e)
+ self.failed = True
+ break
+
+ def _scan(self, port):
+ try:
+ conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ conn.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack("ii", 1, 0))
+ conn.settimeout(self.timeout)
+
+ ret = conn.connect_ex((self.host, port))
+
+ # DATA RECEIVED - SYN ACK
+ if ret == 0:
+ logger.debug('%s:%d - tcp open (SYN-ACK packet)' % (self.host, port))
+ self.results.append((port, PortState.OPEN))
+
+ # RST RECEIVED - PORT CLOSED
+ elif ret == 111:
+ logger.debug('%s:%d - tcp closed (RST packet)' % (self.host, port))
+ self.results.append((port, PortState.CLOSED))
+
+ # ERR CODE 11 - TIMEOUT
+ elif ret == 11:
+ self.results.append((port, PortState.FILTERED))
+
+ else:
+ logger.debug('%s:%d - code %d' % (self.host, port, ret))
+
+ conn.close()
+
+ except socket.timeout:
+ self.results.append((port, PortState.FILTERED)) \ No newline at end of file
diff --git a/lib/util.py b/lib/util.py
new file mode 100644
index 0000000..c6087a7
--- /dev/null
+++ b/lib/util.py
@@ -0,0 +1,4 @@
+class Colored:
+ GREEN = '\033[92m'
+ RED = '\033[91m'
+ END = '\033[0m' \ No newline at end of file
diff --git a/lib/worker.py b/lib/worker.py
new file mode 100644
index 0000000..f8d6c55
--- /dev/null
+++ b/lib/worker.py
@@ -0,0 +1,38 @@
+import logging
+
+from threading import Thread
+from lib.scanner import TCPScanner
+
+logger = logging.getLogger(__name__)
+
+
+class Worker(Thread):
+ def __init__(self, name, host, opened=None, concurrency=None, timeout=None):
+ Thread.__init__(self)
+
+ assert concurrency is not None
+
+ self.done = False
+ self.name = name
+ self.concurrency = concurrency
+ self.opened = opened
+
+ scanner_kw = {}
+ if timeout is not None:
+ scanner_kw['timeout'] = timeout
+ self.scanner = TCPScanner(host, range(0, 65535), **scanner_kw)
+
+ def run(self):
+ logger.info(f'starting {self.name} ({self.concurrency} threads)')
+ self.scanner.scan(num_threads=self.concurrency)
+ self.done = not self.scanner.failed
+ logger.info(f'finished {self.name}')
+
+ def get_results(self):
+ return self.scanner.results
+
+ def is_expected(self, port):
+ return (self.opened is not None) and (port in self.opened)
+
+ def get_host(self):
+ return self.scanner.host