File size: 4,261 Bytes
a97cdfe
da9899a
 
 
 
 
32ea1ed
a97cdfe
 
 
da9899a
d123f27
a97cdfe
 
32ea1ed
da9899a
32ea1ed
da9899a
 
 
 
 
 
 
 
 
a97cdfe
da9899a
 
a97cdfe
da9899a
 
32ea1ed
da9899a
 
 
32ea1ed
da9899a
 
d123f27
 
 
a97cdfe
d123f27
 
 
 
a97cdfe
 
d123f27
a97cdfe
 
d123f27
 
 
a97cdfe
d123f27
 
 
a97cdfe
d123f27
a97cdfe
 
 
d123f27
a97cdfe
d123f27
 
 
a97cdfe
d123f27
a97cdfe
 
 
d123f27
da9899a
a97cdfe
32ea1ed
d123f27
 
a97cdfe
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d123f27
da9899a
 
 
 
a97cdfe
da9899a
 
d123f27
da9899a
a97cdfe
d123f27
da9899a
a97cdfe
 
 
32ea1ed
a97cdfe
32ea1ed
 
 
 
 
 
a97cdfe
 
 
 
32ea1ed
a97cdfe
32ea1ed
a97cdfe
32ea1ed
a97cdfe
32ea1ed
a97cdfe
0e93030
d123f27
32ea1ed
 
da9899a
a97cdfe
 
d123f27
32ea1ed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
from flask import Flask, render_template_string
import subprocess
import threading
import queue
import requests
import time
import re
from datetime import datetime
import psycopg2
from psycopg2 import pool

# --- Config ---
TARGET_PORT = 11434  # Ollama port
NUM_CHECKERS = 50    # Workers
DB_URL = "postgresql://neondb_owner:npg_r7oFwW5XsmtG@ep-patient-lake-agwy3kca-pooler.c-2.eu-central-1.aws.neon.tech/ollama?sslmode=require"

# --- Global State ---
processed_ips = set()
ip_queue = queue.Queue()
active_checks = 0
stats = {
    "found": 0,
    "verified_models": 0,
    "verification_failed": 0,
    "api_success": 0,
    "api_failed": 0,
    "start_time": time.time()
}

# --- DB Pool ---
db_pool = psycopg2.pool.SimpleConnectionPool(
    minconn=1,
    maxconn=10,
    dsn=DB_URL
)

# --- Flask App ---
app = Flask(__name__)

# --- Homepage (Real-Time Stats) ---
@app.route('/')
def home():
    uptime = int(time.time() - stats["start_time"])
    return render_template_string('''
        <!DOCTYPE html>
        <html>
        <head>
            <title>Niansuh ZMap Scanner</title>
            <meta http-equiv="refresh" content="1">
            <style>
                body { font-family: monospace; background: #000; color: #0f0; padding: 20px; }
                .stats { font-size: 1.5em; line-height: 1.8; }
                .scanned { color: #ff0; }
                .verified { color: #0ff; }
                .queue { color: #f0f; }
                h1 { color: #f00; }
            </style>
        </head>
        <body>
            <h1>NIANSUH ZMAP SCANNER</h1>
            <div class="stats">
                <p>πŸ” Scanned IPs: <span class="scanned">{{ stats.found }}</span></p>
                <p>βœ… Verified Ollama: <span class="verified">{{ stats.verified_models }}</span></p>
                <p>πŸš€ Queue Size: <span class="queue">{{ queue_size }}</span></p>
                <p>πŸ”„ Active Checks: {{ active_checks }}</p>
                <p>⏱️ Uptime: {{ uptime }}s</p>
            </div>
        </body>
        </html>
    ''', stats=stats, queue_size=ip_queue.qsize(), active_checks=active_checks, uptime=uptime)

# --- Verify Ollama ---
def verify_ollama(ip):
    global active_checks, stats
    active_checks += 1
    try:
        url = f"http://{ip}:{TARGET_PORT}/api/tags"
        response = requests.get(url, timeout=3)
        if response.status_code == 200 and "models" in response.json():
            stats["verified_models"] += 1
            conn = db_pool.getconn()
            try:
                with conn.cursor() as cur:
                    cur.execute("""
                        INSERT INTO providers (ip, port, first_seen)
                        VALUES (%s, %s, %s)
                        ON CONFLICT (ip) DO NOTHING
                    """, (ip, TARGET_PORT, datetime.utcnow()))
                conn.commit()
                stats["api_success"] += 1
            except Exception as e:
                print(f"DB Error: {e}")
                stats["api_failed"] += 1
            finally:
                db_pool.putconn(conn)
    except:
        stats["verification_failed"] += 1
    finally:
        active_checks -= 1

# --- Worker ---
def worker():
    while True:
        if not ip_queue.empty():
            ip = ip_queue.get()
            verify_ollama(ip)
        time.sleep(0.01)

# --- ZMap Scanner ---
def run_zmap():
    print("=== Starting ZMap Scan ===")
    process = subprocess.Popen(
        ["sudo", "zmap", "-p", str(TARGET_PORT), "-o", "-"],
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        universal_newlines=True
    )

    for line in process.stdout:
        ip = line.strip()
        if re.match(r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$", ip):
            if ip not in processed_ips:
                processed_ips.add(ip)
                stats["found"] += 1
                ip_queue.put(ip)

    print("ZMap finished. Restarting in 5 sec...")
    time.sleep(5)
    run_zmap()

# --- Start ---
if __name__ == '__main__':
    # Start workers
    for _ in range(NUM_CHECKERS):
        threading.Thread(target=worker, daemon=True).start()

    # Start ZMap
    threading.Thread(target=run_zmap, daemon=True).start()

    app.run(host='0.0.0.0', port=5000, threaded=True)