feat: rule inheritance, rule groups, rule show/inspect redesign, rule add/update --extends --group, list filters
This commit is contained in:
parent
6ac1a7d3a2
commit
7b32dcfebc
4 changed files with 504 additions and 328 deletions
File diff suppressed because it is too large
Load diff
|
|
@ -38,6 +38,7 @@ function json::rule_resolve() { python3 "$JSON_HELPER" rule_resolve "$
|
||||||
function json::rule_resolve_field() { python3 "$JSON_HELPER" rule_resolve_field "$@" </dev/null; }
|
function json::rule_resolve_field() { python3 "$JSON_HELPER" rule_resolve_field "$@" </dev/null; }
|
||||||
function json::rule_inspect() { python3 "$JSON_HELPER" rule_inspect "$@" </dev/null; }
|
function json::rule_inspect() { python3 "$JSON_HELPER" rule_inspect "$@" </dev/null; }
|
||||||
function json::find_rule_file() { python3 "$JSON_HELPER" find_rule_file "$@" </dev/null; }
|
function json::find_rule_file() { python3 "$JSON_HELPER" find_rule_file "$@" </dev/null; }
|
||||||
|
function json::get_raw() { python3 "$JSON_HELPER" get_raw "$@" </dev/null; }
|
||||||
|
|
||||||
function json::peer_transfer() {
|
function json::peer_transfer() {
|
||||||
ACTIVITY_TOTAL_LOW="$(config::activity_total_low)" \
|
ACTIVITY_TOTAL_LOW="$(config::activity_total_low)" \
|
||||||
|
|
|
||||||
|
|
@ -748,15 +748,18 @@ def fmt_datetime(iso_str, fmt):
|
||||||
except:
|
except:
|
||||||
print(iso_str)
|
print(iso_str)
|
||||||
|
|
||||||
def create_rule(file, name, desc, dns_redirect, allow_ips, block_ips, block_ports):
|
def create_rule(file, name, desc, dns_redirect, allow_ips, block_ips,
|
||||||
|
block_ports, allow_ports='', extends='', group=''):
|
||||||
rule = {
|
rule = {
|
||||||
'name': name,
|
'name': name,
|
||||||
'desc': desc,
|
'desc': desc,
|
||||||
|
'group': group,
|
||||||
'dns_redirect': dns_redirect == 'true',
|
'dns_redirect': dns_redirect == 'true',
|
||||||
'allow_ips': [x for x in allow_ips.split(',') if x] if allow_ips else [],
|
'extends': [x for x in extends.split(',') if x] if extends else [],
|
||||||
'block_ips': [x for x in block_ips.split(',') if x] if block_ips else [],
|
'allow_ips': [x for x in allow_ips.split(',') if x] if allow_ips else [],
|
||||||
|
'allow_ports': [x for x in allow_ports.split(',') if x] if allow_ports else [],
|
||||||
|
'block_ips': [x for x in block_ips.split(',') if x] if block_ips else [],
|
||||||
'block_ports': [x for x in block_ports.split(',') if x] if block_ports else [],
|
'block_ports': [x for x in block_ports.split(',') if x] if block_ports else [],
|
||||||
'allow_ports': []
|
|
||||||
}
|
}
|
||||||
with open(file, 'w') as f:
|
with open(file, 'w') as f:
|
||||||
json.dump(rule, f, indent=2)
|
json.dump(rule, f, indent=2)
|
||||||
|
|
@ -985,8 +988,10 @@ def _rule_resolve_internal(rules_dir, rule_name, visited=None):
|
||||||
rule = json.load(f)
|
rule = json.load(f)
|
||||||
|
|
||||||
merged = {
|
merged = {
|
||||||
'allow_ips': [], 'allow_ports': [],
|
'allow_ips': [],
|
||||||
'block_ips': [], 'block_ports': [],
|
'allow_ports': [],
|
||||||
|
'block_ips': [],
|
||||||
|
'block_ports': [],
|
||||||
'dns_redirect': False
|
'dns_redirect': False
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -999,15 +1004,21 @@ def _rule_resolve_internal(rules_dir, rule_name, visited=None):
|
||||||
if base.get('dns_redirect'):
|
if base.get('dns_redirect'):
|
||||||
merged['dns_redirect'] = True
|
merged['dns_redirect'] = True
|
||||||
|
|
||||||
merged['allow_ips'] = list(dict.fromkeys(merged['allow_ips'] + rule.get('allow_ips', [])))
|
# Merge own fields — use .get() with defaults for all fields
|
||||||
merged['allow_ports'] = list(dict.fromkeys(merged['allow_ports'] + rule.get('allow_ports', [])))
|
merged['allow_ips'] = list(dict.fromkeys(
|
||||||
merged['block_ips'] = list(dict.fromkeys(merged['block_ips'] + rule.get('block_ips', [])))
|
merged['allow_ips'] + rule.get('allow_ips', [])))
|
||||||
merged['block_ports'] = list(dict.fromkeys(merged['block_ports'] + rule.get('block_ports', [])))
|
merged['allow_ports'] = list(dict.fromkeys(
|
||||||
if rule.get('dns_redirect'):
|
merged['allow_ports'] + rule.get('allow_ports', [])))
|
||||||
|
merged['block_ips'] = list(dict.fromkeys(
|
||||||
|
merged['block_ips'] + rule.get('block_ips', [])))
|
||||||
|
merged['block_ports'] = list(dict.fromkeys(
|
||||||
|
merged['block_ports'] + rule.get('block_ports', [])))
|
||||||
|
if rule.get('dns_redirect', False):
|
||||||
merged['dns_redirect'] = True
|
merged['dns_redirect'] = True
|
||||||
|
|
||||||
merged['name'] = rule['name']
|
merged['name'] = rule.get('name', rule_name)
|
||||||
merged['desc'] = rule.get('desc', '')
|
merged['desc'] = rule.get('desc', '')
|
||||||
|
merged['group'] = rule.get('group', '')
|
||||||
merged['extends'] = rule.get('extends', [])
|
merged['extends'] = rule.get('extends', [])
|
||||||
return merged
|
return merged
|
||||||
|
|
||||||
|
|
@ -1102,7 +1113,24 @@ def find_rule_file(rules_dir, rule_name):
|
||||||
]:
|
]:
|
||||||
if os.path.exists(path):
|
if os.path.exists(path):
|
||||||
return path
|
return path
|
||||||
raise FileNotFoundError(f"Rule not found: {rule_name}")
|
return ""
|
||||||
|
|
||||||
|
def get_raw(file, key):
|
||||||
|
try:
|
||||||
|
with open(file) as f:
|
||||||
|
data = json.load(f)
|
||||||
|
val = data.get(key) # returns None if missing
|
||||||
|
if val is None:
|
||||||
|
pass # print nothing
|
||||||
|
elif isinstance(val, bool):
|
||||||
|
print(str(val).lower())
|
||||||
|
elif isinstance(val, list):
|
||||||
|
for v in val:
|
||||||
|
print(v)
|
||||||
|
else:
|
||||||
|
print(val)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
commands = {
|
commands = {
|
||||||
'get': lambda args: get(args[0], args[1]),
|
'get': lambda args: get(args[0], args[1]),
|
||||||
|
|
@ -1130,7 +1158,12 @@ commands = {
|
||||||
'rule_list_data': lambda args: rule_list_data(args[0], args[1]),
|
'rule_list_data': lambda args: rule_list_data(args[0], args[1]),
|
||||||
'group_list_data': lambda args: group_list_data(args[0], args[1]),
|
'group_list_data': lambda args: group_list_data(args[0], args[1]),
|
||||||
'fmt_datetime': lambda args: fmt_datetime(args[0], args[1]),
|
'fmt_datetime': lambda args: fmt_datetime(args[0], args[1]),
|
||||||
'create_rule': lambda args: create_rule(args[0], args[1], args[2], args[3], args[4], args[5], args[6]),
|
'create_rule': lambda args: create_rule(
|
||||||
|
args[0], args[1], args[2], args[3], args[4], args[5], args[6],
|
||||||
|
args[7] if len(args) > 7 else '',
|
||||||
|
args[8] if len(args) > 8 else '',
|
||||||
|
args[9] if len(args) > 9 else ''
|
||||||
|
),
|
||||||
'cleanup_config': lambda args: cleanup_config(args[0]),
|
'cleanup_config': lambda args: cleanup_config(args[0]),
|
||||||
'remove_peer_block': lambda args: remove_peer_block(args[0], args[1]),
|
'remove_peer_block': lambda args: remove_peer_block(args[0], args[1]),
|
||||||
'create_group': lambda args: create_group(args[0], args[1], args[2]),
|
'create_group': lambda args: create_group(args[0], args[1], args[2]),
|
||||||
|
|
@ -1145,6 +1178,7 @@ commands = {
|
||||||
'rule_resolve_field': lambda args: rule_resolve_field(args[0], args[1], args[2]),
|
'rule_resolve_field': lambda args: rule_resolve_field(args[0], args[1], args[2]),
|
||||||
'rule_inspect': lambda args: rule_inspect(args[0], args[1]),
|
'rule_inspect': lambda args: rule_inspect(args[0], args[1]),
|
||||||
'find_rule_file': lambda args: print(find_rule_file(args[0], args[1])),
|
'find_rule_file': lambda args: print(find_rule_file(args[0], args[1])),
|
||||||
|
'get_raw': lambda args: print(get_raw(args[0], args[1])),
|
||||||
}
|
}
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,9 @@ function rule::is_base() {
|
||||||
|
|
||||||
function rule::exists() {
|
function rule::exists() {
|
||||||
local name="${1:-}"
|
local name="${1:-}"
|
||||||
[[ -f "$(rule::path "${name}")" ]] || \
|
local path
|
||||||
[[ -f "$(ctx::rules::base)/${name}.rule" ]]
|
path=$(json::find_rule_file "$(ctx::rules)" "$name")
|
||||||
|
[[ -n "$path" ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
function rule::require_assignable() {
|
function rule::require_assignable() {
|
||||||
|
|
@ -36,6 +37,13 @@ function rule::get() {
|
||||||
json::rule_resolve_field "$(ctx::rules)" "$name" "$key"
|
json::rule_resolve_field "$(ctx::rules)" "$name" "$key"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function rule::get_own() {
|
||||||
|
local name="${1:-}" key="${2:-}"
|
||||||
|
local file
|
||||||
|
file=$(rule::path "$name") || return 0
|
||||||
|
json::get_raw "$file" "$key"
|
||||||
|
}
|
||||||
|
|
||||||
function rule::get_resolved() {
|
function rule::get_resolved() {
|
||||||
local name="${1:-}"
|
local name="${1:-}"
|
||||||
json::rule_resolve "$(ctx::rules)" "$name"
|
json::rule_resolve "$(ctx::rules)" "$name"
|
||||||
|
|
@ -43,7 +51,9 @@ function rule::get_resolved() {
|
||||||
|
|
||||||
function rule::path() {
|
function rule::path() {
|
||||||
local name="${1:-}"
|
local name="${1:-}"
|
||||||
json::find_rule_file "$(ctx::rules)" "$name"
|
local path
|
||||||
|
path=$(json::find_rule_file "$(ctx::rules)" "$name")
|
||||||
|
[[ -n "$path" ]] && echo "$path" || return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
function rule::get_all() {
|
function rule::get_all() {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue