from flask import Flask, jsonify, render_template_string
import subprocess
import threading
import queue
import requests
import psycopg2
from psycopg2 import pool
import time
from datetime import datetime
import re
# --- Config ---
MASSCAN_RATE = 10000 # Reduced to avoid ISP blocks
TARGET_PORT = 11434 # Ollama default port
TARGET_RANGE = "0.0.0.0/0" # Scan everything
NUM_CHECKERS = 50 # Workers
PROCESSED_IPS_LIMIT = 1000000
# --- DB Config ---
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,
"cache_clears": 0,
"last_scan_time": time.time(),
}
# --- DB Connection 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():
return render_template_string('''
Niansuh Masscan - Live Stats
NIANSUH MASSCAN - LIVE STATS
🔍 Scanned IPs: {{ stats.found }}
✅ Verified Ollama: {{ stats.verified_models }}
🚀 Queue: {{ queue_size }}
🔄 Active Checks: {{ active_checks }}
🗃️ In Memory: {{ in_memory }}
⏱️ Uptime: {{ uptime }} seconds
''', stats=stats, queue_size=ip_queue.qsize(), active_checks=active_checks, in_memory=len(processed_ips), uptime=int(time.time() - stats["last_scan_time"]))
# --- Stats API ---
@app.route('/v1/stats')
def get_stats():
return jsonify({
**stats,
"queue_size": ip_queue.qsize(),
"active_checks": active_checks,
"in_memory": len(processed_ips),
"uptime": int(time.time() - stats["last_scan_time"])
})
# --- API Endpoint (Save IPs) ---
@app.route('/add-provider', methods=['POST'])
def add_provider():
ip = request.json.get('ip')
if not ip:
stats["api_failed"] += 1
return jsonify({"error": "No IP provided"}), 400
conn = db_pool.getconn()
try:
with conn.cursor() as cur:
cur.execute("""
INSERT INTO providers (ip, port, first_seen, last_seen)
VALUES (%s, %s, %s, %s)
ON CONFLICT (ip) DO UPDATE SET last_seen = %s
""", (ip, TARGET_PORT, datetime.utcnow(), datetime.utcnow(), datetime.utcnow()))
conn.commit()
stats["api_success"] += 1
return jsonify({"status": "success"}), 200
except Exception as e:
print(f"DB Error: {e}")
stats["api_failed"] += 1
return jsonify({"error": str(e)}), 500
finally:
db_pool.putconn(conn)
# --- Verify Ollama Instance ---
def verify_and_send_ip(ip):
global active_checks
active_checks += 1
url = f"http://{ip}:{TARGET_PORT}/api/tags"
try:
response = requests.get(url, timeout=3)
if response.status_code == 200 and "models" in response.json():
stats["verified_models"] += 1
requests.post("http://127.0.0.1:5000/add-provider", json={"ip": ip}, timeout=2)
except:
stats["verification_failed"] += 1
finally:
active_checks -= 1
# --- Worker (Process IPs) ---
def worker():
while True:
if not ip_queue.empty():
ip = ip_queue.get()
verify_and_send_ip(ip)
time.sleep(0.01)
# --- Masscan Runner (Now Works) ---
def run_masscan():
print("=== NIANSUH MASSCAN STARTED ===")
print(f"Scanning {TARGET_RANGE} at {MASSCAN_RATE} pps...")
# Run masscan with sudo (required for raw sockets)
process = subprocess.Popen(
["sudo", "masscan", TARGET_RANGE, "-p", str(TARGET_PORT), "--rate", str(MASSCAN_RATE), "--output-format", "list"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
universal_newlines=True
)
for line in process.stdout:
line = line.strip()
if re.match(r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$", line): # Match IPs
if line not in processed_ips:
processed_ips.add(line)
stats["found"] += 1
ip_queue.put(line)
if len(processed_ips) >= PROCESSED_IPS_LIMIT:
processed_ips.clear()
stats["cache_clears"] += 1
print("Masscan stopped. Restarting in 5 sec...")
time.sleep(5)
run_masscan()
# --- Start Everything ---
if __name__ == '__main__':
# Start workers
for _ in range(NUM_CHECKERS):
threading.Thread(target=worker, daemon=True).start()
# Start masscan in a separate thread
threading.Thread(target=run_masscan, daemon=True).start()
# Start Flask
app.run(host='0.0.0.0', port=5000, threaded=True)