written new tests

This commit is contained in:
nik012003
2022-06-28 16:02:52 +02:00
parent b9a2f136b0
commit 8fb4218689
5 changed files with 127 additions and 54 deletions

View File

@@ -6,12 +6,15 @@ RUN apt-get update && apt-get -y install build-essential libboost-system-dev lib
RUN mkdir /execute RUN mkdir /execute
WORKDIR /execute WORKDIR /execute
COPY ./backend/ /execute/ ADD ./backend/requirements.txt /execute/requirements.txt
RUN pip install --no-cache-dir -r /execute/requirements.txt RUN pip install --no-cache-dir -r /execute/requirements.txt
ARG GCC_PARAMS ARG GCC_PARAMS
RUN c++ -O3 $GCC_PARAMS -o proxy/proxy proxy/proxy.cpp -pthread -lboost_system -lboost_thread RUN mkdir proxy
ADD ./backend/proxy/proxy.cpp /execute/proxy/proxy.cpp
RUN c++ -O3 -march=native $GCC_PARAMS -o proxy/proxy proxy/proxy.cpp -pthread -lboost_system -lboost_thread
COPY ./backend/ /execute/
COPY ./frontend/build/ ./frontend/ COPY ./frontend/build/ ./frontend/
RUN usermod -a -G root nobody RUN usermod -a -G root nobody

View File

@@ -10,7 +10,8 @@ ON_DOCKER = len(sys.argv) > 1 and sys.argv[1] == "DOCKER"
DEBUG = len(sys.argv) > 1 and sys.argv[1] == "DEBUG" DEBUG = len(sys.argv) > 1 and sys.argv[1] == "DEBUG"
# DB init # DB init
db = SQLite('firegex') if not os.path.exists("db"): os.mkdir("db")
db = SQLite('db/firegex.db')
db.connect() db.connect()
conf = KeyValueStorage(db) conf = KeyValueStorage(db)
firewall = ProxyManager(db) firewall = ProxyManager(db)
@@ -25,12 +26,13 @@ def shutdown_event():
app.add_middleware(SessionMiddleware, secret_key=os.urandom(32)) app.add_middleware(SessionMiddleware, secret_key=os.urandom(32))
SESSION_TOKEN = secrets.token_hex(8) SESSION_TOKEN = secrets.token_hex(8)
APP_STATUS = "init" APP_STATUS = "init"
REACT_BUILD_DIR = "../frontend/build/" if not ON_DOCKER else "../frontend/" REACT_BUILD_DIR = "../frontend/build/" if not ON_DOCKER else "frontend/"
REACT_HTML_PATH = os.path.join(REACT_BUILD_DIR,"index.html") REACT_HTML_PATH = os.path.join(REACT_BUILD_DIR,"index.html")
def is_loggined(request: Request): def is_loggined(request: Request):
global SESSION_TOKEN
return request.session.get("token", "") == SESSION_TOKEN return request.session.get("token", "") == SESSION_TOKEN
def login_check(request: Request): def login_check(request: Request):
@@ -54,7 +56,7 @@ class PasswordChangeForm(BaseModel):
@app.post("/api/login") @app.post("/api/login")
async def login_api(request: Request, form: PasswordForm): async def login_api(request: Request, form: PasswordForm):
global APP_STATUS global APP_STATUS, SESSION_TOKEN
if APP_STATUS != "run": raise HTTPException(status_code=400) if APP_STATUS != "run": raise HTTPException(status_code=400)
if form.password == "": if form.password == "":
@@ -75,7 +77,7 @@ async def logout(request: Request):
@app.post('/api/change-password') @app.post('/api/change-password')
async def change_password(request: Request, form: PasswordChangeForm): async def change_password(request: Request, form: PasswordChangeForm):
login_check(request) login_check(request)
global APP_STATUS global APP_STATUS, SESSION_TOKEN
if APP_STATUS != "run": raise HTTPException(status_code=400) if APP_STATUS != "run": raise HTTPException(status_code=400)
if form.password == "": if form.password == "":
@@ -91,7 +93,7 @@ async def change_password(request: Request, form: PasswordChangeForm):
@app.post('/api/set-password') @app.post('/api/set-password')
async def set_password(request: Request, form: PasswordForm): async def set_password(request: Request, form: PasswordForm):
global APP_STATUS global APP_STATUS, SESSION_TOKEN
if APP_STATUS != "init": raise HTTPException(status_code=400) if APP_STATUS != "init": raise HTTPException(status_code=400)
if form.password == "": if form.password == "":
return {"status":"Cannot insert an empty password!"} return {"status":"Cannot insert an empty password!"}

View File

@@ -13,13 +13,12 @@ class SQLite():
self.lock = threading.Lock() self.lock = threading.Lock()
def connect(self) -> None: def connect(self) -> None:
if not os.path.exists("db"): os.mkdir("db")
try: try:
self.conn = sqlite3.connect("db/" + self.db_name + '.db', check_same_thread = False) self.conn = sqlite3.connect(self.db_name, check_same_thread = False)
except Exception: except Exception:
with open("db/" + self.db_name + '.db', 'x'): with open(self.db_name, 'x'):
pass pass
self.conn = sqlite3.connect("db/" + self.db_name + '.db', check_same_thread = False) self.conn = sqlite3.connect(self.db_name, check_same_thread = False)
def dict_factory(cursor, row): def dict_factory(cursor, row):
d = {} d = {}
for idx, col in enumerate(cursor.description): for idx, col in enumerate(cursor.description):

View File

@@ -1,13 +1,16 @@
from requests import Session from requests import Session
class ProxyAPI: class FiregexAPI:
def __init__(self,address,password): def __init__(self,address):
self.s = Session() self.s = Session()
self.address = address self.address = address
self.password = password
def connect(self): def login(self,password):
req = self.s.post(f"{self.address}api/login", json={"password":self.password}) req = self.s.post(f"{self.address}api/login", json={"password":password})
return req.json()["status"] == "ok"
def logout(self):
req = self.s.get(f"{self.address}api/logout")
return req.json()["status"] == "ok" return req.json()["status"] == "ok"
def create_service(self,service_name,service_port): def create_service(self,service_name,service_port):
@@ -16,16 +19,14 @@ class ProxyAPI:
def get_service_details(self,service_name): def get_service_details(self,service_name):
req = self.s.get(f"{self.address}api/services") req = self.s.get(f"{self.address}api/services")
internal_port = service_id = None service = None
try: try:
for service in req.json(): for service in req.json():
if service["name"] == service_name: if service["name"] == service_name:
service_id = service["id"] return service
internal_port = service["internal_port"]
break
except Exception: except Exception:
pass pass
return service_id,internal_port return service
def get_service_status(self,service_id): def get_service_status(self,service_id):
req = self.s.get(f"{self.address}api/service/{service_id}") req = self.s.get(f"{self.address}api/service/{service_id}")
@@ -35,6 +36,19 @@ class ProxyAPI:
req = self.s.get(f"{self.address}api/service/{service_id}/regexes") req = self.s.get(f"{self.address}api/service/{service_id}/regexes")
return req.json() return req.json()
def get_regex(self,regex_id):
req = self.s.get(f"{self.address}api/regex/{regex_id}")
return req.json()
def add_regex(self,service_id,regex,is_blacklist = True, is_case_sensitive = True, mode = "B"):
req = self.s.post(f"{self.address}api/regexes/add",
json={"is_blacklist":is_blacklist,"is_case_sensitive":is_case_sensitive,"service_id":service_id,"mode":mode,"regex":regex})
return req.json()["status"] == "ok"
def delete_regex(self,regex_id):
req = self.s.get(f"{self.address}api/regex/{regex_id}/delete")
return req.json()["status"] == "ok"
def start(self,service_id): def start(self,service_id):
req = self.s.get(f"{self.address}api/service/{service_id}/start") req = self.s.get(f"{self.address}api/service/{service_id}/start")
return req.json()["status"] == "ok" return req.json()["status"] == "ok"
@@ -51,8 +65,3 @@ class ProxyAPI:
req = self.s.get(f"{self.address}api/service/{service_id}/delete") req = self.s.get(f"{self.address}api/service/{service_id}/delete")
return req.json()["status"] == "ok" return req.json()["status"] == "ok"
def add_regex(self,service_id,regex,is_blacklist = True, is_case_sensitive = True, mode = "B"):
req = self.s.post(f"{self.address}api/regexes/add",
json={"is_blacklist":is_blacklist,"is_case_sensitive":is_case_sensitive,"service_id":service_id,"mode":mode,"regex":regex})
return req.json()["status"] == "ok"

View File

@@ -2,7 +2,7 @@
import argparse, socket,secrets, base64 import argparse, socket,secrets, base64
from time import sleep from time import sleep
from multiprocessing import Process from multiprocessing import Process
from proxyapi import ProxyAPI from firegexapi import FiregexAPI
pref = "\033[" pref = "\033["
reset = f"{pref}0m" reset = f"{pref}0m"
@@ -33,16 +33,16 @@ puts(f"Testing will start on ", color=colors.cyan, end="")
puts(f"{args.address}", color=colors.yellow) puts(f"{args.address}", color=colors.yellow)
proxy = ProxyAPI(args.address,args.password) firegex = FiregexAPI(args.address)
service_created = False service_created = False
#Connect to Firegex #Connect to Firegex
if (proxy.connect()): puts(f"Sucessfully logged in ✔", color=colors.green) if (firegex.login(args.password)): puts(f"Sucessfully logged in ✔", color=colors.green)
else: puts(f"Test Failed: Unknown response or wrong passowrd ✗", color=colors.red); exit(1) else: puts(f"Test Failed: Unknown response or wrong passowrd ✗", color=colors.red); exit(1)
#Create new Service #Create new Service
if (proxy.create_service(args.service_name,args.service_port)): if (firegex.create_service(args.service_name,args.service_port)):
puts(f"Sucessfully created service {args.service_name} with public port {args.service_port}", color=colors.green) puts(f"Sucessfully created service {args.service_name} with public port {args.service_port}", color=colors.green)
service_created = True service_created = True
else: puts(f"Test Failed: Couldn't create service ✗", color=colors.red); exit(1) else: puts(f"Test Failed: Couldn't create service ✗", color=colors.red); exit(1)
@@ -50,7 +50,7 @@ else: puts(f"Test Failed: Couldn't create service ✗", color=colors.red); exit(
#Delete the Service and exit #Delete the Service and exit
def exit_test(status_code=0): def exit_test(status_code=0):
if service_created: if service_created:
if(proxy.delete(service_id)): if(firegex.delete(service_id)):
puts(f"Sucessfully delete service with id {service_id}", color=colors.green) puts(f"Sucessfully delete service with id {service_id}", color=colors.green)
else: else:
puts(f"Test Failed: Couldn't delete service ✗", color=colors.red); exit(1) puts(f"Test Failed: Couldn't delete service ✗", color=colors.red); exit(1)
@@ -59,13 +59,17 @@ def exit_test(status_code=0):
exit(status_code) exit(status_code)
#Find the Service #Find the Service
service_id, internal_port = proxy.get_service_details(args.service_name) service = firegex.get_service_details(args.service_name)
if (internal_port): puts(f"Sucessfully received the internal port {internal_port}", color=colors.green) if (service):
internal_port= service["internal_port"]
service_id = service["id"]
puts(f"Sucessfully received the internal port {internal_port}", color=colors.green)
else: puts(f"Test Failed: Coulnd't get the service internal port ✗", color=colors.red); exit_test(1) else: puts(f"Test Failed: Coulnd't get the service internal port ✗", color=colors.red); exit_test(1)
#Start listener #Start listener
def startServer(port): def startServer(port):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('127.0.0.1', port)) sock.bind(('127.0.0.1', port))
sock.listen(8) sock.listen(8)
while True: while True:
@@ -78,7 +82,7 @@ server = Process(target=startServer,args=[internal_port])
server.start() server.start()
#Start firewall #Start firewall
if(proxy.start(service_id)): puts(f"Sucessfully started service with id {service_id}", color=colors.green) if(firegex.start(service_id)): puts(f"Sucessfully started service with id {service_id}", color=colors.green)
else: puts(f"Test Failed: Coulnd't start the service ✗", color=colors.red); exit_test(1) else: puts(f"Test Failed: Coulnd't start the service ✗", color=colors.red); exit_test(1)
#Hacky solution - wait a bit for the server to start #Hacky solution - wait a bit for the server to start
@@ -101,25 +105,33 @@ else:
#Add new regex #Add new regex
secret = bytes(secrets.token_hex(16).encode()) secret = bytes(secrets.token_hex(16).encode())
regex = base64.b64encode(secret).decode() regex = base64.b64encode(secret).decode()
if(proxy.add_regex(service_id,regex)): puts(f"Sucessfully added regex {secret}", color=colors.green) if(firegex.add_regex(service_id,regex)): puts(f"Sucessfully added regex {secret}", color=colors.green)
else: puts(f"Test Failed: Coulnd't start the service", color=colors.red); exit_test(1) else: puts(f"Test Failed: Coulnd't add the regex {secret}", color=colors.red); exit_test(1)
#Check if regex is present in the service #Check if regex is present in the service
n_blocked = 0
def checkRegex(regex): def checkRegex(regex):
for i,r in enumerate(proxy.get_service_regexes(service_id)): global n_blocked
for r in firegex.get_service_regexes(service_id):
if r["regex"] == regex: if r["regex"] == regex:
#Test the regex #Test the regex
if not sendCheckData(secrets.token_bytes(200) + secret + secrets.token_bytes(200)): if not sendCheckData(secrets.token_bytes(200) + secret + secrets.token_bytes(200)):
puts(f"The malicious request was successfully blocked ✔", color=colors.green) puts(f"The malicious request was successfully blocked ✔", color=colors.green)
n_blocked += 1
if firegex.get_regex(r["id"])["n_packets"] == n_blocked:
puts(f"The packed was reported as blocked ✔", color=colors.green)
else: else:
puts(f"Test Failed: The request wasn't blocked ✗", color=colors.red); exit_test(1) puts(f"Test Failed: The packed wasn't reported as blocked ✗", color=colors.red); exit_test(1)
else:
puts(f"Test Failed: The request wasn't blocked ✗", color=colors.red);exit_test(1)
return return
puts(f"Test Failed: The regex wasn't found ✗", color=colors.red) puts(f"Test Failed: The regex wasn't found ✗", color=colors.red); exit_test(1)
checkRegex(regex) checkRegex(regex)
#Pause the proxy #Pause the proxy
if(proxy.pause(service_id)): puts(f"Sucessfully paused service with id {service_id}", color=colors.green) if(firegex.pause(service_id)): puts(f"Sucessfully paused service with id {service_id}", color=colors.green)
else: puts(f"Test Failed: Coulnd't pause the service ✗", color=colors.red); exit_test(1) else: puts(f"Test Failed: Coulnd't pause the service ✗", color=colors.red); exit_test(1)
#Check if it's actually paused #Check if it's actually paused
@@ -127,20 +139,68 @@ if sendCheckData(secrets.token_bytes(200) + secret + secrets.token_bytes(200)):
puts(f"The request wasn't blocked ✔", color=colors.green) puts(f"The request wasn't blocked ✔", color=colors.green)
else: else:
puts(f"Test Failed: The request was blocked when it shouldn't have", color=colors.red) puts(f"Test Failed: The request was blocked when it shouldn't have", color=colors.red)
#Stop the proxy #Stop the proxy
if(proxy.stop(service_id)): puts(f"Sucessfully stopped service with id {service_id}", color=colors.green) if(firegex.stop(service_id)): puts(f"Sucessfully stopped service with id {service_id}", color=colors.green)
else: puts(f"Test Failed: Coulnd't stop the service ✗", color=colors.red); exit_test(1) else: puts(f"Test Failed: Coulnd't stop the service ✗", color=colors.red); exit_test(1)
sleep(100)
#Check if proxy is stopped #Check if proxy is stopped and check if WAIT works
try: def bindForSeconds(port,delay=4):
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('0.0.0.0', args.service_port)) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
puts(f"I could bind to the port, so {service_id} was stopped correctly ✔", color=colors.green) sock.bind(('127.0.0.1', port))
sock.listen()
puts(f"The test could bind to port {port}", color=colors.green)
sleep(delay)
sock.close() sock.close()
except Exception as e: except Exception as e:
print(e) puts(f"The test couldn't bind to port {port}", color=colors.red)
puts(f"Test Failed: Coulnd't bind to port {args.service_port}", color=colors.red); exit_test(1)
bindingTest = Process(target=bindForSeconds, args=[args.service_port])
bindingTest.start()
sleep(1)
#Restart it
if(firegex.pause(service_id)): puts(f"Sucessfully started in pause mode ✔", color=colors.green)
else: puts(f"Test Failed: Coulnd't start the service ✗", color=colors.red); exit_test(1)
if firegex.get_service_details(args.service_name)["status"] == "wait":
puts(f"Service started in WAIT mode ✔", color=colors.green)
else:
puts(f"Service started but it's not WAIT mode ✗", color=colors.red); exit_test(1)
bindingTest.join()
sleep(1)
#Check if service started in pause mode successfully
if firegex.get_service_details(args.service_name)["status"] == "pause":
puts(f"Service started in PAUSE mode ✔", color=colors.green)
else:
puts(f"Service is not in PAUSE mode ✗", color=colors.red); exit_test(1)
if sendCheckData(secrets.token_bytes(200) + secret + secrets.token_bytes(200)):
puts(f"The request wasn't blocked ✔", color=colors.green)
else:
puts(f"Test Failed: The request was blocked when it shouldn't have", color=colors.red)
#Restart it and check
if(firegex.start(service_id)): puts(f"Sucessfully started service with id {service_id}", color=colors.green)
else: puts(f"Test Failed: Coulnd't start the service ✗", color=colors.red); exit_test(1)
checkRegex(regex)
#Delete the regex
def removeRegex(regex):
for r in firegex.get_service_regexes(service_id):
if r["regex"] == regex:
if(firegex.delete_regex(r["id"])): puts(f"Sucessfully deleted regex ✔", color=colors.green)
else: puts(f"Test Failed: Coulnd't deleted the regex ✗", color=colors.red); exit_test(1)
return
puts(f"Test Failed: The regex wasn't found ✗", color=colors.red)
removeRegex(regex)
if sendCheckData(secrets.token_bytes(200) + secret + secrets.token_bytes(200)):
puts(f"The request wasn't blocked ✔", color=colors.green)
else:
puts(f"Test Failed: The request was blocked when it shouldn't have", color=colors.red)
exit_test() exit_test()