mirror of
https://github.com/caiwx86/small-packages.git
synced 2026-10-31 01:35:13 +08:00
update 2026-05-10 09:48:30
This commit is contained in:
1 parent
95ac96413e
commit
0b362674f1
6244 files changed
+2992248
No files matched your search
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,129 @@
|
||||
config config 'config'
|
||||
option 'init' '1'
|
||||
option 'enabled' '0'
|
||||
option 'profile' 'file:example.json'
|
||||
option 'start_delay' '0'
|
||||
option 'scheduled_restart' '0'
|
||||
option 'scheduled_restart_cron' '0 3 * * *'
|
||||
option 'test_profile' '1'
|
||||
option 'core_only' '0'
|
||||
|
||||
config procd 'procd'
|
||||
option 'fast_reload' '0'
|
||||
|
||||
config core 'core'
|
||||
option 'redirect_inbound_tag' 'redirect-in'
|
||||
option 'tproxy_inbound_tag' 'tproxy-in'
|
||||
option 'tun_inbound_tag' 'tun-in'
|
||||
option 'dns_inbound_tag' 'dns-in'
|
||||
option 'fake_ip_dns_server_tag' 'fake-ip-dns-server'
|
||||
|
||||
config mixin 'mixin'
|
||||
option 'log_disabled' '0'
|
||||
option 'log_level' 'info'
|
||||
option 'log_timestamp' '1'
|
||||
option 'dns_independent_cache' '1'
|
||||
option 'dns_reverse_mapping' '1'
|
||||
option 'cache_enabled' '1'
|
||||
option 'cache_store_fakeip' '1'
|
||||
option 'cache_store_rdrc' '1'
|
||||
option 'external_control_ui_path' 'ui'
|
||||
option 'external_control_ui_download_url' 'https://github.com/Zephyruso/zashboard/releases/latest/download/dist-cdn-fonts.zip'
|
||||
|
||||
config proxy 'proxy'
|
||||
option 'enabled' '1'
|
||||
option 'ipv4_dns_hijack' '1'
|
||||
option 'ipv6_dns_hijack' '1'
|
||||
option 'ipv4_proxy' '1'
|
||||
option 'ipv6_proxy' '1'
|
||||
option 'fake_ip_ping_hijack' '1'
|
||||
option 'tcp_mode' 'redirect'
|
||||
option 'udp_mode' 'tun'
|
||||
option 'router_proxy' '1'
|
||||
option 'lan_proxy' '1'
|
||||
list 'lan_inbound_interface' 'lan'
|
||||
list 'reserved_ip' '0.0.0.0/8'
|
||||
list 'reserved_ip' '10.0.0.0/8'
|
||||
list 'reserved_ip' '127.0.0.0/8'
|
||||
list 'reserved_ip' '100.64.0.0/10'
|
||||
list 'reserved_ip' '169.254.0.0/16'
|
||||
list 'reserved_ip' '172.16.0.0/12'
|
||||
list 'reserved_ip' '192.168.0.0/16'
|
||||
list 'reserved_ip' '224.0.0.0/4'
|
||||
list 'reserved_ip' '240.0.0.0/4'
|
||||
list 'reserved_ip6' '::/128'
|
||||
list 'reserved_ip6' '::1/128'
|
||||
list 'reserved_ip6' '::ffff:0:0/96'
|
||||
list 'reserved_ip6' '100::/64'
|
||||
list 'reserved_ip6' '64:ff9b::/96'
|
||||
list 'reserved_ip6' '2001::/32'
|
||||
list 'reserved_ip6' '2001:10::/28'
|
||||
list 'reserved_ip6' '2001:20::/28'
|
||||
list 'reserved_ip6' '2001:db8::/32'
|
||||
list 'reserved_ip6' '2002::/16'
|
||||
list 'reserved_ip6' 'fc00::/7'
|
||||
list 'reserved_ip6' 'fe80::/10'
|
||||
list 'reserved_ip6' 'ff00::/8'
|
||||
option 'bypass_china_mainland_ip' '0'
|
||||
option 'bypass_china_mainland_ip6' '0'
|
||||
option 'proxy_tcp_dport' '0-65535'
|
||||
option 'proxy_udp_dport' '0-65535'
|
||||
list 'bypass_dscp' '4'
|
||||
option 'tun_timeout' '30'
|
||||
option 'tun_interval' '1'
|
||||
|
||||
config router_access_control
|
||||
option 'enabled' '1'
|
||||
list 'user' 'dnsmasq'
|
||||
list 'user' 'ftp'
|
||||
list 'user' 'logd'
|
||||
list 'user' 'nobody'
|
||||
list 'user' 'ntp'
|
||||
list 'user' 'ubus'
|
||||
list 'group' 'dnsmasq'
|
||||
list 'group' 'ftp'
|
||||
list 'group' 'logd'
|
||||
list 'group' 'nogroup'
|
||||
list 'group' 'ntp'
|
||||
list 'group' 'ubus'
|
||||
list 'cgroup' 'services/adguardhome'
|
||||
list 'cgroup' 'services/aria2'
|
||||
list 'cgroup' 'services/dnsmasq'
|
||||
list 'cgroup' 'services/netbird'
|
||||
list 'cgroup' 'services/qbittorrent'
|
||||
list 'cgroup' 'services/sysntpd'
|
||||
list 'cgroup' 'services/tailscale'
|
||||
list 'cgroup' 'services/zerotier'
|
||||
option 'dns' '0'
|
||||
option 'proxy' '0'
|
||||
|
||||
config router_access_control
|
||||
option 'enabled' '1'
|
||||
option 'dns' '1'
|
||||
option 'proxy' '1'
|
||||
|
||||
config lan_access_control
|
||||
option 'enabled' '1'
|
||||
option 'dns' '1'
|
||||
option 'proxy' '1'
|
||||
|
||||
config routing 'routing'
|
||||
option 'tproxy_fw_mark' '0x80'
|
||||
option 'tproxy_fw_mask' '0xFF'
|
||||
option 'tun_fw_mark' '0x81'
|
||||
option 'tun_fw_mask' '0xFF'
|
||||
option 'tproxy_rule_pref' '1024'
|
||||
option 'tun_rule_pref' '1025'
|
||||
option 'tproxy_route_table' '80'
|
||||
option 'tun_route_table' '81'
|
||||
option 'cgroup_id' '0x07250725'
|
||||
option 'cgroup_name' 'momo'
|
||||
option 'dummy_device' 'momo-dummy'
|
||||
|
||||
config log 'log'
|
||||
option 'scheduled_clear' '1'
|
||||
option 'scheduled_clear_cron' '*/5 * * * *'
|
||||
option 'scheduled_clear_size_limit' '1'
|
||||
option 'scheduled_clear_size_limit_unit' 'MB'
|
||||
|
||||
config placeholder 'placeholder'
|
||||
@@ -0,0 +1,563 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
|
||||
START=99
|
||||
STOP=10
|
||||
USE_PROCD=1
|
||||
|
||||
PROG="/usr/bin/sing-box"
|
||||
|
||||
. "$IPKG_INSTROOT/etc/momo/scripts/include.sh"
|
||||
|
||||
extra_command 'update_subscription' 'Update subscription by section id'
|
||||
extra_command 'clear_logs' 'Clear logs if size exceeds the limit'
|
||||
|
||||
boot_func() {
|
||||
# prepare files
|
||||
prepare_files
|
||||
# load config
|
||||
config_load momo
|
||||
# start delay
|
||||
local enabled start_delay
|
||||
config_get_bool enabled "config" "enabled" 0
|
||||
config_get start_delay "config" "start_delay" 0
|
||||
if [ "$enabled" = 1 ] && [ "$start_delay" -gt 0 ]; then
|
||||
log "App" "Start after $start_delay seconds."
|
||||
sleep "$start_delay"
|
||||
fi
|
||||
# start
|
||||
start
|
||||
}
|
||||
|
||||
boot() {
|
||||
boot_func < /dev/null > /dev/null 2>&1 &
|
||||
}
|
||||
|
||||
start_service() {
|
||||
# prepare files
|
||||
prepare_files
|
||||
# load config
|
||||
config_load momo
|
||||
# check if enabled
|
||||
local enabled
|
||||
config_get_bool enabled "config" "enabled" 0
|
||||
if [ "$enabled" = 0 ]; then
|
||||
log "App" "Disabled."
|
||||
log "App" "Exit."
|
||||
return
|
||||
fi
|
||||
# start
|
||||
log "App" "Enabled."
|
||||
log "App" "Start."
|
||||
# check if executable
|
||||
if [ ! -x $PROG ]; then
|
||||
log "App" "Core is not executable."
|
||||
log "App" "Exit."
|
||||
return
|
||||
fi
|
||||
# get config
|
||||
## app config
|
||||
local scheduled_restart scheduled_restart_cron profile test_profile core_only
|
||||
config_get_bool scheduled_restart "config" "scheduled_restart" 0
|
||||
config_get scheduled_restart_cron "config" "scheduled_restart_cron"
|
||||
config_get profile "config" "profile"
|
||||
config_get_bool test_profile "config" "test_profile" 0
|
||||
config_get_bool core_only "config" "core_only" 0
|
||||
## procd config
|
||||
### general
|
||||
local fast_reload
|
||||
config_get_bool fast_reload "procd" "fast_reload" 0
|
||||
### rlimit
|
||||
local rlimit_address_space_soft rlimit_address_space_hard rlimit_data_soft rlimit_data_hard rlimit_stack_soft rlimit_stack_hard rlimit_nofile_soft rlimit_nofile_hard
|
||||
config_get rlimit_address_space_soft "procd" "rlimit_address_space_soft"
|
||||
config_get rlimit_address_space_hard "procd" "rlimit_address_space_hard"
|
||||
config_get rlimit_data_soft "procd" "rlimit_data_soft"
|
||||
config_get rlimit_data_hard "procd" "rlimit_data_hard"
|
||||
config_get rlimit_stack_soft "procd" "rlimit_stack_soft"
|
||||
config_get rlimit_stack_hard "procd" "rlimit_stack_hard"
|
||||
config_get rlimit_nofile_soft "procd" "rlimit_nofile_soft" "$(ulimit -Sn)"
|
||||
config_get rlimit_nofile_hard "procd" "rlimit_nofile_hard" "$(ulimit -Hn)"
|
||||
## core config
|
||||
local redirect_inbound_tag tproxy_inbound_tag tun_inbound_tag dns_inbound_tag fake_ip_dns_server_tag
|
||||
config_get redirect_inbound_tag "core" "redirect_inbound_tag"
|
||||
config_get tproxy_inbound_tag "core" "tproxy_inbound_tag"
|
||||
config_get tun_inbound_tag "core" "tun_inbound_tag"
|
||||
config_get dns_inbound_tag "core" "dns_inbound_tag"
|
||||
config_get fake_ip_dns_server_tag "core" "fake_ip_dns_server_tag"
|
||||
## proxy config
|
||||
local proxy_enabled ipv4_dns_hijack ipv6_dns_hijack tcp_mode udp_mode
|
||||
config_get_bool proxy_enabled "proxy" "enabled" 0
|
||||
config_get_bool ipv4_dns_hijack "proxy" "ipv4_dns_hijack" 0
|
||||
config_get_bool ipv6_dns_hijack "proxy" "ipv6_dns_hijack" 0
|
||||
config_get tcp_mode "proxy" "tcp_mode"
|
||||
config_get udp_mode "proxy" "udp_mode"
|
||||
## log config
|
||||
local log_scheduled_clear log_scheduled_clear_cron
|
||||
config_get_bool log_scheduled_clear "log" "scheduled_clear" 0
|
||||
config_get log_scheduled_clear_cron "log" "scheduled_clear_cron"
|
||||
# get profile
|
||||
local profile_type; profile_type=$(echo "$profile" | cut -d ':' -f 1)
|
||||
local profile_id; profile_id=$(echo "$profile" | cut -d ':' -f 2)
|
||||
if [ "$profile_type" = "file" ]; then
|
||||
local profile_name; profile_name="$profile_id"
|
||||
local profile_file; profile_file="$PROFILES_DIR/$profile_name"
|
||||
log "Profile" "Use file: $profile_name."
|
||||
if [ ! -f "$profile_file" ]; then
|
||||
log "Profile" "File not found."
|
||||
log "App" "Exit."
|
||||
return
|
||||
fi
|
||||
cp -f "$profile_file" "$RUN_PROFILE_PATH"
|
||||
elif [ "$profile_type" = "subscription" ]; then
|
||||
local subscription_section; subscription_section="$profile_id"
|
||||
local subscription_name subscription_prefer
|
||||
config_get subscription_name "$subscription_section" "name"
|
||||
config_get subscription_prefer "$subscription_section" "prefer" "remote"
|
||||
log "Profile" "Use subscription: $subscription_name."
|
||||
local subscription_file; subscription_file="$SUBSCRIPTIONS_DIR/$subscription_section.json"
|
||||
if [ "$subscription_prefer" = "remote" ] || [ ! -f "$subscription_file" ]; then
|
||||
update_subscription "$subscription_section"
|
||||
fi
|
||||
if [ ! -f "$subscription_file" ]; then
|
||||
log "Profile" "Subscription file not found."
|
||||
log "App" "Exit."
|
||||
return
|
||||
fi
|
||||
cp -f "$subscription_file" "$RUN_PROFILE_PATH"
|
||||
else
|
||||
log "Profile" "No profile/subscription selected."
|
||||
log "App" "Exit."
|
||||
return
|
||||
fi
|
||||
# mixin
|
||||
if [ "$core_only" = 0 ]; then
|
||||
log "Mixin" "Mixin config."
|
||||
ucode -S "$MIXIN_UC"
|
||||
fi
|
||||
# check profile
|
||||
if [ "$core_only" = 0 ] && [ "$proxy_enabled" = 1 ]; then
|
||||
log "Profile" "Checking..."
|
||||
if [ "$ipv4_dns_hijack" = 1 ] || [ "$ipv6_dns_hijack" = 1 ]; then
|
||||
local dns_port; dns_port=$(jsonfilter -q -i "$RUN_PROFILE_PATH" -e "@['inbounds'][*]" | jsonfilter -q -a -e "@[@['tag']='$dns_inbound_tag']" | jsonfilter -q -a -e "@[@['type']='direct']" | jsonfilter -q -e "@['listen_port']")
|
||||
if [ -z "$dns_port" ]; then
|
||||
log "Profile" "Check failed."
|
||||
log "Profile" "DNS inbound not found, should be tagged with $dns_inbound_tag and define listen_port."
|
||||
log "App" "Exit."
|
||||
return
|
||||
fi
|
||||
fi
|
||||
if [ "$tcp_mode" = "redirect" ]; then
|
||||
local redirect_port; redirect_port=$(jsonfilter -q -i "$RUN_PROFILE_PATH" -e "@['inbounds'][*]" | jsonfilter -q -a -e "@[@['tag']='$redirect_inbound_tag']" | jsonfilter -q -a -e "@[@['type']='redirect']" | jsonfilter -q -e "@['listen_port']")
|
||||
if [ -z "$redirect_port" ]; then
|
||||
log "Profile" "Check failed."
|
||||
log "Profile" "Redirect inbound not found, should be tagged with $redirect_inbound_tag and define listen_port."
|
||||
log "App" "Exit."
|
||||
return
|
||||
fi
|
||||
fi
|
||||
if [ "$tcp_mode" = "tproxy" ] || [ "$udp_mode" = "tproxy" ]; then
|
||||
local tproxy_port; tproxy_port=$(jsonfilter -q -i "$RUN_PROFILE_PATH" -e "@['inbounds'][*]" | jsonfilter -q -a -e "@[@['tag']='$tproxy_inbound_tag']" | jsonfilter -q -a -e "@[@['type']='tproxy']" | jsonfilter -q -e "@['listen_port']")
|
||||
if [ -z "$tproxy_port" ]; then
|
||||
log "Profile" "Check failed."
|
||||
log "Profile" "TPROXY inbound not found, should be tagged with $tproxy_inbound_tag and define listen_port."
|
||||
log "App" "Exit."
|
||||
return
|
||||
fi
|
||||
fi
|
||||
if [ "$tcp_mode" = "tun" ] || [ "$udp_mode" = "tun" ]; then
|
||||
local tun_device; tun_device=$(jsonfilter -q -i "$RUN_PROFILE_PATH" -e "@['inbounds'][*]" | jsonfilter -q -a -e "@[@['tag']='$tun_inbound_tag']" | jsonfilter -q -a -e "@[@['type']='tun']" | jsonfilter -q -e "@['interface_name']")
|
||||
if [ -z "$tun_device" ]; then
|
||||
log "Profile" "Check failed."
|
||||
log "Profile" "TUN inbound not found, should be tagged with $tun_inbound_tag and define interface_name."
|
||||
log "App" "Exit."
|
||||
return
|
||||
fi
|
||||
fi
|
||||
log "Profile" "Check passed."
|
||||
fi
|
||||
# test profile
|
||||
if [ "$test_profile" = 1 ]; then
|
||||
log "Profile" "Testing..."
|
||||
if $PROG -D "$RUN_DIR" check >> "$CORE_LOG_PATH" 2>&1; then
|
||||
log "Profile" "Test passed."
|
||||
else
|
||||
log "Profile" "Test failed."
|
||||
log "Profile" "Please check the core log to find out the problem."
|
||||
log "App" "Exit."
|
||||
return
|
||||
fi
|
||||
fi
|
||||
# start core
|
||||
log "Core" "Start."
|
||||
procd_open_instance momo
|
||||
|
||||
procd_set_param command /bin/sh -c "$PROG -D $RUN_DIR run --disable-color >> $CORE_LOG_PATH 2>&1"
|
||||
procd_set_param file "$RUN_PROFILE_PATH"
|
||||
if [ "$fast_reload" = 1 ]; then
|
||||
procd_set_param reload_signal HUP
|
||||
fi
|
||||
procd_set_param pidfile "$PID_FILE_PATH"
|
||||
procd_set_param respawn
|
||||
procd_append_param limits as="${rlimit_address_space_soft:-unlimited} ${rlimit_address_space_hard:-unlimited}"
|
||||
procd_append_param limits data="${rlimit_data_soft:-unlimited} ${rlimit_data_hard:-unlimited}"
|
||||
procd_append_param limits stack="${rlimit_stack_soft:-unlimited} ${rlimit_stack_hard:-unlimited}"
|
||||
procd_append_param limits nofile="${rlimit_nofile_soft} ${rlimit_nofile_hard}"
|
||||
|
||||
procd_close_instance
|
||||
# cron
|
||||
local reload_cron; reload_cron=0
|
||||
if [ "$scheduled_restart" = 1 ] && [ -n "$scheduled_restart_cron" ]; then
|
||||
log "App" "Set scheduled restart."
|
||||
echo "$scheduled_restart_cron /etc/init.d/momo restart #momo scheduled restart" >> "/etc/crontabs/root"
|
||||
reload_cron=1
|
||||
fi
|
||||
if [ "$log_scheduled_clear" = 1 ] && [ -n "$log_scheduled_clear_cron" ]; then
|
||||
log "App" "Set log scheduled clear."
|
||||
echo "$log_scheduled_clear_cron /etc/init.d/momo clear_logs #momo log scheduled clear" >> "/etc/crontabs/root"
|
||||
reload_cron=1
|
||||
fi
|
||||
if [ "$reload_cron" = 1 ]; then
|
||||
/etc/init.d/cron restart
|
||||
fi
|
||||
# set started flag
|
||||
touch "$STARTED_FLAG_PATH"
|
||||
}
|
||||
|
||||
service_started() {
|
||||
# check if started
|
||||
if [ ! -f "$STARTED_FLAG_PATH" ]; then
|
||||
return
|
||||
fi
|
||||
# load config
|
||||
config_load momo
|
||||
# check if proxy enabled
|
||||
local proxy_enabled
|
||||
config_get_bool proxy_enabled "proxy" "enabled" 0
|
||||
if [ "$proxy_enabled" = 0 ]; then
|
||||
log "Proxy" "Disabled."
|
||||
return
|
||||
fi
|
||||
# get config
|
||||
## app config
|
||||
local core_only
|
||||
config_get_bool core_only "config" "core_only" 0
|
||||
## core
|
||||
local tun_inbound_tag fake_ip_dns_server_tag
|
||||
config_get tun_inbound_tag "core" "tun_inbound_tag"
|
||||
config_get fake_ip_dns_server_tag "core" "fake_ip_dns_server_tag"
|
||||
## proxy config
|
||||
### general
|
||||
local ipv4_proxy ipv6_proxy tcp_mode udp_mode tun_timeout tun_interval
|
||||
config_get_bool ipv4_proxy "proxy" "ipv4_proxy" 0
|
||||
config_get_bool ipv6_proxy "proxy" "ipv6_proxy" 0
|
||||
config_get tcp_mode "proxy" "tcp_mode"
|
||||
config_get udp_mode "proxy" "udp_mode"
|
||||
config_get tun_timeout "proxy" "tun_timeout" 30
|
||||
config_get tun_interval "proxy" "tun_interval" 1
|
||||
## routing config
|
||||
local tproxy_fw_mark tproxy_fw_mask tun_fw_mark tun_fw_mask tproxy_rule_pref tun_rule_pref tproxy_route_table tun_route_table cgroup_id cgroup_name dummy_device
|
||||
config_get tproxy_fw_mark "routing" "tproxy_fw_mark" "0x80"
|
||||
config_get tproxy_fw_mask "routing" "tproxy_fw_mask" "0xFF"
|
||||
config_get tun_fw_mark "routing" "tun_fw_mark" "0x81"
|
||||
config_get tun_fw_mask "routing" "tun_fw_mask" "0xFF"
|
||||
config_get tproxy_rule_pref "routing" "tproxy_rule_pref" "1024"
|
||||
config_get tun_rule_pref "routing" "tun_rule_pref" "1025"
|
||||
config_get tproxy_route_table "routing" "tproxy_route_table" "80"
|
||||
config_get tun_route_table "routing" "tun_route_table" "81"
|
||||
config_get cgroup_id "routing" "cgroup_id" "0x12061206"
|
||||
config_get cgroup_name "routing" "cgroup_name" "momo"
|
||||
config_get dummy_device "routing" "dummy_device" "momo-dummy"
|
||||
# prepare config
|
||||
local tproxy_enable; tproxy_enable=0
|
||||
if [ "$tcp_mode" = "tproxy" ] || [ "$udp_mode" = "tproxy" ]; then
|
||||
tproxy_enable=1
|
||||
fi
|
||||
local tun_enable; tun_enable=0
|
||||
if [ "$tcp_mode" = "tun" ] || [ "$udp_mode" = "tun" ]; then
|
||||
tun_enable=1
|
||||
fi
|
||||
local tun_device; tun_device=$(jsonfilter -q -i "$RUN_PROFILE_PATH" -e "@['inbounds'][*]" | jsonfilter -q -a -e "@[@['tag']='$tun_inbound_tag']" | jsonfilter -q -a -e "@[@['type']='tun']" | jsonfilter -q -e "@['interface_name']")
|
||||
local fake_ip6_range; fake_ip6_range=$(jsonfilter -q -i "$RUN_PROFILE_PATH" -e "@['dns']['servers'][*]" | jsonfilter -q -a -e "@[@['tag']='$fake_ip_dns_server_tag']" | jsonfilter -q -e "@['inet6_range']")
|
||||
if [ "$core_only" = 0 ]; then
|
||||
# proxy
|
||||
log "Proxy" "Enabled."
|
||||
# wait for tun device online
|
||||
if [ "$tun_enable" = 1 ]; then
|
||||
log "Proxy" "Waiting for tun device online within $tun_timeout seconds..."
|
||||
while [ "$tun_timeout" -gt 0 ]; do
|
||||
if ip -j link show dev "$tun_device" 2>/dev/null | jsonfilter -q -e "@[@['flags'][@='UP']]" > /dev/null 2>&1; then
|
||||
log "Proxy" "TUN device is online."
|
||||
break
|
||||
fi
|
||||
tun_timeout=$((tun_timeout - tun_interval))
|
||||
sleep "$tun_interval"
|
||||
done
|
||||
if [ "$tun_timeout" -le 0 ]; then
|
||||
log "Proxy" "Timeout, TUN device is not online."
|
||||
log "App" "Exit."
|
||||
return
|
||||
fi
|
||||
fi
|
||||
# fix compatible with dockerd
|
||||
## cgroupfs-mount
|
||||
### when cgroupfs-mount is installed, cgroupv1 will mounted instead of cgroupv2, we need to create cgroup manually
|
||||
if mount | grep -q -w "^cgroup"; then
|
||||
mkdir -p "/sys/fs/cgroup/net_cls/$cgroup_name"
|
||||
echo "$cgroup_id" > "/sys/fs/cgroup/net_cls/$cgroup_name/net_cls.classid"
|
||||
cat "$PID_FILE_PATH" > "/sys/fs/cgroup/net_cls/$cgroup_name/cgroup.procs"
|
||||
fi
|
||||
## kmod-br-netfilter
|
||||
### when kmod-br-netfilter is loaded, bridge-nf-call-iptables and bridge-nf-call-ip6tables are set to 1, we need to set them to 0 if tproxy is enabled
|
||||
if [ "$tproxy_enable" = 1 ] && (lsmod | grep -q br_netfilter); then
|
||||
if [ "$ipv4_proxy" = 1 ]; then
|
||||
local bridge_nf_call_iptables; bridge_nf_call_iptables=$(sysctl -e -n net.bridge.bridge-nf-call-iptables)
|
||||
if [ "$bridge_nf_call_iptables" = 1 ]; then
|
||||
touch "$BRIDGE_NF_CALL_IPTABLES_FLAG_PATH"
|
||||
sysctl -q -w net.bridge.bridge-nf-call-iptables=0
|
||||
fi
|
||||
fi
|
||||
if [ "$ipv6_proxy" = 1 ]; then
|
||||
local bridge_nf_call_ip6tables; bridge_nf_call_ip6tables=$(sysctl -e -n net.bridge.bridge-nf-call-ip6tables)
|
||||
if [ "$bridge_nf_call_ip6tables" = 1 ]; then
|
||||
touch "$BRIDGE_NF_CALL_IP6TABLES_FLAG_PATH"
|
||||
sysctl -q -w net.bridge.bridge-nf-call-ip6tables=0
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
# ip route and rule
|
||||
if [ "$tproxy_enable" = 1 ]; then
|
||||
if [ "$ipv4_proxy" = 1 ]; then
|
||||
ip -4 route add local default dev lo table "$tproxy_route_table"
|
||||
ip -4 rule add pref "$tproxy_rule_pref" fwmark "$tproxy_fw_mark/$tproxy_fw_mask" table "$tproxy_route_table"
|
||||
fi
|
||||
if [ "$ipv6_proxy" = 1 ]; then
|
||||
ip -6 route add local default dev lo table "$tproxy_route_table"
|
||||
ip -6 rule add pref "$tproxy_rule_pref" fwmark "$tproxy_fw_mark/$tproxy_fw_mask" table "$tproxy_route_table"
|
||||
fi
|
||||
fi
|
||||
if [ "$tun_enable" = 1 ]; then
|
||||
if [ "$ipv4_proxy" = 1 ]; then
|
||||
ip -4 route add unicast default dev "$tun_device" table "$tun_route_table"
|
||||
ip -4 rule add pref "$tun_rule_pref" fwmark "$tun_fw_mark/$tun_fw_mask" table "$tun_route_table"
|
||||
fi
|
||||
if [ "$ipv6_proxy" = 1 ]; then
|
||||
ip -6 route add unicast default dev "$tun_device" table "$tun_route_table"
|
||||
ip -6 rule add pref "$tun_rule_pref" fwmark "$tun_fw_mark/$tun_fw_mask" table "$tun_route_table"
|
||||
fi
|
||||
$FIREWALL_INCLUDE_SH
|
||||
fi
|
||||
if [ -n "$fake_ip6_range" ]; then
|
||||
ip link add "$dummy_device" type dummy
|
||||
ip link set dev "$dummy_device" up
|
||||
ip -6 route add "$fake_ip6_range" dev "$dummy_device"
|
||||
fi
|
||||
# hijack
|
||||
utpl -S "$HIJACK_UT" | nft -f -
|
||||
# check hijack
|
||||
if nft list tables | grep -q momo; then
|
||||
log "Proxy" "Hijack successful."
|
||||
else
|
||||
log "Proxy" "Hijack failed."
|
||||
log "App" "Exit."
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
service_stopped() {
|
||||
cleanup
|
||||
}
|
||||
|
||||
reload_service() {
|
||||
cleanup
|
||||
start
|
||||
}
|
||||
|
||||
service_triggers() {
|
||||
procd_add_reload_trigger "momo"
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
# load config
|
||||
config_load momo
|
||||
# get config
|
||||
## routing config
|
||||
local tproxy_route_table tun_route_table dummy_device
|
||||
config_get tproxy_route_table "routing" "tproxy_route_table" "80"
|
||||
config_get tun_route_table "routing" "tun_route_table" "81"
|
||||
config_get dummy_device "routing" "dummy_device" "momo-dummy"
|
||||
# delete routing policy
|
||||
ip -4 rule del table "$tproxy_route_table" > /dev/null 2>&1
|
||||
ip -4 rule del table "$tun_route_table" > /dev/null 2>&1
|
||||
ip -6 rule del table "$tproxy_route_table" > /dev/null 2>&1
|
||||
ip -6 rule del table "$tun_route_table" > /dev/null 2>&1
|
||||
# delete routing table
|
||||
ip -4 route flush table "$tproxy_route_table" > /dev/null 2>&1
|
||||
ip -4 route flush table "$tun_route_table" > /dev/null 2>&1
|
||||
ip -6 route flush table "$tproxy_route_table" > /dev/null 2>&1
|
||||
ip -6 route flush table "$tun_route_table" > /dev/null 2>&1
|
||||
# delete dummy device
|
||||
ip -6 link del "$dummy_device" > /dev/null 2>&1
|
||||
# delete hijack
|
||||
nft delete table inet momo > /dev/null 2>&1
|
||||
local handles handle
|
||||
handles=$(nft --json list table inet fw4 | jsonfilter -q -e "@['nftables'][*]['rule']" | jsonfilter -q -a -e "@[@['chain']='input']" | jsonfilter -q -a -e "@[@['comment']='momo']" | jsonfilter -q -a -e "@[*]['handle']")
|
||||
for handle in $handles; do
|
||||
nft delete rule inet fw4 input handle "$handle"
|
||||
done
|
||||
handles=$(nft --json list table inet fw4 | jsonfilter -q -e "@['nftables'][*]['rule']" | jsonfilter -q -a -e "@[@['chain']='forward']" | jsonfilter -q -a -e "@[@['comment']='momo']" | jsonfilter -q -a -e "@[*]['handle']")
|
||||
for handle in $handles; do
|
||||
nft delete rule inet fw4 forward handle "$handle"
|
||||
done
|
||||
# delete started flag
|
||||
rm "$STARTED_FLAG_PATH" > /dev/null 2>&1
|
||||
# revert fix compatible with dockerd
|
||||
## kmod-br-netfilter
|
||||
if rm "$BRIDGE_NF_CALL_IPTABLES_FLAG_PATH" > /dev/null 2>&1; then
|
||||
sysctl -q -w net.bridge.bridge-nf-call-iptables=1
|
||||
fi
|
||||
if rm "$BRIDGE_NF_CALL_IP6TABLES_FLAG_PATH" > /dev/null 2>&1; then
|
||||
sysctl -q -w net.bridge.bridge-nf-call-ip6tables=1
|
||||
fi
|
||||
# delete cron
|
||||
sed -i "/#momo/d" "/etc/crontabs/root" > /dev/null 2>&1
|
||||
/etc/init.d/cron restart
|
||||
}
|
||||
|
||||
clear_logs() {
|
||||
# load config
|
||||
config_load momo
|
||||
# get config
|
||||
## log config
|
||||
local log_scheduled_clear_size_limit log_scheduled_clear_size_limit_unit
|
||||
config_get log_scheduled_clear_size_limit "log" "scheduled_clear_size_limit" 1
|
||||
config_get log_scheduled_clear_size_limit_unit "log" "scheduled_clear_size_limit_unit" "MB"
|
||||
# prepare config
|
||||
local log_scheduled_clear_size_limit_in_bytes; log_scheduled_clear_size_limit_in_bytes=0
|
||||
case "$log_scheduled_clear_size_limit_unit" in
|
||||
B)
|
||||
log_scheduled_clear_size_limit_in_bytes=$((log_scheduled_clear_size_limit))
|
||||
;;
|
||||
KB)
|
||||
log_scheduled_clear_size_limit_in_bytes=$((log_scheduled_clear_size_limit * 1024))
|
||||
;;
|
||||
MB)
|
||||
log_scheduled_clear_size_limit_in_bytes=$((log_scheduled_clear_size_limit * 1024 * 1024))
|
||||
;;
|
||||
GB)
|
||||
log_scheduled_clear_size_limit_in_bytes=$((log_scheduled_clear_size_limit * 1024 * 1024 * 1024))
|
||||
;;
|
||||
esac
|
||||
# clear logs
|
||||
if [ -f "$APP_LOG_PATH" ] && [ "$(wc -c < "$APP_LOG_PATH")" -ge "$log_scheduled_clear_size_limit_in_bytes" ]; then
|
||||
echo -n > "$APP_LOG_PATH"
|
||||
log "Log" "App log is cleared due to scheduled clear and exceeding size limits."
|
||||
fi
|
||||
if [ -f "$CORE_LOG_PATH" ] && [ "$(wc -c < "$CORE_LOG_PATH")" -ge "$log_scheduled_clear_size_limit_in_bytes" ]; then
|
||||
echo -n > "$CORE_LOG_PATH"
|
||||
log "Log" "Core log is cleared due to scheduled clear and exceeding size limits."
|
||||
fi
|
||||
}
|
||||
|
||||
update_subscription() {
|
||||
local subscription_section; subscription_section="$1"
|
||||
if [ -z "$subscription_section" ]; then
|
||||
return
|
||||
fi
|
||||
# load config
|
||||
config_load momo
|
||||
# get subscription config
|
||||
local subscription_name subscription_info_url subscription_url subscription_user_agent
|
||||
config_get subscription_name "$subscription_section" "name"
|
||||
config_get subscription_info_url "$subscription_section" "info_url"
|
||||
config_get subscription_url "$subscription_section" "url"
|
||||
config_get subscription_user_agent "$subscription_section" "user_agent"
|
||||
# reset subscription info
|
||||
uci_remove "momo" "$subscription_section" "expire" > /dev/null 2>&1
|
||||
uci_remove "momo" "$subscription_section" "upload" > /dev/null 2>&1
|
||||
uci_remove "momo" "$subscription_section" "download" > /dev/null 2>&1
|
||||
uci_remove "momo" "$subscription_section" "total" > /dev/null 2>&1
|
||||
uci_remove "momo" "$subscription_section" "used" > /dev/null 2>&1
|
||||
uci_remove "momo" "$subscription_section" "avaliable" > /dev/null 2>&1
|
||||
uci_remove "momo" "$subscription_section" "update" > /dev/null 2>&1
|
||||
uci_remove "momo" "$subscription_section" "success" > /dev/null 2>&1
|
||||
# update subscription
|
||||
log "Profile" "Update subscription: $subscription_name."
|
||||
local success
|
||||
local subscription_info_header_tmpfile; subscription_info_header_tmpfile="$TEMP_DIR/$subscription_section.info.header"
|
||||
local subscription_header_tmpfile; subscription_header_tmpfile="$TEMP_DIR/$subscription_section.header"
|
||||
local subscription_tmpfile; subscription_tmpfile="$TEMP_DIR/$subscription_section.json"
|
||||
local subscription_info_file
|
||||
local subscription_file; subscription_file="$SUBSCRIPTIONS_DIR/$subscription_section.json"
|
||||
# fetch subscription info
|
||||
if [ -n "$subscription_info_url" ]; then
|
||||
log "Profile" "Fetch subscription info."
|
||||
if curl -s -f -m 120 --connect-timeout 15 --retry 3 -L -X GET -A "$subscription_user_agent" -D "$subscription_info_header_tmpfile" "$subscription_info_url" > /dev/null 2>&1; then
|
||||
if [ ! -f "$subscription_info_file" ] && grep -q -i "subscription-userinfo:" "$subscription_info_header_tmpfile"; then
|
||||
subscription_info_file="$subscription_info_header_tmpfile"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
# download subscription
|
||||
log "Profile" "Download subscription."
|
||||
if curl -s -f -m 120 --connect-timeout 15 --retry 3 -L -X GET -A "$subscription_user_agent" -D "$subscription_header_tmpfile" -o "$subscription_tmpfile" "$subscription_url" > /dev/null 2>&1; then
|
||||
log "Profile" "Subscription download successful."
|
||||
if [ ! -f "$subscription_info_file" ] && grep -q -i "subscription-userinfo:" "$subscription_header_tmpfile"; then
|
||||
subscription_info_file="$subscription_header_tmpfile"
|
||||
fi
|
||||
log "Profile" "Subscription download successful."
|
||||
success=1
|
||||
else
|
||||
log "Profile" "Subscription download failed."
|
||||
success=0
|
||||
fi
|
||||
# check if success
|
||||
if [ "$success" = 1 ]; then
|
||||
log "Profile" "Subscription update successful."
|
||||
if [ -f "$subscription_info_file" ]; then
|
||||
local subscription_expire subscription_upload subscription_download subscription_total subscription_used subscription_avaliable
|
||||
subscription_expire=$(grep -i "subscription-userinfo: " "$subscription_info_file" | grep -i -o -E "expire=[[:digit:]]+" | cut -d '=' -f 2)
|
||||
subscription_upload=$(grep -i "subscription-userinfo: " "$subscription_info_file" | grep -i -o -E "upload=[[:digit:]]+" | cut -d '=' -f 2)
|
||||
subscription_download=$(grep -i "subscription-userinfo: " "$subscription_info_file" | grep -i -o -E "download=[[:digit:]]+" | cut -d '=' -f 2)
|
||||
subscription_total=$(grep -i "subscription-userinfo: " "$subscription_info_file" | grep -i -o -E "total=[[:digit:]]+" | cut -d '=' -f 2)
|
||||
if [ -n "$subscription_upload" ] && [ -n "$subscription_download" ]; then
|
||||
subscription_used=$((subscription_upload + subscription_download))
|
||||
if [ -n "$subscription_total" ]; then
|
||||
subscription_avaliable=$((subscription_total - subscription_used))
|
||||
fi
|
||||
fi
|
||||
# update subscription info
|
||||
if [ -n "$subscription_expire" ]; then
|
||||
uci_set "momo" "$subscription_section" "expire" "$(date "+%Y-%m-%d %H:%M:%S" -d "@$subscription_expire")"
|
||||
fi
|
||||
if [ -n "$subscription_upload" ]; then
|
||||
uci_set "momo" "$subscription_section" "upload" "$(format_filesize "$subscription_upload")"
|
||||
fi
|
||||
if [ -n "$subscription_download" ]; then
|
||||
uci_set "momo" "$subscription_section" "download" "$(format_filesize "$subscription_download")"
|
||||
fi
|
||||
if [ -n "$subscription_total" ]; then
|
||||
uci_set "momo" "$subscription_section" "total" "$(format_filesize "$subscription_total")"
|
||||
fi
|
||||
if [ -n "$subscription_used" ]; then
|
||||
uci_set "momo" "$subscription_section" "used" "$(format_filesize "$subscription_used")"
|
||||
fi
|
||||
if [ -n "$subscription_avaliable" ]; then
|
||||
uci_set "momo" "$subscription_section" "avaliable" "$(format_filesize "$subscription_avaliable")"
|
||||
fi
|
||||
fi
|
||||
uci_set "momo" "$subscription_section" "update" "$(date "+%Y-%m-%d %H:%M:%S")"
|
||||
uci_set "momo" "$subscription_section" "success" "1"
|
||||
# update subscription file
|
||||
rm -f "$subscription_info_header_tmpfile"
|
||||
rm -f "$subscription_header_tmpfile"
|
||||
mv -f "$subscription_tmpfile" "$subscription_file"
|
||||
elif [ "$success" = 0 ]; then
|
||||
log "Profile" "Subscription update failed."
|
||||
# update subscription info
|
||||
uci_set "momo" "$subscription_section" "success" "0"
|
||||
# remove tmpfile
|
||||
rm -f "$subscription_info_header_tmpfile"
|
||||
rm -f "$subscription_header_tmpfile"
|
||||
rm -f "$subscription_tmpfile"
|
||||
fi
|
||||
uci_commit "momo"
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
/etc/momo/profiles/
|
||||
/etc/momo/subscriptions/
|
||||
@@ -0,0 +1,343 @@
|
||||
#!/bin/sh
|
||||
|
||||
. "$IPKG_INSTROOT/etc/momo/scripts/include.sh"
|
||||
|
||||
enabled=`uci get momo.config.enabled`
|
||||
|
||||
if [ "$enabled" == "0" ]; then
|
||||
uci set momo.config.enabled=1
|
||||
uci commit momo
|
||||
/etc/init.d/momo restart
|
||||
fi
|
||||
|
||||
echo \
|
||||
"
|
||||
# Momo Debug Info
|
||||
## system
|
||||
\`\`\`shell
|
||||
`
|
||||
cat /etc/openwrt_release
|
||||
`
|
||||
\`\`\`
|
||||
## kernel
|
||||
\`\`\`
|
||||
`
|
||||
uname -a
|
||||
`
|
||||
\`\`\`
|
||||
## application
|
||||
\`\`\`
|
||||
`
|
||||
if [ -x "/bin/opkg" ]; then
|
||||
opkg list-installed "momo"
|
||||
opkg list-installed "luci-app-momo"
|
||||
elif [ -x "/usr/bin/apk" ]; then
|
||||
apk list -I "momo"
|
||||
apk list -I "luci-app-momo"
|
||||
fi
|
||||
`
|
||||
\`\`\`
|
||||
## config
|
||||
\`\`\`json
|
||||
`
|
||||
ucode -S -e '
|
||||
import { cursor } from "uci";
|
||||
|
||||
const uci = cursor();
|
||||
|
||||
const config = uci.get_all("momo");
|
||||
const result = {};
|
||||
|
||||
for (let section_id in config) {
|
||||
const section = config[section_id];
|
||||
const section_type = section[".type"];
|
||||
if (result[section_type] == null) {
|
||||
result[section_type] = [];
|
||||
}
|
||||
push(result[section_type], section);
|
||||
}
|
||||
for (let section_type in result) {
|
||||
for (let section in result[section_type]) {
|
||||
delete section[".anonymous"];
|
||||
delete section[".type"];
|
||||
delete section[".name"];
|
||||
delete section[".index"];
|
||||
}
|
||||
}
|
||||
if (exists(result, "subscription")) {
|
||||
for (let x in result["subscription"]) {
|
||||
if (exists(x, "url")) {
|
||||
x["url"] = "*";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (exists(result, "lan_access_control")) {
|
||||
for (let x in result["lan_access_control"]) {
|
||||
if (exists(x, "ip")) {
|
||||
for (let i = 0; i < length(x["ip"]); i++) {
|
||||
x["ip"][i] = "*";
|
||||
}
|
||||
}
|
||||
if (exists(x, "ip6")) {
|
||||
for (let i = 0; i < length(x["ip6"]); i++) {
|
||||
x["ip6"][i] = "*";
|
||||
}
|
||||
}
|
||||
if (exists(x, "mac")) {
|
||||
for (let i = 0; i < length(x["mac"]); i++) {
|
||||
x["mac"][i] = "*";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
delete result["placeholder"];
|
||||
print(result);
|
||||
'
|
||||
`
|
||||
\`\`\`
|
||||
## profile
|
||||
\`\`\`json
|
||||
`
|
||||
ucode -S -e '
|
||||
import { readfile } from "fs";
|
||||
|
||||
function desensitize_inbounds(inbounds) {
|
||||
for (let x in inbounds) {
|
||||
if (exists(x, "password")) {
|
||||
x["password"] = "*";
|
||||
}
|
||||
if (exists(x, "users")) {
|
||||
x["users"] = "*";
|
||||
}
|
||||
if (exists(x, "obfs")) {
|
||||
if (exists(x["obfs"], "password")) {
|
||||
x["obfs"]["password"] = "*";
|
||||
}
|
||||
}
|
||||
if (exists(x, "tls")) {
|
||||
if (exists(x["tls"], "server_name")) {
|
||||
x["tls"]["server_name"] = "*";
|
||||
}
|
||||
if (exists(x["tls"], "certificate")) {
|
||||
x["tls"]["certificate"] = "*";
|
||||
}
|
||||
if (exists(x["tls"], "key")) {
|
||||
x["tls"]["key"] = "*";
|
||||
}
|
||||
if (exists(x["tls"], "acme")) {
|
||||
x["tls"]["acme"] = {};
|
||||
}
|
||||
if (exists(x["tls"], "reality")) {
|
||||
if (exists(x["tls"]["reality"], "private_key")) {
|
||||
x["tls"]["reality"]["private_key"] = "*";
|
||||
}
|
||||
if (exists(x["tls"]["reality"], "short_id")) {
|
||||
x["tls"]["reality"]["short_id"] = "*";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (exists(x, "transport")) {
|
||||
if (exists(x["transport"], "host")) {
|
||||
x["transport"]["host"] = "*";
|
||||
}
|
||||
if (exists(x["transport"], "path")) {
|
||||
x["transport"]["path"] = "*";
|
||||
}
|
||||
if (exists(x["transport"], "server_name")) {
|
||||
x["transport"]["server_name"] = "*";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function desensitize_outbounds(outbounds) {
|
||||
for (let x in outbounds) {
|
||||
if (exists(x, "server")) {
|
||||
x["server"] = "*";
|
||||
}
|
||||
if (exists(x, "server_port")) {
|
||||
x["server_port"] = "*";
|
||||
}
|
||||
if (exists(x, "server_ports")) {
|
||||
x["server_port"] = "*";
|
||||
}
|
||||
if (exists(x, "sni")) {
|
||||
x["sni"] = "*";
|
||||
}
|
||||
if (exists(x, "ports")) {
|
||||
x["ports"] = "*";
|
||||
}
|
||||
if (exists(x, "port-range")) {
|
||||
x["port-range"] = "*";
|
||||
}
|
||||
if (exists(x, "uuid")) {
|
||||
x["uuid"] = "*";
|
||||
}
|
||||
if (exists(x, "private-key")) {
|
||||
x["private-key"] = "*";
|
||||
}
|
||||
if (exists(x, "public-key")) {
|
||||
x["public-key"] = "*";
|
||||
}
|
||||
if (exists(x, "token")) {
|
||||
x["token"] = "*";
|
||||
}
|
||||
if (exists(x, "user")) {
|
||||
x["user"] = "*";
|
||||
}
|
||||
if (exists(x, "username")) {
|
||||
x["username"] = "*";
|
||||
}
|
||||
if (exists(x, "password")) {
|
||||
x["password"] = "*";
|
||||
}
|
||||
if (exists(x, "obfs")) {
|
||||
if (exists(x["obfs"], "password")) {
|
||||
x["obfs"]["password"] = "*";
|
||||
}
|
||||
}
|
||||
if (exists(x, "tls")) {
|
||||
if (exists(x["tls"], "server_name")) {
|
||||
x["tls"]["server_name"] = "*";
|
||||
}
|
||||
if (exists(x["tls"], "certificate")) {
|
||||
x["tls"]["certificate"] = "*";
|
||||
}
|
||||
if (exists(x["tls"], "reality")) {
|
||||
if (exists(x["tls"]["reality"], "public_key")) {
|
||||
x["tls"]["reality"]["public_key"] = "*";
|
||||
}
|
||||
if (exists(x["tls"]["reality"], "short_id")) {
|
||||
x["tls"]["reality"]["short_id"] = "*";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (exists(x, "transport")) {
|
||||
if (exists(x["transport"], "host")) {
|
||||
x["transport"]["host"] = "*";
|
||||
}
|
||||
if (exists(x["transport"], "path")) {
|
||||
x["transport"]["path"] = "*";
|
||||
}
|
||||
if (exists(x["transport"], "server_name")) {
|
||||
x["transport"]["server_name"] = "*";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function desensitize_endpoints(endpoints) {
|
||||
for (let x in endpoints) {
|
||||
if (exists(x, "private_key")) {
|
||||
x["private_key"] = "*";
|
||||
}
|
||||
if (exists(x, "peers")) {
|
||||
for (let y in x["peers"]) {
|
||||
if (exists(y, "address")) {
|
||||
y["address"] = "*";
|
||||
}
|
||||
if (exists(y, "port")) {
|
||||
y["port"] = "*";
|
||||
}
|
||||
if (exists(y, "public_key")) {
|
||||
y["public_key"] = "*";
|
||||
}
|
||||
if (exists(y, "pre_shared_key")) {
|
||||
y["pre_shared_key"] = "*";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (exists(x, "auth_key")) {
|
||||
x["auth_key"] = "*";
|
||||
}
|
||||
if (exists(x, "control_url")) {
|
||||
x["control_url"] = "*";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function desensitize_profile() {
|
||||
const profile = json(readfile("/etc/momo/run/config.json"));
|
||||
if (exists(profile, "experimental") && exists(profile["experimental"], "clash_api") && exists(profile["experimental"]["clash_api"], "secret")) {
|
||||
profile["secret"] = "*";
|
||||
}
|
||||
if (exists(profile, "inbounds")) {
|
||||
desensitize_inbounds(profile["inbounds"]);
|
||||
}
|
||||
if (exists(profile, "outbounds")) {
|
||||
desensitize_outbounds(profile["outbounds"]);
|
||||
}
|
||||
if (exists(profile, "endpoints")) {
|
||||
desensitize_endpoints(profile["endpoints"]);
|
||||
}
|
||||
if (exists(profile, "services")) {
|
||||
profile["services"] = [];
|
||||
}
|
||||
return profile;
|
||||
}
|
||||
|
||||
print(desensitize_profile());
|
||||
'
|
||||
`
|
||||
\`\`\`
|
||||
## ip rule
|
||||
\`\`\`
|
||||
`
|
||||
ip rule list
|
||||
`
|
||||
\`\`\`
|
||||
## ip route
|
||||
\`\`\`
|
||||
TPROXY:
|
||||
`
|
||||
ip route list table "$(uci get momo.routing.tproxy_route_table)"
|
||||
`
|
||||
|
||||
TUN:
|
||||
`
|
||||
ip route list table "$(uci get momo.routing.tun_route_table)"
|
||||
`
|
||||
\`\`\`
|
||||
## ip6 rule
|
||||
\`\`\`
|
||||
`
|
||||
ip -6 rule list
|
||||
`
|
||||
\`\`\`
|
||||
## ip6 route
|
||||
\`\`\`
|
||||
TPROXY:
|
||||
`
|
||||
ip -6 route list table "$(uci get momo.routing.tproxy_route_table)"
|
||||
`
|
||||
|
||||
TUN:
|
||||
`
|
||||
ip -6 route list table "$(uci get momo.routing.tun_route_table)"
|
||||
`
|
||||
\`\`\`
|
||||
## firewall tables
|
||||
\`\`\`
|
||||
`
|
||||
nft list tables
|
||||
`
|
||||
\`\`\`
|
||||
## firewall
|
||||
\`\`\`
|
||||
`
|
||||
nft list table inet momo
|
||||
`
|
||||
\`\`\`
|
||||
## service
|
||||
\`\`\`json
|
||||
`
|
||||
/etc/init.d/momo info
|
||||
`
|
||||
\`\`\`
|
||||
"
|
||||
|
||||
if [ "$enabled" == "0" ]; then
|
||||
uci set momo.config.enabled=0
|
||||
uci commit momo
|
||||
/etc/init.d/momo restart
|
||||
fi
|
||||
@@ -0,0 +1,23 @@
|
||||
#!/bin/sh
|
||||
|
||||
. "$IPKG_INSTROOT/lib/functions.sh"
|
||||
. "$IPKG_INSTROOT/etc/momo/scripts/include.sh"
|
||||
|
||||
config_load momo
|
||||
config_get_bool enabled "config" "enabled" 0
|
||||
config_get_bool core_only "config" "core_only" 0
|
||||
config_get_bool proxy_enabled "proxy" "enabled" 0
|
||||
config_get tcp_mode "proxy" "tcp_mode"
|
||||
config_get udp_mode "proxy" "udp_mode"
|
||||
config_get tun_inbound_tag "core" "tun_inbound_tag"
|
||||
|
||||
if [ "$enabled" = 1 ] && [ "$core_only" = 0 ] && [ "$proxy_enabled" = 1 ]; then
|
||||
if [ "$tcp_mode" = "tun" ] || [ "$udp_mode" = "tun" ]; then
|
||||
tun_device=$(jsonfilter -q -i "$RUN_PROFILE_PATH" -e "@['inbounds'][*]" | jsonfilter -q -a -e "@[@['tag']='$tun_inbound_tag']" | jsonfilter -q -a -e "@[@['type']='tun']" | jsonfilter -q -e "@['interface_name']")
|
||||
nft insert rule inet fw4 input iifname "$tun_device" counter accept comment "momo"
|
||||
nft insert rule inet fw4 forward oifname "$tun_device" counter accept comment "momo"
|
||||
nft insert rule inet fw4 forward iifname "$tun_device" counter accept comment "momo"
|
||||
fi
|
||||
fi
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,128 @@
|
||||
#!/bin/sh
|
||||
|
||||
. "$IPKG_INSTROOT/usr/share/libubox/jshn.sh"
|
||||
|
||||
# paths
|
||||
|
||||
## home
|
||||
HOME_DIR="/etc/momo"
|
||||
PROFILES_DIR="$HOME_DIR/profiles"
|
||||
SUBSCRIPTIONS_DIR="$HOME_DIR/subscriptions"
|
||||
|
||||
## run
|
||||
RUN_DIR="$HOME_DIR/run"
|
||||
RUN_PROFILE_PATH="$RUN_DIR/config.json"
|
||||
|
||||
## ucode
|
||||
UCODE_DIR="$HOME_DIR/ucode"
|
||||
INCLUDE_UC="$UCODE_DIR/include.uc"
|
||||
MIXIN_UC="$UCODE_DIR/mixin.uc"
|
||||
HIJACK_UT="$UCODE_DIR/hijack.ut"
|
||||
|
||||
## scripts
|
||||
SH_DIR="$HOME_DIR/scripts"
|
||||
INCLUDE_SH="$SH_DIR/include.sh"
|
||||
FIREWALL_INCLUDE_SH="$SH_DIR/firewall_include.sh"
|
||||
DEBUG_SH="$SH_DIR/debug.sh"
|
||||
|
||||
## firewall
|
||||
NFT_DIR="$HOME_DIR/firewall"
|
||||
GEOIP_CN_NFT="$NFT_DIR/geoip_cn.nft"
|
||||
GEOIP6_CN_NFT="$NFT_DIR/geoip6_cn.nft"
|
||||
|
||||
## log
|
||||
LOG_DIR="/var/log/momo"
|
||||
APP_LOG_PATH="$LOG_DIR/app.log"
|
||||
CORE_LOG_PATH="$LOG_DIR/core.log"
|
||||
DEBUG_LOG_PATH="$LOG_DIR/debug.log"
|
||||
|
||||
## temp
|
||||
TEMP_DIR="/var/run/momo"
|
||||
PID_FILE_PATH="$TEMP_DIR/momo.pid"
|
||||
STARTED_FLAG_PATH="$TEMP_DIR/started.flag"
|
||||
BRIDGE_NF_CALL_IPTABLES_FLAG_PATH="$TEMP_DIR/bridge_nf_call_iptables.flag"
|
||||
BRIDGE_NF_CALL_IP6TABLES_FLAG_PATH="$TEMP_DIR/bridge_nf_call_ip6tables.flag"
|
||||
|
||||
# functions
|
||||
get_paths() {
|
||||
json_init
|
||||
|
||||
json_add_string home_dir "$HOME_DIR"
|
||||
json_add_string profiles_dir "$PROFILES_DIR"
|
||||
json_add_string subscriptions_dir "$SUBSCRIPTIONS_DIR"
|
||||
|
||||
json_add_string run_dir "$RUN_DIR"
|
||||
json_add_string run_profile_path "$RUN_PROFILE_PATH"
|
||||
|
||||
json_add_string ucode_dir "$UCODE_DIR"
|
||||
json_add_string include_uc "$INCLUDE_UC"
|
||||
json_add_string hijack_ut "$HIJACK_UT"
|
||||
|
||||
json_add_string sh_dir "$SH_DIR"
|
||||
json_add_string include_sh "$INCLUDE_SH"
|
||||
json_add_string firewall_include_sh "$FIREWALL_INCLUDE_SH"
|
||||
json_add_string debug_sh "$DEBUG_SH"
|
||||
|
||||
json_add_string nft_dir "$NFT_DIR"
|
||||
json_add_string geoip_cn_nft "$GEOIP_CN_NFT"
|
||||
json_add_string geoip6_cn_nft "$GEOIP6_CN_NFT"
|
||||
|
||||
json_add_string log_dir "$LOG_DIR"
|
||||
json_add_string app_log_path "$APP_LOG_PATH"
|
||||
json_add_string core_log_path "$CORE_LOG_PATH"
|
||||
json_add_string debug_log_path "$DEBUG_LOG_PATH"
|
||||
|
||||
json_add_string temp_dir "$TEMP_DIR"
|
||||
json_add_string pid_file_path "$PID_FILE_PATH"
|
||||
json_add_string started_flag_path "$STARTED_FLAG_PATH"
|
||||
json_add_string bridge_nf_call_iptables_flag_path "$BRIDGE_NF_CALL_IPTABLES_FLAG_PATH"
|
||||
json_add_string bridge_nf_call_ip6tables_flag_path "$BRIDGE_NF_CALL_IP6TABLES_FLAG_PATH"
|
||||
|
||||
json_dump
|
||||
|
||||
json_cleanup
|
||||
}
|
||||
|
||||
format_filesize() {
|
||||
local b; b=1
|
||||
local kb; kb=$((b * 1024))
|
||||
local mb; mb=$((kb * 1024))
|
||||
local gb; gb=$((mb * 1024))
|
||||
local tb; tb=$((gb * 1024))
|
||||
local pb; pb=$((tb * 1024))
|
||||
local size; size=$1
|
||||
if [ -n "$size" ]; then
|
||||
if [ "$size" -lt "$kb" ]; then
|
||||
echo "$(awk "BEGIN {print $size / $b}") B"
|
||||
elif [ "$size" -lt "$mb" ]; then
|
||||
echo "$(awk "BEGIN {print $size / $kb}") KB"
|
||||
elif [ "$size" -lt "$gb" ]; then
|
||||
echo "$(awk "BEGIN {print $size / $mb}") MB"
|
||||
elif [ "$size" -lt "$tb" ]; then
|
||||
echo "$(awk "BEGIN {print $size / $gb}") GB"
|
||||
elif [ "$size" -lt "$pb" ]; then
|
||||
echo "$(awk "BEGIN {print $size / $tb}") TB"
|
||||
else
|
||||
echo "$(awk "BEGIN {print $size / $pb}") PB"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
prepare_files() {
|
||||
if [ ! -d "$LOG_DIR" ]; then
|
||||
mkdir -p "$LOG_DIR"
|
||||
fi
|
||||
if [ ! -f "$APP_LOG_PATH" ]; then
|
||||
touch "$APP_LOG_PATH"
|
||||
fi
|
||||
if [ ! -f "$CORE_LOG_PATH" ]; then
|
||||
touch "$CORE_LOG_PATH"
|
||||
fi
|
||||
if [ ! -d "$TEMP_DIR" ]; then
|
||||
mkdir -p "$TEMP_DIR"
|
||||
fi
|
||||
}
|
||||
|
||||
log() {
|
||||
echo "[$(date "+%Y-%m-%d %H:%M:%S")] [$1] $2" >> "$APP_LOG_PATH"
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
#!/bin/sh
|
||||
|
||||
. "$IPKG_INSTROOT/etc/momo/scripts/include.sh"
|
||||
|
||||
uci -q batch <<-EOF > /dev/null
|
||||
del firewall.momo
|
||||
set firewall.momo=include
|
||||
set firewall.momo.type=script
|
||||
set firewall.momo.path=$FIREWALL_INCLUDE_SH
|
||||
set firewall.momo.fw4_compatible=1
|
||||
commit firewall
|
||||
EOF
|
||||
@@ -0,0 +1,21 @@
|
||||
#!/bin/sh
|
||||
|
||||
. "$IPKG_INSTROOT/etc/momo/scripts/include.sh"
|
||||
|
||||
# check momo.config.init
|
||||
init=$(uci -q get momo.config.init); [ -z "$init" ] && return
|
||||
|
||||
# generate random string for api secret and authentication password
|
||||
random=$(awk 'BEGIN{srand(); printf "%06d", int(rand() * 1000000)}')
|
||||
|
||||
# set momo.mixin.api_secret
|
||||
uci set momo.mixin.external_control_api_secret="$random"
|
||||
|
||||
# remove momo.config.init
|
||||
uci del momo.config.init
|
||||
|
||||
# commit
|
||||
uci commit momo
|
||||
|
||||
# exit with 0
|
||||
exit 0
|
||||
@@ -0,0 +1,58 @@
|
||||
#!/bin/sh
|
||||
|
||||
. "$IPKG_INSTROOT/etc/momo/scripts/include.sh"
|
||||
|
||||
# since v1.0.2
|
||||
|
||||
section_placeholder=$(uci -q get momo.placeholder); [ -z "$section_placeholder" ] && uci set momo.placeholder="placeholder"
|
||||
|
||||
# since v1.1.0
|
||||
|
||||
proxy_bypass_china_mainland_ip=$(uci -q get momo.proxy.bypass_china_mainland_ip)
|
||||
proxy_bypass_china_mainland_ip6=$(uci -q get momo.proxy.bypass_china_mainland_ip6)
|
||||
[ -z "$proxy_bypass_china_mainland_ip6" ] && uci set momo.proxy.bypass_china_mainland_ip6=$proxy_bypass_china_mainland_ip
|
||||
|
||||
routing_tproxy_fw_mask=$(uci -q get momo.routing.tproxy_fw_mask); [ -z "$routing_tproxy_fw_mask" ] && uci set momo.routing.tproxy_fw_mask=0xFF
|
||||
routing_tun_fw_mask=$(uci -q get momo.routing.tun_fw_mask); [ -z "$routing_tun_fw_mask" ] && uci set momo.routing.tun_fw_mask=0xFF
|
||||
|
||||
procd=$(uci -q get momo.procd); [ -z "$procd" ] && {
|
||||
uci set momo.procd=procd
|
||||
uci set momo.procd.fast_reload=$(uci -q get momo.config.fast_reload)
|
||||
uci del momo.config.fast_reload
|
||||
}
|
||||
|
||||
# since v1.1.1
|
||||
|
||||
dummy_device=$(uci -q get momo.routing.dummy_device); [ -z "$dummy_device" ] && uci set momo.routing.dummy_device=momo-dummy
|
||||
|
||||
# since v1.1.2
|
||||
|
||||
config_scheduled_restart_cron=$(uci -q get momo.config.scheduled_restart_cron); [ -z "$config_scheduled_restart_cron" ] && uci rename momo.config.cron_expression="scheduled_restart_cron"
|
||||
|
||||
section_log=$(uci -q get momo.log); [ -z "$section_log" ] && {
|
||||
uci set momo.log=log
|
||||
uci set momo.log.scheduled_clear=1
|
||||
uci set momo.log.scheduled_clear_cron="*/5 * * * *"
|
||||
uci set momo.log.scheduled_clear_size_limit=1
|
||||
uci set momo.log.scheduled_clear_size_limit_unit=MB
|
||||
}
|
||||
|
||||
section_mixin=$(uci -q get momo.mixin); [ -z "$section_mixin" ] && {
|
||||
uci set momo.mixin=mixin
|
||||
uci set momo.mixin.log_disabled='0'
|
||||
uci set momo.mixin.log_level='info'
|
||||
uci set momo.mixin.log_timestamp='1'
|
||||
uci set momo.mixin.dns_independent_cache='1'
|
||||
uci set momo.mixin.dns_reverse_mapping='1'
|
||||
uci set momo.mixin.cache_enabled='1'
|
||||
uci set momo.mixin.cache_store_fakeip='1'
|
||||
uci set momo.mixin.cache_store_rdrc='1'
|
||||
uci set momo.mixin.external_control_ui_path='ui'
|
||||
uci set momo.mixin.external_control_ui_download_url='https://github.com/Zephyruso/zashboard/releases/latest/download/dist-cdn-fonts.zip'
|
||||
}
|
||||
|
||||
# commit
|
||||
uci commit momo
|
||||
|
||||
# exit with 0
|
||||
exit 0
|
||||
@@ -0,0 +1,614 @@
|
||||
#!/usr/bin/utpl
|
||||
|
||||
{%-
|
||||
'use strict';
|
||||
|
||||
import { readfile } from 'fs';
|
||||
import { cursor } from 'uci';
|
||||
import { connect } from 'ubus';
|
||||
import { get_paths, uci_bool, uci_array, get_cgroups_version, get_users, get_groups, get_cgroups } from '/etc/momo/ucode/include.uc';
|
||||
|
||||
const fw4 = require('fw4');
|
||||
|
||||
const paths = get_paths();
|
||||
|
||||
const cgroups_version = get_cgroups_version();
|
||||
|
||||
const users = get_users();
|
||||
const groups = get_groups();
|
||||
const cgroups = get_cgroups();
|
||||
|
||||
const uci = cursor();
|
||||
const ubus = connect();
|
||||
|
||||
const profile = json(readfile(paths.run_profile_path));
|
||||
|
||||
uci.load('momo');
|
||||
|
||||
let redir_port;
|
||||
let tproxy_port;
|
||||
let tun_device;
|
||||
let dns_port;
|
||||
let fake_ip_range;
|
||||
let fake_ip6_range;
|
||||
|
||||
const redirect_inbound_tag = uci.get('momo', 'core', 'redirect_inbound_tag');
|
||||
const tproxy_inbound_tag = uci.get('momo', 'core', 'tproxy_inbound_tag');
|
||||
const tun_inbound_tag = uci.get('momo', 'core', 'tun_inbound_tag');
|
||||
const dns_inbound_tag = uci.get('momo', 'core', 'dns_inbound_tag');
|
||||
const fake_ip_dns_server_tag = uci.get('momo', 'core', 'fake_ip_dns_server_tag');
|
||||
|
||||
let profile_array;
|
||||
profile_array = filter(profile['inbounds'], (x) => x['tag'] == redirect_inbound_tag);
|
||||
if (length(profile_array) > 0) {
|
||||
redir_port = profile_array[0]['listen_port'];
|
||||
}
|
||||
profile_array = filter(profile['inbounds'], (x) => x['tag'] == tproxy_inbound_tag);
|
||||
if (length(profile_array) > 0) {
|
||||
tproxy_port = profile_array[0]['listen_port'];
|
||||
}
|
||||
profile_array = filter(profile['inbounds'], (x) => x['tag'] == tun_inbound_tag);
|
||||
if (length(profile_array) > 0) {
|
||||
tun_device = profile_array[0]['interface_name'];
|
||||
}
|
||||
profile_array = filter(profile['inbounds'], (x) => x['tag'] == dns_inbound_tag);
|
||||
if (length(profile_array) > 0) {
|
||||
dns_port = profile_array[0]['listen_port'];
|
||||
}
|
||||
profile_array = filter(profile['dns']['servers'], (x) => x['tag'] == fake_ip_dns_server_tag);
|
||||
if (length(profile_array) > 0) {
|
||||
fake_ip_range = profile_array[0]['inet4_range'];
|
||||
fake_ip6_range = profile_array[0]['inet6_range'];
|
||||
}
|
||||
|
||||
const ipv4_dns_hijack = uci_bool(uci.get('momo', 'proxy', 'ipv4_dns_hijack'));
|
||||
const ipv6_dns_hijack = uci_bool(uci.get('momo', 'proxy', 'ipv6_dns_hijack'));
|
||||
const ipv4_proxy = uci_bool(uci.get('momo', 'proxy', 'ipv4_proxy'));
|
||||
const ipv6_proxy = uci_bool(uci.get('momo', 'proxy', 'ipv6_proxy'));
|
||||
const fake_ip_ping_hijack = uci_bool(uci.get('momo', 'proxy', 'fake_ip_ping_hijack'));
|
||||
const tcp_mode = uci.get('momo', 'proxy', 'tcp_mode');
|
||||
const udp_mode = uci.get('momo', 'proxy', 'udp_mode');
|
||||
|
||||
const router_proxy = uci_bool(uci.get('momo', 'proxy', 'router_proxy'));
|
||||
const router_access_control = [];
|
||||
uci.foreach('momo', 'router_access_control', (access_control) => {
|
||||
access_control['enabled'] = uci_bool(access_control['enabled']);
|
||||
access_control['user'] = filter(uci_array(access_control['user']), (x) => index(users, x) >= 0);
|
||||
access_control['group'] = filter(uci_array(access_control['group']), (x) => index(groups, x) >= 0);
|
||||
access_control['cgroup'] = filter(uci_array(access_control['cgroup']), (x) => index(cgroups, x) >= 0);
|
||||
access_control['proxy'] = uci_bool(access_control['proxy']);
|
||||
access_control['dns'] = uci_bool(access_control['dns']);
|
||||
if (access_control['enabled']) {
|
||||
push(router_access_control, access_control);
|
||||
}
|
||||
});
|
||||
|
||||
const lan_proxy = uci_bool(uci.get('momo', 'proxy', 'lan_proxy'));
|
||||
const lan_inbound_interface = uci_array(uci.get('momo', 'proxy', 'lan_inbound_interface'));
|
||||
const lan_inbound_device = [];
|
||||
for (let interface in lan_inbound_interface) {
|
||||
const status = ubus.call('network.interface', 'status', { 'interface': interface });
|
||||
const device = status?.l3_device ?? status?.device ?? '';
|
||||
if (device != '') {
|
||||
push(lan_inbound_device, device);
|
||||
}
|
||||
}
|
||||
const lan_access_control = [];
|
||||
uci.foreach('momo', 'lan_access_control', (access_control) => {
|
||||
access_control['enabled'] = uci_bool(access_control['enabled']);
|
||||
access_control['ip'] = uci_array(access_control['ip']);
|
||||
access_control['ip6'] = uci_array(access_control['ip6']);
|
||||
access_control['mac'] = uci_array(access_control['mac']);
|
||||
access_control['proxy'] = uci_bool(access_control['proxy']);
|
||||
access_control['dns'] = uci_bool(access_control['dns']);
|
||||
if (access_control['enabled']) {
|
||||
push(lan_access_control, access_control);
|
||||
}
|
||||
});
|
||||
|
||||
const reserved_ip = uci_array(uci.get('momo', 'proxy', 'reserved_ip'));
|
||||
const reserved_ip6 = uci_array(uci.get('momo', 'proxy', 'reserved_ip6'));
|
||||
const bypass_china_mainland_ip = uci_bool(uci.get('momo', 'proxy', 'bypass_china_mainland_ip'));
|
||||
const bypass_china_mainland_ip6 = uci_bool(uci.get('momo', 'proxy', 'bypass_china_mainland_ip6'));
|
||||
const proxy_tcp_dport = split((uci.get('momo', 'proxy', 'proxy_tcp_dport') ?? '0-65535'), ' ');
|
||||
const proxy_udp_dport = split((uci.get('momo', 'proxy', 'proxy_udp_dport') ?? '0-65535'), ' ');
|
||||
const bypass_dscp = uci_array(uci.get('momo', 'proxy', 'bypass_dscp'));
|
||||
const bypass_fwmark = [];
|
||||
for (let fwmark in uci_array(uci.get('momo', 'proxy', 'bypass_fwmark'))) {
|
||||
let mark;
|
||||
let mask = '0xFFFFFFFF';
|
||||
if (index(fwmark, '/') >= 0) {
|
||||
const parts = split(fwmark, '/');
|
||||
mark = parts[0];
|
||||
mask = parts[1];
|
||||
} else {
|
||||
mark = fwmark;
|
||||
}
|
||||
push(bypass_fwmark, { mark: mark, mask: mask });
|
||||
}
|
||||
|
||||
const cgroup_id = uci.get('momo', 'routing', 'cgroup_id') ?? '0x07250725';
|
||||
const cgroup_name = uci.get('momo', 'routing', 'cgroup_name') ?? 'momo';
|
||||
const tproxy_fw_mark = uci.get('momo', 'routing', 'tproxy_fw_mark') ?? '0x80';
|
||||
const tproxy_fw_mask = uci.get('momo', 'routing', 'tproxy_fw_mask') ?? '0xFF';
|
||||
const tproxy_fw_umask = fw4.hex(~tproxy_fw_mask & 0xFFFFFFFF);
|
||||
const tun_fw_mark = uci.get('momo', 'routing', 'tun_fw_mark') ?? '0x81';
|
||||
const tun_fw_mask = uci.get('momo', 'routing', 'tun_fw_mask') ?? '0xFF';
|
||||
const tun_fw_umask = fw4.hex(~tun_fw_mask & 0xFFFFFFFF);
|
||||
|
||||
const dns_hijack_nfproto = [];
|
||||
if (ipv4_dns_hijack) {
|
||||
push(dns_hijack_nfproto, 'ipv4');
|
||||
}
|
||||
if (ipv6_dns_hijack) {
|
||||
push(dns_hijack_nfproto, 'ipv6');
|
||||
}
|
||||
|
||||
const proxy_nfproto = [];
|
||||
if (ipv4_proxy) {
|
||||
push(proxy_nfproto, 'ipv4');
|
||||
}
|
||||
if (ipv6_proxy) {
|
||||
push(proxy_nfproto, 'ipv6');
|
||||
}
|
||||
|
||||
const proxy_dport = [];
|
||||
for (let port in proxy_tcp_dport) {
|
||||
push(proxy_dport, `tcp . ${port}`);
|
||||
}
|
||||
for (let port in proxy_udp_dport) {
|
||||
push(proxy_dport, `udp . ${port}`);
|
||||
}
|
||||
-%}
|
||||
|
||||
table inet momo {
|
||||
set dns_hijack_nfproto {
|
||||
type nf_proto
|
||||
flags interval
|
||||
{% if (length(dns_hijack_nfproto) > 0): %}
|
||||
elements = {
|
||||
{{ join(', ', dns_hijack_nfproto) }}
|
||||
}
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
set proxy_nfproto {
|
||||
type nf_proto
|
||||
flags interval
|
||||
{% if (length(proxy_nfproto) > 0): %}
|
||||
elements = {
|
||||
{{ join(', ', proxy_nfproto) }}
|
||||
}
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
set reserved_ip {
|
||||
type ipv4_addr
|
||||
flags interval
|
||||
auto-merge
|
||||
{% if (length(reserved_ip) > 0): %}
|
||||
elements = {
|
||||
{{ join(', ', reserved_ip) }}
|
||||
}
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
set reserved_ip6 {
|
||||
type ipv6_addr
|
||||
flags interval
|
||||
auto-merge
|
||||
{% if (length(reserved_ip6) > 0): %}
|
||||
elements = {
|
||||
{{ join(', ', reserved_ip6) }}
|
||||
}
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
set lan_inbound_device {
|
||||
type ifname
|
||||
flags interval
|
||||
auto-merge
|
||||
{% if (length(lan_inbound_device) > 0): %}
|
||||
elements = {
|
||||
{{ join(', ', map(lan_inbound_device, (x) => `"${x}"`)) }}
|
||||
}
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
set china_ip {
|
||||
type ipv4_addr
|
||||
flags interval
|
||||
}
|
||||
|
||||
set china_ip6 {
|
||||
type ipv6_addr
|
||||
flags interval
|
||||
}
|
||||
|
||||
set proxy_dport {
|
||||
type inet_proto . inet_service
|
||||
flags interval
|
||||
auto-merge
|
||||
{% if (length(proxy_dport) > 0): %}
|
||||
elements = {
|
||||
{{ join(', ', proxy_dport) }}
|
||||
}
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
set bypass_dscp {
|
||||
type dscp
|
||||
flags interval
|
||||
auto-merge
|
||||
{% if (length(bypass_dscp) > 0): %}
|
||||
elements = {
|
||||
{{ join(', ', bypass_dscp) }}
|
||||
}
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
{% if (router_proxy): %}
|
||||
chain router_dns_hijack {
|
||||
{% for (let access_control in router_access_control): %}
|
||||
{% if (length(access_control['user']) == 0 && length(access_control['group']) == 0 && length(access_control['cgroup']) == 0): %}
|
||||
meta nfproto @dns_hijack_nfproto meta l4proto { tcp, udp } th dport 53 counter {% if (access_control['dns']): %} redirect to :{{ dns_port }} {% else %} return {% endif %} #
|
||||
{% else %}
|
||||
{% if (length(access_control['user']) > 0): %}
|
||||
meta nfproto @dns_hijack_nfproto meta l4proto { tcp, udp } meta skuid { {{ join(', ', access_control['user']) }} } th dport 53 counter {% if (access_control['dns']): %} redirect to :{{ dns_port }} {% else %} return {% endif %} #
|
||||
{% endif %}
|
||||
{% if (length(access_control['group']) > 0): %}
|
||||
meta nfproto @dns_hijack_nfproto meta l4proto { tcp, udp } meta skgid { {{ join(', ', access_control['group']) }} } th dport 53 counter {% if (access_control['dns']): %} redirect to :{{ dns_port }} {% else %} return {% endif %} #
|
||||
{% endif %}
|
||||
{% if (cgroups_version == 2 && length(access_control['cgroup']) > 0): %}
|
||||
{% for (let cgroup in access_control['cgroup']): %}
|
||||
meta nfproto @dns_hijack_nfproto meta l4proto { tcp, udp } socket cgroupv2 level {{ length(split(cgroup, '/')) }} "{{ cgroup }}" th dport 53 counter {% if (access_control['dns']): %} redirect to :{{ dns_port }} {% else %} return {% endif %} #
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
}
|
||||
|
||||
{% if (tcp_mode == 'redirect'): %}
|
||||
chain router_redirect {
|
||||
{% for (let access_control in router_access_control): %}
|
||||
{% if (length(access_control['user']) == 0 && length(access_control['group']) == 0 && length(access_control['cgroup']) == 0): %}
|
||||
meta nfproto @proxy_nfproto meta l4proto tcp counter {% if (access_control['proxy']): %} redirect to :{{ redir_port }} {% else %} return {% endif %} #
|
||||
{% else %}
|
||||
{% if (length(access_control['user']) > 0): %}
|
||||
meta nfproto @proxy_nfproto meta l4proto tcp meta skuid { {{ join(', ', access_control['user']) }} } counter {% if (access_control['proxy']): %} redirect to :{{ redir_port }} {% else %} return {% endif %} #
|
||||
{% endif %}
|
||||
{% if (length(access_control['group']) > 0): %}
|
||||
meta nfproto @proxy_nfproto meta l4proto tcp meta skgid { {{ join(', ', access_control['group']) }} } counter {% if (access_control['proxy']): %} redirect to :{{ redir_port }} {% else %} return {% endif %} #
|
||||
{% endif %}
|
||||
{% if (cgroups_version == 2 && length(access_control['cgroup']) > 0): %}
|
||||
{% for (let cgroup in access_control['cgroup']): %}
|
||||
meta nfproto @proxy_nfproto meta l4proto tcp socket cgroupv2 level {{ length(split(cgroup, '/')) }} "{{ cgroup }}" counter {% if (access_control['proxy']): %} redirect to :{{ redir_port }} {% else %} return {% endif %} #
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
{% if (tcp_mode == 'tproxy' || udp_mode == 'tproxy'): %}
|
||||
chain router_tproxy {
|
||||
{% for (let access_control in router_access_control): %}
|
||||
{% if (length(access_control['user']) == 0 && length(access_control['group']) == 0 && length(access_control['cgroup']) == 0): %}
|
||||
{% if (access_control['dns']): %}
|
||||
meta nfproto @dns_hijack_nfproto meta l4proto { tcp, udp } th dport 53 counter return #
|
||||
{% endif %}
|
||||
meta nfproto @proxy_nfproto meta l4proto { tcp, udp } {% if (access_control['proxy']): %} meta mark set meta mark & {{ tproxy_fw_umask }} | {{ tproxy_fw_mark }} counter accept {% else %} counter return {% endif %} #
|
||||
{% else %}
|
||||
{% if (length(access_control['user']) > 0): %}
|
||||
{% if (access_control['dns']): %}
|
||||
meta nfproto @dns_hijack_nfproto meta l4proto { tcp, udp } meta skuid { {{ join(', ', access_control['user']) }} } th dport 53 counter return #
|
||||
{% endif %}
|
||||
meta nfproto @proxy_nfproto meta l4proto { tcp, udp } meta skuid { {{ join(', ', access_control['user']) }} } {% if (access_control['proxy']): %} meta mark set meta mark & {{ tproxy_fw_umask }} | {{ tproxy_fw_mark }} counter accept {% else %} counter return {% endif %} #
|
||||
{% endif %}
|
||||
{% if (length(access_control['group']) > 0): %}
|
||||
{% if (access_control['dns']): %}
|
||||
meta nfproto @dns_hijack_nfproto meta l4proto { tcp, udp } meta skgid { {{ join(', ', access_control['group']) }} } th dport 53 counter return #
|
||||
{% endif %}
|
||||
meta nfproto @proxy_nfproto meta l4proto { tcp, udp } meta skgid { {{ join(', ', access_control['group']) }} } {% if (access_control['proxy']): %} meta mark set meta mark & {{ tproxy_fw_umask }} | {{ tproxy_fw_mark }} counter accept {% else %} counter return {% endif %} #
|
||||
{% endif %}
|
||||
{% if (cgroups_version == 2 && length(access_control['cgroup']) > 0): %}
|
||||
{% for (let cgroup in access_control['cgroup']): %}
|
||||
{% if (access_control['dns']): %}
|
||||
meta nfproto @dns_hijack_nfproto meta l4proto { tcp, udp } socket cgroupv2 level {{ length(split(cgroup, '/')) }} "{{ cgroup }}" th dport 53 counter return #
|
||||
{% endif %}
|
||||
meta nfproto @proxy_nfproto meta l4proto { tcp, udp } socket cgroupv2 level {{ length(split(cgroup, '/')) }} "{{ cgroup }}" {% if (access_control['proxy']): %} meta mark set meta mark & {{ tproxy_fw_umask }} | {{ tproxy_fw_mark }} counter accept {% else %} counter return {% endif %} #
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
{% if (tcp_mode == 'tun' || udp_mode == 'tun'): %}
|
||||
chain router_tun {
|
||||
{% for (let access_control in router_access_control): %}
|
||||
{% if (length(access_control['user']) == 0 && length(access_control['group']) == 0 && length(access_control['cgroup']) == 0): %}
|
||||
{% if (access_control['dns']): %}
|
||||
meta nfproto @dns_hijack_nfproto meta l4proto { tcp, udp } th dport 53 counter return #
|
||||
{% endif %}
|
||||
meta nfproto @proxy_nfproto meta l4proto { tcp, udp } {% if (access_control['proxy']): %} meta mark set meta mark & {{ tun_fw_umask }} | {{ tun_fw_mark }} counter accept {% else %} counter return {% endif %} #
|
||||
{% else %}
|
||||
{% if (length(access_control['user']) > 0): %}
|
||||
{% if (access_control['dns']): %}
|
||||
meta nfproto @dns_hijack_nfproto meta l4proto { tcp, udp } meta skuid { {{ join(', ', access_control['user']) }} } th dport 53 counter return #
|
||||
{% endif %}
|
||||
meta nfproto @proxy_nfproto meta l4proto { tcp, udp } meta skuid { {{ join(', ', access_control['user']) }} } {% if (access_control['proxy']): %} meta mark set meta mark & {{ tun_fw_umask }} | {{ tun_fw_mark }} counter accept {% else %} counter return {% endif %} #
|
||||
{% endif %}
|
||||
{% if (length(access_control['group']) > 0): %}
|
||||
{% if (access_control['dns']): %}
|
||||
meta nfproto @dns_hijack_nfproto meta l4proto { tcp, udp } meta skgid { {{ join(', ', access_control['group']) }} } th dport 53 counter return #
|
||||
{% endif %}
|
||||
meta nfproto @proxy_nfproto meta l4proto { tcp, udp } meta skgid { {{ join(', ', access_control['group']) }} } {% if (access_control['proxy']): %} meta mark set meta mark & {{ tun_fw_umask }} | {{ tun_fw_mark }} counter accept {% else %} counter return {% endif %} #
|
||||
{% endif %}
|
||||
{% if (cgroups_version == 2 && length(access_control['cgroup']) > 0): %}
|
||||
{% for (let cgroup in access_control['cgroup']): %}
|
||||
{% if (access_control['dns']): %}
|
||||
meta nfproto @dns_hijack_nfproto meta l4proto { tcp, udp } socket cgroupv2 level {{ length(split(cgroup, '/')) }} "{{ cgroup }}" th dport 53 counter return #
|
||||
{% endif %}
|
||||
meta nfproto @proxy_nfproto meta l4proto { tcp, udp } socket cgroupv2 level {{ length(split(cgroup, '/')) }} "{{ cgroup }}" {% if (access_control['proxy']): %} meta mark set meta mark & {{ tun_fw_umask }} | {{ tun_fw_mark }} counter accept {% else %} counter return {% endif %} #
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if (lan_proxy): %}
|
||||
chain lan_dns_hijack {
|
||||
{% for (let access_control in lan_access_control): %}
|
||||
{% if (length(access_control['ip']) == 0 && length(access_control['ip6']) == 0 && length(access_control['mac']) == 0): %}
|
||||
meta nfproto @dns_hijack_nfproto meta l4proto { tcp, udp } th dport 53 counter {% if (access_control['dns']): %} redirect to :{{ dns_port }} {% else %} return {% endif %} #
|
||||
{% else %}
|
||||
{% if (length(access_control['ip']) > 0): %}
|
||||
{% if (ipv4_dns_hijack): %}
|
||||
meta l4proto { tcp, udp } ip saddr { {{ join(', ', access_control['ip']) }} } th dport 53 counter {% if (access_control['dns']): %} redirect to :{{ dns_port }} {% else %} return {% endif %} #
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if (length(access_control['ip6']) > 0): %}
|
||||
{% if (ipv6_dns_hijack): %}
|
||||
meta l4proto { tcp, udp } ip6 saddr { {{ join(', ', access_control['ip6']) }} } th dport 53 counter {% if (access_control['dns']): %} redirect to :{{ dns_port }} {% else %} return {% endif %} #
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if (length(access_control['mac']) > 0): %}
|
||||
meta nfproto @dns_hijack_nfproto meta l4proto { tcp, udp } ether saddr { {{ join(', ', access_control['mac']) }} } th dport 53 counter {% if (access_control['dns']): %} redirect to :{{ dns_port }} {% else %} return {% endif %} #
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
}
|
||||
|
||||
{% if (tcp_mode == 'redirect'): %}
|
||||
chain lan_redirect {
|
||||
{% for (let access_control in lan_access_control): %}
|
||||
{% if (length(access_control['ip']) == 0 && length(access_control['ip6']) == 0 && length(access_control['mac']) == 0): %}
|
||||
meta nfproto @proxy_nfproto meta l4proto tcp counter {% if (access_control['proxy']): %} redirect to :{{ redir_port }} {% else %} counter return {% endif %} #
|
||||
{% else %}
|
||||
{% if (length(access_control['ip']) > 0): %}
|
||||
{% if (ipv4_proxy): %}
|
||||
meta l4proto tcp ip saddr { {{ join(', ', access_control['ip']) }} } counter {% if (access_control['proxy']): %} redirect to :{{ redir_port }} {% else %} return {% endif %} #
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if (length(access_control['ip6']) > 0): %}
|
||||
{% if (ipv6_proxy): %}
|
||||
meta l4proto tcp ip6 saddr { {{ join(', ', access_control['ip6']) }} } counter {% if (access_control['proxy']): %} redirect to :{{ redir_port }} {% else %} return {% endif %} #
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if (length(access_control['mac']) > 0): %}
|
||||
meta nfproto @proxy_nfproto meta l4proto tcp ether saddr { {{ join(', ', access_control['mac']) }} } counter {% if (access_control['proxy']): %} redirect to :{{ redir_port }} {% else %} return {% endif %} #
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
{% if (tcp_mode == 'tproxy' || udp_mode == 'tproxy'): %}
|
||||
chain lan_tproxy {
|
||||
{% for (let access_control in lan_access_control): %}
|
||||
{% if (length(access_control['ip']) == 0 && length(access_control['ip6']) == 0 && length(access_control['mac']) == 0): %}
|
||||
{% if (access_control['dns']): %}
|
||||
meta nfproto @dns_hijack_nfproto meta l4proto { tcp, udp } th dport 53 counter return #
|
||||
{% endif %}
|
||||
meta nfproto @proxy_nfproto meta l4proto { tcp, udp } {% if (access_control['proxy']): %} meta mark set meta mark & {{ tproxy_fw_umask }} | {{ tproxy_fw_mark }} tproxy to :{{ tproxy_port }} counter accept {% else %} counter return {% endif %} #
|
||||
{% else %}
|
||||
{% if (length(access_control['ip']) > 0): %}
|
||||
{% if (access_control['dns']): %}
|
||||
{% if (ipv4_dns_hijack): %}
|
||||
meta l4proto { tcp, udp } ip saddr { {{ join(', ', access_control['ip']) }} } th dport 53 counter return #
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if (ipv4_proxy): %}
|
||||
meta l4proto { tcp, udp } ip saddr { {{ join(', ', access_control['ip']) }} } {% if (access_control['proxy']): %} meta mark set meta mark & {{ tproxy_fw_umask }} | {{ tproxy_fw_mark }} tproxy ip to :{{ tproxy_port }} counter accept {% else %} counter return {% endif %} #
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if (length(access_control['ip6']) > 0): %}
|
||||
{% if (access_control['dns']): %}
|
||||
{% if (ipv6_dns_hijack): %}
|
||||
meta l4proto { tcp, udp } ip6 saddr { {{ join(', ', access_control['ip6']) }} } th dport 53 counter return #
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if (ipv6_proxy): %}
|
||||
meta l4proto { tcp, udp } ip6 saddr { {{ join(', ', access_control['ip6']) }} } {% if (access_control['proxy']): %} meta mark set meta mark & {{ tproxy_fw_umask }} | {{ tproxy_fw_mark }} tproxy ip6 to :{{ tproxy_port }} counter accept {% else %} counter return {% endif %} #
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if (length(access_control['mac']) > 0): %}
|
||||
{% if (access_control['dns']): %}
|
||||
meta nfproto @dns_hijack_nfproto meta l4proto { tcp, udp } ether saddr { {{ join(', ', access_control['mac']) }} } th dport 53 counter return #
|
||||
{% endif %}
|
||||
meta nfproto @proxy_nfproto meta l4proto { tcp, udp } ether saddr { {{ join(', ', access_control['mac']) }} } {% if (access_control['proxy']): %} meta mark set meta mark & {{ tproxy_fw_umask }} | {{ tproxy_fw_mark }} tproxy to :{{ tproxy_port }} counter accept {% else %} counter return {% endif %} #
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
{% if (tcp_mode == 'tun' || udp_mode == 'tun'): %}
|
||||
chain lan_tun {
|
||||
{% for (let access_control in lan_access_control): %}
|
||||
{% if (length(access_control['ip']) == 0 && length(access_control['ip6']) == 0 && length(access_control['mac']) == 0): %}
|
||||
{% if (access_control['dns']): %}
|
||||
meta nfproto @dns_hijack_nfproto meta l4proto { tcp, udp } th dport 53 counter return #
|
||||
{% endif %}
|
||||
meta nfproto @proxy_nfproto meta l4proto { tcp, udp } {% if (access_control['proxy']): %} meta mark set meta mark & {{ tun_fw_umask }} | {{ tun_fw_mark }} counter accept {% else %} counter return {% endif %} #
|
||||
{% else %}
|
||||
{% if (length(access_control['ip']) > 0): %}
|
||||
{% if (access_control['dns']): %}
|
||||
{% if (ipv4_dns_hijack): %}
|
||||
meta l4proto { tcp, udp } ip saddr { {{ join(', ', access_control['ip']) }} } th dport 53 counter return #
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if (ipv4_proxy): %}
|
||||
meta l4proto { tcp, udp } ip saddr { {{ join(', ', access_control['ip']) }} } {% if (access_control['proxy']): %} meta mark set meta mark & {{ tun_fw_umask }} | {{ tun_fw_mark }} counter accept {% else %} counter return {% endif %} #
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if (length(access_control['ip6']) > 0): %}
|
||||
{% if (access_control['dns']): %}
|
||||
{% if (ipv6_dns_hijack): %}
|
||||
meta l4proto { tcp, udp } ip6 saddr { {{ join(', ', access_control['ip6']) }} } th dport 53 counter return #
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if (ipv6_proxy): %}
|
||||
meta l4proto { tcp, udp } ip6 saddr { {{ join(', ', access_control['ip6']) }} } {% if (access_control['proxy']): %} meta mark set meta mark & {{ tun_fw_umask }} | {{ tun_fw_mark }} counter accept {% else %} counter return {% endif %} #
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if (length(access_control['mac']) > 0): %}
|
||||
{% if (access_control['dns']): %}
|
||||
meta nfproto @dns_hijack_nfproto meta l4proto { tcp, udp } ether saddr { {{ join(', ', access_control['mac']) }} } th dport 53 counter return #
|
||||
{% endif %}
|
||||
meta nfproto @proxy_nfproto meta l4proto { tcp, udp } ether saddr { {{ join(', ', access_control['mac']) }} } {% if (access_control['proxy']): %} meta mark set meta mark & {{ tun_fw_umask }} | {{ tun_fw_mark }} counter accept {% else %} counter return {% endif %} #
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if (router_proxy): %}
|
||||
chain nat_output {
|
||||
type nat hook output priority filter; policy accept;
|
||||
{% if (cgroups_version == 1): %}
|
||||
meta cgroup {{ cgroup_id }} counter return
|
||||
{% elif (cgroups_version == 2): %}
|
||||
socket cgroupv2 level 2 "services/{{ cgroup_name }}" counter return
|
||||
{% endif %}
|
||||
jump router_dns_hijack
|
||||
{% if (tcp_mode == 'redirect'): %}
|
||||
fib daddr type { local, broadcast, anycast, multicast } counter return
|
||||
ct direction reply counter return
|
||||
ip daddr @reserved_ip {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
|
||||
ip6 daddr @reserved_ip6 {% if (fake_ip6_range): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return
|
||||
ip daddr @china_ip counter return
|
||||
ip6 daddr @china_ip6 counter return
|
||||
meta nfproto ipv4 meta l4proto . th dport != @proxy_dport {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
|
||||
meta nfproto ipv6 meta l4proto . th dport != @proxy_dport {% if (fake_ip6_range): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return
|
||||
meta l4proto { tcp, udp } ip dscp @bypass_dscp {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
|
||||
meta l4proto { tcp, udp } ip6 dscp @bypass_dscp {% if (fake_ip6_range): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return
|
||||
{% for (let fwmark in bypass_fwmark): %}
|
||||
meta mark & {{ fwmark.mask }} == {{ fwmark.mark }} counter return
|
||||
{% endfor %}
|
||||
jump router_redirect
|
||||
{% endif %}
|
||||
{% if (fake_ip_ping_hijack): %}
|
||||
{% if (fake_ip_range): %}
|
||||
icmp type echo-request ip daddr {{ fake_ip_range }} counter redirect
|
||||
{% endif %}
|
||||
{% if (fake_ip6_range): %}
|
||||
icmpv6 type echo-request ip6 daddr {{ fake_ip6_range }} counter redirect
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
chain mangle_output {
|
||||
type route hook output priority mangle; policy accept;
|
||||
{% if (cgroups_version == 1): %}
|
||||
meta cgroup {{ cgroup_id }} counter return
|
||||
{% elif (cgroups_version == 2): %}
|
||||
socket cgroupv2 level 2 "services/{{ cgroup_name }}" counter return
|
||||
{% endif %}
|
||||
fib daddr type { local, broadcast, anycast, multicast } counter return
|
||||
ct direction reply counter return
|
||||
ip daddr @reserved_ip {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
|
||||
ip6 daddr @reserved_ip6 {% if (fake_ip6_range): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return
|
||||
ip daddr @china_ip counter return
|
||||
ip6 daddr @china_ip6 counter return
|
||||
meta nfproto ipv4 meta l4proto . th dport != @proxy_dport {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
|
||||
meta nfproto ipv6 meta l4proto . th dport != @proxy_dport {% if (fake_ip6_range): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return
|
||||
meta l4proto { tcp, udp } ip dscp @bypass_dscp {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
|
||||
meta l4proto { tcp, udp } ip6 dscp @bypass_dscp {% if (fake_ip6_range): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return
|
||||
{% for (let fwmark in bypass_fwmark): %}
|
||||
meta mark & {{ fwmark.mask }} == {{ fwmark.mark }} counter return
|
||||
{% endfor %}
|
||||
meta l4proto vmap { tcp: {% if (tcp_mode == 'tproxy'): %} jump router_tproxy {% elif (tcp_mode == 'tun'): %} jump router_tun {% else %} continue {% endif %}, udp: {% if (udp_mode == 'tproxy'): %} jump router_tproxy {% elif (udp_mode == 'tun'): %} jump router_tun {% else %} continue {% endif %} }
|
||||
}
|
||||
|
||||
chain mangle_prerouting_router {
|
||||
type filter hook prerouting priority mangle - 1; policy accept;
|
||||
{% if (tcp_mode == 'tproxy' || udp_mode == 'tproxy'): %}
|
||||
iifname lo meta l4proto { tcp, udp } meta mark & {{ tproxy_fw_mask }} == {{ tproxy_fw_mark }} tproxy to :{{ tproxy_port }} counter accept
|
||||
{% endif %}
|
||||
{% if (tcp_mode == 'tun' || udp_mode == 'tun'): %}
|
||||
iifname "{{ tun_device }}" meta l4proto { icmp, tcp, udp } counter accept
|
||||
{% endif %}
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
{% if (lan_proxy): %}
|
||||
chain dstnat {
|
||||
type nat hook prerouting priority dstnat + 1; policy accept;
|
||||
iifname @lan_inbound_device jump lan_dns_hijack
|
||||
{% if (tcp_mode == 'redirect'): %}
|
||||
fib daddr type { local, broadcast, anycast, multicast } counter return
|
||||
ct direction reply counter return
|
||||
ip daddr @reserved_ip {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
|
||||
ip6 daddr @reserved_ip6 {% if (fake_ip6_range): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return
|
||||
ip daddr @china_ip counter return
|
||||
ip6 daddr @china_ip6 counter return
|
||||
meta nfproto ipv4 meta l4proto . th dport != @proxy_dport {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
|
||||
meta nfproto ipv6 meta l4proto . th dport != @proxy_dport {% if (fake_ip6_range): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return
|
||||
meta l4proto { tcp, udp } ip dscp @bypass_dscp {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
|
||||
meta l4proto { tcp, udp } ip6 dscp @bypass_dscp {% if (fake_ip6_range): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return
|
||||
{% for (let fwmark in bypass_fwmark): %}
|
||||
meta mark & {{ fwmark.mask }} == {{ fwmark.mark }} counter return
|
||||
{% endfor %}
|
||||
iifname @lan_inbound_device jump lan_redirect
|
||||
{% endif %}
|
||||
{% if (fake_ip_ping_hijack): %}
|
||||
{% if (fake_ip_range): %}
|
||||
icmp type echo-request ip daddr {{ fake_ip_range }} counter redirect
|
||||
{% endif %}
|
||||
{% if (fake_ip6_range): %}
|
||||
icmpv6 type echo-request ip6 daddr {{ fake_ip6_range }} counter redirect
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
chain mangle_prerouting_lan {
|
||||
type filter hook prerouting priority mangle; policy accept;
|
||||
fib daddr type { local, broadcast, anycast, multicast } counter return
|
||||
ct direction reply counter return
|
||||
ip daddr @reserved_ip {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
|
||||
ip6 daddr @reserved_ip6 {% if (fake_ip6_range): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return
|
||||
ip daddr @china_ip counter return
|
||||
ip6 daddr @china_ip6 counter return
|
||||
meta nfproto ipv4 meta l4proto . th dport != @proxy_dport {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
|
||||
meta nfproto ipv6 meta l4proto . th dport != @proxy_dport {% if (fake_ip6_range): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return
|
||||
meta l4proto { tcp, udp } ip dscp @bypass_dscp {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
|
||||
meta l4proto { tcp, udp } ip6 dscp @bypass_dscp {% if (fake_ip6_range): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return
|
||||
{% for (let fwmark in bypass_fwmark): %}
|
||||
meta mark & {{ fwmark.mask }} == {{ fwmark.mark }} counter return
|
||||
{% endfor %}
|
||||
iifname @lan_inbound_device meta l4proto vmap { tcp: {% if (tcp_mode == 'tproxy'): %} jump lan_tproxy {% elif (tcp_mode == 'tun'): %} jump lan_tun {% else %} continue {% endif %}, udp: {% if (udp_mode == 'tproxy'): %} jump lan_tproxy {% elif (udp_mode == 'tun'): %} jump lan_tun {% else %} continue {% endif %} }
|
||||
}
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
{% if (bypass_china_mainland_ip): %}
|
||||
include "/etc/momo/firewall/geoip_cn.nft"
|
||||
{% endif %}
|
||||
{% if (bypass_china_mainland_ip6): %}
|
||||
include "/etc/momo/firewall/geoip6_cn.nft"
|
||||
{% endif %}
|
||||
@@ -0,0 +1,133 @@
|
||||
import { readfile, writefile, popen } from 'fs';
|
||||
|
||||
export function get_paths() {
|
||||
let result = {};
|
||||
const process = popen('. /etc/momo/scripts/include.sh && get_paths');
|
||||
if (process) {
|
||||
result = json(process);
|
||||
process.close();
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
export function uci_bool(obj) {
|
||||
return obj == null ? null : obj == '1';
|
||||
};
|
||||
|
||||
export function uci_int(obj) {
|
||||
return obj == null ? null : int(obj);
|
||||
};
|
||||
|
||||
export function uci_array(obj) {
|
||||
if (obj == null) {
|
||||
return [];
|
||||
}
|
||||
if (type(obj) == 'array') {
|
||||
return uniq(obj);
|
||||
}
|
||||
return [obj];
|
||||
};
|
||||
|
||||
export function merge(target, ...sources) {
|
||||
for (let source in sources) {
|
||||
for (let key in keys(source)) {
|
||||
const target_value = target[key];
|
||||
const target_value_type = type(target_value);
|
||||
const source_value = source[key];
|
||||
const source_value_type = type(source_value);
|
||||
if (target_value_type === 'object' && source_value_type === 'object') {
|
||||
target[key] = merge(target_value, source_value);
|
||||
} else {
|
||||
target[key] = source[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
return target;
|
||||
};
|
||||
|
||||
export function merge_exists(target, ...sources) {
|
||||
for (let source in sources) {
|
||||
for (let key in keys(source)) {
|
||||
if (exists(target, key)) {
|
||||
const target_value = target[key];
|
||||
const target_value_type = type(target_value);
|
||||
const source_value = source[key];
|
||||
const source_value_type = type(source_value);
|
||||
if (target_value_type === 'object' && source_value_type === 'object') {
|
||||
target[key] = merge_exists(target_value, source_value);
|
||||
} else {
|
||||
target[key] = source[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return target;
|
||||
};
|
||||
|
||||
export function trim_all(obj) {
|
||||
if (obj == null) {
|
||||
return null;
|
||||
}
|
||||
if (type(obj) == 'string') {
|
||||
if (length(obj) == 0) {
|
||||
return null;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
if (type(obj) == 'array') {
|
||||
if (length(obj) == 0) {
|
||||
return null;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
if (type(obj) == 'object') {
|
||||
const obj_keys = keys(obj);
|
||||
for (let key in obj_keys) {
|
||||
obj[key] = trim_all(obj[key]);
|
||||
if (obj[key] == null) {
|
||||
delete obj[key];
|
||||
}
|
||||
}
|
||||
if (length(keys(obj)) == 0) {
|
||||
return null;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
|
||||
export function get_cgroups_version() {
|
||||
return system('mount | grep -q -w "^cgroup"') == 0 ? 1 : 2;
|
||||
};
|
||||
|
||||
export function get_users() {
|
||||
return map(split(readfile('/etc/passwd'), '\n'), (x) => split(x, ':')[0]);
|
||||
};
|
||||
|
||||
export function get_groups() {
|
||||
return map(split(readfile('/etc/group'), '\n'), (x) => split(x, ':')[0]);
|
||||
};
|
||||
|
||||
export function get_cgroups() {
|
||||
const result = [];
|
||||
if (get_cgroups_version() == 2) {
|
||||
const cgroup_path = '/sys/fs/cgroup/';
|
||||
const process = popen(`find ${cgroup_path} -type d -mindepth 1`);
|
||||
if (process) {
|
||||
for (let line = process.read('line'); length(line); line = process.read('line')) {
|
||||
push(result, substr(trim(line), length(cgroup_path)));
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
export function load_profile() {
|
||||
const paths = get_paths();
|
||||
return json(readfile(paths.run_profile_path));
|
||||
};
|
||||
|
||||
export function save_profile(obj) {
|
||||
const paths = get_paths();
|
||||
return writefile(paths.run_profile_path, obj);
|
||||
};
|
||||
@@ -0,0 +1,48 @@
|
||||
#!/usr/bin/ucode
|
||||
|
||||
'use strict';
|
||||
|
||||
import { cursor } from 'uci';
|
||||
import { uci_bool, uci_int, uci_array, merge, trim_all, load_profile, save_profile } from '/etc/momo/ucode/include.uc';
|
||||
|
||||
const uci = cursor();
|
||||
|
||||
const config = {};
|
||||
|
||||
config['log'] = {};
|
||||
config['log']['disabled'] = uci_bool(uci.get('momo', 'mixin', 'log_disabled'));
|
||||
config['log']['level'] = uci.get('momo', 'mixin', 'log_level');
|
||||
config['log']['timestamp'] = uci_bool(uci.get('momo', 'mixin', 'log_timestamp'));
|
||||
config['log']['output'] = uci.get('momo', 'mixin', 'log_output');
|
||||
|
||||
config['dns'] = {};
|
||||
config['dns']['strategy'] = uci.get('momo', 'mixin', 'dns_strategy');
|
||||
config['dns']['disable_cache'] = uci_bool(uci.get('momo', 'mixin', 'dns_disable_cache'));
|
||||
config['dns']['disable_expire'] = uci_bool(uci.get('momo', 'mixin', 'dns_disable_expire'));
|
||||
config['dns']['independent_cache'] = uci_bool(uci.get('momo', 'mixin', 'dns_independent_cache'));
|
||||
config['dns']['cache_capacity'] = uci_int(uci.get('momo', 'mixin', 'dns_cache_capacity'));
|
||||
config['dns']['reverse_mapping'] = uci_bool(uci.get('momo', 'mixin', 'dns_reverse_mapping'));
|
||||
|
||||
config['ntp'] = {};
|
||||
config['ntp']['enabled'] = uci_bool(uci.get('momo', 'mixin', 'ntp_enabled'));
|
||||
config['ntp']['server'] = uci.get('momo', 'mixin', 'ntp_server');
|
||||
config['ntp']['server_port'] = uci_int(uci.get('momo', 'mixin', 'ntp_server_port'));
|
||||
config['ntp']['interval'] = uci.get('momo', 'mixin', 'ntp_interval');
|
||||
|
||||
config['experimental'] = {};
|
||||
|
||||
config['experimental']['cache_file'] = {};
|
||||
config['experimental']['cache_file']['enabled'] = uci_bool(uci.get('momo', 'mixin', 'cache_enabled'));
|
||||
config['experimental']['cache_file']['path'] = uci.get('momo', 'mixin', 'cache_path');
|
||||
config['experimental']['cache_file']['store_fakeip'] = uci_bool(uci.get('momo', 'mixin', 'cache_store_fakeip'));
|
||||
config['experimental']['cache_file']['store_rdrc'] = uci_bool(uci.get('momo', 'mixin', 'cache_store_rdrc'));
|
||||
|
||||
config['experimental']['clash_api'] = {};
|
||||
config['experimental']['clash_api']['external_ui'] = uci.get('momo', 'mixin', 'external_control_ui_path');
|
||||
config['experimental']['clash_api']['external_ui_download_url'] = uci.get('momo', 'mixin', 'external_control_ui_download_url');
|
||||
config['experimental']['clash_api']['external_controller'] = uci.get('momo', 'mixin', 'external_control_api_listen');
|
||||
config['experimental']['clash_api']['secret'] = uci.get('momo', 'mixin', 'external_control_api_secret');
|
||||
|
||||
const profile = load_profile();
|
||||
|
||||
save_profile(merge(profile, trim_all(config)));
|
||||
Reference in new issue
Block a user