diff --git a/agent/agent.py b/agent/agent.py index dcf3312..02e13a2 100644 --- a/agent/agent.py +++ b/agent/agent.py @@ -50,7 +50,7 @@ def _save_tunnel_state(self, tun_id, pid, content_hash, metadata): state_file = f"{CONFIG_DIR}/{tun_id}.state" with open(state_file, "w") as f: json.dump({"pid": pid, "hash": content_hash, "metadata": metadata or {}}, f) - except Exception: + except (OSError, TypeError): pass def _load_tunnel_state(self): @@ -73,12 +73,12 @@ def wait(self, timeout=None): pass def terminate(self): try: os.kill(self.pid, signal.SIGTERM) - except: pass + except (ProcessLookupError, OSError): pass self.running_processes[tun_id] = AdoptedProcess(pid) self.running_configs[tun_id] = data.get("hash") self.running_metadata[tun_id] = data.get("metadata", {}) print(f"[Agent] 🔗 Adopted existing live process for tunnel {tun_id} (PID {pid})") - except Exception: + except (json.JSONDecodeError, OSError, TypeError): pass def _adopt_running_system_processes(self, configs): @@ -116,16 +116,16 @@ def terminate(self): } print(f"[Agent] 🛡️ Successfully adopted active background process {core_type} for tunnel {tun_id} (PID {pid})") break - except Exception: + except (OSError, ValueError): pass - except Exception: + except (OSError, ValueError): pass def _load_agent_restart_nonce(self): try: with open(AGENT_RESTART_NONCE_PATH, "r") as f: return int(f.read().strip() or 0) - except Exception: + except (OSError, ValueError): return 0 def _save_agent_restart_nonce(self, nonce): @@ -150,7 +150,7 @@ def get_system_metrics(self): total_delta = sum(fields) - total if total_delta > 0: metrics["cpu_percent"] = round(100.0 * (1.0 - idle_delta / total_delta), 1) - except: + except (OSError, ValueError, IndexError): pass try: @@ -167,13 +167,13 @@ def get_system_metrics(self): avail_mb = mem.get("MemAvailable", mem.get("MemFree", 0)) // 1024 metrics["ram_total_mb"] = total_mb metrics["ram_used_mb"] = max(0, total_mb - avail_mb) - except: + except (OSError, ValueError, IndexError): pass try: with open("/proc/uptime", "r") as f: metrics["uptime_seconds"] = int(float(f.readline().split()[0])) - except: + except (OSError, ValueError, IndexError): pass try: @@ -192,7 +192,7 @@ def get_system_metrics(self): tx_total += int(stats[8]) metrics["net_rx_bytes"] = rx_total metrics["net_tx_bytes"] = tx_total - except: + except (OSError, ValueError, IndexError): pass return metrics @@ -219,7 +219,7 @@ def ensure_hawal_core_binary(self): if os.path.exists(local_static_bin) and os.path.isfile(local_static_bin): temp_bin = f"{HAWAL_CORE_BIN}.tmp_{os.getpid()}" shutil.copy(local_static_bin, temp_bin) - os.chmod(temp_bin, 0o755) + os.chmod(temp_bin, 0o750) os.replace(temp_bin, HAWAL_CORE_BIN) print("[Agent] ✅ Hawal Core v2 binary installed from local panel.") return True @@ -229,7 +229,7 @@ def ensure_hawal_core_binary(self): temp_bin = f"{HAWAL_CORE_BIN}.tmp_{os.getpid()}" with urllib.request.urlopen(req, timeout=15) as resp, open(temp_bin, "wb") as out: shutil.copyfileobj(resp, out) - os.chmod(temp_bin, 0o755) + os.chmod(temp_bin, 0o750) os.replace(temp_bin, HAWAL_CORE_BIN) print("[Agent] ✅ Hawal Core v2 binary downloaded and installed.") return True @@ -243,9 +243,9 @@ def ensure_backhaul_binary(self): try: if os.path.exists("/usr/local/bin/backhaul"): shutil.copy("/usr/local/bin/backhaul", BACKHAUL_BIN) - os.chmod(BACKHAUL_BIN, 0o755) + os.chmod(BACKHAUL_BIN, 0o750) return True - except: + except (OSError, shutil.Error): pass return True @@ -258,7 +258,7 @@ def ensure_paqet_binary(self): local_static_bin = "/opt/hawal-panel/app/static/bin/paqet" if os.path.exists(local_static_bin) and os.path.isfile(local_static_bin): shutil.copy(local_static_bin, PAQET_BIN) - os.chmod(PAQET_BIN, 0o755) + os.chmod(PAQET_BIN, 0o750) print("[Agent] ✅ Paqet binary installed from local panel.") return True @@ -275,7 +275,7 @@ def ensure_paqet_binary(self): try: subprocess.run(["apt-get", "install", "-y", "libpcap0.8"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, timeout=20) - except: + except (subprocess.SubprocessError, OSError): pass import tarfile, io @@ -291,7 +291,7 @@ def ensure_paqet_binary(self): temp_bin = f"{PAQET_BIN}.download" with open(temp_bin, "wb") as out: out.write(f.read()) - os.chmod(temp_bin, 0o755) + os.chmod(temp_bin, 0o750) os.replace(temp_bin, PAQET_BIN) print(f"[Agent] ✅ Paqet ({arch}) binary installed successfully.") return True @@ -324,7 +324,7 @@ def ensure_gost_binary(self): source = tar.extractfile(member) with open(f"{GOST_BIN}.download", "wb") as out: out.write(source.read()) - os.chmod(f"{GOST_BIN}.download", 0o755) + os.chmod(f"{GOST_BIN}.download", 0o750) os.replace(f"{GOST_BIN}.download", GOST_BIN) print("[Agent] ✅ GOST binary installed successfully.") return True @@ -347,25 +347,23 @@ def get_network_info(self): if "via" in parts: gateway_ip = parts[parts.index("via") + 1] break - except: + except (subprocess.SubprocessError, OSError): pass try: res = subprocess.check_output(["ip", "-4", "addr", "show", iface], stderr=subprocess.DEVNULL).decode('utf-8') - import re m = re.search(r'inet\s+(\d+\.\d+\.\d+\.\d+)', res) if m: local_ip = m.group(1) - except: + except (subprocess.SubprocessError, OSError): pass try: if gateway_ip: subprocess.run(["ping", "-c", "1", "-W", "1", gateway_ip], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) res = subprocess.check_output(["ip", "neigh", "show", gateway_ip], stderr=subprocess.DEVNULL).decode('utf-8') - import re m = re.search(r'([0-9a-fA-F]{2}(?::[0-9a-fA-F]{2}){5})', res) if m: gateway_mac = m.group(1) - except: + except (subprocess.SubprocessError, OSError): pass return iface, local_ip, gateway_mac @@ -467,7 +465,7 @@ def sync_tunnels(self): self.agent_restart_nonce = requested_nonce print("[Agent] 🔄 Restart requested by panel.") self.shutdown_requested = True - except Exception as e: + except (urllib.error.URLError, TimeoutError, json.JSONDecodeError, OSError): pass def report_logs(self): @@ -490,7 +488,7 @@ def report_logs(self): ) with urllib.request.urlopen(req, timeout=5): self.last_log_report = time.time() - except Exception: + except (urllib.error.URLError, TimeoutError, OSError): pass def apply_configs(self, configs): @@ -608,7 +606,7 @@ def cleanup_orphaned_cores(self): for bin_path in core_binaries: name = os.path.basename(bin_path) subprocess.run(["pkill", "-9", "-f", f"{BIN_DIR}/{name}"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) - except Exception: + except (subprocess.SubprocessError, OSError): pass def _extract_ports(self, metadata): @@ -619,13 +617,13 @@ def _extract_ports(self, metadata): if core_port: try: ports_to_free.add(int(core_port)) - except Exception: + except (ValueError, TypeError): pass for rule in metadata.get("ports", []): try: p_str = str(rule).split("=")[0].split(":")[-1].strip() ports_to_free.add(int(p_str)) - except Exception: + except (ValueError, TypeError): pass return ports_to_free @@ -634,7 +632,7 @@ def _free_ports(self, ports): try: subprocess.run(["fuser", "-k", "-9", f"{port}/tcp"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) subprocess.run(["fuser", "-k", "-9", f"{port}/udp"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) - except Exception: + except (subprocess.SubprocessError, OSError): pass if ports: time.sleep(0.1) @@ -666,17 +664,17 @@ def stop_tunnel_process(self, tun_id): state_file = f"{CONFIG_DIR}/{tun_id}.state" if os.path.exists(state_file): try: os.remove(state_file) - except: pass + except OSError: pass if tun_id in self.running_processes: proc = self.running_processes[tun_id] pid = proc.pid try: pgid = os.getpgid(pid) os.killpg(pgid, signal.SIGTERM) - except Exception: + except (ProcessLookupError, OSError): try: proc.terminate() - except Exception: + except (ProcessLookupError, OSError): pass deadline = time.time() + 2.0 while time.time() < deadline: @@ -687,14 +685,14 @@ def stop_tunnel_process(self, tun_id): try: pgid = os.getpgid(pid) os.killpg(pgid, signal.SIGKILL) - except Exception: + except (ProcessLookupError, OSError): try: proc.kill() - except Exception: + except (ProcessLookupError, OSError): pass try: proc.wait(timeout=1) - except Exception: + except (subprocess.TimeoutExpired, ProcessLookupError, OSError): pass del self.running_processes[tun_id] self.running_configs.pop(tun_id, None) @@ -714,7 +712,7 @@ def _ensure_acct_chains(self): subprocess.run(["iptables", "-I", "INPUT", "1", "-j", "HAWAL_ACCT_IN"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) if subprocess.run(["iptables", "-C", "OUTPUT", "-j", "HAWAL_ACCT_OUT"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode != 0: subprocess.run(["iptables", "-I", "OUTPUT", "1", "-j", "HAWAL_ACCT_OUT"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) - except Exception: + except (subprocess.SubprocessError, OSError): pass def _sync_acct_rules(self, ports): @@ -729,7 +727,7 @@ def _sync_acct_rules(self, ports): subprocess.run(["iptables", "-A", "HAWAL_ACCT_IN", "-p", proto, "--dport", p_str], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) if subprocess.run(["iptables", "-C", "HAWAL_ACCT_OUT", "-p", proto, "--sport", p_str], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode != 0: subprocess.run(["iptables", "-A", "HAWAL_ACCT_OUT", "-p", proto, "--sport", p_str], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) - except Exception: + except (subprocess.SubprocessError, OSError): pass def _read_acct_counters(self): @@ -745,7 +743,7 @@ def _read_acct_counters(self): if m: p = int(m.group(1)) bytes_in[p] = bytes_in.get(p, 0) + int(parts[1]) - except Exception: + except (subprocess.SubprocessError, OSError): pass try: @@ -758,7 +756,7 @@ def _read_acct_counters(self): if m: p = int(m.group(1)) bytes_out[p] = bytes_out.get(p, 0) + int(parts[1]) - except Exception: + except (subprocess.SubprocessError, OSError): pass return bytes_in, bytes_out @@ -777,7 +775,7 @@ def track_and_report_traffic(self): p_str = str(rule).split("=")[0].split(":")[-1].strip() if p_str.isdigit(): fwd_ports.append(int(p_str)) - except Exception: + except (ValueError, IndexError): pass core_p = metadata.get("core_port") @@ -822,7 +820,7 @@ def track_and_report_traffic(self): ) with urllib.request.urlopen(req, timeout=4) as _: pass - except Exception: + except (urllib.error.URLError, TimeoutError, OSError): pass def _iptables_bytes(self, chain, port_kind, port): diff --git a/app/auth.py b/app/auth.py index c4f6f5a..b197cb2 100644 --- a/app/auth.py +++ b/app/auth.py @@ -31,7 +31,7 @@ def _save_sessions_to_disk(sessions): valid = {k: v for k, v in sessions.items() if isinstance(v, (int, float)) and v > now} with open(SESSIONS_FILE, "w", encoding="utf-8") as f: json.dump(valid, f) - except Exception: + except (OSError, TypeError): pass # Active in-memory session tokens loaded from disk diff --git a/app/backhaul.py b/app/backhaul.py index a50c89f..886d2b7 100644 --- a/app/backhaul.py +++ b/app/backhaul.py @@ -1,4 +1,3 @@ -import json from app.db import list_tunnels def validate_tunnel_ports(core_port, server_node_id, current_tunnel_id=None): diff --git a/app/config.py b/app/config.py index 0acd072..2f24e78 100644 --- a/app/config.py +++ b/app/config.py @@ -47,7 +47,7 @@ def load_settings(): merged = dict(DEFAULT_SETTINGS) merged.update(data) return merged - except: + except Exception: return dict(DEFAULT_SETTINGS) def save_settings(new_settings): diff --git a/app/db.py b/app/db.py index 69c74e3..9620df6 100644 --- a/app/db.py +++ b/app/db.py @@ -85,34 +85,34 @@ def init_db(): # Automatic migrations for existing databases try: cursor.execute("ALTER TABLE tunnels ADD COLUMN core_type TEXT NOT NULL DEFAULT 'hawal'") - except: + except sqlite3.OperationalError: pass try: cursor.execute("ALTER TABLE tunnels ADD COLUMN bytes_in INTEGER DEFAULT 0") - except: + except sqlite3.OperationalError: pass try: cursor.execute("ALTER TABLE tunnels ADD COLUMN bytes_out INTEGER DEFAULT 0") - except: + except sqlite3.OperationalError: pass try: cursor.execute("ALTER TABLE tunnels ADD COLUMN restart_nonce INTEGER NOT NULL DEFAULT 0") - except: + except sqlite3.OperationalError: pass try: cursor.execute("ALTER TABLE tunnels ADD COLUMN kcp_mode TEXT DEFAULT 'normal'") - except: + except sqlite3.OperationalError: pass try: cursor.execute("ALTER TABLE nodes ADD COLUMN agent_restart_nonce INTEGER NOT NULL DEFAULT 0") - except: + except sqlite3.OperationalError: pass try: cursor.execute("ALTER TABLE nodes ADD COLUMN country_code TEXT DEFAULT 'GLOBAL'") cursor.execute("ALTER TABLE nodes ADD COLUMN country_name TEXT DEFAULT 'خارج'") cursor.execute("ALTER TABLE nodes ADD COLUMN flag TEXT DEFAULT '🌐'") cursor.execute("ALTER TABLE nodes ADD COLUMN city TEXT DEFAULT ''") - except: + except sqlite3.OperationalError: pass # Traffic samples time-series table @@ -139,7 +139,7 @@ def init_db(): ]: try: cursor.execute(f"ALTER TABLE nodes ADD COLUMN {col} {col_type}") - except Exception: + except sqlite3.OperationalError: pass conn.commit() @@ -246,7 +246,7 @@ def list_tunnels(): d = dict(r) try: d["ports"] = json.loads(d["ports_json"]) - except: + except (json.JSONDecodeError, TypeError): d["ports"] = [] tunnels.append(d) return tunnels @@ -259,7 +259,7 @@ def get_tunnel(tunnel_id): d = dict(row) try: d["ports"] = json.loads(d["ports_json"]) - except: + except (json.JSONDecodeError, TypeError): d["ports"] = [] return d diff --git a/app/geoip.py b/app/geoip.py index 45fa751..7e9047b 100644 --- a/app/geoip.py +++ b/app/geoip.py @@ -1,6 +1,6 @@ import urllib.request +import urllib.error import json -import socket # In-memory cache for IP lookups GEOIP_CACHE = {} @@ -84,7 +84,7 @@ def resolve_geoip(ip): } GEOIP_CACHE[ip] = res return res - except Exception as e: + except (urllib.error.URLError, json.JSONDecodeError, TimeoutError, OSError): pass # Fallback heuristic for Iran IPs if offline diff --git a/app/hawal_engine.py b/app/hawal_engine.py index fd71d12..4d5e3ca 100644 --- a/app/hawal_engine.py +++ b/app/hawal_engine.py @@ -1,5 +1,3 @@ -import json - def generate_hawal_core_server_config(tunnel_dict): """ Generates JSON configuration dictionary for Hawal Core (Server Mode) diff --git a/app/ping_tool.py b/app/ping_tool.py index 9924734..b5cf5f4 100644 --- a/app/ping_tool.py +++ b/app/ping_tool.py @@ -1,8 +1,6 @@ import asyncio import re -import socket import time -from app.db import record_ping async def run_ping(target_ip, count=4): """ diff --git a/app/server.py b/app/server.py index 2804be6..6ede152 100644 --- a/app/server.py +++ b/app/server.py @@ -24,7 +24,7 @@ ) from app.backhaul import validate_tunnel_ports, generate_server_config, generate_client_config, generate_docker_compose from app.gost_engine import generate_gost_server_command, generate_gost_client_command -from app.ping_tool import run_ping, run_tcp_ping +from app.ping_tool import run_ping from app.auth import ( is_first_time_setup, setup_admin, authenticate, validate_session, invalidate_session @@ -96,7 +96,7 @@ async def broadcast_ws(data): try: writer.write(msg) await writer.drain() - except: + except (ConnectionError, OSError): dead.append(writer) for w in dead: CONNECTED_WS_CLIENTS.discard(w) @@ -199,18 +199,17 @@ def fetch_panel_version_sync(dev=False): } async def get_panel_version_info(dev=False, force=False): - global _VERSION_CACHE now = time.time() - if not force and _VERSION_CACHE["data"] and (now - _VERSION_CACHE["ts"] < 600) and (_VERSION_CACHE["dev"] == dev): + if not force and _VERSION_CACHE.get("data") and (now - _VERSION_CACHE.get("ts", 0) < 600) and (_VERSION_CACHE.get("dev") == dev): return _VERSION_CACHE["data"] data = await asyncio.to_thread(fetch_panel_version_sync, dev) if "Error" not in data.get("release_name", ""): - _VERSION_CACHE = { + _VERSION_CACHE.update({ "data": data, "ts": now, "dev": dev - } + }) return data def update_panel_sync(dev=False, target_version=None): @@ -270,8 +269,8 @@ def update_panel_sync(dev=False, target_version=None): p = os.path.join(install_dir, exec_file) if os.path.exists(p): try: - os.chmod(p, 0o755) - except Exception: + os.chmod(p, 0o750) + except OSError: pass subprocess.run(f"rm -rf '{staging_dir}' '{tar_path}'", shell=True) @@ -305,7 +304,7 @@ async def background_traffic_collector(self): try: clean_old_traffic_samples(retention_days=35) self.last_cleanup_time = now - except Exception: + except sqlite3.Error: pass # Sample local master node network traffic from /proc/net/dev directly @@ -365,7 +364,7 @@ async def background_traffic_collector(self): "last_time": now, "rx": rx_total, "tx": tx_total, "last_sample_time": now, "accum_rx": 0, "accum_tx": 0 } - except Exception: + except (OSError, ValueError, KeyError): pass # Sample local tunnel accounting counters from iptables HAWAL_ACCT_IN / HAWAL_ACCT_OUT @@ -381,7 +380,7 @@ async def background_traffic_collector(self): try: p_str = str(rule).split("=")[0].split(":")[-1].strip() fwd_ports.append(int(p_str)) - except Exception: + except (ValueError, IndexError): pass target_ports = fwd_ports if fwd_ports else [tun.get("core_port")] cur_in = sum(ports_in.get(p, 0) for p in target_ports) @@ -409,7 +408,7 @@ async def background_traffic_collector(self): } if tunnel_updated: await broadcast_ws({"event": "tunnel_updated"}) - except Exception: + except (sqlite3.Error, KeyError): pass except Exception: await asyncio.sleep(5) @@ -427,7 +426,7 @@ def _read_kernel_acct(self): if m: p = int(m.group(1)) bytes_in[p] = bytes_in.get(p, 0) + int(parts[1]) - except Exception: + except (subprocess.SubprocessError, OSError): pass try: @@ -440,7 +439,7 @@ def _read_kernel_acct(self): if m: p = int(m.group(1)) bytes_out[p] = bytes_out.get(p, 0) + int(parts[1]) - except Exception: + except (subprocess.SubprocessError, OSError): pass return bytes_in, bytes_out @@ -505,17 +504,17 @@ async def handle_client(self, reader, writer): except Exception as e: try: self.send_json(writer, {"error": str(e)}, status=500) - except: + except (ConnectionError, OSError): pass finally: try: await writer.drain() - except: + except (ConnectionError, OSError): pass try: writer.close() await writer.wait_closed() - except: + except (ConnectionError, OSError): pass async def route_request(self, method, path, query, headers, body, writer): @@ -861,7 +860,7 @@ async def route_request(self, method, path, query, headers, body, writer): if body: try: data = json.loads(body.decode('utf-8')) - except Exception: + except (json.JSONDecodeError, UnicodeDecodeError): pass dev = bool(data.get("dev", False)) target_version = data.get("version") @@ -881,7 +880,7 @@ async def schedule_restart(): await asyncio.sleep(1) try: subprocess.Popen(["systemctl", "restart", "hawal-panel"]) - except Exception: + except (subprocess.SubprocessError, OSError): pass asyncio.create_task(schedule_restart()) return @@ -1020,7 +1019,7 @@ async def schedule_restart(): try: p_str = str(rule).split("=")[0].split(":")[-1].strip() fwd_ports.append(int(p_str)) - except Exception: + except (ValueError, IndexError): pass target_ports = fwd_ports if fwd_ports else [t.get("core_port")] @@ -1035,7 +1034,7 @@ async def schedule_restart(): while subprocess.run(["iptables", "-D", "HAWAL_ACCT_OUT", "-p", proto, "--sport", p_str], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode == 0: pass subprocess.run(["iptables", "-A", "HAWAL_ACCT_OUT", "-p", proto, "--sport", p_str], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) - except Exception: + except (subprocess.SubprocessError, OSError): pass self.tunnel_traffic_tracker[tunnel_id] = { @@ -1055,7 +1054,7 @@ async def schedule_restart(): try: subprocess.run(["iptables", "-Z", "HAWAL_ACCT_IN"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) subprocess.run(["iptables", "-Z", "HAWAL_ACCT_OUT"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) - except Exception: + except (subprocess.SubprocessError, OSError): pass self.send_json(writer, {"success": True}) await broadcast_ws({"event": "tunnel_updated"}) @@ -1084,7 +1083,7 @@ async def schedule_restart(): if 1 <= p <= 65535: test_port = p break - except: + except (ValueError, TypeError): pass if not test_port: @@ -1098,7 +1097,7 @@ async def schedule_restart(): lsock.connect(("127.0.0.1", test_port)) lsock.close() local_ok = True - except: + except (socket.error, OSError): pass # 2. Measure actual inter-server network RTT (Iran -> Germany) @@ -1118,7 +1117,7 @@ async def schedule_restart(): sock.close() connected = True break - except: + except (socket.error, OSError): continue time.sleep(0.04) @@ -1241,7 +1240,7 @@ async def schedule_restart(): if latency_val is not None: try: latency_val = float(latency_val) - except: + except (ValueError, TypeError): latency_val = None if latency_val is None: @@ -1253,7 +1252,7 @@ async def schedule_restart(): rtt_us = struct.unpack_from('I', raw, 68)[0] if rtt_us > 0: latency_val = round(rtt_us / 1000.0, 1) - except Exception: + except (socket.error, struct.error, OSError): pass update_node_heartbeat( @@ -1420,10 +1419,9 @@ async def handle_ws_dashboard(self, reader, writer): length = int.from_bytes(raw_len, 'big') mask = await reader.read(4) data = await reader.read(length) - # Unmask - unmasked = bytes([b ^ mask[i % 4] for i, b in enumerate(data)]) + _ = bytes([b ^ mask[i % 4] for i, b in enumerate(data)]) # Handle client ping or requests if needed - except: + except (ConnectionError, OSError, asyncio.CancelledError): pass finally: CONNECTED_WS_CLIENTS.discard(writer) @@ -1564,7 +1562,7 @@ async def serve_template(self, filename, writer): writer.write(resp.encode('utf-8')) try: await writer.drain() - except: + except (ConnectionError, OSError): pass async def serve_static_file(self, filepath, writer, method="GET"): @@ -1588,7 +1586,7 @@ async def serve_static_file(self, filepath, writer, method="GET"): writer.write(resp_headers.encode('utf-8') + content) try: await writer.drain() - except: + except (ConnectionError, OSError): pass def send_redirect(self, writer, location, set_cookie=None): diff --git a/app/static/bin/hawal-core b/app/static/bin/hawal-core index 5ba7376..1f57945 100755 Binary files a/app/static/bin/hawal-core and b/app/static/bin/hawal-core differ diff --git a/app/static/js/agent.py b/app/static/js/agent.py index ecbca6e..02e13a2 100644 --- a/app/static/js/agent.py +++ b/app/static/js/agent.py @@ -50,7 +50,7 @@ def _save_tunnel_state(self, tun_id, pid, content_hash, metadata): state_file = f"{CONFIG_DIR}/{tun_id}.state" with open(state_file, "w") as f: json.dump({"pid": pid, "hash": content_hash, "metadata": metadata or {}}, f) - except Exception: + except (OSError, TypeError): pass def _load_tunnel_state(self): @@ -73,12 +73,12 @@ def wait(self, timeout=None): pass def terminate(self): try: os.kill(self.pid, signal.SIGTERM) - except: pass + except (ProcessLookupError, OSError): pass self.running_processes[tun_id] = AdoptedProcess(pid) self.running_configs[tun_id] = data.get("hash") self.running_metadata[tun_id] = data.get("metadata", {}) print(f"[Agent] 🔗 Adopted existing live process for tunnel {tun_id} (PID {pid})") - except Exception: + except (json.JSONDecodeError, OSError, TypeError): pass def _adopt_running_system_processes(self, configs): @@ -116,16 +116,16 @@ def terminate(self): } print(f"[Agent] 🛡️ Successfully adopted active background process {core_type} for tunnel {tun_id} (PID {pid})") break - except Exception: + except (OSError, ValueError): pass - except Exception: + except (OSError, ValueError): pass def _load_agent_restart_nonce(self): try: with open(AGENT_RESTART_NONCE_PATH, "r") as f: return int(f.read().strip() or 0) - except Exception: + except (OSError, ValueError): return 0 def _save_agent_restart_nonce(self, nonce): @@ -150,7 +150,7 @@ def get_system_metrics(self): total_delta = sum(fields) - total if total_delta > 0: metrics["cpu_percent"] = round(100.0 * (1.0 - idle_delta / total_delta), 1) - except: + except (OSError, ValueError, IndexError): pass try: @@ -167,13 +167,13 @@ def get_system_metrics(self): avail_mb = mem.get("MemAvailable", mem.get("MemFree", 0)) // 1024 metrics["ram_total_mb"] = total_mb metrics["ram_used_mb"] = max(0, total_mb - avail_mb) - except: + except (OSError, ValueError, IndexError): pass try: with open("/proc/uptime", "r") as f: metrics["uptime_seconds"] = int(float(f.readline().split()[0])) - except: + except (OSError, ValueError, IndexError): pass try: @@ -192,7 +192,7 @@ def get_system_metrics(self): tx_total += int(stats[8]) metrics["net_rx_bytes"] = rx_total metrics["net_tx_bytes"] = tx_total - except: + except (OSError, ValueError, IndexError): pass return metrics @@ -202,7 +202,7 @@ def ensure_hawal_core_binary(self): if os.path.exists(HAWAL_CORE_BIN) and os.path.isfile(HAWAL_CORE_BIN) and os.access(HAWAL_CORE_BIN, os.X_OK): try: out = subprocess.check_output([HAWAL_CORE_BIN, "-version"], text=True, timeout=2) - if "v2.0" in out: + if "v2." in out or "Hawal Stealth Core" in out: is_v2 = True except Exception: is_v2 = False @@ -217,16 +217,20 @@ def ensure_hawal_core_binary(self): try: local_static_bin = "/opt/hawal-panel/app/static/bin/hawal-core" if os.path.exists(local_static_bin) and os.path.isfile(local_static_bin): - shutil.copy(local_static_bin, HAWAL_CORE_BIN) - os.chmod(HAWAL_CORE_BIN, 0o755) + temp_bin = f"{HAWAL_CORE_BIN}.tmp_{os.getpid()}" + shutil.copy(local_static_bin, temp_bin) + os.chmod(temp_bin, 0o750) + os.replace(temp_bin, HAWAL_CORE_BIN) print("[Agent] ✅ Hawal Core v2 binary installed from local panel.") return True url = f"{self.panel_url}/static/bin/hawal-core" req = urllib.request.Request(url, headers={"Authorization": f"Bearer {self.token}"}) - with urllib.request.urlopen(req, timeout=15) as resp, open(HAWAL_CORE_BIN, "wb") as out: + temp_bin = f"{HAWAL_CORE_BIN}.tmp_{os.getpid()}" + with urllib.request.urlopen(req, timeout=15) as resp, open(temp_bin, "wb") as out: shutil.copyfileobj(resp, out) - os.chmod(HAWAL_CORE_BIN, 0o755) + os.chmod(temp_bin, 0o750) + os.replace(temp_bin, HAWAL_CORE_BIN) print("[Agent] ✅ Hawal Core v2 binary downloaded and installed.") return True except Exception as e: @@ -239,9 +243,9 @@ def ensure_backhaul_binary(self): try: if os.path.exists("/usr/local/bin/backhaul"): shutil.copy("/usr/local/bin/backhaul", BACKHAUL_BIN) - os.chmod(BACKHAUL_BIN, 0o755) + os.chmod(BACKHAUL_BIN, 0o750) return True - except: + except (OSError, shutil.Error): pass return True @@ -254,7 +258,7 @@ def ensure_paqet_binary(self): local_static_bin = "/opt/hawal-panel/app/static/bin/paqet" if os.path.exists(local_static_bin) and os.path.isfile(local_static_bin): shutil.copy(local_static_bin, PAQET_BIN) - os.chmod(PAQET_BIN, 0o755) + os.chmod(PAQET_BIN, 0o750) print("[Agent] ✅ Paqet binary installed from local panel.") return True @@ -271,7 +275,7 @@ def ensure_paqet_binary(self): try: subprocess.run(["apt-get", "install", "-y", "libpcap0.8"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, timeout=20) - except: + except (subprocess.SubprocessError, OSError): pass import tarfile, io @@ -287,7 +291,7 @@ def ensure_paqet_binary(self): temp_bin = f"{PAQET_BIN}.download" with open(temp_bin, "wb") as out: out.write(f.read()) - os.chmod(temp_bin, 0o755) + os.chmod(temp_bin, 0o750) os.replace(temp_bin, PAQET_BIN) print(f"[Agent] ✅ Paqet ({arch}) binary installed successfully.") return True @@ -320,7 +324,7 @@ def ensure_gost_binary(self): source = tar.extractfile(member) with open(f"{GOST_BIN}.download", "wb") as out: out.write(source.read()) - os.chmod(f"{GOST_BIN}.download", 0o755) + os.chmod(f"{GOST_BIN}.download", 0o750) os.replace(f"{GOST_BIN}.download", GOST_BIN) print("[Agent] ✅ GOST binary installed successfully.") return True @@ -343,25 +347,23 @@ def get_network_info(self): if "via" in parts: gateway_ip = parts[parts.index("via") + 1] break - except: + except (subprocess.SubprocessError, OSError): pass try: res = subprocess.check_output(["ip", "-4", "addr", "show", iface], stderr=subprocess.DEVNULL).decode('utf-8') - import re m = re.search(r'inet\s+(\d+\.\d+\.\d+\.\d+)', res) if m: local_ip = m.group(1) - except: + except (subprocess.SubprocessError, OSError): pass try: if gateway_ip: subprocess.run(["ping", "-c", "1", "-W", "1", gateway_ip], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) res = subprocess.check_output(["ip", "neigh", "show", gateway_ip], stderr=subprocess.DEVNULL).decode('utf-8') - import re m = re.search(r'([0-9a-fA-F]{2}(?::[0-9a-fA-F]{2}){5})', res) if m: gateway_mac = m.group(1) - except: + except (subprocess.SubprocessError, OSError): pass return iface, local_ip, gateway_mac @@ -463,7 +465,7 @@ def sync_tunnels(self): self.agent_restart_nonce = requested_nonce print("[Agent] 🔄 Restart requested by panel.") self.shutdown_requested = True - except Exception as e: + except (urllib.error.URLError, TimeoutError, json.JSONDecodeError, OSError): pass def report_logs(self): @@ -486,7 +488,7 @@ def report_logs(self): ) with urllib.request.urlopen(req, timeout=5): self.last_log_report = time.time() - except Exception: + except (urllib.error.URLError, TimeoutError, OSError): pass def apply_configs(self, configs): @@ -604,7 +606,7 @@ def cleanup_orphaned_cores(self): for bin_path in core_binaries: name = os.path.basename(bin_path) subprocess.run(["pkill", "-9", "-f", f"{BIN_DIR}/{name}"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) - except Exception: + except (subprocess.SubprocessError, OSError): pass def _extract_ports(self, metadata): @@ -615,13 +617,13 @@ def _extract_ports(self, metadata): if core_port: try: ports_to_free.add(int(core_port)) - except Exception: + except (ValueError, TypeError): pass for rule in metadata.get("ports", []): try: p_str = str(rule).split("=")[0].split(":")[-1].strip() ports_to_free.add(int(p_str)) - except Exception: + except (ValueError, TypeError): pass return ports_to_free @@ -630,7 +632,7 @@ def _free_ports(self, ports): try: subprocess.run(["fuser", "-k", "-9", f"{port}/tcp"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) subprocess.run(["fuser", "-k", "-9", f"{port}/udp"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) - except Exception: + except (subprocess.SubprocessError, OSError): pass if ports: time.sleep(0.1) @@ -662,17 +664,17 @@ def stop_tunnel_process(self, tun_id): state_file = f"{CONFIG_DIR}/{tun_id}.state" if os.path.exists(state_file): try: os.remove(state_file) - except: pass + except OSError: pass if tun_id in self.running_processes: proc = self.running_processes[tun_id] pid = proc.pid try: pgid = os.getpgid(pid) os.killpg(pgid, signal.SIGTERM) - except Exception: + except (ProcessLookupError, OSError): try: proc.terminate() - except Exception: + except (ProcessLookupError, OSError): pass deadline = time.time() + 2.0 while time.time() < deadline: @@ -683,14 +685,14 @@ def stop_tunnel_process(self, tun_id): try: pgid = os.getpgid(pid) os.killpg(pgid, signal.SIGKILL) - except Exception: + except (ProcessLookupError, OSError): try: proc.kill() - except Exception: + except (ProcessLookupError, OSError): pass try: proc.wait(timeout=1) - except Exception: + except (subprocess.TimeoutExpired, ProcessLookupError, OSError): pass del self.running_processes[tun_id] self.running_configs.pop(tun_id, None) @@ -710,7 +712,7 @@ def _ensure_acct_chains(self): subprocess.run(["iptables", "-I", "INPUT", "1", "-j", "HAWAL_ACCT_IN"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) if subprocess.run(["iptables", "-C", "OUTPUT", "-j", "HAWAL_ACCT_OUT"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode != 0: subprocess.run(["iptables", "-I", "OUTPUT", "1", "-j", "HAWAL_ACCT_OUT"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) - except Exception: + except (subprocess.SubprocessError, OSError): pass def _sync_acct_rules(self, ports): @@ -725,7 +727,7 @@ def _sync_acct_rules(self, ports): subprocess.run(["iptables", "-A", "HAWAL_ACCT_IN", "-p", proto, "--dport", p_str], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) if subprocess.run(["iptables", "-C", "HAWAL_ACCT_OUT", "-p", proto, "--sport", p_str], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode != 0: subprocess.run(["iptables", "-A", "HAWAL_ACCT_OUT", "-p", proto, "--sport", p_str], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) - except Exception: + except (subprocess.SubprocessError, OSError): pass def _read_acct_counters(self): @@ -741,7 +743,7 @@ def _read_acct_counters(self): if m: p = int(m.group(1)) bytes_in[p] = bytes_in.get(p, 0) + int(parts[1]) - except Exception: + except (subprocess.SubprocessError, OSError): pass try: @@ -754,7 +756,7 @@ def _read_acct_counters(self): if m: p = int(m.group(1)) bytes_out[p] = bytes_out.get(p, 0) + int(parts[1]) - except Exception: + except (subprocess.SubprocessError, OSError): pass return bytes_in, bytes_out @@ -773,7 +775,7 @@ def track_and_report_traffic(self): p_str = str(rule).split("=")[0].split(":")[-1].strip() if p_str.isdigit(): fwd_ports.append(int(p_str)) - except Exception: + except (ValueError, IndexError): pass core_p = metadata.get("core_port") @@ -818,7 +820,7 @@ def track_and_report_traffic(self): ) with urllib.request.urlopen(req, timeout=4) as _: pass - except Exception: + except (urllib.error.URLError, TimeoutError, OSError): pass def _iptables_bytes(self, chain, port_kind, port): diff --git a/bin/hawal b/bin/hawal index d6dbfb9..b684b70 100755 --- a/bin/hawal +++ b/bin/hawal @@ -13,7 +13,6 @@ import sqlite3 import socket import ssl import subprocess -import shutil from pathlib import Path # Styling & ANSI Colors @@ -67,7 +66,7 @@ def format_bytes(bytes_count): return f"{n:.1f} {unit}" n /= 1024.0 return f"{n:.1f} PB" - except: + except (ValueError, TypeError): return "0 B" def service_status(service_name): @@ -88,7 +87,7 @@ def get_master_db_connection(): return None try: return sqlite3.connect(MASTER_DB) - except: + except (sqlite3.Error, OSError): return None def master_get_nodes(): @@ -101,7 +100,7 @@ def master_get_nodes(): rows = cur.execute("SELECT * FROM nodes").fetchall() con.close() return [dict(zip(cols, r)) for r in rows] - except: + except (sqlite3.Error, OSError): return [] def master_get_tunnels(): @@ -114,7 +113,7 @@ def master_get_tunnels(): rows = cur.execute("SELECT * FROM tunnels").fetchall() con.close() return [dict(zip(cols, r)) for r in rows] - except: + except (sqlite3.Error, OSError): return [] # ------------------------------------------------------------- @@ -126,7 +125,7 @@ def agent_get_config(): try: with open(AGENT_JSON, "r", encoding="utf-8") as f: return json.load(f) - except: + except (json.JSONDecodeError, OSError): return {} # ------------------------------------------------------------- @@ -164,7 +163,7 @@ def cmd_tunnels(): ports_str = ", ".join(ports_list[:3]) if len(ports_list) > 3: ports_str += f" (+{len(ports_list)-3})" - except: + except (json.JSONDecodeError, TypeError): ports_str = str(raw_ports) # Node destination @@ -403,7 +402,7 @@ def cmd_info(): data = json.load(f) token = data.get("master_token", "N/A") port = data.get("panel_port", 9090) - except: + except (json.JSONDecodeError, OSError): pass rc, ip, _ = run_cmd("curl -s -m 3 https://api.ipify.org || hostname -I | awk '{print $1}'") diff --git a/bin/hawal-core b/bin/hawal-core index 5ba7376..1f57945 100755 Binary files a/bin/hawal-core and b/bin/hawal-core differ diff --git a/core/v2/carrier/rawpaq/raw_linux.go b/core/v2/carrier/rawpaq/raw_linux.go index fcacec7..4e647e2 100644 --- a/core/v2/carrier/rawpaq/raw_linux.go +++ b/core/v2/carrier/rawpaq/raw_linux.go @@ -115,20 +115,27 @@ func (b *LinuxRawBackend) Open(ctx context.Context, req PacketRequest) (net.Pack } // Resolve local port - localPort := 0 + var localPort uint16 if req.LocalAddress != "" { _, pStr, err := net.SplitHostPort(req.LocalAddress) if err == nil { - localPort, _ = strconv.Atoi(pStr) + if p, err := strconv.ParseUint(pStr, 10, 16); err == nil { + localPort = uint16(p) + } } } if localPort == 0 { - localPort = pickEphemeralPort() + ephem := pickEphemeralPort() + if ephem > 0 && ephem <= 65535 { + localPort = uint16(ephem) + } else { + localPort = 45000 + } } // Resolve remote endpoint (if dialer) var remoteIP net.IP - remotePort := 0 + var remotePort uint16 if req.Role == RoleDialer && req.RemoteAddress != "" { host, pStr, err := net.SplitHostPort(req.RemoteAddress) if err == nil { @@ -139,7 +146,9 @@ func (b *LinuxRawBackend) Open(ctx context.Context, req PacketRequest) (net.Pack break } } - remotePort, _ = strconv.Atoi(pStr) + if p, err := strconv.ParseUint(pStr, 10, 16); err == nil { + remotePort = uint16(p) + } } } @@ -183,7 +192,7 @@ func (b *LinuxRawBackend) Open(ctx context.Context, req PacketRequest) (net.Pack _ = unix.SetsockoptInt(fd, unix.SOL_SOCKET, unix.SO_SNDBUF, 4*1024*1024) // Attach in-kernel BPF filter to drop all unrelated traffic at kernel layer - if prog, err := buildBPFFilter(req.Role, uint16(localPort), uint16(remotePort)); err == nil { + if prog, err := buildBPFFilter(req.Role, localPort, remotePort); err == nil { sockFilter := make([]unix.SockFilter, len(prog)) for i, inst := range prog { sockFilter[i] = unix.SockFilter{Code: inst.Op, Jt: inst.Jt, Jf: inst.Jf, K: inst.K} @@ -216,9 +225,9 @@ type rawTCPPacketConn struct { fd int iface *net.Interface localIP net.IP - localPort int + localPort uint16 remoteIP net.IP - remotePort int + remotePort uint16 routerMAC net.HardwareAddr role Role seqCounter atomic.Uint32 @@ -259,10 +268,10 @@ func (c *rawTCPPacketConn) ReadFrom(p []byte) (int, net.Addr, error) { } // Port filtering verification (backup in case BPF is bypassed) - if int(dstPort) != c.localPort { + if dstPort != c.localPort { continue } - if c.role == RoleDialer && c.remotePort > 0 && int(srcPort) != c.remotePort { + if c.role == RoleDialer && c.remotePort > 0 && srcPort != c.remotePort { continue } @@ -286,7 +295,7 @@ func (c *rawTCPPacketConn) WriteTo(p []byte, addr net.Addr) (int, error) { } var dstIP net.IP - dstPort := c.remotePort + dstPort := int(c.remotePort) switch a := addr.(type) { case *net.UDPAddr: @@ -303,7 +312,7 @@ func (c *rawTCPPacketConn) WriteTo(p []byte, addr net.Addr) (int, error) { } } - if dstIP == nil || dstPort <= 0 { + if dstIP == nil || dstPort <= 0 || dstPort > 65535 { return 0, errors.New("rawpaq: invalid destination address for raw write") } @@ -317,7 +326,7 @@ func (c *rawTCPPacketConn) WriteTo(p []byte, addr net.Addr) (int, error) { c.routerMAC, c.localIP, dstIP, - uint16(c.localPort), + c.localPort, uint16(dstPort), seq, ack, @@ -346,7 +355,7 @@ func (c *rawTCPPacketConn) Close() error { } func (c *rawTCPPacketConn) LocalAddr() net.Addr { - return &net.UDPAddr{IP: c.localIP, Port: c.localPort} + return &net.UDPAddr{IP: c.localIP, Port: int(c.localPort)} } func (c *rawTCPPacketConn) SetDeadline(t time.Time) error { diff --git a/core/v2/secure/handshaker.go b/core/v2/secure/handshaker.go index 29a7cea..8960d37 100644 --- a/core/v2/secure/handshaker.go +++ b/core/v2/secure/handshaker.go @@ -37,7 +37,7 @@ func (h *NoiseHandshaker) Handshake(ctx context.Context, role Role, link carrier if timeout <= 0 { timeout = 10 * time.Second } - ctx, cancel := context.WithTimeout(ctx, timeout) + _, cancel := context.WithTimeout(ctx, timeout) defer cancel() _ = link.SetDeadline(time.Now().Add(timeout)) diff --git a/server.py b/server.py index 0a5b6b9..cc6d5be 100755 --- a/server.py +++ b/server.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 import asyncio -import sys import argparse from app.server import HTTPServer from app.config import DEFAULT_PORT, DEFAULT_HOST diff --git a/tests/test_auth.py b/tests/test_auth.py index f4b9d05..2af9b9d 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -26,8 +26,8 @@ def test_hash_and_verify_password(self): from app.auth import hash_password, verify_password pwd = "SuperSecretPassword123!" pw_hash, salt = hash_password(pwd) - self.assertTrue(len(pw_hash) > 30) - self.assertTrue(len(salt) > 10) + self.assertGreater(len(pw_hash), 30) + self.assertGreater(len(salt), 10) self.assertTrue(verify_password(pwd, pw_hash, salt)) self.assertFalse(verify_password("WrongPassword", pw_hash, salt)) @@ -50,7 +50,7 @@ def test_setup_admin_validation(self): # Successful setup ok, tok, err = setup_admin("admin", "MySecurePass2026!") self.assertTrue(ok) - self.assertTrue(len(tok) > 20) + self.assertGreater(len(tok), 20) self.assertEqual(err, "") self.assertFalse(is_first_time_setup())