more RESTful APIs
This commit is contained in:
11
Dockerfile
11
Dockerfile
@@ -14,11 +14,10 @@ RUN bun run build
|
|||||||
|
|
||||||
|
|
||||||
#Building main conteiner
|
#Building main conteiner
|
||||||
FROM --platform=$TARGETARCH debian:trixie-slim AS base
|
FROM --platform=$TARGETARCH registry.fedoraproject.org/fedora:latest
|
||||||
RUN apt-get update -qq && apt-get upgrade -qq && \
|
RUN dnf -y update && dnf install -y python3-pip @development-tools gcc-c++ \
|
||||||
apt-get install -qq python3-pip build-essential \
|
libnetfilter_queue-devel libnfnetlink-devel libmnl-devel libcap-ng-utils \
|
||||||
libnetfilter-queue-dev libnfnetlink-dev libmnl-dev libcap2-bin\
|
nftables vectorscan-devel libtins-devel python3-nftables libpcap-devel boost-devel
|
||||||
nftables libvectorscan-dev libtins-dev python3-nftables
|
|
||||||
|
|
||||||
RUN mkdir -p /execute/modules
|
RUN mkdir -p /execute/modules
|
||||||
WORKDIR /execute
|
WORKDIR /execute
|
||||||
@@ -28,7 +27,7 @@ RUN pip3 install --no-cache-dir --break-system-packages -r /execute/requirements
|
|||||||
|
|
||||||
COPY ./backend/binsrc /execute/binsrc
|
COPY ./backend/binsrc /execute/binsrc
|
||||||
RUN g++ binsrc/nfqueue.cpp -o modules/cppqueue -std=c++23 -O3 -lnetfilter_queue -pthread -lnfnetlink $(pkg-config --cflags --libs libtins libhs libmnl)
|
RUN g++ binsrc/nfqueue.cpp -o modules/cppqueue -std=c++23 -O3 -lnetfilter_queue -pthread -lnfnetlink $(pkg-config --cflags --libs libtins libhs libmnl)
|
||||||
RUN g++ binsrc/nfproxy-tun.cpp -o modules/cppnfproxy -std=c++23 -O3 -lnetfilter_queue -pthread -lnfnetlink $(pkg-config --cflags --libs libtins libmnl)
|
#RUN g++ binsrc/nfproxy-tun.cpp -o modules/cppnfproxy -std=c++23 -O3 -lnetfilter_queue -pthread -lnfnetlink $(pkg-config --cflags --libs libtins libmnl)
|
||||||
|
|
||||||
COPY ./backend/ /execute/
|
COPY ./backend/ /execute/
|
||||||
COPY --from=frontend /app/dist/ ./frontend/
|
COPY --from=frontend /app/dist/ ./frontend/
|
||||||
|
|||||||
@@ -1,20 +1,14 @@
|
|||||||
#include <linux/netfilter/nfnetlink_queue.h>
|
#include <linux/netfilter/nfnetlink_queue.h>
|
||||||
#include <libnetfilter_queue/libnetfilter_queue.h>
|
#include <libnetfilter_queue/libnetfilter_queue.h>
|
||||||
#include <linux/netfilter/nfnetlink_conntrack.h>
|
#include <linux/netfilter/nfnetlink_conntrack.h>
|
||||||
#include <tins/tins.h>
|
|
||||||
#include <tins/tcp_ip/stream_follower.h>
|
|
||||||
#include <tins/tcp_ip/stream_identifier.h>
|
|
||||||
#include <libmnl/libmnl.h>
|
#include <libmnl/libmnl.h>
|
||||||
#include <linux/netfilter.h>
|
#include <linux/netfilter.h>
|
||||||
#include <linux/netfilter/nfnetlink.h>
|
#include <linux/netfilter/nfnetlink.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <hs.h>
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
using Tins::TCPIP::Stream;
|
|
||||||
using Tins::TCPIP::StreamFollower;
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
#ifndef NETFILTER_CLASS_CPP
|
#ifndef NETFILTER_CLASS_CPP
|
||||||
|
|||||||
@@ -133,10 +133,6 @@ class SocketTunnelQueue: public NfQueueExecutor {
|
|||||||
|
|
||||||
SocketTunnelQueue(int queue) : NfQueueExecutor(queue, &queue_cb) {}
|
SocketTunnelQueue(int queue) : NfQueueExecutor(queue, &queue_cb) {}
|
||||||
|
|
||||||
~SocketTunnelQueue() {
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // PROXY_TUNNEL_CPP
|
#endif // PROXY_TUNNEL_CPP
|
||||||
@@ -130,6 +130,7 @@ class FirewallManager:
|
|||||||
def allow_dhcp(self):
|
def allow_dhcp(self):
|
||||||
return self.db.get("allow_dhcp", "1") == "1"
|
return self.db.get("allow_dhcp", "1") == "1"
|
||||||
|
|
||||||
@drop_invalid.setter
|
@allow_dhcp.setter
|
||||||
def allow_dhcp_set(self, value):
|
def allow_dhcp(self, value):
|
||||||
self.db.set("allow_dhcp", "1" if value else "0")
|
self.db.set("allow_dhcp", "1" if value else "0")
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import traceback
|
|||||||
from utils import DEBUG
|
from utils import DEBUG
|
||||||
from fastapi import HTTPException
|
from fastapi import HTTPException
|
||||||
|
|
||||||
|
#TODO copied file, review
|
||||||
|
|
||||||
nft = FiregexTables()
|
nft = FiregexTables()
|
||||||
|
|
||||||
class RegexFilter:
|
class RegexFilter:
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ from modules.nfregex.nftables import FiregexTables, FiregexFilter
|
|||||||
from modules.nfregex.models import Regex, Service
|
from modules.nfregex.models import Regex, Service
|
||||||
from utils.sqlite import SQLite
|
from utils.sqlite import SQLite
|
||||||
|
|
||||||
|
#TODO copied file, review
|
||||||
|
|
||||||
class STATUS:
|
class STATUS:
|
||||||
STOP = "stop"
|
STOP = "stop"
|
||||||
ACTIVE = "active"
|
ACTIVE = "active"
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import base64
|
|
||||||
|
|
||||||
class Service:
|
class Service:
|
||||||
def __init__(self, service_id: str, status: str, port: int, name: str, proto: str, ip_int: str, **other):
|
def __init__(self, service_id: str, status: str, port: int, name: str, proto: str, ip_int: str, **other):
|
||||||
self.id = service_id
|
self.id = service_id
|
||||||
@@ -14,17 +12,14 @@ class Service:
|
|||||||
return cls(**var)
|
return cls(**var)
|
||||||
|
|
||||||
|
|
||||||
class Regex:
|
class PyFilter:
|
||||||
def __init__(self, regex_id: int, regex: bytes, mode: str, service_id: str, blocked_packets: int, is_case_sensitive: bool, active: bool, **other):
|
def __init__(self, filter_id:int, name: str, blocked_packets: int, edited_packets: int, active: bool, **other):
|
||||||
self.regex = regex
|
self.filter_id = filter_id
|
||||||
self.mode = mode
|
self.name = name
|
||||||
self.service_id = service_id
|
|
||||||
self.blocked_packets = blocked_packets
|
self.blocked_packets = blocked_packets
|
||||||
self.id = regex_id
|
self.edited_packets = edited_packets
|
||||||
self.is_case_sensitive = is_case_sensitive
|
|
||||||
self.active = active
|
self.active = active
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_dict(cls, var: dict):
|
def from_dict(cls, var: dict):
|
||||||
var['regex'] = base64.b64decode(var['regex'])
|
|
||||||
return cls(**var)
|
return cls(**var)
|
||||||
@@ -71,7 +71,7 @@ async def get_settings():
|
|||||||
"""Get the firewall settings"""
|
"""Get the firewall settings"""
|
||||||
return firewall.settings
|
return firewall.settings
|
||||||
|
|
||||||
@app.post("/settings/set", response_model=StatusMessageModel)
|
@app.put("/settings", response_model=StatusMessageModel)
|
||||||
async def set_settings(form: FirewallSettings):
|
async def set_settings(form: FirewallSettings):
|
||||||
"""Set the firewall settings"""
|
"""Set the firewall settings"""
|
||||||
firewall.settings = form
|
firewall.settings = form
|
||||||
@@ -86,13 +86,13 @@ async def get_rule_list():
|
|||||||
"enabled": firewall.enabled
|
"enabled": firewall.enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
@app.get('/enable', response_model=StatusMessageModel)
|
@app.post('/enable', response_model=StatusMessageModel)
|
||||||
async def enable_firewall():
|
async def enable_firewall():
|
||||||
"""Request enabling the firewall"""
|
"""Request enabling the firewall"""
|
||||||
firewall.enabled = True
|
firewall.enabled = True
|
||||||
return await apply_changes()
|
return await apply_changes()
|
||||||
|
|
||||||
@app.get('/disable', response_model=StatusMessageModel)
|
@app.post('/disable', response_model=StatusMessageModel)
|
||||||
async def disable_firewall():
|
async def disable_firewall():
|
||||||
"""Request disabling the firewall"""
|
"""Request disabling the firewall"""
|
||||||
firewall.enabled = False
|
firewall.enabled = False
|
||||||
@@ -128,9 +128,9 @@ def parse_and_check_rule(rule:RuleModel):
|
|||||||
|
|
||||||
return rule
|
return rule
|
||||||
|
|
||||||
@app.post('/rules/set', response_model=StatusMessageModel)
|
@app.post('/rules', response_model=StatusMessageModel)
|
||||||
async def add_new_service(form: RuleFormAdd):
|
async def add_new_service(form: RuleFormAdd):
|
||||||
"""Add a new service"""
|
"""Edit rule table"""
|
||||||
rules = [parse_and_check_rule(ele) for ele in form.rules]
|
rules = [parse_and_check_rule(ele) for ele in form.rules]
|
||||||
try:
|
try:
|
||||||
db.queries(["DELETE FROM rules"]+
|
db.queries(["DELETE FROM rules"]+
|
||||||
|
|||||||
260
backend/routers/nfproxy.py
Normal file
260
backend/routers/nfproxy.py
Normal file
@@ -0,0 +1,260 @@
|
|||||||
|
import secrets
|
||||||
|
import sqlite3
|
||||||
|
from fastapi import APIRouter, HTTPException
|
||||||
|
from pydantic import BaseModel
|
||||||
|
from modules.nfproxy.nftables import FiregexTables
|
||||||
|
from modules.nfproxy.firewall import STATUS, FirewallManager
|
||||||
|
from utils.sqlite import SQLite
|
||||||
|
from utils import ip_parse, refactor_name, socketio_emit, PortType
|
||||||
|
from utils.models import ResetRequest, StatusMessageModel
|
||||||
|
|
||||||
|
# TODO copied file, review
|
||||||
|
class ServiceModel(BaseModel):
|
||||||
|
service_id: str
|
||||||
|
status: str
|
||||||
|
port: PortType
|
||||||
|
name: str
|
||||||
|
proto: str
|
||||||
|
ip_int: str
|
||||||
|
n_filters: int
|
||||||
|
edited_packets: int
|
||||||
|
blocked_packets: int
|
||||||
|
|
||||||
|
class RenameForm(BaseModel):
|
||||||
|
name:str
|
||||||
|
|
||||||
|
class PyFilterModel(BaseModel):
|
||||||
|
filter_id: int
|
||||||
|
name: str
|
||||||
|
blocked_packets: int
|
||||||
|
edited_packets: int
|
||||||
|
active: bool
|
||||||
|
|
||||||
|
class ServiceAddForm(BaseModel):
|
||||||
|
name: str
|
||||||
|
port: PortType
|
||||||
|
proto: str
|
||||||
|
ip_int: str
|
||||||
|
|
||||||
|
class ServiceAddResponse(BaseModel):
|
||||||
|
status:str
|
||||||
|
service_id: str|None = None
|
||||||
|
|
||||||
|
app = APIRouter()
|
||||||
|
|
||||||
|
db = SQLite('db/nft-pyfilters.db', {
|
||||||
|
'services': {
|
||||||
|
'service_id': 'VARCHAR(100) PRIMARY KEY',
|
||||||
|
'status': 'VARCHAR(100) NOT NULL',
|
||||||
|
'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"))',
|
||||||
|
'ip_int': 'VARCHAR(100) NOT NULL',
|
||||||
|
},
|
||||||
|
'pyfilter': {
|
||||||
|
'filter_id': 'INTEGER PRIMARY KEY',
|
||||||
|
'name': 'VARCHAR(100) NOT NULL',
|
||||||
|
'blocked_packets': 'INTEGER UNSIGNED NOT NULL DEFAULT 0',
|
||||||
|
'edited_packets': 'INTEGER UNSIGNED NOT NULL DEFAULT 0',
|
||||||
|
'service_id': 'VARCHAR(100) NOT NULL',
|
||||||
|
'active' : 'BOOLEAN NOT NULL CHECK (active IN (0, 1)) DEFAULT 1',
|
||||||
|
'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_pyfilter_service ON pyfilter (name, service_id);"
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
async def refresh_frontend(additional:list[str]=[]):
|
||||||
|
await socketio_emit(["nfproxy"]+additional)
|
||||||
|
|
||||||
|
async def reset(params: ResetRequest):
|
||||||
|
if not params.delete:
|
||||||
|
db.backup()
|
||||||
|
await firewall.close()
|
||||||
|
FiregexTables().reset()
|
||||||
|
if params.delete:
|
||||||
|
db.delete()
|
||||||
|
db.init()
|
||||||
|
else:
|
||||||
|
db.restore()
|
||||||
|
try:
|
||||||
|
await firewall.init()
|
||||||
|
except Exception as e:
|
||||||
|
raise HTTPException(status_code=500, detail=str(e))
|
||||||
|
|
||||||
|
async def startup():
|
||||||
|
db.init()
|
||||||
|
try:
|
||||||
|
await firewall.init()
|
||||||
|
except Exception as e:
|
||||||
|
print("WARNING cannot start firewall:", e)
|
||||||
|
|
||||||
|
async def shutdown():
|
||||||
|
db.backup()
|
||||||
|
await firewall.close()
|
||||||
|
db.disconnect()
|
||||||
|
db.restore()
|
||||||
|
|
||||||
|
def gen_service_id():
|
||||||
|
while True:
|
||||||
|
res = secrets.token_hex(8)
|
||||||
|
if len(db.query('SELECT 1 FROM services WHERE service_id = ?;', res)) == 0:
|
||||||
|
break
|
||||||
|
return res
|
||||||
|
|
||||||
|
firewall = FirewallManager(db)
|
||||||
|
|
||||||
|
@app.get('/services', response_model=list[ServiceModel])
|
||||||
|
async def get_service_list():
|
||||||
|
"""Get the list of existent firegex services"""
|
||||||
|
return db.query("""
|
||||||
|
SELECT
|
||||||
|
s.service_id service_id,
|
||||||
|
s.status status,
|
||||||
|
s.port port,
|
||||||
|
s.name name,
|
||||||
|
s.proto proto,
|
||||||
|
s.ip_int ip_int,
|
||||||
|
COUNT(f.filter_id) 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
|
||||||
|
GROUP BY s.service_id;
|
||||||
|
""")
|
||||||
|
|
||||||
|
@app.get('/services/{service_id}', response_model=ServiceModel)
|
||||||
|
async def get_service_by_id(service_id: str):
|
||||||
|
"""Get info about a specific service using his id"""
|
||||||
|
res = db.query("""
|
||||||
|
SELECT
|
||||||
|
s.service_id service_id,
|
||||||
|
s.status status,
|
||||||
|
s.port port,
|
||||||
|
s.name name,
|
||||||
|
s.proto proto,
|
||||||
|
s.ip_int ip_int,
|
||||||
|
COUNT(f.filter_id) 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
|
||||||
|
WHERE s.service_id = ? GROUP BY s.service_id;
|
||||||
|
""", service_id)
|
||||||
|
if len(res) == 0:
|
||||||
|
raise HTTPException(status_code=400, detail="This service does not exists!")
|
||||||
|
return res[0]
|
||||||
|
|
||||||
|
@app.post('/services/{service_id}/stop', response_model=StatusMessageModel)
|
||||||
|
async def service_stop(service_id: str):
|
||||||
|
"""Request the stop of a specific service"""
|
||||||
|
await firewall.get(service_id).next(STATUS.STOP)
|
||||||
|
await refresh_frontend()
|
||||||
|
return {'status': 'ok'}
|
||||||
|
|
||||||
|
@app.post('/services/{service_id}/start', response_model=StatusMessageModel)
|
||||||
|
async def service_start(service_id: str):
|
||||||
|
"""Request the start of a specific service"""
|
||||||
|
await firewall.get(service_id).next(STATUS.ACTIVE)
|
||||||
|
await refresh_frontend()
|
||||||
|
return {'status': 'ok'}
|
||||||
|
|
||||||
|
@app.delete('/services/{service_id}', response_model=StatusMessageModel)
|
||||||
|
async def service_delete(service_id: str):
|
||||||
|
"""Request the deletion of a specific service"""
|
||||||
|
db.query('DELETE FROM services WHERE service_id = ?;', service_id)
|
||||||
|
db.query('DELETE FROM pyfilter WHERE service_id = ?;', service_id)
|
||||||
|
await firewall.remove(service_id)
|
||||||
|
await refresh_frontend()
|
||||||
|
return {'status': 'ok'}
|
||||||
|
|
||||||
|
@app.put('/services/{service_id}/rename', response_model=StatusMessageModel)
|
||||||
|
async def service_rename(service_id: str, form: RenameForm):
|
||||||
|
"""Request to change the name of a specific service"""
|
||||||
|
form.name = refactor_name(form.name)
|
||||||
|
if not form.name:
|
||||||
|
raise HTTPException(status_code=400, detail="The name cannot be empty!")
|
||||||
|
try:
|
||||||
|
db.query('UPDATE services SET name=? WHERE service_id = ?;', form.name, service_id)
|
||||||
|
except sqlite3.IntegrityError:
|
||||||
|
raise HTTPException(status_code=400, detail="This name is already used")
|
||||||
|
await refresh_frontend()
|
||||||
|
return {'status': 'ok'}
|
||||||
|
|
||||||
|
@app.get('/services/{service_id}/pyfilters', response_model=list[PyFilterModel])
|
||||||
|
async def get_service_pyfilter_list(service_id: str):
|
||||||
|
"""Get the list of the pyfilters of a service"""
|
||||||
|
if not db.query("SELECT 1 FROM services s WHERE s.service_id = ?;", service_id):
|
||||||
|
raise HTTPException(status_code=400, detail="This service does not exists!")
|
||||||
|
return db.query("""
|
||||||
|
SELECT
|
||||||
|
filter_id, 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):
|
||||||
|
"""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)
|
||||||
|
if len(res) == 0:
|
||||||
|
raise HTTPException(status_code=400, detail="This filter does not exists!")
|
||||||
|
return res[0]
|
||||||
|
|
||||||
|
@app.delete('/pyfilters/{filter_id}', response_model=StatusMessageModel)
|
||||||
|
async def pyfilter_delete(filter_id: int):
|
||||||
|
"""Delete a pyfilter using his id"""
|
||||||
|
res = db.query('SELECT * FROM pyfilter WHERE filter_id = ?;', filter_id)
|
||||||
|
if len(res) != 0:
|
||||||
|
db.query('DELETE FROM pyfilter WHERE filter_id = ?;', filter_id)
|
||||||
|
await firewall.get(res[0]["service_id"]).update_filters()
|
||||||
|
await refresh_frontend()
|
||||||
|
|
||||||
|
return {'status': 'ok'}
|
||||||
|
|
||||||
|
@app.post('/pyfilters/{filter_id}/enable', response_model=StatusMessageModel)
|
||||||
|
async def pyfilter_enable(filter_id: int):
|
||||||
|
"""Request the enabling of a pyfilter"""
|
||||||
|
res = db.query('SELECT * FROM pyfilter WHERE filter_id = ?;', filter_id)
|
||||||
|
if len(res) != 0:
|
||||||
|
db.query('UPDATE pyfilter SET active=1 WHERE filter_id = ?;', filter_id)
|
||||||
|
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):
|
||||||
|
"""Request the deactivation of a pyfilter"""
|
||||||
|
res = db.query('SELECT * FROM pyfilter WHERE filter_id = ?;', filter_id)
|
||||||
|
if len(res) != 0:
|
||||||
|
db.query('UPDATE pyfilter SET active=0 WHERE filter_id = ?;', filter_id)
|
||||||
|
await firewall.get(res[0]["service_id"]).update_filters()
|
||||||
|
await refresh_frontend()
|
||||||
|
return {'status': 'ok'}
|
||||||
|
|
||||||
|
@app.post('/services', response_model=ServiceAddResponse)
|
||||||
|
async def add_new_service(form: ServiceAddForm):
|
||||||
|
"""Add a new service"""
|
||||||
|
try:
|
||||||
|
form.ip_int = ip_parse(form.ip_int)
|
||||||
|
except ValueError:
|
||||||
|
raise HTTPException(status_code=400, detail="Invalid address")
|
||||||
|
if form.proto not in ["tcp", "http"]:
|
||||||
|
raise HTTPException(status_code=400, detail="Invalid protocol")
|
||||||
|
srv_id = None
|
||||||
|
try:
|
||||||
|
srv_id = gen_service_id()
|
||||||
|
db.query("INSERT INTO services (service_id ,name, port, status, proto, ip_int) VALUES (?, ?, ?, ?, ?, ?)",
|
||||||
|
srv_id, refactor_name(form.name), form.port, STATUS.STOP, form.proto, form.ip_int)
|
||||||
|
except sqlite3.IntegrityError:
|
||||||
|
raise HTTPException(status_code=400, detail="This type of service already exists")
|
||||||
|
await firewall.reload()
|
||||||
|
await refresh_frontend()
|
||||||
|
return {'status': 'ok', 'service_id': srv_id}
|
||||||
|
|
||||||
|
#TODO check all the APIs and add
|
||||||
|
# 1. API to change the python filter file
|
||||||
|
# 2. a socketio mechanism to lock the previous feature
|
||||||
@@ -134,7 +134,7 @@ async def get_service_list():
|
|||||||
GROUP BY s.service_id;
|
GROUP BY s.service_id;
|
||||||
""")
|
""")
|
||||||
|
|
||||||
@app.get('/service/{service_id}', response_model=ServiceModel)
|
@app.get('/services/{service_id}', response_model=ServiceModel)
|
||||||
async def get_service_by_id(service_id: str):
|
async def get_service_by_id(service_id: str):
|
||||||
"""Get info about a specific service using his id"""
|
"""Get info about a specific service using his id"""
|
||||||
res = db.query("""
|
res = db.query("""
|
||||||
@@ -154,21 +154,21 @@ async def get_service_by_id(service_id: str):
|
|||||||
raise HTTPException(status_code=400, detail="This service does not exists!")
|
raise HTTPException(status_code=400, detail="This service does not exists!")
|
||||||
return res[0]
|
return res[0]
|
||||||
|
|
||||||
@app.get('/service/{service_id}/stop', response_model=StatusMessageModel)
|
@app.post('/services/{service_id}/stop', response_model=StatusMessageModel)
|
||||||
async def service_stop(service_id: str):
|
async def service_stop(service_id: str):
|
||||||
"""Request the stop of a specific service"""
|
"""Request the stop of a specific service"""
|
||||||
await firewall.get(service_id).next(STATUS.STOP)
|
await firewall.get(service_id).next(STATUS.STOP)
|
||||||
await refresh_frontend()
|
await refresh_frontend()
|
||||||
return {'status': 'ok'}
|
return {'status': 'ok'}
|
||||||
|
|
||||||
@app.get('/service/{service_id}/start', response_model=StatusMessageModel)
|
@app.post('/services/{service_id}/start', response_model=StatusMessageModel)
|
||||||
async def service_start(service_id: str):
|
async def service_start(service_id: str):
|
||||||
"""Request the start of a specific service"""
|
"""Request the start of a specific service"""
|
||||||
await firewall.get(service_id).next(STATUS.ACTIVE)
|
await firewall.get(service_id).next(STATUS.ACTIVE)
|
||||||
await refresh_frontend()
|
await refresh_frontend()
|
||||||
return {'status': 'ok'}
|
return {'status': 'ok'}
|
||||||
|
|
||||||
@app.get('/service/{service_id}/delete', response_model=StatusMessageModel)
|
@app.delete('/services/{service_id}', response_model=StatusMessageModel)
|
||||||
async def service_delete(service_id: str):
|
async def service_delete(service_id: str):
|
||||||
"""Request the deletion of a specific service"""
|
"""Request the deletion of a specific service"""
|
||||||
db.query('DELETE FROM services WHERE service_id = ?;', service_id)
|
db.query('DELETE FROM services WHERE service_id = ?;', service_id)
|
||||||
@@ -177,7 +177,7 @@ async def service_delete(service_id: str):
|
|||||||
await refresh_frontend()
|
await refresh_frontend()
|
||||||
return {'status': 'ok'}
|
return {'status': 'ok'}
|
||||||
|
|
||||||
@app.post('/service/{service_id}/rename', response_model=StatusMessageModel)
|
@app.put('/services/{service_id}/rename', response_model=StatusMessageModel)
|
||||||
async def service_rename(service_id: str, form: RenameForm):
|
async def service_rename(service_id: str, form: RenameForm):
|
||||||
"""Request to change the name of a specific service"""
|
"""Request to change the name of a specific service"""
|
||||||
form.name = refactor_name(form.name)
|
form.name = refactor_name(form.name)
|
||||||
@@ -190,7 +190,7 @@ async def service_rename(service_id: str, form: RenameForm):
|
|||||||
await refresh_frontend()
|
await refresh_frontend()
|
||||||
return {'status': 'ok'}
|
return {'status': 'ok'}
|
||||||
|
|
||||||
@app.get('/service/{service_id}/regexes', response_model=list[RegexModel])
|
@app.get('/services/{service_id}/regexes', response_model=list[RegexModel])
|
||||||
async def get_service_regexe_list(service_id: str):
|
async def get_service_regexe_list(service_id: str):
|
||||||
"""Get the list of the regexes of a service"""
|
"""Get the list of the regexes of a service"""
|
||||||
if not db.query("SELECT 1 FROM services s WHERE s.service_id = ?;", service_id):
|
if not db.query("SELECT 1 FROM services s WHERE s.service_id = ?;", service_id):
|
||||||
@@ -202,7 +202,7 @@ async def get_service_regexe_list(service_id: str):
|
|||||||
FROM regexes WHERE service_id = ?;
|
FROM regexes WHERE service_id = ?;
|
||||||
""", service_id)
|
""", service_id)
|
||||||
|
|
||||||
@app.get('/regex/{regex_id}', response_model=RegexModel)
|
@app.get('/regexes/{regex_id}', response_model=RegexModel)
|
||||||
async def get_regex_by_id(regex_id: int):
|
async def get_regex_by_id(regex_id: int):
|
||||||
"""Get regex info using his id"""
|
"""Get regex info using his id"""
|
||||||
res = db.query("""
|
res = db.query("""
|
||||||
@@ -215,7 +215,7 @@ async def get_regex_by_id(regex_id: int):
|
|||||||
raise HTTPException(status_code=400, detail="This regex does not exists!")
|
raise HTTPException(status_code=400, detail="This regex does not exists!")
|
||||||
return res[0]
|
return res[0]
|
||||||
|
|
||||||
@app.get('/regex/{regex_id}/delete', response_model=StatusMessageModel)
|
@app.delete('/regexes/{regex_id}', response_model=StatusMessageModel)
|
||||||
async def regex_delete(regex_id: int):
|
async def regex_delete(regex_id: int):
|
||||||
"""Delete a regex using his id"""
|
"""Delete a regex using his id"""
|
||||||
res = db.query('SELECT * FROM regexes WHERE regex_id = ?;', regex_id)
|
res = db.query('SELECT * FROM regexes WHERE regex_id = ?;', regex_id)
|
||||||
@@ -226,7 +226,7 @@ async def regex_delete(regex_id: int):
|
|||||||
|
|
||||||
return {'status': 'ok'}
|
return {'status': 'ok'}
|
||||||
|
|
||||||
@app.get('/regex/{regex_id}/enable', response_model=StatusMessageModel)
|
@app.post('/regexes/{regex_id}/enable', response_model=StatusMessageModel)
|
||||||
async def regex_enable(regex_id: int):
|
async def regex_enable(regex_id: int):
|
||||||
"""Request the enabling of a regex"""
|
"""Request the enabling of a regex"""
|
||||||
res = db.query('SELECT * FROM regexes WHERE regex_id = ?;', regex_id)
|
res = db.query('SELECT * FROM regexes WHERE regex_id = ?;', regex_id)
|
||||||
@@ -236,7 +236,7 @@ async def regex_enable(regex_id: int):
|
|||||||
await refresh_frontend()
|
await refresh_frontend()
|
||||||
return {'status': 'ok'}
|
return {'status': 'ok'}
|
||||||
|
|
||||||
@app.get('/regex/{regex_id}/disable', response_model=StatusMessageModel)
|
@app.post('/regexes/{regex_id}/disable', response_model=StatusMessageModel)
|
||||||
async def regex_disable(regex_id: int):
|
async def regex_disable(regex_id: int):
|
||||||
"""Request the deactivation of a regex"""
|
"""Request the deactivation of a regex"""
|
||||||
res = db.query('SELECT * FROM regexes WHERE regex_id = ?;', regex_id)
|
res = db.query('SELECT * FROM regexes WHERE regex_id = ?;', regex_id)
|
||||||
@@ -246,7 +246,7 @@ async def regex_disable(regex_id: int):
|
|||||||
await refresh_frontend()
|
await refresh_frontend()
|
||||||
return {'status': 'ok'}
|
return {'status': 'ok'}
|
||||||
|
|
||||||
@app.post('/regexes/add', response_model=StatusMessageModel)
|
@app.post('/regexes', response_model=StatusMessageModel)
|
||||||
async def add_new_regex(form: RegexAddForm):
|
async def add_new_regex(form: RegexAddForm):
|
||||||
"""Add a new regex"""
|
"""Add a new regex"""
|
||||||
try:
|
try:
|
||||||
@@ -263,7 +263,7 @@ async def add_new_regex(form: RegexAddForm):
|
|||||||
await refresh_frontend()
|
await refresh_frontend()
|
||||||
return {'status': 'ok'}
|
return {'status': 'ok'}
|
||||||
|
|
||||||
@app.post('/services/add', response_model=ServiceAddResponse)
|
@app.post('/services', response_model=ServiceAddResponse)
|
||||||
async def add_new_service(form: ServiceAddForm):
|
async def add_new_service(form: ServiceAddForm):
|
||||||
"""Add a new service"""
|
"""Add a new service"""
|
||||||
try:
|
try:
|
||||||
@@ -299,7 +299,8 @@ async def metrics():
|
|||||||
FROM regexes r LEFT JOIN services s ON s.service_id = r.service_id;
|
FROM regexes r LEFT JOIN services s ON s.service_id = r.service_id;
|
||||||
""")
|
""")
|
||||||
metrics = []
|
metrics = []
|
||||||
sanitize = lambda s : s.replace('\\', '\\\\').replace('"', '\\"').replace('\n', '\\n')
|
def sanitize(s):
|
||||||
|
return s.replace('\\', '\\\\').replace('"', '\\"').replace('\n', '\\n')
|
||||||
for stat in stats:
|
for stat in stats:
|
||||||
props = f'service_name="{sanitize(stat["name"])}",regex="{sanitize(b64decode(stat["regex"]).decode())}",mode="{stat["mode"]}",is_case_sensitive="{stat["is_case_sensitive"]}"'
|
props = f'service_name="{sanitize(stat["name"])}",regex="{sanitize(b64decode(stat["regex"]).decode())}",mode="{stat["mode"]}",is_case_sensitive="{stat["is_case_sensitive"]}"'
|
||||||
metrics.append(f'firegex_blocked_packets{{{props}}} {stat["blocked_packets"]}')
|
metrics.append(f'firegex_blocked_packets{{{props}}} {stat["blocked_packets"]}')
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ async def get_service_list():
|
|||||||
"""Get the list of existent firegex services"""
|
"""Get the list of existent firegex services"""
|
||||||
return db.query("SELECT service_id, active, public_port, proxy_port, name, proto, ip_src, ip_dst FROM services;")
|
return db.query("SELECT service_id, active, public_port, proxy_port, name, proto, ip_src, ip_dst FROM services;")
|
||||||
|
|
||||||
@app.get('/service/{service_id}', response_model=ServiceModel)
|
@app.get('/services/{service_id}', response_model=ServiceModel)
|
||||||
async def get_service_by_id(service_id: str):
|
async def get_service_by_id(service_id: str):
|
||||||
"""Get info about a specific service using his id"""
|
"""Get info about a specific service using his id"""
|
||||||
res = db.query("SELECT service_id, active, public_port, proxy_port, name, proto, ip_src, ip_dst FROM services WHERE service_id = ?;", service_id)
|
res = db.query("SELECT service_id, active, public_port, proxy_port, name, proto, ip_src, ip_dst FROM services WHERE service_id = ?;", service_id)
|
||||||
@@ -100,21 +100,21 @@ async def get_service_by_id(service_id: str):
|
|||||||
raise HTTPException(status_code=400, detail="This service does not exists!")
|
raise HTTPException(status_code=400, detail="This service does not exists!")
|
||||||
return res[0]
|
return res[0]
|
||||||
|
|
||||||
@app.get('/service/{service_id}/stop', response_model=StatusMessageModel)
|
@app.post('/services/{service_id}/stop', response_model=StatusMessageModel)
|
||||||
async def service_stop(service_id: str):
|
async def service_stop(service_id: str):
|
||||||
"""Request the stop of a specific service"""
|
"""Request the stop of a specific service"""
|
||||||
await firewall.get(service_id).disable()
|
await firewall.get(service_id).disable()
|
||||||
await refresh_frontend()
|
await refresh_frontend()
|
||||||
return {'status': 'ok'}
|
return {'status': 'ok'}
|
||||||
|
|
||||||
@app.get('/service/{service_id}/start', response_model=StatusMessageModel)
|
@app.post('/services/{service_id}/start', response_model=StatusMessageModel)
|
||||||
async def service_start(service_id: str):
|
async def service_start(service_id: str):
|
||||||
"""Request the start of a specific service"""
|
"""Request the start of a specific service"""
|
||||||
await firewall.get(service_id).enable()
|
await firewall.get(service_id).enable()
|
||||||
await refresh_frontend()
|
await refresh_frontend()
|
||||||
return {'status': 'ok'}
|
return {'status': 'ok'}
|
||||||
|
|
||||||
@app.get('/service/{service_id}/delete', response_model=StatusMessageModel)
|
@app.delete('/services/{service_id}', response_model=StatusMessageModel)
|
||||||
async def service_delete(service_id: str):
|
async def service_delete(service_id: str):
|
||||||
"""Request the deletion of a specific service"""
|
"""Request the deletion of a specific service"""
|
||||||
db.query('DELETE FROM services WHERE service_id = ?;', service_id)
|
db.query('DELETE FROM services WHERE service_id = ?;', service_id)
|
||||||
@@ -122,7 +122,7 @@ async def service_delete(service_id: str):
|
|||||||
await refresh_frontend()
|
await refresh_frontend()
|
||||||
return {'status': 'ok'}
|
return {'status': 'ok'}
|
||||||
|
|
||||||
@app.post('/service/{service_id}/rename', response_model=StatusMessageModel)
|
@app.put('/services/{service_id}/rename', response_model=StatusMessageModel)
|
||||||
async def service_rename(service_id: str, form: RenameForm):
|
async def service_rename(service_id: str, form: RenameForm):
|
||||||
"""Request to change the name of a specific service"""
|
"""Request to change the name of a specific service"""
|
||||||
form.name = refactor_name(form.name)
|
form.name = refactor_name(form.name)
|
||||||
@@ -139,7 +139,7 @@ class ChangeDestination(BaseModel):
|
|||||||
ip_dst: str
|
ip_dst: str
|
||||||
proxy_port: PortType
|
proxy_port: PortType
|
||||||
|
|
||||||
@app.post('/service/{service_id}/change-destination', response_model=StatusMessageModel)
|
@app.put('/services/{service_id}/change-destination', response_model=StatusMessageModel)
|
||||||
async def service_change_destination(service_id: str, form: ChangeDestination):
|
async def service_change_destination(service_id: str, form: ChangeDestination):
|
||||||
"""Request to change the proxy destination of the service"""
|
"""Request to change the proxy destination of the service"""
|
||||||
|
|
||||||
@@ -162,7 +162,7 @@ async def service_change_destination(service_id: str, form: ChangeDestination):
|
|||||||
await refresh_frontend()
|
await refresh_frontend()
|
||||||
return {'status': 'ok'}
|
return {'status': 'ok'}
|
||||||
|
|
||||||
@app.post('/services/add', response_model=ServiceAddResponse)
|
@app.post('/services', response_model=ServiceAddResponse)
|
||||||
async def add_new_service(form: ServiceAddForm):
|
async def add_new_service(form: ServiceAddForm):
|
||||||
"""Add a new service"""
|
"""Add a new service"""
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useQuery } from "@tanstack/react-query"
|
import { useQuery } from "@tanstack/react-query"
|
||||||
import { ServerResponse } from "../../js/models"
|
import { ServerResponse } from "../../js/models"
|
||||||
import { getapi, postapi } from "../../js/utils"
|
import { getapi, postapi, putapi } from "../../js/utils"
|
||||||
|
|
||||||
export enum Protocol {
|
export enum Protocol {
|
||||||
TCP = "tcp",
|
TCP = "tcp",
|
||||||
@@ -79,15 +79,15 @@ export const firewall = {
|
|||||||
return await getapi("firewall/settings") as FirewallSettings;
|
return await getapi("firewall/settings") as FirewallSettings;
|
||||||
},
|
},
|
||||||
setsettings: async(data:FirewallSettings) => {
|
setsettings: async(data:FirewallSettings) => {
|
||||||
return await postapi("firewall/settings/set", data) as ServerResponse;
|
return await putapi("firewall/settings", data) as ServerResponse;
|
||||||
},
|
},
|
||||||
enable: async() => {
|
enable: async() => {
|
||||||
return await getapi("firewall/enable") as ServerResponse;
|
return await postapi("firewall/enable") as ServerResponse;
|
||||||
},
|
},
|
||||||
disable: async() => {
|
disable: async() => {
|
||||||
return await getapi("firewall/disable") as ServerResponse;
|
return await postapi("firewall/disable") as ServerResponse;
|
||||||
},
|
},
|
||||||
ruleset: async (data:RuleAddForm) => {
|
ruleset: async (data:RuleAddForm) => {
|
||||||
return await postapi("firewall/rules/set", data) as ServerResponseListed;
|
return await postapi("firewall/rules", data) as ServerResponseListed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { RegexFilter, ServerResponse } from "../../js/models"
|
import { RegexFilter, ServerResponse } from "../../js/models"
|
||||||
import { getapi, postapi } from "../../js/utils"
|
import { deleteapi, getapi, postapi, putapi } from "../../js/utils"
|
||||||
import { RegexAddForm } from "../../js/models"
|
import { RegexAddForm } from "../../js/models"
|
||||||
import { useQuery, useQueryClient } from "@tanstack/react-query"
|
import { useQuery, useQueryClient } from "@tanstack/react-query"
|
||||||
|
|
||||||
@@ -40,44 +40,44 @@ export const nfregex = {
|
|||||||
return await getapi("nfregex/services") as Service[];
|
return await getapi("nfregex/services") as Service[];
|
||||||
},
|
},
|
||||||
serviceinfo: async (service_id:string) => {
|
serviceinfo: async (service_id:string) => {
|
||||||
return await getapi(`nfregex/service/${service_id}`) as Service;
|
return await getapi(`nfregex/services/${service_id}`) as Service;
|
||||||
},
|
},
|
||||||
regexdelete: async (regex_id:number) => {
|
regexdelete: async (regex_id:number) => {
|
||||||
const { status } = await getapi(`nfregex/regex/${regex_id}/delete`) as ServerResponse;
|
const { status } = await deleteapi(`nfregex/regexes/${regex_id}`) as ServerResponse;
|
||||||
return status === "ok"?undefined:status
|
return status === "ok"?undefined:status
|
||||||
},
|
},
|
||||||
regexenable: async (regex_id:number) => {
|
regexenable: async (regex_id:number) => {
|
||||||
const { status } = await getapi(`nfregex/regex/${regex_id}/enable`) as ServerResponse;
|
const { status } = await postapi(`nfregex/regexes/${regex_id}/enable`) as ServerResponse;
|
||||||
return status === "ok"?undefined:status
|
return status === "ok"?undefined:status
|
||||||
},
|
},
|
||||||
regexdisable: async (regex_id:number) => {
|
regexdisable: async (regex_id:number) => {
|
||||||
const { status } = await getapi(`nfregex/regex/${regex_id}/disable`) as ServerResponse;
|
const { status } = await postapi(`nfregex/regexes/${regex_id}/disable`) as ServerResponse;
|
||||||
return status === "ok"?undefined:status
|
return status === "ok"?undefined:status
|
||||||
},
|
},
|
||||||
servicestart: async (service_id:string) => {
|
servicestart: async (service_id:string) => {
|
||||||
const { status } = await getapi(`nfregex/service/${service_id}/start`) as ServerResponse;
|
const { status } = await postapi(`nfregex/services/${service_id}/start`) as ServerResponse;
|
||||||
return status === "ok"?undefined:status
|
return status === "ok"?undefined:status
|
||||||
},
|
},
|
||||||
servicerename: async (service_id:string, name: string) => {
|
servicerename: async (service_id:string, name: string) => {
|
||||||
const { status } = await postapi(`nfregex/service/${service_id}/rename`,{ name }) as ServerResponse;
|
const { status } = await putapi(`nfregex/services/${service_id}/rename`,{ name }) as ServerResponse;
|
||||||
return status === "ok"?undefined:status
|
return status === "ok"?undefined:status
|
||||||
},
|
},
|
||||||
servicestop: async (service_id:string) => {
|
servicestop: async (service_id:string) => {
|
||||||
const { status } = await getapi(`nfregex/service/${service_id}/stop`) as ServerResponse;
|
const { status } = await postapi(`nfregex/services/${service_id}/stop`) as ServerResponse;
|
||||||
return status === "ok"?undefined:status
|
return status === "ok"?undefined:status
|
||||||
},
|
},
|
||||||
servicesadd: async (data:ServiceAddForm) => {
|
servicesadd: async (data:ServiceAddForm) => {
|
||||||
return await postapi("nfregex/services/add",data) as ServiceAddResponse;
|
return await postapi("nfregex/services",data) as ServiceAddResponse;
|
||||||
},
|
},
|
||||||
servicedelete: async (service_id:string) => {
|
servicedelete: async (service_id:string) => {
|
||||||
const { status } = await getapi(`nfregex/service/${service_id}/delete`) as ServerResponse;
|
const { status } = await deleteapi(`nfregex/services/${service_id}`) as ServerResponse;
|
||||||
return status === "ok"?undefined:status
|
return status === "ok"?undefined:status
|
||||||
},
|
},
|
||||||
regexesadd: async (data:RegexAddForm) => {
|
regexesadd: async (data:RegexAddForm) => {
|
||||||
const { status } = await postapi("nfregex/regexes/add",data) as ServerResponse;
|
const { status } = await postapi("nfregex/regexes",data) as ServerResponse;
|
||||||
return status === "ok"?undefined:status
|
return status === "ok"?undefined:status
|
||||||
},
|
},
|
||||||
serviceregexes: async (service_id:string) => {
|
serviceregexes: async (service_id:string) => {
|
||||||
return await getapi(`nfregex/service/${service_id}/regexes`) as RegexFilter[];
|
return await getapi(`nfregex/services/${service_id}/regexes`) as RegexFilter[];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -29,24 +29,6 @@ function ServiceRow({ service }:{ service:Service }) {
|
|||||||
validate:{ proxy_port: (value) => (value > 0 && value < 65536)? null : "Invalid proxy port" }
|
validate:{ proxy_port: (value) => (value > 0 && value < 65536)? null : "Invalid proxy port" }
|
||||||
})
|
})
|
||||||
|
|
||||||
const onChangeProxyPort = ({proxy_port}:{proxy_port:number}) => {
|
|
||||||
if (proxy_port === service.proxy_port) return
|
|
||||||
if (proxy_port > 0 && proxy_port < 65536 && proxy_port !== service.public_port){
|
|
||||||
porthijack.changedestination(service.service_id, service.ip_dst, proxy_port).then( res => {
|
|
||||||
if (res.status === "ok"){
|
|
||||||
okNotify(`Service ${service.name} destination port has changed in ${ proxy_port }`, `Successfully changed destination port`)
|
|
||||||
}else{
|
|
||||||
errorNotify(`Error while changing the destination port of ${service.name}`,`Error: ${res.status}`)
|
|
||||||
}
|
|
||||||
}).catch( err => {
|
|
||||||
errorNotify("Request for changing port failed!",`Error: [ ${err} ]`)
|
|
||||||
})
|
|
||||||
}else{
|
|
||||||
form.setFieldValue("proxy_port", service.proxy_port)
|
|
||||||
errorNotify(`Error while changing the destination port of ${service.name}`,`Insert a valid port number`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const stopService = async () => {
|
const stopService = async () => {
|
||||||
setButtonLoading(true)
|
setButtonLoading(true)
|
||||||
|
|
||||||
@@ -119,21 +101,7 @@ function ServiceRow({ service }:{ service:Service }) {
|
|||||||
<Space h="sm" />
|
<Space h="sm" />
|
||||||
<Badge color="blue" radius="sm" size="md" variant="filled">
|
<Badge color="blue" radius="sm" size="md" variant="filled">
|
||||||
<Box className="center-flex">
|
<Box className="center-flex">
|
||||||
TO {service.ip_dst} :
|
TO {service.ip_dst} : service.proxy_port
|
||||||
<form onSubmit={form.onSubmit((v)=>portInputRef.current?.blur())}>
|
|
||||||
<PortInput
|
|
||||||
defaultValue={service.proxy_port}
|
|
||||||
size="xs"
|
|
||||||
variant="unstyled"
|
|
||||||
style={{
|
|
||||||
width: (10+form.values.proxy_port.toString().length*6.2) +"px"
|
|
||||||
}}
|
|
||||||
className="firegex__porthijack__servicerow__portInput"
|
|
||||||
onBlur={(e)=>{onChangeProxyPort({proxy_port:parseInt(e.target.value)})}}
|
|
||||||
ref={portInputRef}
|
|
||||||
{...form.getInputProps("proxy_port")}
|
|
||||||
/>
|
|
||||||
</form>
|
|
||||||
</Box>
|
</Box>
|
||||||
</Badge>
|
</Badge>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { ServerResponse } from "../../js/models"
|
import { ServerResponse } from "../../js/models"
|
||||||
import { getapi, postapi } from "../../js/utils"
|
import { deleteapi, getapi, postapi, putapi } from "../../js/utils"
|
||||||
import { useQuery } from "@tanstack/react-query"
|
import { useQuery } from "@tanstack/react-query"
|
||||||
|
|
||||||
export type GeneralStats = {
|
export type GeneralStats = {
|
||||||
@@ -37,28 +37,28 @@ export const porthijack = {
|
|||||||
return await getapi("porthijack/services") as Service[];
|
return await getapi("porthijack/services") as Service[];
|
||||||
},
|
},
|
||||||
serviceinfo: async (service_id:string) => {
|
serviceinfo: async (service_id:string) => {
|
||||||
return await getapi(`porthijack/service/${service_id}`) as Service;
|
return await getapi(`porthijack/services/${service_id}`) as Service;
|
||||||
},
|
},
|
||||||
servicestart: async (service_id:string) => {
|
servicestart: async (service_id:string) => {
|
||||||
const { status } = await getapi(`porthijack/service/${service_id}/start`) as ServerResponse;
|
const { status } = await postapi(`porthijack/services/${service_id}/start`) as ServerResponse;
|
||||||
return status === "ok"?undefined:status
|
return status === "ok"?undefined:status
|
||||||
},
|
},
|
||||||
servicerename: async (service_id:string, name: string) => {
|
servicerename: async (service_id:string, name: string) => {
|
||||||
const { status } = await postapi(`porthijack/service/${service_id}/rename`,{ name }) as ServerResponse;
|
const { status } = await putapi(`porthijack/services/${service_id}/rename`,{ name }) as ServerResponse;
|
||||||
return status === "ok"?undefined:status
|
return status === "ok"?undefined:status
|
||||||
},
|
},
|
||||||
servicestop: async (service_id:string) => {
|
servicestop: async (service_id:string) => {
|
||||||
const { status } = await getapi(`porthijack/service/${service_id}/stop`) as ServerResponse;
|
const { status } = await postapi(`porthijack/services/${service_id}/stop`) as ServerResponse;
|
||||||
return status === "ok"?undefined:status
|
return status === "ok"?undefined:status
|
||||||
},
|
},
|
||||||
servicesadd: async (data:ServiceAddForm) => {
|
servicesadd: async (data:ServiceAddForm) => {
|
||||||
return await postapi("porthijack/services/add",data) as ServiceAddResponse;
|
return await postapi("porthijack/services",data) as ServiceAddResponse;
|
||||||
},
|
},
|
||||||
servicedelete: async (service_id:string) => {
|
servicedelete: async (service_id:string) => {
|
||||||
const { status } = await getapi(`porthijack/service/${service_id}/delete`) as ServerResponse;
|
const { status } = await deleteapi(`porthijack/services/${service_id}`) as ServerResponse;
|
||||||
return status === "ok"?undefined:status
|
return status === "ok"?undefined:status
|
||||||
},
|
},
|
||||||
changedestination: async (service_id:string, ip_dst:string, proxy_port:number) => {
|
changedestination: async (service_id:string, ip_dst:string, proxy_port:number) => {
|
||||||
return await postapi(`porthijack/service/${service_id}/change-destination`, {proxy_port, ip_dst}) as ServerResponse;
|
return await putapi(`porthijack/services/${service_id}/change-destination`, {proxy_port, ip_dst}) as ServerResponse;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -22,26 +22,6 @@ export const queryClient = new QueryClient({ defaultOptions: { queries: {
|
|||||||
staleTime: Infinity
|
staleTime: Infinity
|
||||||
} }})
|
} }})
|
||||||
|
|
||||||
export async function getapi(path:string):Promise<any>{
|
|
||||||
|
|
||||||
return await new Promise((resolve, reject) => {
|
|
||||||
fetch(`${IS_DEV?`http://${DEV_IP_BACKEND}`:""}/api/${path}`,{
|
|
||||||
credentials: "same-origin",
|
|
||||||
headers: { "Authorization" : "Bearer " + window.localStorage.getItem("access_token")}
|
|
||||||
}).then(res => {
|
|
||||||
if(res.status === 401) window.location.reload()
|
|
||||||
if(!res.ok){
|
|
||||||
const errorDefault = res.statusText
|
|
||||||
return res.json().then( res => reject(getErrorMessageFromServerResponse(res, errorDefault)) ).catch( _err => reject(errorDefault))
|
|
||||||
}
|
|
||||||
res.json().then( res => resolve(res) ).catch( err => reject(err))
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
reject(err)
|
|
||||||
})
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getErrorMessage(e: any) {
|
export function getErrorMessage(e: any) {
|
||||||
let error = "Unknown error";
|
let error = "Unknown error";
|
||||||
if(typeof e == "string") return e
|
if(typeof e == "string") return e
|
||||||
@@ -56,7 +36,6 @@ export function getErrorMessage(e: any) {
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function getErrorMessageFromServerResponse(e: any, def:string = "Unknown error") {
|
export function getErrorMessageFromServerResponse(e: any, def:string = "Unknown error") {
|
||||||
if (e.status){
|
if (e.status){
|
||||||
return e.status
|
return e.status
|
||||||
@@ -74,17 +53,17 @@ export function getErrorMessageFromServerResponse(e: any, def:string = "Unknown
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export async function postapi(path:string,data:any,is_form:boolean=false):Promise<any>{
|
export async function genericapi(method:string,path:string,data:any = undefined, is_form:boolean=false):Promise<any>{
|
||||||
return await new Promise((resolve, reject) => {
|
return await new Promise((resolve, reject) => {
|
||||||
fetch(`${IS_DEV?`http://${DEV_IP_BACKEND}`:""}/api/${path}`, {
|
fetch(`${IS_DEV?`http://${DEV_IP_BACKEND}`:""}/api/${path}`, {
|
||||||
method: 'POST',
|
method: method,
|
||||||
credentials: "same-origin",
|
credentials: "same-origin",
|
||||||
cache: 'no-cache',
|
cache: 'no-cache',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': is_form ? 'application/x-www-form-urlencoded' : 'application/json',
|
...(data?{'Content-Type': is_form ? 'application/x-www-form-urlencoded' : 'application/json'}:{}),
|
||||||
"Authorization" : "Bearer " + window.localStorage.getItem("access_token")
|
"Authorization" : "Bearer " + window.localStorage.getItem("access_token")
|
||||||
},
|
},
|
||||||
body: is_form ? (new URLSearchParams(data)).toString() : JSON.stringify(data)
|
body: data? (is_form ? (new URLSearchParams(data)).toString() : JSON.stringify(data)) : undefined
|
||||||
}).then(res => {
|
}).then(res => {
|
||||||
if(res.status === 401) window.location.reload()
|
if(res.status === 401) window.location.reload()
|
||||||
if(res.status === 406) resolve({status:"Wrong Password"})
|
if(res.status === 406) resolve({status:"Wrong Password"})
|
||||||
@@ -100,6 +79,22 @@ export async function postapi(path:string,data:any,is_form:boolean=false):Promis
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getapi(path:string):Promise<any>{
|
||||||
|
return await genericapi("GET",path)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function postapi(path:string,data:any=undefined,is_form:boolean=false):Promise<any>{
|
||||||
|
return await genericapi("POST",path,data,is_form)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function deleteapi(path:string):Promise<any>{
|
||||||
|
return await genericapi("DELETE",path)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function putapi(path:string,data:any):Promise<any>{
|
||||||
|
return await genericapi("PUT",path,data)
|
||||||
|
}
|
||||||
|
|
||||||
export function getMainPath(){
|
export function getMainPath(){
|
||||||
const paths = window.location.pathname.split("/")
|
const paths = window.location.pathname.split("/")
|
||||||
if (paths.length > 1) return paths[1]
|
if (paths.length > 1) return paths[1]
|
||||||
|
|||||||
1
start.py
1
start.py
@@ -1,4 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
import argparse
|
import argparse
|
||||||
import sys
|
import sys
|
||||||
|
|||||||
@@ -19,11 +19,17 @@ class BearerSession():
|
|||||||
headers["Content-Type"] = "application/x-www-form-urlencoded"
|
headers["Content-Type"] = "application/x-www-form-urlencoded"
|
||||||
return self.s.post(endpoint, json=json, data=data, headers=headers)
|
return self.s.post(endpoint, json=json, data=data, headers=headers)
|
||||||
|
|
||||||
|
def delete(self, endpoint, json={}):
|
||||||
|
return self.s.delete(endpoint, json=json, headers=self.headers)
|
||||||
|
|
||||||
|
def put(self, endpoint, json={}):
|
||||||
|
return self.s.put(endpoint, json=json, headers=self.headers)
|
||||||
|
|
||||||
def get(self, endpoint, json={}):
|
def get(self, endpoint, json={}):
|
||||||
return self.s.get(endpoint, json=json, headers=self.headers)
|
return self.s.get(endpoint, json=json, headers=self.headers)
|
||||||
|
|
||||||
def set_token(self,token):
|
def set_token(self,token):
|
||||||
self.headers = {"Authorization": f"Bearer {token}"}
|
self.headers = {"Authorization": f"Bearer {token}"}
|
||||||
|
|
||||||
def unset_token(self):
|
def unset_token(self):
|
||||||
self.headers = {}
|
self.headers = {}
|
||||||
@@ -72,62 +78,57 @@ class FiregexAPI:
|
|||||||
def reset(self, delete: bool):
|
def reset(self, delete: bool):
|
||||||
self.s.post(f"{self.address}api/reset", json={"delete":delete})
|
self.s.post(f"{self.address}api/reset", json={"delete":delete})
|
||||||
|
|
||||||
#Netfilter regex
|
|
||||||
def nf_get_stats(self):
|
|
||||||
req = self.s.get(f"{self.address}api/nfregex/stats")
|
|
||||||
return req.json()
|
|
||||||
|
|
||||||
def nf_get_services(self):
|
def nf_get_services(self):
|
||||||
req = self.s.get(f"{self.address}api/nfregex/services")
|
req = self.s.get(f"{self.address}api/nfregex/services")
|
||||||
return req.json()
|
return req.json()
|
||||||
|
|
||||||
def nf_get_service(self,service_id: str):
|
def nf_get_service(self,service_id: str):
|
||||||
req = self.s.get(f"{self.address}api/nfregex/service/{service_id}")
|
req = self.s.get(f"{self.address}api/nfregex/services/{service_id}")
|
||||||
return req.json()
|
return req.json()
|
||||||
|
|
||||||
def nf_stop_service(self,service_id: str):
|
def nf_stop_service(self,service_id: str):
|
||||||
req = self.s.get(f"{self.address}api/nfregex/service/{service_id}/stop")
|
req = self.s.post(f"{self.address}api/nfregex/services/{service_id}/stop")
|
||||||
return verify(req)
|
return verify(req)
|
||||||
|
|
||||||
def nf_start_service(self,service_id: str):
|
def nf_start_service(self,service_id: str):
|
||||||
req = self.s.get(f"{self.address}api/nfregex/service/{service_id}/start")
|
req = self.s.post(f"{self.address}api/nfregex/services/{service_id}/start")
|
||||||
return verify(req)
|
return verify(req)
|
||||||
|
|
||||||
def nf_delete_service(self,service_id: str):
|
def nf_delete_service(self,service_id: str):
|
||||||
req = self.s.get(f"{self.address}api/nfregex/service/{service_id}/delete")
|
req = self.s.delete(f"{self.address}api/nfregex/services/{service_id}")
|
||||||
return verify(req)
|
return verify(req)
|
||||||
|
|
||||||
def nf_rename_service(self,service_id: str, newname: str):
|
def nf_rename_service(self,service_id: str, newname: str):
|
||||||
req = self.s.post(f"{self.address}api/nfregex/service/{service_id}/rename" , json={"name":newname})
|
req = self.s.put(f"{self.address}api/nfregex/services/{service_id}/rename" , json={"name":newname})
|
||||||
return verify(req)
|
return verify(req)
|
||||||
|
|
||||||
def nf_get_service_regexes(self,service_id: str):
|
def nf_get_service_regexes(self,service_id: str):
|
||||||
req = self.s.get(f"{self.address}api/nfregex/service/{service_id}/regexes")
|
req = self.s.get(f"{self.address}api/nfregex/services/{service_id}/regexes")
|
||||||
return req.json()
|
return req.json()
|
||||||
|
|
||||||
def nf_get_regex(self,regex_id: str):
|
def nf_get_regex(self,regex_id: str):
|
||||||
req = self.s.get(f"{self.address}api/nfregex/regex/{regex_id}")
|
req = self.s.get(f"{self.address}api/nfregex/regexes/{regex_id}")
|
||||||
return req.json()
|
return req.json()
|
||||||
|
|
||||||
def nf_delete_regex(self,regex_id: str):
|
def nf_delete_regex(self,regex_id: str):
|
||||||
req = self.s.get(f"{self.address}api/nfregex/regex/{regex_id}/delete")
|
req = self.s.delete(f"{self.address}api/nfregex/regexes/{regex_id}")
|
||||||
return verify(req)
|
return verify(req)
|
||||||
|
|
||||||
def nf_enable_regex(self,regex_id: str):
|
def nf_enable_regex(self,regex_id: str):
|
||||||
req = self.s.get(f"{self.address}api/nfregex/regex/{regex_id}/enable")
|
req = self.s.post(f"{self.address}api/nfregex/regexes/{regex_id}/enable")
|
||||||
return verify(req)
|
return verify(req)
|
||||||
|
|
||||||
def nf_disable_regex(self,regex_id: str):
|
def nf_disable_regex(self,regex_id: str):
|
||||||
req = self.s.get(f"{self.address}api/nfregex/regex/{regex_id}/disable")
|
req = self.s.post(f"{self.address}api/nfregex/regexes/{regex_id}/disable")
|
||||||
return verify(req)
|
return verify(req)
|
||||||
|
|
||||||
def nf_add_regex(self, service_id: str, regex: str, mode: str, active: bool, is_case_sensitive: bool):
|
def nf_add_regex(self, service_id: str, regex: str, mode: str, active: bool, is_case_sensitive: bool):
|
||||||
req = self.s.post(f"{self.address}api/nfregex/regexes/add",
|
req = self.s.post(f"{self.address}api/nfregex/regexes",
|
||||||
json={"service_id": service_id, "regex": regex, "mode": mode, "active": active, "is_case_sensitive": is_case_sensitive})
|
json={"service_id": service_id, "regex": regex, "mode": mode, "active": active, "is_case_sensitive": is_case_sensitive})
|
||||||
return verify(req)
|
return verify(req)
|
||||||
|
|
||||||
def nf_add_service(self, name: str, port: int, proto: str, ip_int: str):
|
def nf_add_service(self, name: str, port: int, proto: str, ip_int: str):
|
||||||
req = self.s.post(f"{self.address}api/nfregex/services/add" ,
|
req = self.s.post(f"{self.address}api/nfregex/services" ,
|
||||||
json={"name":name,"port":port, "proto": proto, "ip_int": ip_int})
|
json={"name":name,"port":port, "proto": proto, "ip_int": ip_int})
|
||||||
return req.json()["service_id"] if verify(req) else False
|
return req.json()["service_id"] if verify(req) else False
|
||||||
|
|
||||||
@@ -137,30 +138,30 @@ class FiregexAPI:
|
|||||||
return req.json()
|
return req.json()
|
||||||
|
|
||||||
def ph_get_service(self,service_id: str):
|
def ph_get_service(self,service_id: str):
|
||||||
req = self.s.get(f"{self.address}api/porthijack/service/{service_id}")
|
req = self.s.get(f"{self.address}api/porthijack/services/{service_id}")
|
||||||
return req.json()
|
return req.json()
|
||||||
|
|
||||||
def ph_stop_service(self,service_id: str):
|
def ph_stop_service(self,service_id: str):
|
||||||
req = self.s.get(f"{self.address}api/porthijack/service/{service_id}/stop")
|
req = self.s.post(f"{self.address}api/porthijack/services/{service_id}/stop")
|
||||||
return verify(req)
|
return verify(req)
|
||||||
|
|
||||||
def ph_start_service(self,service_id: str):
|
def ph_start_service(self,service_id: str):
|
||||||
req = self.s.get(f"{self.address}api/porthijack/service/{service_id}/start")
|
req = self.s.post(f"{self.address}api/porthijack/services/{service_id}/start")
|
||||||
return verify(req)
|
return verify(req)
|
||||||
|
|
||||||
def ph_delete_service(self,service_id: str):
|
def ph_delete_service(self,service_id: str):
|
||||||
req = self.s.get(f"{self.address}api/porthijack/service/{service_id}/delete")
|
req = self.s.delete(f"{self.address}api/porthijack/services/{service_id}")
|
||||||
return verify(req)
|
return verify(req)
|
||||||
|
|
||||||
def ph_rename_service(self,service_id: str,newname: str):
|
def ph_rename_service(self,service_id: str,newname: str):
|
||||||
req = self.s.post(f"{self.address}api/porthijack/service/{service_id}/rename" , json={"name":newname})
|
req = self.s.put(f"{self.address}api/porthijack/services/{service_id}/rename" , json={"name":newname})
|
||||||
return verify(req)
|
return verify(req)
|
||||||
|
|
||||||
def ph_change_destination(self,service_id: str, ip_dst:string , proxy_port: int):
|
def ph_change_destination(self,service_id: str, ip_dst:string , proxy_port: int):
|
||||||
req = self.s.post(f"{self.address}api/porthijack/service/{service_id}/change-destination", json={"ip_dst": ip_dst, "proxy_port": proxy_port})
|
req = self.s.put(f"{self.address}api/porthijack/services/{service_id}/change-destination", json={"ip_dst": ip_dst, "proxy_port": proxy_port})
|
||||||
return verify(req)
|
return verify(req)
|
||||||
|
|
||||||
def ph_add_service(self, name: str, public_port: int, proxy_port: int, proto: str, ip_src: str, ip_dst: str):
|
def ph_add_service(self, name: str, public_port: int, proxy_port: int, proto: str, ip_src: str, ip_dst: str):
|
||||||
req = self.s.post(f"{self.address}api/porthijack/services/add" ,
|
req = self.s.post(f"{self.address}api/porthijack/services" ,
|
||||||
json={"name":name, "public_port": public_port, "proxy_port":proxy_port, "proto": proto, "ip_src": ip_src, "ip_dst": ip_dst})
|
json={"name":name, "public_port": public_port, "proxy_port":proxy_port, "proto": proto, "ip_src": ip_src, "ip_dst": ip_dst})
|
||||||
return req.json()["service_id"] if verify(req) else False
|
return req.json()["service_id"] if verify(req) else False
|
||||||
|
|||||||
Reference in New Issue
Block a user