1+ #!/usr/bin/env python3
2+
3+ import os
4+ import subprocess
5+ import sys
6+ import time
7+ import socket
8+ from datetime import datetime
9+ from scapy .all import IP , TCP , sr1 , conf
10+
11+ # -----------------------------
12+ # Config
13+ # -----------------------------
14+ REQUIRED_FILES = [
15+ "antiddos-yuki" ,
16+ "user-rules.nft" ,
17+ "default-rules.nft" ,
18+ "script.conf" ,
19+ "sysctl.conf" ,
20+ "functions.sh" ,
21+ ]
22+
23+ NFTABLES_CONF = "/etc/nftables.conf"
24+ SYSCTL_CONF = "/etc/sysctl.d/99-yuki.conf"
25+
26+ SYN_TEST_IP = "127.0.0.1"
27+ SYN_TEST_PORT = 22
28+ SYN_RATE_PPS = 4
29+ SYN_DURATION = 3 # seconds
30+
31+ script_path = os .path .abspath (__file__ )
32+ script_dir = os .path .dirname (script_path )
33+ project_root = os .path .abspath (os .path .join (script_dir , ".." ))
34+
35+ # -----------------------------
36+ # Utils
37+ # -----------------------------
38+ def check_exists_and_nonempty (file_path ):
39+ print (f"📁 Looking for: { file_path } " )
40+ print (f"🔍 Checking { file_path } ..." )
41+ if not os .path .isfile (file_path ):
42+ sys .exit (f"❌ { file_path } does not exist" )
43+ print ("✅ File exists" )
44+ if os .path .getsize (file_path ) == 0 :
45+ sys .exit (f"❌ { file_path } is empty" )
46+ print ("✅ File not empty" )
47+ with open (file_path , 'rb' ) as f :
48+ if b'\r \n ' in f .read ():
49+ sys .exit (f"❌ { file_path } uses CRLF line endings" )
50+ print ("✅ File uses LF line endings" )
51+ with open (file_path , 'r' , errors = 'ignore' ) as f :
52+ if 'TODO: ' in f .read ():
53+ sys .exit (f"❌ { file_path } contains TODO comments" )
54+ print ("✅ No TODOs in file" )
55+
56+
57+ def check_network ():
58+ def run (name , cmd ):
59+ print (f"🔌 { name } : " , end = "" )
60+ start = time .time ()
61+ result = subprocess .run (cmd , shell = True , stdout = subprocess .DEVNULL , stderr = subprocess .DEVNULL )
62+ if result .returncode != 0 :
63+ sys .exit ("❌ failed" )
64+ print (f"✅ success in { int ((time .time () - start )* 1000 )} ms" )
65+
66+ run ("Ping 1.1.1.1" , "ping -c1 1.1.1.1" )
67+ run ("Ping google.com" , "ping -c1 google.com" )
68+ run ("Curl Google" , "curl -s https://google.com" )
69+ run ("DNS resolve" , "getent hosts example.com" )
70+ run ("APT update" , "apt update -qq" )
71+
72+
73+ def run_antiddos ():
74+ print ("🚀 Running antiddos-yuki..." )
75+ subprocess .run (["sudo" , "bash" , "antiddos-yuki" ], check = True )
76+
77+
78+ def validate_ruleset ():
79+ print ("🧾 Checking ruleset..." )
80+ output = subprocess .check_output (["sudo" , "nft" , "list" , "ruleset" ], text = True )
81+ required_patterns = [
82+ "goto user-ruleset" ,
83+ "chain user-ruleset" ,
84+ "ct state new tcp dport 22" ,
85+ "chain prerouting {" ,
86+ "chain ingress {" ,
87+ "table inet yuki {" ,
88+ ]
89+ for pattern in required_patterns :
90+ if pattern not in output :
91+ sys .exit (f"❌ Missing '{ pattern } '" )
92+ print (f"✅ Found '{ pattern } '" )
93+
94+ def systemd_nftables_check ():
95+ print ("🔧 Verifying systemd starts nftables without errors..." )
96+ result = subprocess .run (["sudo" , "systemctl" , "start" , "nftables" ], stdout = subprocess .PIPE , stderr = subprocess .PIPE )
97+ if result .returncode != 0 :
98+ print (result .stderr .decode ())
99+ sys .exit ("❌ systemctl failed to start nftables" )
100+ print ("✅ nftables started successfully via systemd" )
101+
102+
103+ # -----------------------------
104+ # Main
105+ # -----------------------------
106+ # -----------------------------
107+ # Main
108+ # -----------------------------
109+ def main ():
110+ print ("📍 Current working directory:" , os .getcwd ())
111+
112+ print ("\n 📂 Files and dirs in current dir:" )
113+ for item in os .listdir ("." ):
114+ print (" └──" , item )
115+
116+ print ("\n 📂 Files and dirs in script dir:" )
117+ for item in os .listdir (script_dir ):
118+ print (" └──" , item )
119+
120+ print ("\n 📂 Files and dirs in project root:" )
121+ for item in os .listdir (project_root ):
122+ print (" └──" , item )
123+
124+ print ("\n 🔎 Full path of each REQUIRED_FILE:" )
125+ for file in REQUIRED_FILES :
126+ full_path = os .path .join (project_root , file )
127+ print (f" { file } → { full_path } → { 'FOUND ✅' if os .path .exists (full_path ) else 'MISSING ❌' } " )
128+
129+ os .chdir (".." )
130+ print ("📦 Starting tests..." )
131+
132+ for file in REQUIRED_FILES :
133+ check_exists_and_nonempty (file )
134+
135+ run_antiddos ()
136+ check_exists_and_nonempty (NFTABLES_CONF )
137+ validate_ruleset ()
138+ check_network ()
139+ check_exists_and_nonempty (SYSCTL_CONF )
140+ run_antiddos ()
141+ systemd_nftables_check ()
142+
143+ print ("🎉 All tests passed!" )
144+
145+ if __name__ == "__main__" :
146+ main ()
0 commit comments