rkihacker commited on
Commit
d123f27
Β·
verified Β·
1 Parent(s): 32ea1ed

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +70 -64
app.py CHANGED
@@ -1,4 +1,4 @@
1
- from flask import Flask, jsonify, request
2
  import subprocess
3
  import threading
4
  import queue
@@ -7,16 +7,14 @@ import psycopg2
7
  from psycopg2 import pool
8
  import time
9
  from datetime import datetime
10
- import os
11
  import re
12
 
13
- # --- Config (Still Reckless) ---
14
- MASSCAN_RATE = 10000 # Reduced to avoid ISP blocks (10k pps is still aggressive)
15
  TARGET_PORT = 11434 # Ollama default port
16
  TARGET_RANGE = "0.0.0.0/0" # Scan everything
17
- NUM_CHECKERS = 50 # Reduced to avoid overwhelming the system
18
- API_ENDPOINT = "/add-provider"
19
- PROCESSED_IPS_LIMIT = 1000000 # Clear memory occasionally
20
 
21
  # --- DB Config ---
22
  DB_URL = "postgresql://neondb_owner:npg_r7oFwW5XsmtG@ep-patient-lake-agwy3kca-pooler.c-2.eu-central-1.aws.neon.tech/ollama?sslmode=require"
@@ -32,6 +30,7 @@ stats = {
32
  "api_success": 0,
33
  "api_failed": 0,
34
  "cache_clears": 0,
 
35
  }
36
 
37
  # --- DB Connection Pool ---
@@ -44,18 +43,50 @@ db_pool = psycopg2.pool.SimpleConnectionPool(
44
  # --- Flask App ---
45
  app = Flask(__name__)
46
 
47
- # --- Stats Endpoint ---
48
- @app.route('/v1/stats', methods=['GET'])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  def get_stats():
50
  return jsonify({
51
  **stats,
52
  "queue_size": ip_queue.qsize(),
53
  "active_checks": active_checks,
54
- "in_memory": len(processed_ips)
 
55
  })
56
 
57
  # --- API Endpoint (Save IPs) ---
58
- @app.route(API_ENDPOINT, methods=['POST'])
59
  def add_provider():
60
  ip = request.json.get('ip')
61
  if not ip:
@@ -65,17 +96,16 @@ def add_provider():
65
  conn = db_pool.getconn()
66
  try:
67
  with conn.cursor() as cur:
68
- cur.execute(
69
- """INSERT INTO providers (ip, port, first_seen, last_seen)
70
- VALUES (%s, %s, %s, %s)
71
- ON CONFLICT (ip) DO UPDATE SET last_seen = %s""",
72
- (ip, TARGET_PORT, datetime.utcnow(), datetime.utcnow(), datetime.utcnow())
73
- )
74
  conn.commit()
75
  stats["api_success"] += 1
76
  return jsonify({"status": "success"}), 200
77
  except Exception as e:
78
- print(f"DB Error: {e}") # Debug DB issues
79
  stats["api_failed"] += 1
80
  return jsonify({"error": str(e)}), 500
81
  finally:
@@ -83,16 +113,15 @@ def add_provider():
83
 
84
  # --- Verify Ollama Instance ---
85
  def verify_and_send_ip(ip):
86
- global active_checks, stats
87
- url = f"http://{ip}:{TARGET_PORT}/api/tags" # Ollama's actual endpoint
 
88
  try:
89
  response = requests.get(url, timeout=3)
90
- if response.status_code == 200:
91
- data = response.json()
92
- if "models" in data: # Confirm it's an Ollama instance
93
- stats["verified_models"] += 1
94
- requests.post(f"http://127.0.0.1:5000{API_ENDPOINT}", json={"ip": ip}, timeout=2)
95
- except Exception as e:
96
  stats["verification_failed"] += 1
97
  finally:
98
  active_checks -= 1
@@ -100,38 +129,31 @@ def verify_and_send_ip(ip):
100
  # --- Worker (Process IPs) ---
101
  def worker():
102
  while True:
103
- if not ip_queue.empty() and active_checks < NUM_CHECKERS:
104
  ip = ip_queue.get()
105
- active_checks += 1
106
  verify_and_send_ip(ip)
107
- time.sleep(0.01) # Small delay to prevent CPU overload
108
 
109
- # --- Masscan Runner (Now Actually Works) ---
110
  def run_masscan():
111
- print("=== Niansuh Masscan Started ===")
112
  print(f"Scanning {TARGET_RANGE} at {MASSCAN_RATE} pps...")
113
- print(f"Workers: {NUM_CHECKERS}")
114
 
115
  # Run masscan with sudo (required for raw sockets)
116
  process = subprocess.Popen(
117
- ["sudo", "masscan", TARGET_RANGE, "-p", str(TARGET_PORT), "--rate", str(MASSCAN_RATE)],
118
  stdout=subprocess.PIPE,
119
  stderr=subprocess.PIPE,
120
  universal_newlines=True
121
  )
122
 
123
- # Regex to extract IPs
124
- ip_regex = re.compile(r"Discovered open port \d+/tcp on ([\d\.]+)")
125
-
126
  for line in process.stdout:
127
  line = line.strip()
128
- match = ip_regex.search(line)
129
- if match:
130
- ip = match.group(1)
131
- if ip not in processed_ips:
132
- processed_ips.add(ip)
133
  stats["found"] += 1
134
- ip_queue.put(ip)
135
 
136
  if len(processed_ips) >= PROCESSED_IPS_LIMIT:
137
  processed_ips.clear()
@@ -139,32 +161,16 @@ def run_masscan():
139
 
140
  print("Masscan stopped. Restarting in 5 sec...")
141
  time.sleep(5)
142
- run_masscan() # Restart if it crashes
143
 
144
- # --- Start Workers & Masscan ---
145
  if __name__ == '__main__':
146
- # Start workers (only in main process)
147
  for _ in range(NUM_CHECKERS):
148
  threading.Thread(target=worker, daemon=True).start()
149
 
150
  # Start masscan in a separate thread
151
- masscan_thread = threading.Thread(target=run_masscan, daemon=True)
152
- masscan_thread.start()
153
-
154
- # Start stats reporter
155
- def report_stats():
156
- while True:
157
- print(f"""
158
- === STATS ===
159
- Found: {stats['found']}
160
- Verified: {stats['verified_models']}
161
- Queue: {ip_queue.qsize()}
162
- Active Checks: {active_checks}
163
- API Success: {stats['api_success']}
164
- """)
165
- time.sleep(2)
166
-
167
- threading.Thread(target=report_stats, daemon=True).start()
168
-
169
- # Run Flask
170
  app.run(host='0.0.0.0', port=5000, threaded=True)
 
1
+ from flask import Flask, jsonify, render_template_string
2
  import subprocess
3
  import threading
4
  import queue
 
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"
 
30
  "api_success": 0,
31
  "api_failed": 0,
32
  "cache_clears": 0,
33
+ "last_scan_time": time.time(),
34
  }
35
 
36
  # --- DB Connection Pool ---
 
43
  # --- Flask App ---
44
  app = Flask(__name__)
45
 
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:
 
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:
 
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
 
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()
 
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)