swapped to golang
This commit is contained in:
parent
2f5cacd57b
commit
98cfb706cf
2 changed files with 372 additions and 262 deletions
372
main.go
Normal file
372
main.go
Normal file
|
@ -0,0 +1,372 @@
|
||||||
|
package main
|
||||||
|
// sorry in advance for anyone who has to read this
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"runtime"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type OpenPort struct {
|
||||||
|
IP string
|
||||||
|
Port int
|
||||||
|
Hostname string
|
||||||
|
Fingerprint string
|
||||||
|
}
|
||||||
|
const batchSize = 255
|
||||||
|
var printMutex sync.Mutex
|
||||||
|
var (
|
||||||
|
summaryFile *os.File
|
||||||
|
writer *bufio.Writer
|
||||||
|
fileLock sync.Mutex
|
||||||
|
)
|
||||||
|
var (
|
||||||
|
openPorts []OpenPort
|
||||||
|
openPortsLock sync.Mutex
|
||||||
|
ipLineMap = make(map[string]int)
|
||||||
|
openPortMsgs []string
|
||||||
|
)
|
||||||
|
|
||||||
|
func clearScreen() {
|
||||||
|
fmt.Print("\033[2J")
|
||||||
|
}
|
||||||
|
|
||||||
|
func moveCursor(row, col int) {
|
||||||
|
fmt.Printf("\033[%d;%dH", row, col)
|
||||||
|
}
|
||||||
|
|
||||||
|
func clearLine() {
|
||||||
|
fmt.Print("\033[K")
|
||||||
|
}
|
||||||
|
|
||||||
|
func safePrint(format string, a ...interface{}) {
|
||||||
|
printMutex.Lock()
|
||||||
|
defer printMutex.Unlock()
|
||||||
|
fmt.Printf(format, a...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func safePrintln(a ...interface{}) {
|
||||||
|
printMutex.Lock()
|
||||||
|
defer printMutex.Unlock()
|
||||||
|
fmt.Println(a...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func printStatusLine(ip, msg string) {
|
||||||
|
if line, ok := ipLineMap[ip]; ok {
|
||||||
|
moveCursor(line, 0)
|
||||||
|
clearLine()
|
||||||
|
fmt.Printf("[%s] %s", ip, msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func printOpenPortLine(msg string) {
|
||||||
|
openPortsLock.Lock()
|
||||||
|
defer openPortsLock.Unlock()
|
||||||
|
openPortMsgs = append(openPortMsgs, msg)
|
||||||
|
moveCursor(len(ipLineMap)+2+len(openPortMsgs), 0)
|
||||||
|
clearLine()
|
||||||
|
fmt.Println(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func isPrivateIP(ipStr string) bool {
|
||||||
|
ip := net.ParseIP(ipStr)
|
||||||
|
if ip == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
privateBlocks := []string{
|
||||||
|
"10.0.0.0/8",
|
||||||
|
"172.16.0.0/12",
|
||||||
|
"192.168.0.0/16",
|
||||||
|
"127.0.0.0/8",
|
||||||
|
}
|
||||||
|
for _, cidr := range privateBlocks {
|
||||||
|
_, block, _ := net.ParseCIDR(cidr)
|
||||||
|
if block.Contains(ip) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func pingIP(ip string, pingCmd []string) bool {
|
||||||
|
cmd := exec.Command(pingCmd[0], append(pingCmd[1:], ip)...)
|
||||||
|
err := cmd.Run()
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func grabBanner(ip string, port int) string {
|
||||||
|
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", ip, port), 1*time.Second)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
conn.SetReadDeadline(time.Now().Add(1 * time.Second))
|
||||||
|
buf := make([]byte, 1024)
|
||||||
|
n, _ := conn.Read(buf)
|
||||||
|
return strings.TrimSpace(string(buf[:n]))
|
||||||
|
}
|
||||||
|
|
||||||
|
func identifyServiceAndOS(ip string, port int) string {
|
||||||
|
data, err := os.ReadFile("services.json")
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
var services map[string]map[string]string
|
||||||
|
json.Unmarshal(data, &services)
|
||||||
|
|
||||||
|
portStr := strconv.Itoa(port)
|
||||||
|
if info, ok := services[portStr]; ok {
|
||||||
|
banner := grabBanner(ip, port)
|
||||||
|
if banner != "" {
|
||||||
|
return fmt.Sprintf("%s banner: %s", info["name"], banner)
|
||||||
|
}
|
||||||
|
return info["name"]
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func scanPort(ip string, port int, wg *sync.WaitGroup) {
|
||||||
|
printStatusLine(ip, fmt.Sprintf("scanning port %d...", port))
|
||||||
|
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", ip, port), 500*time.Millisecond)
|
||||||
|
if err == nil {
|
||||||
|
conn.Close()
|
||||||
|
host, err := net.LookupAddr(ip)
|
||||||
|
hostname := "unknown hostname"
|
||||||
|
if err == nil && len(host) > 0 {
|
||||||
|
hostname = strings.TrimSuffix(host[0], ".")
|
||||||
|
}
|
||||||
|
fingerprint := identifyServiceAndOS(ip, port)
|
||||||
|
openPortsLock.Lock()
|
||||||
|
openPorts = append(openPorts, OpenPort{ip, port, hostname, fingerprint})
|
||||||
|
line := fmt.Sprintf(" - %s : port %d open - hostname: %s", ip, port, hostname)
|
||||||
|
if fingerprint != "" {
|
||||||
|
line += " | " + fingerprint
|
||||||
|
}
|
||||||
|
|
||||||
|
fileLock.Lock()
|
||||||
|
summaryFile.WriteString(line + "\n")
|
||||||
|
fileLock.Unlock()
|
||||||
|
openPortsLock.Unlock()
|
||||||
|
msg := fmt.Sprintf("[%s] port %d is OPEN (%s)", ip, port, hostname)
|
||||||
|
if fingerprint != "" {
|
||||||
|
msg += " | " + fingerprint
|
||||||
|
}
|
||||||
|
printOpenPortLine(msg)
|
||||||
|
printStatusLine(ip, fmt.Sprintf("open port found: %d", port))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func scanPortsForIP(ip string, portStart, portEnd int) {
|
||||||
|
const maxGoroutines = 50
|
||||||
|
guard := make(chan struct{}, maxGoroutines)
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
|
for port := portStart; port <= portEnd; port++ {
|
||||||
|
guard <- struct{}{}
|
||||||
|
wg.Add(1)
|
||||||
|
go func(p int) {
|
||||||
|
defer wg.Done()
|
||||||
|
scanPort(ip, p, &wg)
|
||||||
|
<-guard
|
||||||
|
}(port)
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
printStatusLine(ip, "scan done.")
|
||||||
|
}
|
||||||
|
|
||||||
|
func pingIPsConcurrently(ips []string, pingCmd []string) []string {
|
||||||
|
var alive []string
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
var lock sync.Mutex
|
||||||
|
for _, ip := range ips {
|
||||||
|
wg.Add(1)
|
||||||
|
go func(ip string) {
|
||||||
|
defer wg.Done()
|
||||||
|
if !isPrivateIP(ip) {
|
||||||
|
fmt.Printf("[+] skipping ping for public IP %s\n", ip)
|
||||||
|
lock.Lock()
|
||||||
|
alive = append(alive, ip)
|
||||||
|
lock.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if pingIP(ip, pingCmd) {
|
||||||
|
fmt.Printf("[+] found %s\n", ip)
|
||||||
|
lock.Lock()
|
||||||
|
alive = append(alive, ip)
|
||||||
|
lock.Unlock()
|
||||||
|
} else {
|
||||||
|
fmt.Printf("[~] no response from %s\n", ip)
|
||||||
|
}
|
||||||
|
|
||||||
|
}(ip)
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
return alive
|
||||||
|
}
|
||||||
|
|
||||||
|
func ipRange(start, end string) ([]string, error) {
|
||||||
|
startIP := net.ParseIP(start).To4()
|
||||||
|
endIP := net.ParseIP(end).To4()
|
||||||
|
if startIP == nil || endIP == nil {
|
||||||
|
return nil, fmt.Errorf("invalid IP")
|
||||||
|
}
|
||||||
|
|
||||||
|
var ips []string
|
||||||
|
for ip := startIP; !ipAfter(ip, endIP); ip = nextIP(ip) {
|
||||||
|
ips = append(ips, ip.String())
|
||||||
|
}
|
||||||
|
return ips, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ipAfter(a, b net.IP) bool {
|
||||||
|
for i := 0; i < 4; i++ {
|
||||||
|
if a[i] > b[i] {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if a[i] < b[i] {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func nextIP(ip net.IP) net.IP {
|
||||||
|
next := make(net.IP, len(ip))
|
||||||
|
copy(next, ip)
|
||||||
|
for i := 3; i >= 0; i-- {
|
||||||
|
next[i]++
|
||||||
|
if next[i] != 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return next
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var err error
|
||||||
|
summaryFile, err = os.Create("summary.txt")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("[!] failed to open summary file:", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
defer summaryFile.Close()
|
||||||
|
reader := bufio.NewReader(os.Stdin)
|
||||||
|
fmt.Print("enter IP range (e.g., 192.168.1.1-192.168.1.20): ")
|
||||||
|
ipInput, _ := reader.ReadString('\n')
|
||||||
|
ipInput = strings.TrimSpace(ipInput)
|
||||||
|
if ipInput == "" {
|
||||||
|
ipInput = "192.168.0.0-192.168.255.255"
|
||||||
|
}
|
||||||
|
fmt.Print("port range (e.g., 1-65535): ")
|
||||||
|
portInput, _ := reader.ReadString('\n')
|
||||||
|
portInput = strings.TrimSpace(portInput)
|
||||||
|
if portInput == "" {
|
||||||
|
portInput = "1-10000"
|
||||||
|
}
|
||||||
|
ipParts := strings.Split(ipInput, "-")
|
||||||
|
portParts := strings.Split(portInput, "-")
|
||||||
|
if len(ipParts) != 2 || len(portParts) != 2 {
|
||||||
|
fmt.Println("[!] bad input.")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
ipList, err := ipRange(ipParts[0], ipParts[1])
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("[!] bad IP range:", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
portStart, _ := strconv.Atoi(portParts[0])
|
||||||
|
portEnd, _ := strconv.Atoi(portParts[1])
|
||||||
|
|
||||||
|
fmt.Println("--------------------------------------------------")
|
||||||
|
fmt.Printf("scanning %s to %s\n", ipParts[0], ipParts[1])
|
||||||
|
fmt.Printf("ports %d to %d\n", portStart, portEnd)
|
||||||
|
fmt.Println("started at:", time.Now())
|
||||||
|
fmt.Println("--------------------------------------------------")
|
||||||
|
|
||||||
|
pingCmd := []string{}
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "windows":
|
||||||
|
pingCmd = []string{"ping", "-n", "1", "-w", "1000"}
|
||||||
|
case "darwin":
|
||||||
|
pingCmd = []string{"ping", "-c", "1"}
|
||||||
|
default:
|
||||||
|
pingCmd = []string{"ping", "-c", "1", "-W", "1"}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("[~] pinging IPs...")
|
||||||
|
var alive []string
|
||||||
|
for i := 0; i < len(ipList); i += batchSize {
|
||||||
|
end := i + batchSize
|
||||||
|
if end > len(ipList) {
|
||||||
|
end = len(ipList)
|
||||||
|
}
|
||||||
|
batch := ipList[i:end]
|
||||||
|
fmt.Printf("[~] pinging IPs %d to %d...\n", i+1, end)
|
||||||
|
batchAlive := pingIPsConcurrently(batch, pingCmd)
|
||||||
|
alive = append(alive, batchAlive...)
|
||||||
|
}
|
||||||
|
if len(alive) == 0 {
|
||||||
|
fmt.Println("[-] no IPs responded to ping. exiting.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
clearScreen()
|
||||||
|
for idx, ip := range alive {
|
||||||
|
ipLineMap[ip] = idx + 1
|
||||||
|
printStatusLine(ip, "waiting to scan...")
|
||||||
|
}
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
for i := 0; i < len(alive); i += batchSize {
|
||||||
|
end := i + batchSize
|
||||||
|
if end > len(alive) {
|
||||||
|
end = len(alive)
|
||||||
|
}
|
||||||
|
batch := alive[i:end]
|
||||||
|
for _, ip := range batch {
|
||||||
|
wg.Add(1)
|
||||||
|
go func(ip string) {
|
||||||
|
defer wg.Done()
|
||||||
|
scanPortsForIP(ip, portStart, portEnd)
|
||||||
|
}(ip)
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
moveCursor(len(ipLineMap)+3+len(openPortMsgs), 0)
|
||||||
|
clearLine()
|
||||||
|
fmt.Println("\n--------------------------------------------------")
|
||||||
|
fmt.Println("scan done at:", time.Now())
|
||||||
|
fmt.Println("--------------------------------------------------")
|
||||||
|
|
||||||
|
file, err := os.Create("summary.txt")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("[!] failed to write summary:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
if len(openPorts) == 0 {
|
||||||
|
file.WriteString("no open ports found.\n")
|
||||||
|
} else {
|
||||||
|
file.WriteString("[+] scan summary: open ports found with fingerprints\n")
|
||||||
|
for _, p := range openPorts {
|
||||||
|
line := fmt.Sprintf(" - %s : port %d open - hostname: %s", p.IP, p.Port, p.Hostname)
|
||||||
|
if p.Fingerprint != "" {
|
||||||
|
line += " | " + p.Fingerprint
|
||||||
|
}
|
||||||
|
file.WriteString(line + "\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Println("[+] scan summary written to summary.txt")
|
||||||
|
}
|
262
main.py
262
main.py
|
@ -1,262 +0,0 @@
|
||||||
import socket
|
|
||||||
from datetime import datetime
|
|
||||||
import ipaddress
|
|
||||||
import sys
|
|
||||||
import subprocess
|
|
||||||
import platform
|
|
||||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
||||||
import threading
|
|
||||||
import queue
|
|
||||||
import json
|
|
||||||
|
|
||||||
log_queue = queue.Queue()
|
|
||||||
|
|
||||||
print_lock = threading.Lock()
|
|
||||||
ip_status_lock = threading.Lock()
|
|
||||||
shutdown_event = threading.Event()
|
|
||||||
ip_line_map = {}
|
|
||||||
open_ports = []
|
|
||||||
open_ports_lock = threading.Lock()
|
|
||||||
open_port_msgs = []
|
|
||||||
open_port_msgs_lock = threading.Lock()
|
|
||||||
bottom_log_start_line = 0
|
|
||||||
|
|
||||||
def clear_screen():
|
|
||||||
sys.stdout.write("\033[2J")
|
|
||||||
sys.stdout.flush()
|
|
||||||
|
|
||||||
def move_cursor(row, col=0):
|
|
||||||
sys.stdout.write(f"\033[{row};{col}H")
|
|
||||||
|
|
||||||
def clear_line():
|
|
||||||
sys.stdout.write("\033[K")
|
|
||||||
|
|
||||||
def print_status_line(ip, msg):
|
|
||||||
with ip_status_lock:
|
|
||||||
line = ip_line_map.get(ip)
|
|
||||||
if line:
|
|
||||||
move_cursor(line)
|
|
||||||
clear_line()
|
|
||||||
sys.stdout.write(f"[{ip}] {msg}")
|
|
||||||
sys.stdout.flush()
|
|
||||||
|
|
||||||
def print_open_port_line(msg):
|
|
||||||
with open_port_msgs_lock:
|
|
||||||
open_port_msgs.append(msg)
|
|
||||||
bottom_line = len(ip_line_map) + 2 + len(open_port_msgs)
|
|
||||||
move_cursor(bottom_line)
|
|
||||||
clear_line()
|
|
||||||
sys.stdout.write(msg + "\n")
|
|
||||||
sys.stdout.flush()
|
|
||||||
|
|
||||||
def ping_ip(ip, ping_cmd):
|
|
||||||
try:
|
|
||||||
cmd = ping_cmd + [ip]
|
|
||||||
result = subprocess.run(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, timeout=1)
|
|
||||||
return result.returncode == 0
|
|
||||||
except subprocess.TimeoutExpired:
|
|
||||||
return False
|
|
||||||
except:
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def is_private_ip(ip):
|
|
||||||
return ipaddress.IPv4Address(ip).is_private
|
|
||||||
|
|
||||||
def grab_banner(ip, port):
|
|
||||||
try:
|
|
||||||
s = socket.socket()
|
|
||||||
s.settimeout(1)
|
|
||||||
s.connect((ip, port))
|
|
||||||
if port == 22:
|
|
||||||
banner = s.recv(1024).decode(errors='ignore').strip()
|
|
||||||
return banner
|
|
||||||
elif port == 5900:
|
|
||||||
banner = s.recv(12).decode(errors='ignore').strip()
|
|
||||||
return banner
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
except:
|
|
||||||
return None
|
|
||||||
finally:
|
|
||||||
s.close()
|
|
||||||
|
|
||||||
def identify_service_and_os(ip, port):
|
|
||||||
json_path = "services.json"
|
|
||||||
try:
|
|
||||||
with open(json_path, "r") as f:
|
|
||||||
data = json.load(f)
|
|
||||||
services = {int(k): v for k, v in data.items()}
|
|
||||||
except Exception:
|
|
||||||
services = {}
|
|
||||||
|
|
||||||
service_info = services.get(port)
|
|
||||||
fingerprint = None
|
|
||||||
if service_info:
|
|
||||||
banner = grab_banner(ip, port)
|
|
||||||
if banner:
|
|
||||||
fingerprint = f"{service_info['name']} banner: {banner}"
|
|
||||||
else:
|
|
||||||
fingerprint = f"{service_info['name']}"
|
|
||||||
|
|
||||||
return fingerprint
|
|
||||||
|
|
||||||
def scan_port(ip, port):
|
|
||||||
print_status_line(ip, f"scanning port {port}...")
|
|
||||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
||||||
s.settimeout(0.5)
|
|
||||||
try:
|
|
||||||
result = s.connect_ex((ip, port))
|
|
||||||
if result == 0:
|
|
||||||
try:
|
|
||||||
hostname = socket.gethostbyaddr(ip)[0]
|
|
||||||
except socket.herror:
|
|
||||||
hostname = "unknown hostname"
|
|
||||||
fingerprint = identify_service_and_os(ip, port)
|
|
||||||
with open_ports_lock:
|
|
||||||
open_ports.append((ip, port, hostname, fingerprint))
|
|
||||||
msg = f"[{ip}] port {port} is OPEN ({hostname})"
|
|
||||||
if fingerprint:
|
|
||||||
msg += f" | {fingerprint}"
|
|
||||||
print_open_port_line(msg)
|
|
||||||
print_status_line(ip, f"open port found: {port}")
|
|
||||||
finally:
|
|
||||||
s.close()
|
|
||||||
|
|
||||||
def scan_ports_for_ip(ip, port_start, port_end):
|
|
||||||
with ThreadPoolExecutor(max_workers=10) as p_exec:
|
|
||||||
futures = [p_exec.submit(scan_port, ip, port) for port in range(port_start, port_end + 1)]
|
|
||||||
for future in as_completed(futures):
|
|
||||||
if shutdown_event.is_set():
|
|
||||||
break
|
|
||||||
try:
|
|
||||||
future.result()
|
|
||||||
except Exception as e:
|
|
||||||
with print_lock:
|
|
||||||
print(f"[!] port scan err on {ip}: {e}")
|
|
||||||
print_status_line(ip, "scan done.")
|
|
||||||
|
|
||||||
def ping_ip_threaded(ip, ping_cmd):
|
|
||||||
if shutdown_event.is_set():
|
|
||||||
return None
|
|
||||||
return ip if ping_ip(ip, ping_cmd) else None
|
|
||||||
|
|
||||||
def ping_ips_concurrently(ips, ping_cmd, max_workers=50):
|
|
||||||
alive_ips = []
|
|
||||||
with ThreadPoolExecutor(max_workers=max_workers) as executor:
|
|
||||||
futures = {executor.submit(ping_ip_threaded, ip, ping_cmd): ip for ip in ips}
|
|
||||||
for future in as_completed(futures):
|
|
||||||
if shutdown_event.is_set():
|
|
||||||
break
|
|
||||||
ip = futures[future]
|
|
||||||
try:
|
|
||||||
result = future.result()
|
|
||||||
if result:
|
|
||||||
alive_ips.append(ip)
|
|
||||||
print(f"[+] found {ip}")
|
|
||||||
else:
|
|
||||||
print(f"[~] no response from {ip}")
|
|
||||||
except Exception as e:
|
|
||||||
print(f"[!] ping error for {ip}: {e}")
|
|
||||||
return alive_ips
|
|
||||||
|
|
||||||
def main():
|
|
||||||
try:
|
|
||||||
ip_range = input("enter ip range (e.g., 192.168.1.1-192.168.1.20) [default 192.168.0.0-192.168.255.255]: ").strip()
|
|
||||||
port_range = input("port range (e.g., 1-65535) [default 1-10000]: ").strip()
|
|
||||||
if ip_range == "":
|
|
||||||
ip_start_str, ip_end_str = "192.168.0.0", "192.168.255.255"
|
|
||||||
else:
|
|
||||||
ip_start_str, ip_end_str = ip_range.split('-')
|
|
||||||
if port_range == "":
|
|
||||||
port_start, port_end = 1, 10000
|
|
||||||
else:
|
|
||||||
port_start, port_end = map(int, port_range.split('-'))
|
|
||||||
ip_start = ipaddress.IPv4Address(ip_start_str)
|
|
||||||
ip_end = ipaddress.IPv4Address(ip_end_str)
|
|
||||||
if ip_start > ip_end:
|
|
||||||
raise ValueError("start ip > end ip")
|
|
||||||
except Exception as e:
|
|
||||||
print(f"[!] bad input: {e}")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
print("-"*60)
|
|
||||||
print(f"scanning {ip_start} to {ip_end}")
|
|
||||||
print(f"ports {port_start} to {port_end}")
|
|
||||||
print("started at:", str(datetime.now()))
|
|
||||||
print("-"*60)
|
|
||||||
|
|
||||||
osname = platform.system().lower()
|
|
||||||
if osname == "windows":
|
|
||||||
ping_cmd = ["ping", "-n", "1", "-w", "1000"]
|
|
||||||
elif osname == "darwin":
|
|
||||||
ping_cmd = ["ping", "-c", "1"]
|
|
||||||
else:
|
|
||||||
ping_cmd = ["ping", "-c", "1", "-W", "1"]
|
|
||||||
|
|
||||||
all_ips = [str(ipaddress.IPv4Address(i)) for i in range(int(ip_start), int(ip_end)+1)]
|
|
||||||
|
|
||||||
any_public = False
|
|
||||||
for ip_str in all_ips:
|
|
||||||
ip_obj = ipaddress.IPv4Address(ip_str)
|
|
||||||
if not (ip_obj.is_private or ip_obj.is_loopback or ip_obj.is_reserved):
|
|
||||||
any_public = True
|
|
||||||
break
|
|
||||||
|
|
||||||
if any_public:
|
|
||||||
print("[~] public IPs detected, skipping ping and scanning directly...")
|
|
||||||
ips_to_scan = all_ips
|
|
||||||
else:
|
|
||||||
private_ips = [ip for ip in all_ips if is_private_ip(ip)]
|
|
||||||
print("[~] pinging private IPs...")
|
|
||||||
alive_ips = ping_ips_concurrently(private_ips, ping_cmd)
|
|
||||||
if not alive_ips:
|
|
||||||
print("[-] no IPs responded to ping. exiting.")
|
|
||||||
sys.exit(0)
|
|
||||||
ips_to_scan = alive_ips
|
|
||||||
|
|
||||||
clear_screen()
|
|
||||||
for idx, ip in enumerate(ips_to_scan):
|
|
||||||
ip_line_map[ip] = idx + 1
|
|
||||||
for ip in ips_to_scan:
|
|
||||||
print_status_line(ip, "waiting to scan...")
|
|
||||||
with ThreadPoolExecutor(max_workers=50) as ip_executor:
|
|
||||||
futures = []
|
|
||||||
for ip in ips_to_scan:
|
|
||||||
if shutdown_event.is_set():
|
|
||||||
break
|
|
||||||
futures.append(ip_executor.submit(scan_ports_for_ip, ip, port_start, port_end))
|
|
||||||
|
|
||||||
for future in as_completed(futures):
|
|
||||||
try:
|
|
||||||
future.result()
|
|
||||||
except Exception as e:
|
|
||||||
print(f"[!] error scanning IP: {e}")
|
|
||||||
|
|
||||||
|
|
||||||
bottom_line = len(ip_line_map) + 3 + len(open_port_msgs)
|
|
||||||
move_cursor(bottom_line, 0)
|
|
||||||
clear_line()
|
|
||||||
|
|
||||||
print("\n" + "-"*60)
|
|
||||||
print("scan done at:", str(datetime.now()))
|
|
||||||
print("-"*60 + "\n")
|
|
||||||
|
|
||||||
with open("summary.txt", "w") as f:
|
|
||||||
if open_ports:
|
|
||||||
f.write("[+] scan summary: open ports found with fingerprints\n")
|
|
||||||
for ip, port, host, fingerprint in open_ports:
|
|
||||||
f.write(f" - {ip} : port {port} open - hostname: {host}")
|
|
||||||
if fingerprint:
|
|
||||||
f.write(f" | {fingerprint}")
|
|
||||||
f.write("\n")
|
|
||||||
else:
|
|
||||||
f.write("no open ports found.\n")
|
|
||||||
|
|
||||||
print("[+] scan summary written to summary.txt :p\n")
|
|
||||||
if __name__ == "__main__":
|
|
||||||
try:
|
|
||||||
main()
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
print("\n[!] ctrl+c caught. stopping...")
|
|
||||||
sys.exit(1)
|
|
Loading…
Add table
Add a link
Reference in a new issue