Fixed real-time regex
This commit is contained in:
@@ -1,6 +1,8 @@
|
|||||||
from signal import SIGUSR1
|
from signal import SIGUSR1
|
||||||
|
from secrets import token_urlsafe
|
||||||
import subprocess, re, os
|
import subprocess, re, os
|
||||||
|
|
||||||
|
|
||||||
#c++ -o proxy proxy.cpp
|
#c++ -o proxy proxy.cpp
|
||||||
|
|
||||||
class Filter:
|
class Filter:
|
||||||
@@ -25,33 +27,36 @@ class Filter:
|
|||||||
yield case_sensitive + "S" + self.regex.hex() if self.is_blacklist else case_sensitive + "s"+ self.regex.hex()
|
yield case_sensitive + "S" + self.regex.hex() if self.is_blacklist else case_sensitive + "s"+ self.regex.hex()
|
||||||
|
|
||||||
class Proxy:
|
class Proxy:
|
||||||
def __init__(self, internal_port, public_port, filters=None, public_host="0.0.0.0", internal_host="127.0.0.1"):
|
def __init__(self, internal_port, public_port, callback_blocked_update=None, filters=None, public_host="0.0.0.0", internal_host="127.0.0.1"):
|
||||||
self.public_host = public_host
|
self.public_host = public_host
|
||||||
self.public_port = public_port
|
self.public_port = public_port
|
||||||
self.internal_host = internal_host
|
self.internal_host = internal_host
|
||||||
self.internal_port = internal_port
|
self.internal_port = internal_port
|
||||||
self.filters = set(filters) if filters else set([])
|
self.filters = set(filters) if filters else set([])
|
||||||
self.process = None
|
self.process = None
|
||||||
|
self.callback_blocked_update = callback_blocked_update
|
||||||
|
self.config_file_path = None
|
||||||
|
while self.config_file_path is None:
|
||||||
|
config_file_path = os.path.join("/tmp/" + token_urlsafe(16))
|
||||||
|
if not os.path.exists(config_file_path):
|
||||||
|
self.config_file_path = config_file_path
|
||||||
|
|
||||||
def start(self, callback=None):
|
def start(self, in_pause=False):
|
||||||
if self.process is None:
|
if self.process is None:
|
||||||
filter_map = self.compile_filters()
|
filter_map = self.compile_filters()
|
||||||
filters_codes = list(filter_map.keys())
|
filters_codes = list(filter_map.keys()) if not in_pause else []
|
||||||
proxy_binary_path = os.path.join(os.path.dirname(os.path.abspath(__file__)),"./proxy")
|
proxy_binary_path = os.path.join(os.path.dirname(os.path.abspath(__file__)),"./proxy")
|
||||||
config_file_path = os.path.join(os.path.dirname(os.path.abspath(__file__)),"./config_file")
|
self.__write_config(filters_codes)
|
||||||
with open(config_file_path,'w') as config_file:
|
|
||||||
for line in filters_codes:
|
|
||||||
config_file.write(line + '\n')
|
|
||||||
|
|
||||||
self.process = subprocess.Popen(
|
self.process = subprocess.Popen(
|
||||||
[proxy_binary_path, str(self.public_host), str(self.public_port), str(self.internal_host), str(self.internal_port), config_file_path],
|
[proxy_binary_path, str(self.public_host), str(self.public_port), str(self.internal_host), str(self.internal_port), self.config_file_path],
|
||||||
stdout=subprocess.PIPE, universal_newlines=True
|
stdout=subprocess.PIPE, universal_newlines=True
|
||||||
)
|
)
|
||||||
for stdout_line in iter(self.process.stdout.readline, ""):
|
for stdout_line in iter(self.process.stdout.readline, ""):
|
||||||
if stdout_line.startswith("BLOCKED"):
|
if stdout_line.startswith("BLOCKED"):
|
||||||
regex_id = stdout_line.split()[1]
|
regex_id = stdout_line.split()[1]
|
||||||
filter_map[regex_id].blocked+=1
|
filter_map[regex_id].blocked+=1
|
||||||
if callback: callback(filter_map[regex_id])
|
if self.callback_blocked_update: self.callback_blocked_update(filter_map[regex_id])
|
||||||
self.process.stdout.close()
|
self.process.stdout.close()
|
||||||
return self.process.wait()
|
return self.process.wait()
|
||||||
|
|
||||||
@@ -68,24 +73,37 @@ class Proxy:
|
|||||||
self.process = None
|
self.process = None
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def restart(self):
|
def restart(self, in_pause=False):
|
||||||
status = self.stop()
|
status = self.stop()
|
||||||
self.start()
|
self.start(in_pause=in_pause)
|
||||||
return status
|
return status
|
||||||
|
|
||||||
|
def __write_config(self, filters_codes):
|
||||||
|
with open(self.config_file_path,'w') as config_file:
|
||||||
|
for line in filters_codes:
|
||||||
|
config_file.write(line + '\n')
|
||||||
|
|
||||||
def reload(self):
|
def reload(self):
|
||||||
if self.process:
|
if self.isactive():
|
||||||
filter_map = self.compile_filters()
|
filter_map = self.compile_filters()
|
||||||
filters_codes = list(filter_map.keys())
|
filters_codes = list(filter_map.keys())
|
||||||
config_file_path = os.path.join(os.path.dirname(os.path.abspath(__file__)),"./config_file")
|
self.__write_config(filters_codes)
|
||||||
with open(config_file_path,'w') as config_file:
|
self.trigger_reload_config()
|
||||||
for line in filters_codes:
|
|
||||||
config_file.write(line + '\n')
|
|
||||||
self.process.send_signal(SIGUSR1)
|
|
||||||
|
|
||||||
def isactive(self):
|
def isactive(self):
|
||||||
return True if self.process else False
|
return True if self.process else False
|
||||||
|
|
||||||
|
def trigger_reload_config(self):
|
||||||
|
self.process.send_signal(SIGUSR1)
|
||||||
|
|
||||||
|
|
||||||
|
def pause(self):
|
||||||
|
if self.isactive():
|
||||||
|
self.__write_config([])
|
||||||
|
self.trigger_reload_config()
|
||||||
|
else:
|
||||||
|
self.start(in_pause=True)
|
||||||
|
|
||||||
def compile_filters(self):
|
def compile_filters(self):
|
||||||
res = {}
|
res = {}
|
||||||
for filter_obj in self.filters:
|
for filter_obj in self.filters:
|
||||||
@@ -95,13 +113,3 @@ class Proxy:
|
|||||||
res[filter] = filter_obj
|
res[filter] = filter_obj
|
||||||
except Exception: pass
|
except Exception: pass
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def add_filter(self, filter):
|
|
||||||
self.filters.add(filter)
|
|
||||||
self.reload()
|
|
||||||
|
|
||||||
def remove_filter(self, filter):
|
|
||||||
try:
|
|
||||||
del self.filters[self.filters.remove(filter)]
|
|
||||||
except ValueError: return
|
|
||||||
self.reload()
|
|
||||||
|
|||||||
@@ -318,12 +318,16 @@ void push_regex(char* arg, bool case_sensitive, vector<pair<string,boost::regex>
|
|||||||
if (case_sensitive){
|
if (case_sensitive){
|
||||||
boost::regex regex(reinterpret_cast<char*>(expr),
|
boost::regex regex(reinterpret_cast<char*>(expr),
|
||||||
reinterpret_cast<char*>(expr) + expr_len);
|
reinterpret_cast<char*>(expr) + expr_len);
|
||||||
|
#ifdef DEBUG
|
||||||
cout << "Added case sensitive regex " << expr << endl;
|
cout << "Added case sensitive regex " << expr << endl;
|
||||||
|
#endif
|
||||||
v.push_back(make_pair(string(arg), regex));
|
v.push_back(make_pair(string(arg), regex));
|
||||||
} else {
|
} else {
|
||||||
boost::regex regex(reinterpret_cast<char*>(expr),
|
boost::regex regex(reinterpret_cast<char*>(expr),
|
||||||
reinterpret_cast<char*>(expr) + expr_len, boost::regex::icase);
|
reinterpret_cast<char*>(expr) + expr_len, boost::regex::icase);
|
||||||
|
#ifdef DEBUG
|
||||||
cout << "Added case insensitive regex " << expr << endl;
|
cout << "Added case insensitive regex " << expr << endl;
|
||||||
|
#endif
|
||||||
v.push_back(make_pair(string(arg), regex));
|
v.push_back(make_pair(string(arg), regex));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from asyncore import file_dispatcher
|
from asyncore import file_dispatcher
|
||||||
|
from imp import reload
|
||||||
from proxy import Filter, Proxy
|
from proxy import Filter, Proxy
|
||||||
import random, string, os, threading, sqlite3, time, atexit, socket
|
import random, string, os, threading, sqlite3, time, atexit, socket
|
||||||
from kthread import KThread
|
from kthread import KThread
|
||||||
@@ -148,14 +149,12 @@ class ProxyManager:
|
|||||||
self.db.query("UPDATE services SET status = ? WHERE service_id = ?;", (status, id))
|
self.db.query("UPDATE services SET status = ? WHERE service_id = ?;", (status, id))
|
||||||
|
|
||||||
def __proxy_starter(self, id, proxy:Proxy, next_status, saved_status):
|
def __proxy_starter(self, id, proxy:Proxy, next_status, saved_status):
|
||||||
def stats_updater(filter:Filter):
|
|
||||||
self.db.query("UPDATE regexes SET blocked_packets = ? WHERE regex_id = ?;", (filter.blocked, filter.code))
|
|
||||||
def func():
|
def func():
|
||||||
while True:
|
while True:
|
||||||
if check_port_is_open(proxy.public_port):
|
if check_port_is_open(proxy.public_port):
|
||||||
self.__update_status_db(id, next_status)
|
self.__update_status_db(id, next_status)
|
||||||
if saved_status[0] == "wait": saved_status[0] = next_status
|
if saved_status[0] == "wait": saved_status[0] = next_status
|
||||||
proxy_status = proxy.start(callback=stats_updater)
|
proxy_status = proxy.start(in_pause=(next_status==STATUS.PAUSE))
|
||||||
if proxy_status == 1:
|
if proxy_status == 1:
|
||||||
self.__update_status_db(id, STATUS.STOP)
|
self.__update_status_db(id, STATUS.STOP)
|
||||||
return
|
return
|
||||||
@@ -170,10 +169,13 @@ class ProxyManager:
|
|||||||
|
|
||||||
proxy = None
|
proxy = None
|
||||||
thr_starter:KThread = None
|
thr_starter:KThread = None
|
||||||
previous_status = "stop"
|
previous_status = STATUS.STOP
|
||||||
filters = {}
|
filters = {}
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
|
restart_required = False
|
||||||
|
reload_required = False
|
||||||
|
|
||||||
data = self.get_service_data(id)
|
data = self.get_service_data(id)
|
||||||
|
|
||||||
#Close thread
|
#Close thread
|
||||||
@@ -182,13 +184,6 @@ class ProxyManager:
|
|||||||
proxy.stop()
|
proxy.stop()
|
||||||
return
|
return
|
||||||
|
|
||||||
restart_required = False
|
|
||||||
|
|
||||||
#Port checks
|
|
||||||
if proxy and (proxy.internal_port != data['internal_port'] or proxy.public_port != data['public_port']):
|
|
||||||
restart_required = True
|
|
||||||
|
|
||||||
|
|
||||||
#Filter check
|
#Filter check
|
||||||
old_filters = set(filters.keys())
|
old_filters = set(filters.keys())
|
||||||
new_filters = set([f["id"] for f in data["filters"]])
|
new_filters = set([f["id"] for f in data["filters"]])
|
||||||
@@ -196,12 +191,12 @@ class ProxyManager:
|
|||||||
#remove old filters
|
#remove old filters
|
||||||
for f in old_filters:
|
for f in old_filters:
|
||||||
if not f in new_filters:
|
if not f in new_filters:
|
||||||
restart_required = False
|
reload_required = True
|
||||||
del filters[f]
|
del filters[f]
|
||||||
|
|
||||||
for f in new_filters:
|
for f in new_filters:
|
||||||
if not f in old_filters:
|
if not f in old_filters:
|
||||||
restart_required = False
|
reload_required = True
|
||||||
filter_info = [ele for ele in data['filters'] if ele["id"] == f][0]
|
filter_info = [ele for ele in data['filters'] if ele["id"] == f][0]
|
||||||
filters[f] = Filter(
|
filters[f] = Filter(
|
||||||
is_case_sensitive=filter_info["is_case_sensitive"],
|
is_case_sensitive=filter_info["is_case_sensitive"],
|
||||||
@@ -213,20 +208,42 @@ class ProxyManager:
|
|||||||
code=f
|
code=f
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def stats_updater(filter:Filter):
|
||||||
|
print("Callback received",filter.blocked, filter.code)
|
||||||
|
self.db.query("UPDATE regexes SET blocked_packets = ? WHERE regex_id = ?;", (filter.blocked, filter.code))
|
||||||
|
|
||||||
|
if not proxy:
|
||||||
|
proxy = Proxy(
|
||||||
|
internal_port=data['internal_port'],
|
||||||
|
public_port=data['public_port'],
|
||||||
|
filters=list(filters.values()),
|
||||||
|
internal_host=LOCALHOST_IP,
|
||||||
|
callback_blocked_update=stats_updater
|
||||||
|
)
|
||||||
|
|
||||||
|
#Port checks
|
||||||
|
if proxy.internal_port != data['internal_port'] or proxy.public_port != data['public_port']:
|
||||||
|
proxy.internal_port = data['internal_port']
|
||||||
|
proxy.public_port = data['public_port']
|
||||||
|
restart_required = True
|
||||||
|
|
||||||
|
#Update filters
|
||||||
|
if reload_required:
|
||||||
|
proxy.filters = list(filters.values())
|
||||||
|
|
||||||
#proxy status managment
|
#proxy status managment
|
||||||
if previous_status != next_status[0] or restart_required:
|
if previous_status != next_status[0]:
|
||||||
if (previous_status, next_status[0]) in [(STATUS.ACTIVE, STATUS.PAUSE), (STATUS.STOP, STATUS.PAUSE), (STATUS.PAUSE, STATUS.PAUSE)]:
|
# ACTIVE -> PAUSE or PAUSE -> ACTIVE
|
||||||
if proxy: proxy.stop()
|
if (previous_status, next_status[0]) in [(STATUS.ACTIVE, STATUS.PAUSE), (STATUS.PAUSE, STATUS.ACTIVE)]:
|
||||||
proxy = Proxy(
|
if restart_required:
|
||||||
internal_port=data['internal_port'],
|
proxy.restart(in_pause=next_status[0])
|
||||||
public_port=data['public_port'],
|
else:
|
||||||
filters=[],
|
if next_status[0] == STATUS.ACTIVE: proxy.reload()
|
||||||
internal_host=LOCALHOST_IP,
|
else: proxy.pause()
|
||||||
)
|
previous_status = next_status[0]
|
||||||
previous_status = next_status[0] = STATUS.PAUSE
|
self.__update_status_db(id, next_status[0])
|
||||||
self.__update_status_db(id, STATUS.WAIT)
|
reload_required = restart_required = False
|
||||||
thr_starter = self.__proxy_starter(id, proxy, STATUS.PAUSE, [previous_status])
|
|
||||||
restart_required = False
|
|
||||||
|
|
||||||
# ACTIVE -> STOP
|
# ACTIVE -> STOP
|
||||||
elif (previous_status,next_status[0]) in [(STATUS.ACTIVE, STATUS.STOP), (STATUS.WAIT, STATUS.STOP), (STATUS.PAUSE, STATUS.STOP)]: #Stop proxy
|
elif (previous_status,next_status[0]) in [(STATUS.ACTIVE, STATUS.STOP), (STATUS.WAIT, STATUS.STOP), (STATUS.PAUSE, STATUS.STOP)]: #Stop proxy
|
||||||
@@ -234,23 +251,20 @@ class ProxyManager:
|
|||||||
proxy.stop()
|
proxy.stop()
|
||||||
previous_status = next_status[0] = STATUS.STOP
|
previous_status = next_status[0] = STATUS.STOP
|
||||||
self.__update_status_db(id, STATUS.STOP)
|
self.__update_status_db(id, STATUS.STOP)
|
||||||
restart_required = False
|
reload_required = restart_required = False
|
||||||
|
|
||||||
elif (previous_status, next_status[0]) in [(STATUS.PAUSE, STATUS.ACTIVE), (STATUS.STOP, STATUS.ACTIVE), (STATUS.ACTIVE, STATUS.ACTIVE)]:
|
# STOP -> ACTIVE or STOP -> PAUSE
|
||||||
if proxy: proxy.stop()
|
elif (previous_status, next_status[0]) in [(STATUS.STOP, STATUS.ACTIVE), (STATUS.STOP, STATUS.PAUSE)]:
|
||||||
proxy = Proxy(
|
previous_status = next_status[0]
|
||||||
internal_port=data['internal_port'],
|
|
||||||
public_port=data['public_port'],
|
|
||||||
filters=list(filters.values()),
|
|
||||||
internal_host=LOCALHOST_IP,
|
|
||||||
)
|
|
||||||
previous_status = next_status[0] = STATUS.ACTIVE
|
|
||||||
self.__update_status_db(id, STATUS.WAIT)
|
self.__update_status_db(id, STATUS.WAIT)
|
||||||
thr_starter = self.__proxy_starter(id, proxy, STATUS.ACTIVE, [previous_status])
|
thr_starter = self.__proxy_starter(id, proxy, next_status[0], [previous_status])
|
||||||
restart_required = False
|
reload_required = restart_required = False
|
||||||
else:
|
else:
|
||||||
self.__update_status_db(id, previous_status)
|
self.__update_status_db(id, previous_status)
|
||||||
|
|
||||||
|
if restart_required: proxy.restart()
|
||||||
|
elif reload_required: proxy.reload()
|
||||||
|
|
||||||
signal.wait()
|
signal.wait()
|
||||||
signal.clear()
|
signal.clear()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user