push: code changes
This commit is contained in:
@@ -10,6 +10,10 @@ from utils.models import ResetRequest, StatusMessageModel
|
||||
import os
|
||||
from firegex.nfproxy.internals import get_filter_names
|
||||
from fastapi.responses import PlainTextResponse
|
||||
from modules.nfproxy.nftables import convert_protocol_to_l4
|
||||
import asyncio
|
||||
import traceback
|
||||
from utils import DEBUG
|
||||
|
||||
class ServiceModel(BaseModel):
|
||||
service_id: str
|
||||
@@ -28,12 +32,10 @@ class RenameForm(BaseModel):
|
||||
|
||||
class SettingsForm(BaseModel):
|
||||
port: PortType|None = None
|
||||
proto: str|None = None
|
||||
ip_int: str|None = None
|
||||
fail_open: bool|None = None
|
||||
|
||||
class PyFilterModel(BaseModel):
|
||||
filter_id: int
|
||||
name: str
|
||||
blocked_packets: int
|
||||
edited_packets: int
|
||||
@@ -52,6 +54,7 @@ class ServiceAddResponse(BaseModel):
|
||||
|
||||
class SetPyFilterForm(BaseModel):
|
||||
code: str
|
||||
sid: str|None = None
|
||||
|
||||
app = APIRouter()
|
||||
|
||||
@@ -62,12 +65,12 @@ db = SQLite('db/nft-pyfilters.db', {
|
||||
'port': 'INT NOT NULL CHECK(port > 0 and port < 65536)',
|
||||
'name': 'VARCHAR(100) NOT NULL UNIQUE',
|
||||
'proto': 'VARCHAR(3) NOT NULL CHECK (proto IN ("tcp", "http"))',
|
||||
'l4_proto': 'VARCHAR(3) NOT NULL CHECK (l4_proto IN ("tcp", "udp"))',
|
||||
'ip_int': 'VARCHAR(100) NOT NULL',
|
||||
'fail_open': 'BOOLEAN NOT NULL CHECK (fail_open IN (0, 1)) DEFAULT 1',
|
||||
},
|
||||
'pyfilter': {
|
||||
'filter_id': 'INTEGER PRIMARY KEY',
|
||||
'name': 'VARCHAR(100) NOT NULL',
|
||||
'name': 'VARCHAR(100) PRIMARY KEY',
|
||||
'blocked_packets': 'INTEGER UNSIGNED NOT NULL DEFAULT 0',
|
||||
'edited_packets': 'INTEGER UNSIGNED NOT NULL DEFAULT 0',
|
||||
'service_id': 'VARCHAR(100) NOT NULL',
|
||||
@@ -75,7 +78,7 @@ db = SQLite('db/nft-pyfilters.db', {
|
||||
'FOREIGN KEY (service_id)':'REFERENCES services (service_id)',
|
||||
},
|
||||
'QUERY':[
|
||||
"CREATE UNIQUE INDEX IF NOT EXISTS unique_services ON services (port, ip_int, proto);",
|
||||
"CREATE UNIQUE INDEX IF NOT EXISTS unique_services ON services (port, ip_int, l4_proto);",
|
||||
"CREATE UNIQUE INDEX IF NOT EXISTS unique_pyfilter_service ON pyfilter (name, service_id);"
|
||||
]
|
||||
})
|
||||
@@ -132,7 +135,7 @@ async def get_service_list():
|
||||
s.proto proto,
|
||||
s.ip_int ip_int,
|
||||
s.fail_open fail_open,
|
||||
COUNT(f.filter_id) n_filters,
|
||||
COUNT(f.name) n_filters,
|
||||
COALESCE(SUM(f.blocked_packets),0) blocked_packets,
|
||||
COALESCE(SUM(f.edited_packets),0) edited_packets
|
||||
FROM services s LEFT JOIN pyfilter f ON s.service_id = f.service_id
|
||||
@@ -151,7 +154,7 @@ async def get_service_by_id(service_id: str):
|
||||
s.proto proto,
|
||||
s.ip_int ip_int,
|
||||
s.fail_open fail_open,
|
||||
COUNT(f.filter_id) n_filters,
|
||||
COUNT(f.name) n_filters,
|
||||
COALESCE(SUM(f.blocked_packets),0) blocked_packets,
|
||||
COALESCE(SUM(f.edited_packets),0) edited_packets
|
||||
FROM services s LEFT JOIN pyfilter f ON s.service_id = f.service_id
|
||||
@@ -202,9 +205,6 @@ async def service_rename(service_id: str, form: RenameForm):
|
||||
@app.put('/services/{service_id}/settings', response_model=StatusMessageModel)
|
||||
async def service_settings(service_id: str, form: SettingsForm):
|
||||
"""Request to change the settings of a specific service (will cause a restart)"""
|
||||
|
||||
if form.proto is not None and form.proto not in ["tcp", "udp"]:
|
||||
raise HTTPException(status_code=400, detail="Invalid protocol")
|
||||
|
||||
if form.port is not None and (form.port < 1 or form.port > 65535):
|
||||
raise HTTPException(status_code=400, detail="Invalid port")
|
||||
@@ -245,38 +245,38 @@ async def get_service_pyfilter_list(service_id: str):
|
||||
raise HTTPException(status_code=400, detail="This service does not exists!")
|
||||
return db.query("""
|
||||
SELECT
|
||||
filter_id, name, blocked_packets, edited_packets, active
|
||||
name, blocked_packets, edited_packets, active
|
||||
FROM pyfilter WHERE service_id = ?;
|
||||
""", service_id)
|
||||
|
||||
@app.get('/pyfilters/{filter_id}', response_model=PyFilterModel)
|
||||
async def get_pyfilter_by_id(filter_id: int):
|
||||
@app.get('/pyfilters/{filter_name}', response_model=PyFilterModel)
|
||||
async def get_pyfilter_by_id(filter_name: str):
|
||||
"""Get pyfilter info using his id"""
|
||||
res = db.query("""
|
||||
SELECT
|
||||
filter_id, name, blocked_packets, edited_packets, active
|
||||
FROM pyfilter WHERE filter_id = ?;
|
||||
""", filter_id)
|
||||
name, blocked_packets, edited_packets, active
|
||||
FROM pyfilter WHERE name = ?;
|
||||
""", filter_name)
|
||||
if len(res) == 0:
|
||||
raise HTTPException(status_code=400, detail="This filter does not exists!")
|
||||
return res[0]
|
||||
|
||||
@app.post('/pyfilters/{filter_id}/enable', response_model=StatusMessageModel)
|
||||
async def pyfilter_enable(filter_id: int):
|
||||
@app.post('/pyfilters/{filter_name}/enable', response_model=StatusMessageModel)
|
||||
async def pyfilter_enable(filter_name: str):
|
||||
"""Request the enabling of a pyfilter"""
|
||||
res = db.query('SELECT * FROM pyfilter WHERE filter_id = ?;', filter_id)
|
||||
res = db.query('SELECT * FROM pyfilter WHERE name = ?;', filter_name)
|
||||
if len(res) != 0:
|
||||
db.query('UPDATE pyfilter SET active=1 WHERE filter_id = ?;', filter_id)
|
||||
db.query('UPDATE pyfilter SET active=1 WHERE name = ?;', filter_name)
|
||||
await firewall.get(res[0]["service_id"]).update_filters()
|
||||
await refresh_frontend()
|
||||
return {'status': 'ok'}
|
||||
|
||||
@app.post('/pyfilters/{filter_id}/disable', response_model=StatusMessageModel)
|
||||
async def pyfilter_disable(filter_id: int):
|
||||
@app.post('/pyfilters/{filter_name}/disable', response_model=StatusMessageModel)
|
||||
async def pyfilter_disable(filter_name: str):
|
||||
"""Request the deactivation of a pyfilter"""
|
||||
res = db.query('SELECT * FROM pyfilter WHERE filter_id = ?;', filter_id)
|
||||
res = db.query('SELECT * FROM pyfilter WHERE name = ?;', filter_name)
|
||||
if len(res) != 0:
|
||||
db.query('UPDATE pyfilter SET active=0 WHERE filter_id = ?;', filter_id)
|
||||
db.query('UPDATE pyfilter SET active=0 WHERE name = ?;', filter_name)
|
||||
await firewall.get(res[0]["service_id"]).update_filters()
|
||||
await refresh_frontend()
|
||||
return {'status': 'ok'}
|
||||
@@ -293,8 +293,8 @@ async def add_new_service(form: ServiceAddForm):
|
||||
srv_id = None
|
||||
try:
|
||||
srv_id = gen_service_id()
|
||||
db.query("INSERT INTO services (service_id ,name, port, status, proto, ip_int, fail_open) VALUES (?, ?, ?, ?, ?, ?, ?)",
|
||||
srv_id, refactor_name(form.name), form.port, STATUS.STOP, form.proto, form.ip_int, form.fail_open)
|
||||
db.query("INSERT INTO services (service_id ,name, port, status, proto, ip_int, fail_open, l4_proto) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
srv_id, refactor_name(form.name), form.port, STATUS.STOP, form.proto, form.ip_int, form.fail_open, convert_protocol_to_l4(form.proto))
|
||||
except sqlite3.IntegrityError:
|
||||
raise HTTPException(status_code=400, detail="This type of service already exists")
|
||||
await firewall.reload()
|
||||
@@ -308,29 +308,41 @@ async def set_pyfilters(service_id: str, form: SetPyFilterForm):
|
||||
if len(service) == 0:
|
||||
raise HTTPException(status_code=400, detail="This service does not exists!")
|
||||
service = service[0]
|
||||
service_id = service["service_id"]
|
||||
srv_proto = service["proto"]
|
||||
|
||||
try:
|
||||
found_filters = get_filter_names(form.code, srv_proto)
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
async with asyncio.timeout(8):
|
||||
try:
|
||||
found_filters = get_filter_names(form.code, srv_proto)
|
||||
except Exception as e:
|
||||
if DEBUG:
|
||||
traceback.print_exc()
|
||||
raise HTTPException(status_code=400, detail="Compile error: "+str(e))
|
||||
|
||||
# Remove filters that are not in the new code
|
||||
existing_filters = db.query("SELECT name FROM pyfilter WHERE service_id = ?;", service_id)
|
||||
existing_filters = [ele["name"] for ele in existing_filters]
|
||||
for filter in existing_filters:
|
||||
if filter not in found_filters:
|
||||
db.query("DELETE FROM pyfilter WHERE name = ?;", filter)
|
||||
|
||||
# Add filters that are in the new code but not in the database
|
||||
for filter in found_filters:
|
||||
if not db.query("SELECT 1 FROM pyfilter WHERE service_id = ? AND name = ?;", service_id, filter):
|
||||
db.query("INSERT INTO pyfilter (name, service_id) VALUES (?, ?);", filter, service["service_id"])
|
||||
|
||||
# Eventually edited filters will be reloaded
|
||||
os.makedirs("db/nfproxy_filters", exist_ok=True)
|
||||
with open(f"db/nfproxy_filters/{service_id}.py", "w") as f:
|
||||
f.write(form.code)
|
||||
await firewall.get(service_id).update_filters()
|
||||
await refresh_frontend()
|
||||
except asyncio.TimeoutError:
|
||||
if DEBUG:
|
||||
traceback.print_exc()
|
||||
raise HTTPException(status_code=400, detail="The operation took too long")
|
||||
|
||||
# Remove filters that are not in the new code
|
||||
existing_filters = db.query("SELECT filter_id FROM pyfilter WHERE service_id = ?;", service_id)
|
||||
for filter in existing_filters:
|
||||
if filter["name"] not in found_filters:
|
||||
db.query("DELETE FROM pyfilter WHERE filter_id = ?;", filter["filter_id"])
|
||||
|
||||
# Add filters that are in the new code but not in the database
|
||||
for filter in found_filters:
|
||||
if not db.query("SELECT 1 FROM pyfilter WHERE service_id = ? AND name = ?;", service_id, filter):
|
||||
db.query("INSERT INTO pyfilter (name, service_id) VALUES (?, ?);", filter, service["service_id"])
|
||||
|
||||
# Eventually edited filters will be reloaded
|
||||
os.makedirs("db/nfproxy_filters", exist_ok=True)
|
||||
with open(f"db/nfproxy_filters/{service_id}.py", "w") as f:
|
||||
f.write(form.code)
|
||||
await firewall.get(service_id).update_filters()
|
||||
await refresh_frontend()
|
||||
return {'status': 'ok'}
|
||||
|
||||
@app.get('/services/{service_id}/pyfilters/code', response_class=PlainTextResponse)
|
||||
@@ -343,7 +355,3 @@ async def get_pyfilters(service_id: str):
|
||||
return f.read()
|
||||
except FileNotFoundError:
|
||||
return ""
|
||||
|
||||
#TODO check all the APIs and add
|
||||
# 1. API to change the python filter file (DONE)
|
||||
# 2. a socketio mechanism to lock the previous feature
|
||||
Reference in New Issue
Block a user