#!/usr/bin/env python3
"""kiraascan — stdlib-only TCP connect scanner (our kit, deployed on kiraa box)
Usage: kiraascan.py IP[:RANGE|LIST] [IP2[:...]] ...
  IP:PORT          single port
  IP:P1-P2         port range inclusive
  IP:P1,P2,P3      port list
  IP               default common ports
"""
import socket, sys
from concurrent.futures import ThreadPoolExecutor, as_completed

COMMON = [21,22,23,25,53,80,110,135,139,143,443,445,993,995,1433,1521,1723,3306,3389,5432,5900,6379,8080,8443,9200,27017]

def parse_arg(a):
    if ":" in a:
        ip, pr = a.rsplit(":", 1)
        if "-" in pr:
            lo, hi = pr.split("-")
            ports = list(range(int(lo), int(hi) + 1))
        elif "," in pr:
            ports = [int(p) for p in pr.split(",")]
        else:
            ports = [int(pr)]
    else:
        ip, ports = a, COMMON
    return [(ip, p) for p in ports]

def check(c):
    ip, port = c
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.settimeout(0.6)
        s.connect((ip, port))
        s.close()
        return (ip, port)
    except Exception:
        return None

def main():
    targets = []
    for a in sys.argv[1:]:
        targets.extend(parse_arg(a))
    print("[kiraascan] %d combos, %d targets" % (len(targets), len(set(t[0] for t in targets))), flush=True)
    open_ = {}
    with ThreadPoolExecutor(max_workers=300) as ex:
        futs = [ex.submit(check, c) for c in targets]
        for f in as_completed(futs):
            r = f.result()
            if r:
                open_.setdefault(r[0], []).append(r[1])
    for ip in sorted(open_):
        print("%s: %s" % (ip, ",".join(str(p) for p in sorted(open_[ip]))), flush=True)
    print("[kiraascan] done: %d hosts with open ports" % len(open_), flush=True)

if __name__ == "__main__":
    main()
