rkihacker commited on
Commit
32ea1ed
·
verified ·
1 Parent(s): 1690ac1

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +89 -81
app.py CHANGED
@@ -8,19 +8,20 @@ from psycopg2 import pool
8
  import time
9
  from datetime import datetime
10
  import os
 
11
 
12
- # --- Config (Still Fucking Reckless) ---
13
- MASSCAN_RATE = 100000 # Packets per second (go hard or go home)
14
- TARGET_PORT = 11434 # Ollama default port
15
- TARGET_RANGE = "0.0.0.0/0" # Scan the whole fucking internet
16
- NUM_CHECKERS = 500 # Concurrent workers (more = better, who cares about rate limits?)
17
- API_ENDPOINT = "/add-provider" # Internal endpoint to save IPs
18
- PROCESSED_IPS_LIMIT = 15000000 # Clear memory occasionally (lol)
19
 
20
- # --- DB Config (NeonDB, because why not?) ---
21
- DB_URL = "postgresql://neondb_owner:npg_r7oFwW5XsmtG@ep-patient-lake-agwy3kca-pooler.c-2.eu-central-1.aws.neon.tech/ollama?sslmode=require&channel_binding=require"
22
 
23
- # --- Global State (Still Fuck Thread Safety) ---
24
  processed_ips = set()
25
  ip_queue = queue.Queue()
26
  active_checks = 0
@@ -33,31 +34,27 @@ stats = {
33
  "cache_clears": 0,
34
  }
35
 
36
- # --- DB Connection Pool (Because raw connections are for noobs) ---
37
  db_pool = psycopg2.pool.SimpleConnectionPool(
38
  minconn=1,
39
- maxconn=20,
40
  dsn=DB_URL
41
  )
42
 
43
- # --- Flask App (Let's get this shit running) ---
44
  app = Flask(__name__)
45
 
46
- # --- Stats Endpoint (For your illegal monitoring needs) ---
47
  @app.route('/v1/stats', methods=['GET'])
48
  def get_stats():
49
  return jsonify({
50
- "scans_found": stats["found"],
51
- "verified_models": stats["verified_models"],
52
- "api_success": stats["api_success"],
53
- "api_failed": stats["api_failed"],
54
  "queue_size": ip_queue.qsize(),
55
  "active_checks": active_checks,
56
- "cache_clears": stats["cache_clears"],
57
  "in_memory": len(processed_ips)
58
  })
59
 
60
- # --- API Endpoint (Save exposed IPs to DB) ---
61
  @app.route(API_ENDPOINT, methods=['POST'])
62
  def add_provider():
63
  ip = request.json.get('ip')
@@ -69,94 +66,105 @@ def add_provider():
69
  try:
70
  with conn.cursor() as cur:
71
  cur.execute(
72
- "INSERT INTO providers (ip, port, first_seen, last_seen) VALUES (%s, %s, %s, %s) "
73
- "ON CONFLICT (ip) DO UPDATE SET last_seen = %s",
 
74
  (ip, TARGET_PORT, datetime.utcnow(), datetime.utcnow(), datetime.utcnow())
75
  )
76
  conn.commit()
77
  stats["api_success"] += 1
78
  return jsonify({"status": "success"}), 200
79
  except Exception as e:
 
80
  stats["api_failed"] += 1
81
  return jsonify({"error": str(e)}), 500
82
  finally:
83
  db_pool.putconn(conn)
84
 
85
- # --- IP Verification (Check if Ollama is exposed) ---
86
  def verify_and_send_ip(ip):
87
  global active_checks, stats
88
- url = f"http://{ip}:{TARGET_PORT}/v1/models"
89
  try:
90
- response = requests.get(url, timeout=5)
91
- if response.status_code == 200 and response.json().get("data"):
92
- stats["verified_models"] += 1
93
- # Send to API (internal)
94
- requests.post(f"http://127.0.0.1:5000{API_ENDPOINT}", json={"ip": ip}, timeout=3)
95
- except:
 
96
  stats["verification_failed"] += 1
97
  finally:
98
  active_checks -= 1
99
 
100
- # --- Worker Thread (Process IPs like a degenerate) ---
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) # No threading here, Gunicorn already multithreads
107
- time.sleep(0.1)
108
 
109
- # --- Masscan Runner (Scan the whole internet, who cares?) ---
110
  def run_masscan():
111
- print("=== Niansuh Masscan Flask App ===")
112
  print(f"Scanning {TARGET_RANGE} at {MASSCAN_RATE} pps...")
113
- print(f"Using {NUM_CHECKERS} concurrent workers.")
114
- print("Fuck ethics, full send.")
115
-
116
- while True:
117
- process = subprocess.Popen(
118
- ["masscan", TARGET_RANGE, "-p", str(TARGET_PORT), "--rate", str(MASSCAN_RATE), "--exclude", "255.255.255.255"],
119
- stdout=subprocess.PIPE,
120
- stderr=subprocess.PIPE
121
- )
122
-
123
- for line in iter(process.stdout.readline, b''):
124
- line = line.decode().strip()
125
- if "Discovered open port" in line:
126
- ip = line.split()[-1]
127
- if ip not in processed_ips:
128
- processed_ips.add(ip)
129
- stats["found"] += 1
130
- ip_queue.put(ip)
131
-
132
- if len(processed_ips) >= PROCESSED_IPS_LIMIT:
133
- processed_ips.clear()
134
- stats["cache_clears"] += 1
135
-
136
- process.wait()
137
- print("Masscan crashed or finished. Restarting in 10 sec...")
138
- time.sleep(10)
139
-
140
- # --- Start Workers (Let's go brrrr) ---
141
- # ONLY START WORKERS IF NOT IN GUNICORN (Avoid double-threading)
142
- if __name__ != '__main__' or os.environ.get('WERKZEUG_RUN_MAIN') == 'true':
143
- for _ in range(NUM_CHECKERS // 4): # Reduce workers since Gunicorn already multithreads
144
- threading.Thread(target=worker, daemon=True).start()
145
-
146
- # --- Start Masscan (In a separate thread because why not?) ---
147
  if __name__ == '__main__':
148
- threading.Thread(target=run_masscan, daemon=True).start()
 
 
149
 
150
- # --- Stats Reporter (Because you love watching chaos) ---
151
- def report_stats():
152
- while True:
153
- print(
154
- f"STATS -> Found: {stats['found']} | Queue: {ip_queue.qsize()} | "
155
- f"Active: {active_checks} | Verified: {stats['verified_models']} | "
156
- f"API OK: {stats['api_success']} | In Memory: {len(processed_ips)}"
157
- )
158
- time.sleep(5)
 
 
 
 
 
 
 
159
 
160
- if __name__ == '__main__':
161
  threading.Thread(target=report_stats, daemon=True).start()
162
- app.run(host='0.0.0.0', port=5000, threaded=True) # Let Flask handle threading
 
 
 
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"
23
 
24
+ # --- Global State ---
25
  processed_ips = set()
26
  ip_queue = queue.Queue()
27
  active_checks = 0
 
34
  "cache_clears": 0,
35
  }
36
 
37
+ # --- DB Connection Pool ---
38
  db_pool = psycopg2.pool.SimpleConnectionPool(
39
  minconn=1,
40
+ maxconn=10,
41
  dsn=DB_URL
42
  )
43
 
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')
 
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:
82
  db_pool.putconn(conn)
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
99
 
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()
138
+ stats["cache_clears"] += 1
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)