Added case-insensitve regex

This commit is contained in:
nik012003
2022-06-17 20:48:27 +02:00
committed by DomySh
parent 07552e36da
commit 4caf7c2bce
8 changed files with 53 additions and 20 deletions

View File

@@ -122,6 +122,7 @@
"service_id": <service_id>, "service_id": <service_id>,
"regex": <base64 encoded regex>, "regex": <base64 encoded regex>,
"is_blacklist": <true|false>, "is_blacklist": <true|false>,
"is_case_sensitive": <true|false>,
"n_packets": <number of blocked packets>, "n_packets": <number of blocked packets>,
"mode": <"C"|"S"|"B"> // Client to server, server to client or both "mode": <"C"|"S"|"B"> // Client to server, server to client or both
}, },
@@ -140,6 +141,7 @@
"service_id": <service_id>, "service_id": <service_id>,
"regex": <base64 encoded regex>, "regex": <base64 encoded regex>,
"is_blacklist": <true|false>, "is_blacklist": <true|false>,
"is_case_sensitive": <true|false>,
"n_packets": <number of blocked packets>, "n_packets": <number of blocked packets>,
"mode": <"C"|"S"|"B"> // Client to server, server to client or both "mode": <"C"|"S"|"B"> // Client to server, server to client or both
} }
@@ -162,6 +164,7 @@
"service_id": <service_id>, "service_id": <service_id>,
"regex": <base64 encoded regex>, "regex": <base64 encoded regex>,
"is_blacklist": <true|false>, "is_blacklist": <true|false>,
"is_case_sensitive": <true|false>,
"mode": <"C"|"S"|"B"> // Client to server, server to client or both "mode": <"C"|"S"|"B"> // Client to server, server to client or both
} }
``` ```

View File

@@ -242,6 +242,7 @@ def get_service_regexes(serv):
'service_id': row[2], 'service_id': row[2],
'regex': row[0], 'regex': row[0],
'is_blacklist': True if row[3] == "1" else False, 'is_blacklist': True if row[3] == "1" else False,
'is_case_sensitive' : True if row[6] == "1" else False,
'mode': row[1], 'mode': row[1],
'n_packets': row[4], 'n_packets': row[4],
} for row in db.query('SELECT * FROM regexes WHERE service_id = ?;', (serv,)) } for row in db.query('SELECT * FROM regexes WHERE service_id = ?;', (serv,))
@@ -258,6 +259,7 @@ def get_regex_id(regex_id):
'service_id': q[0][2], 'service_id': q[0][2],
'regex': q[0][0], 'regex': q[0][0],
'is_blacklist': True if q[0][3] == "1" else False, 'is_blacklist': True if q[0][3] == "1" else False,
'is_case_sensitive' : True if q[0][7] == "1" else False,
'mode': q[0][1], 'mode': q[0][1],
'n_packets': q[0][4], 'n_packets': q[0][4],
} }
@@ -290,6 +292,7 @@ def post_regexes_add():
"regex" : {"type" : "string"}, "regex" : {"type" : "string"},
"is_blacklist" : {"type" : "boolean"}, "is_blacklist" : {"type" : "boolean"},
"mode" : {"type" : "string"}, "mode" : {"type" : "string"},
"is_case_sensitive" : {"type" : "boolean"}
}, },
}) })
if not re.match("^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)?$",req["regex"]): if not re.match("^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)?$",req["regex"]):
@@ -302,8 +305,8 @@ def post_regexes_add():
except Exception: except Exception:
return {"status":"Invalid regex"} return {"status":"Invalid regex"}
try: try:
db.query("INSERT INTO regexes (service_id, regex, is_blacklist, mode) VALUES (?, ?, ?, ?);", db.query("INSERT INTO regexes (service_id, regex, is_blacklist, mode, is_case_sensitive ) VALUES (?, ?, ?, ?, ?);",
(req['service_id'], req['regex'], req['is_blacklist'], req['mode'])) (req['service_id'], req['regex'], req['is_blacklist'], req['mode'], req['is_case_sensitive']))
except sqlite3.IntegrityError: except sqlite3.IntegrityError:
return {'status': 'An identical regex already exists'} return {'status': 'An identical regex already exists'}
@@ -359,14 +362,15 @@ if __name__ == '__main__':
'is_blacklist': 'VARCHAR(1) NOT NULL', 'is_blacklist': 'VARCHAR(1) NOT NULL',
'blocked_packets': 'INTEGER UNSIGNED NOT NULL DEFAULT 0', 'blocked_packets': 'INTEGER UNSIGNED NOT NULL DEFAULT 0',
'regex_id': 'INTEGER PRIMARY KEY', 'regex_id': 'INTEGER PRIMARY KEY',
'FOREIGN KEY (service_id)':'REFERENCES services (service_id)' 'is_case_sensitive' : 'VARCHAR(1) NOT NULL',
'FOREIGN KEY (service_id)':'REFERENCES services (service_id)',
}, },
'keys_values': { 'keys_values': {
'key': 'VARCHAR(100) PRIMARY KEY', 'key': 'VARCHAR(100) PRIMARY KEY',
'value': 'VARCHAR(100) NOT NULL', 'value': 'VARCHAR(100) NOT NULL',
}, },
}) })
db.query("CREATE UNIQUE INDEX IF NOT EXISTS unique_regex_service ON regexes (regex,service_id,is_blacklist,mode);") db.query("CREATE UNIQUE INDEX IF NOT EXISTS unique_regex_service ON regexes (regex,service_id,is_blacklist,mode,is_case_sensitive);")
if DEBUG: if DEBUG:
app.run(host="0.0.0.0", port=8080 ,debug=True) app.run(host="0.0.0.0", port=8080 ,debug=True)
else: else:

View File

@@ -3,8 +3,9 @@ import subprocess, re, os
#c++ -o proxy proxy.cpp #c++ -o proxy proxy.cpp
class Filter: class Filter:
def __init__(self, regex, is_blacklist=True, c_to_s=False, s_to_c=False, blocked_packets=0, code=None): def __init__(self, regex, is_case_sensitive=True, is_blacklist=True, c_to_s=False, s_to_c=False, blocked_packets=0, code=None):
self.regex = regex self.regex = regex
self.is_case_sensitive = is_case_sensitive
self.is_blacklist = is_blacklist self.is_blacklist = is_blacklist
if c_to_s == s_to_c: c_to_s = s_to_c = True # (False, False) == (True, True) if c_to_s == s_to_c: c_to_s = s_to_c = True # (False, False) == (True, True)
self.c_to_s = c_to_s self.c_to_s = c_to_s
@@ -16,10 +17,11 @@ class Filter:
if isinstance(self.regex, str): self.regex = self.regex.encode() if isinstance(self.regex, str): self.regex = self.regex.encode()
if not isinstance(self.regex, bytes): raise Exception("Invalid Regex Paramether") if not isinstance(self.regex, bytes): raise Exception("Invalid Regex Paramether")
re.compile(self.regex) # raise re.error if is invalid! re.compile(self.regex) # raise re.error if is invalid!
case_sensitive = "1" if self.is_case_sensitive else "0"
if self.c_to_s: if self.c_to_s:
yield "C"+self.regex.hex() if self.is_blacklist else "c"+self.regex.hex() yield case_sensitive + "C" + self.regex.hex() if self.is_blacklist else case_sensitive + "c"+ self.regex.hex()
if self.s_to_c: if self.s_to_c:
yield "S"+self.regex.hex() if self.is_blacklist else "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, filters=None, public_host="0.0.0.0", internal_host="127.0.0.1"):

View File

@@ -308,20 +308,26 @@ namespace tcp_proxy
}; };
} }
void push_regex(char* arg, vector<pair<string,boost::regex>> &v){ void push_regex(char* arg, bool case_sensitive, vector<pair<string,boost::regex>> &v){
size_t expr_len = (strlen(arg)-1)/2; size_t expr_len = (strlen(arg)-2)/2;
char expr[expr_len]; char expr[expr_len];
unhexlify(arg+1, arg+strlen(arg)-1, expr); unhexlify(arg+2, arg+strlen(arg)-1, expr);
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);
v.push_back(make_pair(string(arg), regex)); v.push_back(make_pair(string(arg), regex));
} else {
boost::regex regex(reinterpret_cast<char*>(expr),
reinterpret_cast<char*>(expr) + expr_len, boost::regex::icase);
v.push_back(make_pair(string(arg), regex));
}
} }
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
if (argc < 5) if (argc < 5)
{ {
std::cerr << "usage: tcpproxy_server <local host ip> <local port> <forward host ip> <forward port> C..... S....." << std::endl; std::cerr << "usage: tcpproxy_server <local host ip> <local port> <forward host ip> <forward port> 0C..... 1S....." << std::endl;
return 1; return 1;
} }
@@ -330,22 +336,26 @@ int main(int argc, char* argv[])
const std::string local_host = argv[1]; const std::string local_host = argv[1];
const std::string forward_host = argv[3]; const std::string forward_host = argv[3];
for (int i=5;i<argc;i++){ for (int i=5;i<argc;i++){
if (strlen(argv[i]) >= 1){ if (strlen(argv[i]) >= 2){
switch(argv[i][0]){ bool case_sensitive = true;
if(argv[i][0] == '0'){
case_sensitive = false;
}
switch(argv[i][1]){
case 'C': { // Client to server Blacklist case 'C': { // Client to server Blacklist
push_regex(argv[i], regex_c_s_b); push_regex(argv[i], case_sensitive, regex_c_s_b);
break; break;
} }
case 'c': { // Client to server Whitelist case 'c': { // Client to server Whitelist
push_regex(argv[i], regex_c_s_w); push_regex(argv[i], case_sensitive, regex_c_s_w);
break; break;
} }
case 'S': { // Server to client Blacklist case 'S': { // Server to client Blacklist
push_regex(argv[i], regex_s_c_b); push_regex(argv[i], case_sensitive, regex_s_c_b);
break; break;
} }
case 's': { // Server to client Whitelist case 's': { // Server to client Whitelist
push_regex(argv[i], regex_s_c_w); push_regex(argv[i], case_sensitive, regex_s_c_w);
break; break;
} }
} }

View File

@@ -115,6 +115,7 @@ class ProxyManager:
'id': row[5], 'id': row[5],
'regex': row[0], 'regex': row[0],
'is_blacklist': True if row[3] == "1" else False, 'is_blacklist': True if row[3] == "1" else False,
'is_case_sensitive' : True if row[6] == "1" else False,
'mode': row[1], 'mode': row[1],
'n_packets': row[4], 'n_packets': row[4],
} for row in self.db.query('SELECT * FROM regexes WHERE service_id = ?;', (id,))] } for row in self.db.query('SELECT * FROM regexes WHERE service_id = ?;', (id,))]
@@ -203,6 +204,7 @@ class ProxyManager:
restart_required = True restart_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"],
c_to_s=filter_info["mode"] in ["C","B"], c_to_s=filter_info["mode"] in ["C","B"],
s_to_c=filter_info["mode"] in ["S","B"], s_to_c=filter_info["mode"] in ["S","B"],
is_blacklist=filter_info["is_blacklist"], is_blacklist=filter_info["is_blacklist"],

View File

@@ -11,6 +11,7 @@ type RegexAddInfo = {
regex:string, regex:string,
type:string, type:string,
mode:string, mode:string,
is_case_sensitive:boolean,
regex_exact:boolean, regex_exact:boolean,
percentage_encoding:boolean percentage_encoding:boolean
} }
@@ -22,6 +23,7 @@ function AddNewRegex({ opened, onClose, service }:{ opened:boolean, onClose:()=>
regex:"", regex:"",
type:"blacklist", type:"blacklist",
mode:"C <-> S", mode:"C <-> S",
is_case_sensitive:true,
regex_exact:false, regex_exact:false,
percentage_encoding:false percentage_encoding:false
}, },
@@ -55,6 +57,7 @@ function AddNewRegex({ opened, onClose, service }:{ opened:boolean, onClose:()=>
const request:RegexAddForm = { const request:RegexAddForm = {
is_blacklist:values.type !== "whitelist", is_blacklist:values.type !== "whitelist",
is_case_sensitive: values.is_case_sensitive,
service_id: service, service_id: service,
mode: filter_mode?filter_mode:"B", mode: filter_mode?filter_mode:"B",
regex: b64encode(final_regex) regex: b64encode(final_regex)
@@ -65,7 +68,7 @@ function AddNewRegex({ opened, onClose, service }:{ opened:boolean, onClose:()=>
setSubmitLoading(false) setSubmitLoading(false)
close(); close();
fireUpdateRequest(); fireUpdateRequest();
okNotify(`Regex ${getHumanReadableRegex(request.regex)} has been added`, `Successfully added ${request.is_blacklist?"blacklist":"whitelist"} regex to ${request.service_id} service`) okNotify(`Regex ${getHumanReadableRegex(request.regex)} has been added`, `Successfully added ${request.is_case_sensitive?"case sensitive":"case insensitive"} ${request.is_blacklist?"blacklist":"whitelist"} regex to ${request.service_id} service`)
}else if (res.toLowerCase() === "invalid regex"){ }else if (res.toLowerCase() === "invalid regex"){
setSubmitLoading(false) setSubmitLoading(false)
form.setFieldError("regex", "Invalid Regex") form.setFieldError("regex", "Invalid Regex")
@@ -97,6 +100,11 @@ function AddNewRegex({ opened, onClose, service }:{ opened:boolean, onClose:()=>
/> />
</Tooltip> </Tooltip>
<Space h="md" /> <Space h="md" />
<Switch
label="Case sensitive"
{...form.getInputProps('is_case_sensitive', { type: 'checkbox' })}
/>
<Space h="md" />
<Switch <Switch
label="Match exactly the regex" label="Match exactly the regex"
{...form.getInputProps('regex_exact', { type: 'checkbox' })} {...form.getInputProps('regex_exact', { type: 'checkbox' })}

View File

@@ -74,6 +74,8 @@ function RegexView({ regexInfo }:{ regexInfo:RegexFilter }) {
<div className='center-flex-row'> <div className='center-flex-row'>
<Badge size="md" color={exact_regex?"grape":"pink"} variant="filled">Match: {exact_regex?"EXACT":"FIND"}</Badge> <Badge size="md" color={exact_regex?"grape":"pink"} variant="filled">Match: {exact_regex?"EXACT":"FIND"}</Badge>
<Space h="xs" /> <Space h="xs" />
<Badge size="md" color={regexInfo.is_case_sensitive?"red":"green"} variant="filled">Case: {regexInfo.is_case_sensitive?"SENSIIVE":"INSENSITIVE"}</Badge>
<Space h="xs" />
<Badge size="md" color="yellow" variant="filled">Packets filtered: {regexInfo.n_packets}</Badge> <Badge size="md" color="yellow" variant="filled">Packets filtered: {regexInfo.n_packets}</Badge>
<Space h="xs" /> <Space h="xs" />
<Badge size="md" color="blue" variant="filled">Mode: {mode_string}</Badge> <Badge size="md" color="blue" variant="filled">Mode: {mode_string}</Badge>

View File

@@ -42,6 +42,7 @@ export type RegexFilter = {
service_id:string, service_id:string,
regex:string regex:string
is_blacklist:boolean, is_blacklist:boolean,
is_case_sensitive:boolean,
mode:string //C S B => C->S S->C BOTH mode:string //C S B => C->S S->C BOTH
n_packets:number n_packets:number
} }
@@ -49,6 +50,7 @@ export type RegexFilter = {
export type RegexAddForm = { export type RegexAddForm = {
service_id:string, service_id:string,
regex:string, regex:string,
is_case_sensitive:boolean,
is_blacklist:boolean, is_blacklist:boolean,
mode:string // C->S S->C BOTH mode:string // C->S S->C BOTH
} }