rkihacker commited on
Commit
da9899a
·
verified ·
1 Parent(s): 70a10fa

Create app.py

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