rkihacker commited on
Commit
a97cdfe
Β·
verified Β·
1 Parent(s): 2706a7d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +55 -91
app.py CHANGED
@@ -1,22 +1,17 @@
1
- from flask import Flask, jsonify, render_template_string
2
  import subprocess
3
  import threading
4
  import queue
5
  import requests
6
- import psycopg2
7
- from psycopg2 import pool
8
  import time
9
- from datetime import datetime
10
  import re
 
 
 
11
 
12
  # --- Config ---
13
- MASSCAN_RATE = 10000 # Reduced to avoid ISP blocks
14
- TARGET_PORT = 11434 # Ollama default port
15
- TARGET_RANGE = "0.0.0.0/0" # Scan everything
16
- NUM_CHECKERS = 50 # Workers
17
- PROCESSED_IPS_LIMIT = 1000000
18
-
19
- # --- DB Config ---
20
  DB_URL = "postgresql://neondb_owner:npg_r7oFwW5XsmtG@ep-patient-lake-agwy3kca-pooler.c-2.eu-central-1.aws.neon.tech/ollama?sslmode=require"
21
 
22
  # --- Global State ---
@@ -29,11 +24,10 @@ stats = {
29
  "verification_failed": 0,
30
  "api_success": 0,
31
  "api_failed": 0,
32
- "cache_clears": 0,
33
- "last_scan_time": time.time(),
34
  }
35
 
36
- # --- DB Connection Pool ---
37
  db_pool = psycopg2.pool.SimpleConnectionPool(
38
  minconn=1,
39
  maxconn=10,
@@ -46,131 +40,101 @@ app = Flask(__name__)
46
  # --- Homepage (Real-Time Stats) ---
47
  @app.route('/')
48
  def home():
 
49
  return render_template_string('''
50
  <!DOCTYPE html>
51
  <html>
52
  <head>
53
- <title>Niansuh Masscan - Live Stats</title>
54
- <meta http-equiv="refresh" content="2">
55
  <style>
56
- body { font-family: monospace; background: #000; color: #0f0; }
57
- .stats { font-size: 1.2em; }
58
  .scanned { color: #ff0; }
59
  .verified { color: #0ff; }
60
  .queue { color: #f0f; }
 
61
  </style>
62
  </head>
63
  <body>
64
- <h1>NIANSUH MASSCAN - LIVE STATS</h1>
65
  <div class="stats">
66
- <p>πŸ” <span class="scanned">Scanned IPs: {{ stats.found }}</span></p>
67
- <p>βœ… <span class="verified">Verified Ollama: {{ stats.verified_models }}</span></p>
68
- <p>πŸš€ <span class="queue">Queue: {{ queue_size }}</span></p>
69
  <p>πŸ”„ Active Checks: {{ active_checks }}</p>
70
- <p>πŸ—ƒοΈ In Memory: {{ in_memory }}</p>
71
- <p>⏱️ Uptime: {{ uptime }} seconds</p>
72
  </div>
73
  </body>
74
  </html>
75
- ''', stats=stats, queue_size=ip_queue.qsize(), active_checks=active_checks, in_memory=len(processed_ips), uptime=int(time.time() - stats["last_scan_time"]))
76
 
77
- # --- Stats API ---
78
- @app.route('/v1/stats')
79
- def get_stats():
80
- return jsonify({
81
- **stats,
82
- "queue_size": ip_queue.qsize(),
83
- "active_checks": active_checks,
84
- "in_memory": len(processed_ips),
85
- "uptime": int(time.time() - stats["last_scan_time"])
86
- })
87
-
88
- # --- API Endpoint (Save IPs) ---
89
- @app.route('/add-provider', methods=['POST'])
90
- def add_provider():
91
- ip = request.json.get('ip')
92
- if not ip:
93
- stats["api_failed"] += 1
94
- return jsonify({"error": "No IP provided"}), 400
95
-
96
- conn = db_pool.getconn()
97
- try:
98
- with conn.cursor() as cur:
99
- cur.execute("""
100
- INSERT INTO providers (ip, port, first_seen, last_seen)
101
- VALUES (%s, %s, %s, %s)
102
- ON CONFLICT (ip) DO UPDATE SET last_seen = %s
103
- """, (ip, TARGET_PORT, datetime.utcnow(), datetime.utcnow(), datetime.utcnow()))
104
- conn.commit()
105
- stats["api_success"] += 1
106
- return jsonify({"status": "success"}), 200
107
- except Exception as e:
108
- print(f"DB Error: {e}")
109
- stats["api_failed"] += 1
110
- return jsonify({"error": str(e)}), 500
111
- finally:
112
- db_pool.putconn(conn)
113
-
114
- # --- Verify Ollama Instance ---
115
- def verify_and_send_ip(ip):
116
- global active_checks
117
  active_checks += 1
118
- url = f"http://{ip}:{TARGET_PORT}/api/tags"
119
  try:
 
120
  response = requests.get(url, timeout=3)
121
  if response.status_code == 200 and "models" in response.json():
122
  stats["verified_models"] += 1
123
- requests.post("http://127.0.0.1:5000/add-provider", json={"ip": ip}, timeout=2)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
124
  except:
125
  stats["verification_failed"] += 1
126
  finally:
127
  active_checks -= 1
128
 
129
- # --- Worker (Process IPs) ---
130
  def worker():
131
  while True:
132
  if not ip_queue.empty():
133
  ip = ip_queue.get()
134
- verify_and_send_ip(ip)
135
  time.sleep(0.01)
136
 
137
- # --- Masscan Runner (Now Works) ---
138
- def run_masscan():
139
- print("=== NIANSUH MASSCAN STARTED ===")
140
- print(f"Scanning {TARGET_RANGE} at {MASSCAN_RATE} pps...")
141
-
142
- # Run masscan with sudo (required for raw sockets)
143
  process = subprocess.Popen(
144
- ["sudo", "masscan", TARGET_RANGE, "-p", str(TARGET_PORT), "--rate", str(MASSCAN_RATE), "--output-format", "list"],
145
  stdout=subprocess.PIPE,
146
  stderr=subprocess.PIPE,
147
  universal_newlines=True
148
  )
149
 
150
  for line in process.stdout:
151
- line = line.strip()
152
- if re.match(r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$", line): # Match IPs
153
- if line not in processed_ips:
154
- processed_ips.add(line)
155
  stats["found"] += 1
156
- ip_queue.put(line)
157
-
158
- if len(processed_ips) >= PROCESSED_IPS_LIMIT:
159
- processed_ips.clear()
160
- stats["cache_clears"] += 1
161
 
162
- print("Masscan stopped. Restarting in 5 sec...")
163
  time.sleep(5)
164
- run_masscan()
165
 
166
- # --- Start Everything ---
167
  if __name__ == '__main__':
168
  # Start workers
169
  for _ in range(NUM_CHECKERS):
170
  threading.Thread(target=worker, daemon=True).start()
171
 
172
- # Start masscan in a separate thread
173
- threading.Thread(target=run_masscan, daemon=True).start()
174
 
175
- # Start Flask
176
  app.run(host='0.0.0.0', port=5000, threaded=True)
 
1
+ from flask import Flask, render_template_string
2
  import subprocess
3
  import threading
4
  import queue
5
  import requests
 
 
6
  import time
 
7
  import re
8
+ from datetime import datetime
9
+ import psycopg2
10
+ from psycopg2 import pool
11
 
12
  # --- Config ---
13
+ TARGET_PORT = 11434 # Ollama port
14
+ NUM_CHECKERS = 50 # Workers
 
 
 
 
 
15
  DB_URL = "postgresql://neondb_owner:npg_r7oFwW5XsmtG@ep-patient-lake-agwy3kca-pooler.c-2.eu-central-1.aws.neon.tech/ollama?sslmode=require"
16
 
17
  # --- Global State ---
 
24
  "verification_failed": 0,
25
  "api_success": 0,
26
  "api_failed": 0,
27
+ "start_time": time.time()
 
28
  }
29
 
30
+ # --- DB Pool ---
31
  db_pool = psycopg2.pool.SimpleConnectionPool(
32
  minconn=1,
33
  maxconn=10,
 
40
  # --- Homepage (Real-Time Stats) ---
41
  @app.route('/')
42
  def home():
43
+ uptime = int(time.time() - stats["start_time"])
44
  return render_template_string('''
45
  <!DOCTYPE html>
46
  <html>
47
  <head>
48
+ <title>Niansuh ZMap Scanner</title>
49
+ <meta http-equiv="refresh" content="1">
50
  <style>
51
+ body { font-family: monospace; background: #000; color: #0f0; padding: 20px; }
52
+ .stats { font-size: 1.5em; line-height: 1.8; }
53
  .scanned { color: #ff0; }
54
  .verified { color: #0ff; }
55
  .queue { color: #f0f; }
56
+ h1 { color: #f00; }
57
  </style>
58
  </head>
59
  <body>
60
+ <h1>NIANSUH ZMAP SCANNER</h1>
61
  <div class="stats">
62
+ <p>πŸ” Scanned IPs: <span class="scanned">{{ stats.found }}</span></p>
63
+ <p>βœ… Verified Ollama: <span class="verified">{{ stats.verified_models }}</span></p>
64
+ <p>πŸš€ Queue Size: <span class="queue">{{ queue_size }}</span></p>
65
  <p>πŸ”„ Active Checks: {{ active_checks }}</p>
66
+ <p>⏱️ Uptime: {{ uptime }}s</p>
 
67
  </div>
68
  </body>
69
  </html>
70
+ ''', stats=stats, queue_size=ip_queue.qsize(), active_checks=active_checks, uptime=uptime)
71
 
72
+ # --- Verify Ollama ---
73
+ def verify_ollama(ip):
74
+ global active_checks, stats
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  active_checks += 1
 
76
  try:
77
+ url = f"http://{ip}:{TARGET_PORT}/api/tags"
78
  response = requests.get(url, timeout=3)
79
  if response.status_code == 200 and "models" in response.json():
80
  stats["verified_models"] += 1
81
+ conn = db_pool.getconn()
82
+ try:
83
+ with conn.cursor() as cur:
84
+ cur.execute("""
85
+ INSERT INTO providers (ip, port, first_seen)
86
+ VALUES (%s, %s, %s)
87
+ ON CONFLICT (ip) DO NOTHING
88
+ """, (ip, TARGET_PORT, datetime.utcnow()))
89
+ conn.commit()
90
+ stats["api_success"] += 1
91
+ except Exception as e:
92
+ print(f"DB Error: {e}")
93
+ stats["api_failed"] += 1
94
+ finally:
95
+ db_pool.putconn(conn)
96
  except:
97
  stats["verification_failed"] += 1
98
  finally:
99
  active_checks -= 1
100
 
101
+ # --- Worker ---
102
  def worker():
103
  while True:
104
  if not ip_queue.empty():
105
  ip = ip_queue.get()
106
+ verify_ollama(ip)
107
  time.sleep(0.01)
108
 
109
+ # --- ZMap Scanner ---
110
+ def run_zmap():
111
+ print("=== Starting ZMap Scan ===")
 
 
 
112
  process = subprocess.Popen(
113
+ ["sudo", "zmap", "-p", str(TARGET_PORT), "-o", "-"],
114
  stdout=subprocess.PIPE,
115
  stderr=subprocess.PIPE,
116
  universal_newlines=True
117
  )
118
 
119
  for line in process.stdout:
120
+ ip = line.strip()
121
+ if re.match(r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$", ip):
122
+ if ip not in processed_ips:
123
+ processed_ips.add(ip)
124
  stats["found"] += 1
125
+ ip_queue.put(ip)
 
 
 
 
126
 
127
+ print("ZMap finished. Restarting in 5 sec...")
128
  time.sleep(5)
129
+ run_zmap()
130
 
131
+ # --- Start ---
132
  if __name__ == '__main__':
133
  # Start workers
134
  for _ in range(NUM_CHECKERS):
135
  threading.Thread(target=worker, daemon=True).start()
136
 
137
+ # Start ZMap
138
+ threading.Thread(target=run_zmap, daemon=True).start()
139
 
 
140
  app.run(host='0.0.0.0', port=5000, threaded=True)