mirror of
https://github.com/caiwx86/small-packages.git
synced 2026-10-30 23: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
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"bounding": [
|
||||
"CAP_NET_ADMIN",
|
||||
"CAP_NET_BIND_SERVICE",
|
||||
"CAP_NET_RAW",
|
||||
"CAP_SYS_PTRACE"
|
||||
],
|
||||
"effective": [
|
||||
"CAP_NET_ADMIN",
|
||||
"CAP_NET_BIND_SERVICE",
|
||||
"CAP_NET_RAW",
|
||||
"CAP_SYS_PTRACE"
|
||||
],
|
||||
"ambient": [
|
||||
"CAP_NET_ADMIN",
|
||||
"CAP_NET_BIND_SERVICE",
|
||||
"CAP_NET_RAW",
|
||||
"CAP_SYS_PTRACE"
|
||||
],
|
||||
"permitted": [
|
||||
"CAP_NET_ADMIN",
|
||||
"CAP_NET_BIND_SERVICE",
|
||||
"CAP_NET_RAW",
|
||||
"CAP_SYS_PTRACE"
|
||||
],
|
||||
"inheritable": [
|
||||
"CAP_NET_ADMIN",
|
||||
"CAP_NET_BIND_SERVICE",
|
||||
"CAP_NET_RAW",
|
||||
"CAP_SYS_PTRACE"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
|
||||
config homeproxy 'infra'
|
||||
option __warning 'DO NOT EDIT THIS SECTION, OR YOU ARE ON YOUR OWN!'
|
||||
option common_port '22,53,80,143,443,465,587,853,873,993,995,5222,8080,8443,9418'
|
||||
option mixed_port '5330'
|
||||
option redirect_port '5331'
|
||||
option tproxy_port '5332'
|
||||
option dns_port '5333'
|
||||
option dns_redirect '1'
|
||||
option ntp_server 'nil'
|
||||
option sniff_override '1'
|
||||
option udp_timeout ''
|
||||
option tun_name 'singtun0'
|
||||
option tun_addr4 '172.19.0.1/30'
|
||||
option tun_addr6 'fdfe:dcba:9876::1/126'
|
||||
option tun_mtu '9000'
|
||||
option table_mark '100'
|
||||
option self_mark '100'
|
||||
option tproxy_mark '101'
|
||||
option tun_mark '102'
|
||||
|
||||
config homeproxy 'migration'
|
||||
option crontab '1'
|
||||
|
||||
config homeproxy 'config'
|
||||
option main_node 'nil'
|
||||
option main_udp_node 'same'
|
||||
option dns_server 'https://dns.quad9.net/dns-query'
|
||||
option china_dns_server 'https://dns.alidns.com/dns-query'
|
||||
option routing_mode 'bypass_mainland_china'
|
||||
option routing_port 'common'
|
||||
option proxy_mode 'redirect_tproxy'
|
||||
option ipv6_support '1'
|
||||
option github_token ''
|
||||
option log_level 'warn'
|
||||
|
||||
config homeproxy 'control'
|
||||
option lan_proxy_mode 'disabled'
|
||||
list wan_proxy_ipv4_ips '91.105.192.0/23'
|
||||
list wan_proxy_ipv4_ips '91.108.4.0/22'
|
||||
list wan_proxy_ipv4_ips '91.108.8.0/21'
|
||||
list wan_proxy_ipv4_ips '91.108.16.0/21'
|
||||
list wan_proxy_ipv4_ips '91.108.56.0/22'
|
||||
list wan_proxy_ipv4_ips '95.161.64.0/20'
|
||||
list wan_proxy_ipv4_ips '149.154.160.0/20'
|
||||
list wan_proxy_ipv4_ips '185.76.151.0/24'
|
||||
list wan_proxy_ipv6_ips '2001:67c:4e8::/48'
|
||||
list wan_proxy_ipv6_ips '2001:b28:f23c::/47'
|
||||
list wan_proxy_ipv6_ips '2001:b28:f23f::/48'
|
||||
list wan_proxy_ipv6_ips '2a0a:f280::/32'
|
||||
|
||||
config homeproxy 'routing'
|
||||
option sniff_override '1'
|
||||
option default_outbound 'direct-out'
|
||||
option default_outbound_dns 'default-dns'
|
||||
|
||||
config homeproxy 'dns'
|
||||
option dns_strategy 'prefer_ipv4'
|
||||
option default_server 'local-dns'
|
||||
option disable_cache '0'
|
||||
option disable_cache_expire '0'
|
||||
|
||||
config homeproxy 'subscription'
|
||||
option auto_update '0'
|
||||
option allow_insecure '0'
|
||||
option latency_test_mode 'icmp'
|
||||
option packet_encoding 'xudp'
|
||||
option update_via_proxy '0'
|
||||
option auto_update_time '0 */6 * * *'
|
||||
option filter_nodes 'disabled'
|
||||
|
||||
config homeproxy 'server'
|
||||
option enabled '0'
|
||||
option log_level 'warn'
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1 @@
|
||||
202605092310
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1 @@
|
||||
202605092310
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1 @@
|
||||
202605092310
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1 @@
|
||||
202605092310
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
#!/bin/sh
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
# Copyright (C) 2022-2023 ImmortalWrt.org
|
||||
|
||||
NAME="homeproxy"
|
||||
|
||||
log_max_size="50" #KB
|
||||
main_log_file="/var/run/$NAME/$NAME.log"
|
||||
singc_log_file="/var/run/$NAME/sing-box-c.log"
|
||||
sings_log_file="/var/run/$NAME/sing-box-s.log"
|
||||
|
||||
while true; do
|
||||
sleep 180
|
||||
for i in "$main_log_file" "$singc_log_file" "$sings_log_file"; do
|
||||
[ -s "$i" ] || continue
|
||||
[ "$(( $(ls -l "$i" | awk -F ' ' '{print $5}') / 1024 >= log_max_size))" -eq "0" ] || echo "" > "$i"
|
||||
done
|
||||
done
|
||||
+665
@@ -0,0 +1,665 @@
|
||||
#!/usr/bin/utpl -S
|
||||
|
||||
{%-
|
||||
import { readfile } from 'fs';
|
||||
import { cursor } from 'uci';
|
||||
import { isEmpty } from '/etc/homeproxy/scripts/homeproxy.uc';
|
||||
|
||||
const fw4 = require('fw4');
|
||||
|
||||
function array_to_nftarr(array) {
|
||||
if (type(array) !== 'array')
|
||||
return null;
|
||||
|
||||
return `{ ${join(', ', uniq(array))} }`;
|
||||
}
|
||||
|
||||
function resolve_ipv6(str) {
|
||||
if (isEmpty(str))
|
||||
return null;
|
||||
|
||||
let ipv6 = fw4.parse_subnet(str)?.[0];
|
||||
if (!ipv6 || ipv6.family !== 6)
|
||||
return null;
|
||||
|
||||
if (ipv6.bits > -1)
|
||||
return `${ipv6.addr}/${ipv6.bits}`;
|
||||
else
|
||||
return `& ${ipv6.mask} == ${ipv6.addr}`;
|
||||
}
|
||||
|
||||
function resolve_mark(str) {
|
||||
if (isEmpty(str))
|
||||
return null;
|
||||
|
||||
let mark = fw4.parse_mark(str);
|
||||
if (isEmpty(mark))
|
||||
return null;
|
||||
|
||||
if (mark.mask === 0xffffffff)
|
||||
return fw4.hex(mark.mark);
|
||||
else if (mark.mark === 0)
|
||||
return `mark and ${fw4.hex(~mark.mask & 0xffffffff)}`;
|
||||
else if (mark.mark === mark.mask)
|
||||
return `mark or ${fw4.hex(mark.mark)}`;
|
||||
else if (mark.mask === 0)
|
||||
return `mark xor ${fw4.hex(mark.mark)}`;
|
||||
else
|
||||
return `mark and ${fw4.hex(~mark.mask & 0xffffffff)} xor ${fw4.hex(mark.mark)}`;
|
||||
}
|
||||
|
||||
/* Misc config */
|
||||
const resources_dir = '/etc/homeproxy/resources';
|
||||
|
||||
/* UCI config start */
|
||||
const cfgname = 'homeproxy';
|
||||
const uci = cursor();
|
||||
uci.load(cfgname);
|
||||
|
||||
const routing_mode = uci.get(cfgname, 'config', 'routing_mode') || 'bypass_mainland_china';
|
||||
let outbound_node, outbound_udp_node, china_dns_server, bypass_cn_traffic;
|
||||
|
||||
if (routing_mode !== 'custom') {
|
||||
outbound_node = uci.get(cfgname, 'config', 'main_node') || 'nil';
|
||||
outbound_udp_node = uci.get(cfgname, 'config', 'main_udp_node') || 'nil';
|
||||
china_dns_server = uci.get(cfgname, 'config', 'china_dns_server');
|
||||
} else {
|
||||
outbound_node = uci.get(cfgname, 'routing', 'default_outbound') || 'nil';
|
||||
bypass_cn_traffic = uci.get(cfgname, 'routing', 'bypass_cn_traffic') || '0';
|
||||
}
|
||||
|
||||
let routing_port = uci.get(cfgname, 'config', 'routing_port');
|
||||
if (routing_port === 'common')
|
||||
routing_port = uci.get(cfgname, 'infra', 'common_port') || '22,53,80,143,443,465,587,853,873,993,995,8080,8443,9418';
|
||||
|
||||
const proxy_mode = uci.get(cfgname, 'config', 'proxy_mode') || 'redirect_tproxy',
|
||||
ipv6_support = uci.get(cfgname, 'config', 'ipv6_support') || '0';
|
||||
|
||||
let self_mark, redirect_port,
|
||||
tproxy_port, tproxy_mark,
|
||||
tun_name, tun_mark;
|
||||
|
||||
if (match(proxy_mode, /redirect/)) {
|
||||
self_mark = uci.get(cfgname, 'infra', 'self_mark') || '100';
|
||||
redirect_port = uci.get(cfgname, 'infra', 'redirect_port') || '5331';
|
||||
}
|
||||
if (match(proxy_mode, /tproxy/))
|
||||
if (outbound_udp_node !== 'nil' || routing_mode === 'custom') {
|
||||
tproxy_port = uci.get(cfgname, 'infra', 'tproxy_port') || '5332';
|
||||
tproxy_mark = resolve_mark(uci.get(cfgname, 'infra', 'tproxy_mark') || '101');
|
||||
}
|
||||
if (match(proxy_mode, /tun/)) {
|
||||
tun_name = uci.get(cfgname, 'infra', 'tun_name') || 'singtun0';
|
||||
tun_mark = resolve_mark(uci.get(cfgname, 'infra', 'tun_mark') || '102');
|
||||
}
|
||||
|
||||
const control_options = [
|
||||
"listen_interfaces", "lan_proxy_mode",
|
||||
"lan_direct_mac_addrs", "lan_direct_ipv4_ips", "lan_direct_ipv6_ips",
|
||||
"lan_proxy_mac_addrs", "lan_proxy_ipv4_ips", "lan_proxy_ipv6_ips",
|
||||
"lan_gaming_mode_mac_addrs", "lan_gaming_mode_ipv4_ips", "lan_gaming_mode_ipv6_ips",
|
||||
"lan_global_proxy_mac_addrs", "lan_global_proxy_ipv4_ips", "lan_global_proxy_ipv6_ips",
|
||||
"wan_proxy_ipv4_ips", "wan_proxy_ipv6_ips",
|
||||
"wan_direct_ipv4_ips", "wan_direct_ipv6_ips"
|
||||
];
|
||||
const control_info = {};
|
||||
|
||||
for (let i in control_options)
|
||||
control_info[i] = uci.get(cfgname, 'control', i);
|
||||
|
||||
const dns_redirect = uci.get(cfgname, 'infra', 'dns_redirect') || '1';
|
||||
const dns_hijacked = uci.get('dhcp', '@dnsmasq[0]', 'dns_redirect') || '0',
|
||||
dns_port = uci.get('dhcp', '@dnsmasq[0]', 'port') || '53';
|
||||
/* UCI config end */
|
||||
-%}
|
||||
|
||||
{# Reserved addresses -#}
|
||||
set homeproxy_local_addr_v4 {
|
||||
type ipv4_addr
|
||||
flags interval
|
||||
auto-merge
|
||||
elements = {
|
||||
0.0.0.0/8,
|
||||
10.0.0.0/8,
|
||||
100.64.0.0/10,
|
||||
127.0.0.0/8,
|
||||
169.254.0.0/16,
|
||||
172.16.0.0/12,
|
||||
192.0.0.0/24,
|
||||
192.0.2.0/24,
|
||||
192.31.196.0/24,
|
||||
192.52.193.0/24,
|
||||
192.88.99.0/24,
|
||||
192.168.0.0/16,
|
||||
192.175.48.0/24,
|
||||
198.18.0.0/15,
|
||||
198.51.100.0/24,
|
||||
203.0.113.0/24,
|
||||
224.0.0.0/4,
|
||||
240.0.0.0/4
|
||||
}
|
||||
}
|
||||
{% if (ipv6_support === '1'): %}
|
||||
set homeproxy_local_addr_v6 {
|
||||
type ipv6_addr
|
||||
flags interval
|
||||
auto-merge
|
||||
elements = {
|
||||
::/128,
|
||||
::1/128,
|
||||
::ffff:0:0/96,
|
||||
100::/64,
|
||||
64:ff9b::/96,
|
||||
2001::/32,
|
||||
2001:10::/28,
|
||||
2001:20::/28,
|
||||
2001:db8::/28,
|
||||
2002::/16,
|
||||
fc00::/7,
|
||||
fe80::/10,
|
||||
ff00::/8
|
||||
}
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
{% if (routing_mode === 'gfwlist'): %}
|
||||
set homeproxy_gfw_list_v4 {
|
||||
type ipv4_addr
|
||||
flags interval
|
||||
auto-merge
|
||||
}
|
||||
{% if (ipv6_support === '1'): %}
|
||||
set homeproxy_gfw_list_v6 {
|
||||
type ipv6_addr
|
||||
flags interval
|
||||
auto-merge
|
||||
}
|
||||
{% endif /* ipv6_support */ %}
|
||||
{% elif (match(routing_mode, /mainland_china/) || bypass_cn_traffic === '1'): %}
|
||||
set homeproxy_mainland_addr_v4 {
|
||||
type ipv4_addr
|
||||
flags interval
|
||||
auto-merge
|
||||
elements = {
|
||||
{% for (let cnip4 in split(trim(readfile(resources_dir + '/china_ip4.txt')), /[\r\n]/)): %}
|
||||
{{ cnip4 }},
|
||||
{% endfor %}
|
||||
}
|
||||
}
|
||||
{% if ((ipv6_support === '1') || china_dns_server): %}
|
||||
set homeproxy_mainland_addr_v6 {
|
||||
type ipv6_addr
|
||||
flags interval
|
||||
auto-merge
|
||||
elements = {
|
||||
{% for (let cnip6 in split(trim(readfile(resources_dir + '/china_ip6.txt')), /[\r\n]/)): %}
|
||||
{{ cnip6 }},
|
||||
{% endfor %}
|
||||
}
|
||||
}
|
||||
{% endif /* ipv6_support */ %}
|
||||
{% endif /* routing_mode */ %}
|
||||
|
||||
{# WAN ACL addresses #}
|
||||
set homeproxy_wan_proxy_addr_v4 {
|
||||
type ipv4_addr
|
||||
flags interval
|
||||
auto-merge
|
||||
{% if (control_info.wan_proxy_ipv4_ips): %}
|
||||
elements = { {{ join(', ', control_info.wan_proxy_ipv4_ips) }} }
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
{% if (ipv6_support === '1'): %}
|
||||
set homeproxy_wan_proxy_addr_v6 {
|
||||
type ipv6_addr
|
||||
flags interval
|
||||
auto-merge
|
||||
{% if (control_info.wan_proxy_ipv6_ips): %}
|
||||
elements = { {{ join(', ', control_info.wan_proxy_ipv6_ips) }} }
|
||||
{% endif /* wan_proxy_ipv6_ips*/ %}
|
||||
}
|
||||
{% endif /* ipv6_support */ %}
|
||||
|
||||
set homeproxy_wan_direct_addr_v4 {
|
||||
type ipv4_addr
|
||||
flags interval
|
||||
auto-merge
|
||||
{% if (control_info.wan_direct_ipv4_ips): %}
|
||||
elements = { {{ join(', ', control_info.wan_direct_ipv4_ips) }} }
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
{% if (ipv6_support === '1'): %}
|
||||
set homeproxy_wan_direct_addr_v6 {
|
||||
type ipv6_addr
|
||||
flags interval
|
||||
auto-merge
|
||||
{% if (control_info.wan_direct_ipv6_ips): %}
|
||||
elements = { {{ join(', ', control_info.wan_direct_ipv6_ips) }} }
|
||||
{% endif /* wan_direct_ipv6_ips */ %}
|
||||
}
|
||||
{% endif /* ipv6_support */ %}
|
||||
|
||||
{% if (routing_port): %}
|
||||
set homeproxy_routing_port {
|
||||
type inet_service
|
||||
flags interval
|
||||
auto-merge
|
||||
elements = { {{ join(', ', split(routing_port, ',')) }} }
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
{# DNS hijack & TCP redirect #}
|
||||
chain dstnat {
|
||||
{% if ((dns_redirect === '1') && (dns_hijacked !== '1')): %}
|
||||
{% if (control_info.listen_interfaces): %}
|
||||
meta iifname {{ array_to_nftarr(control_info.listen_interfaces) }}
|
||||
{%- endif /* listen_interfaces */ %}
|
||||
meta nfproto { ipv4, ipv6 } udp dport 53 counter redirect to :{{ dns_port }} comment "!{{ cfgname }}: DNS hijack"
|
||||
{% endif /* dns_hijacked */ %}
|
||||
{% if (match(proxy_mode, /redirect/)): %}
|
||||
meta nfproto { {{ (ipv6_support === '1') ? 'ipv4, ipv6' : 'ipv4' }} } meta l4proto tcp jump homeproxy_redirect_lanac
|
||||
{% endif /* proxy_mode */ %}
|
||||
}
|
||||
|
||||
{# TCP redirect #}
|
||||
{% if (match(proxy_mode, /redirect/)): %}
|
||||
chain homeproxy_redirect_proxy {
|
||||
meta l4proto tcp counter redirect to :{{ redirect_port }}
|
||||
}
|
||||
|
||||
chain homeproxy_redirect_proxy_port {
|
||||
{% if (routing_port): %}
|
||||
tcp dport != @homeproxy_routing_port counter return
|
||||
{% endif %}
|
||||
goto homeproxy_redirect_proxy
|
||||
}
|
||||
|
||||
chain homeproxy_redirect_lanac {
|
||||
{% if (control_info.listen_interfaces): %}
|
||||
meta iifname != {{ array_to_nftarr(control_info.listen_interfaces) }} counter return
|
||||
{% endif %}
|
||||
meta mark {{ self_mark }} counter return
|
||||
|
||||
{% if (control_info.lan_proxy_mode === 'listed_only'): %}
|
||||
{% if (!isEmpty(control_info.lan_proxy_ipv4_ips)): %}
|
||||
ip saddr {{ array_to_nftarr(control_info.lan_proxy_ipv4_ips) }} counter goto homeproxy_redirect
|
||||
{% endif /* lan_proxy_ipv4_ips */ %}
|
||||
{% for (let ipv6 in control_info.lan_proxy_ipv6_ips): %}
|
||||
ip6 saddr {{ resolve_ipv6(ipv6) }} counter goto homeproxy_redirect
|
||||
{% endfor /* lan_proxy_ipv6_ips */ %}
|
||||
{% if (!isEmpty(control_info.lan_proxy_mac_addrs)): %}
|
||||
ether saddr {{ array_to_nftarr(control_info.lan_proxy_mac_addrs) }} counter goto homeproxy_redirect
|
||||
{% endif /* lan_proxy_mac_addrs */ %}
|
||||
{% elif (control_info.lan_proxy_mode === 'except_listed'): %}
|
||||
{% if (!isEmpty(control_info.lan_direct_ipv4_ips)): %}
|
||||
ip saddr {{ array_to_nftarr(control_info.lan_direct_ipv4_ips) }} counter return
|
||||
{% endif /* lan_direct_ipv4_ips */ %}
|
||||
{% for (let ipv6 in control_info.lan_direct_ipv6_ips): %}
|
||||
ip6 saddr {{ resolve_ipv6(ipv6) }} counter return
|
||||
{% endfor /* lan_direct_ipv6_ips */ %}
|
||||
{% if (!isEmpty(control_info.lan_direct_mac_addrs)): %}
|
||||
ether saddr {{ array_to_nftarr(control_info.lan_direct_mac_addrs) }} counter return
|
||||
{% endif /* lan_direct_mac_addrs */ %}
|
||||
{% endif /* lan_proxy_mode */ %}
|
||||
|
||||
{% if (control_info.lan_proxy_mode !== 'listed_only'): %}
|
||||
counter goto homeproxy_redirect
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
chain homeproxy_redirect {
|
||||
meta mark {{ self_mark }} counter return
|
||||
|
||||
ip daddr @homeproxy_wan_proxy_addr_v4 counter goto homeproxy_redirect_proxy_port
|
||||
{% if (ipv6_support === '1'): %}
|
||||
ip6 daddr @homeproxy_wan_proxy_addr_v6 counter goto homeproxy_redirect_proxy_port
|
||||
{% endif %}
|
||||
|
||||
ip daddr @homeproxy_local_addr_v4 counter return
|
||||
{% if (ipv6_support === '1'): %}
|
||||
ip6 daddr @homeproxy_local_addr_v6 counter return
|
||||
{% endif %}
|
||||
|
||||
{% if (routing_mode !== 'custom'): %}
|
||||
{% if (!isEmpty(control_info.lan_global_proxy_ipv4_ips)): %}
|
||||
ip saddr {{ array_to_nftarr(control_info.lan_global_proxy_ipv4_ips) }} counter goto homeproxy_redirect_proxy_port
|
||||
{% endif /* lan_global_proxy_ipv4_ips */ %}
|
||||
{% for (let ipv6 in control_info.lan_global_proxy_ipv6_ips): %}
|
||||
ip6 saddr {{ resolve_ipv6(ipv6) }} counter goto homeproxy_redirect_proxy_port
|
||||
{% endfor /* lan_global_proxy_ipv6_ips */ %}
|
||||
{% if (!isEmpty(control_info.lan_global_proxy_mac_addrs)): %}
|
||||
ether saddr {{ array_to_nftarr(control_info.lan_global_proxy_mac_addrs) }} counter goto homeproxy_redirect_proxy_port
|
||||
{% endif /* lan_global_proxy_mac_addrs */ %}
|
||||
{% endif /* routing_mode */ %}
|
||||
|
||||
ip daddr @homeproxy_wan_direct_addr_v4 counter return
|
||||
{% if (ipv6_support === '1'): %}
|
||||
ip6 daddr @homeproxy_wan_direct_addr_v6 counter return
|
||||
{% endif /* ipv6_support */ %}
|
||||
|
||||
{% if (routing_mode === 'gfwlist'): %}
|
||||
ip daddr != @homeproxy_gfw_list_v4 counter return
|
||||
{% if (ipv6_support === '1'): %}
|
||||
ip6 daddr != @homeproxy_gfw_list_v6 counter return
|
||||
{% endif /* ipv6_support */ %}
|
||||
{% elif (routing_mode === 'bypass_mainland_china' || bypass_cn_traffic === '1'): %}
|
||||
ip daddr @homeproxy_mainland_addr_v4 counter return
|
||||
{% if (ipv6_support === '1'): %}
|
||||
ip6 daddr @homeproxy_mainland_addr_v6 counter return
|
||||
{% endif /* ipv6_support */ %}
|
||||
{% elif (routing_mode === 'proxy_mainland_china'): %}
|
||||
ip daddr != @homeproxy_mainland_addr_v4 counter return
|
||||
{% if (ipv6_support === '1'): %}
|
||||
ip6 daddr != @homeproxy_mainland_addr_v6 counter return
|
||||
{% endif /* ipv6_support */ %}
|
||||
{% endif /* routing_mode */ %}
|
||||
|
||||
{% if (!isEmpty(control_info.lan_gaming_mode_ipv4_ips)): %}
|
||||
ip saddr {{ array_to_nftarr(control_info.lan_gaming_mode_ipv4_ips) }} counter goto homeproxy_redirect_proxy
|
||||
{% endif /* lan_gaming_mode_ipv4_ips */ %}
|
||||
{% for (let ipv6 in control_info.lan_gaming_mode_ipv6_ips): %}
|
||||
ip6 saddr {{ resolve_ipv6(ipv6) }} counter goto homeproxy_redirect_proxy
|
||||
{% endfor /* lan_gaming_mode_ipv6_ips */ %}
|
||||
{% if (!isEmpty(control_info.lan_gaming_mode_mac_addrs)): %}
|
||||
ether saddr {{ array_to_nftarr(control_info.lan_gaming_mode_mac_addrs) }} counter goto homeproxy_redirect_proxy
|
||||
{% endif /* lan_gaming_mode_mac_addrs */ %}
|
||||
|
||||
counter goto homeproxy_redirect_proxy_port
|
||||
}
|
||||
|
||||
chain homeproxy_output_redir {
|
||||
type nat hook output priority filter -105; policy accept
|
||||
meta nfproto { {{ (ipv6_support === '1') ? 'ipv4, ipv6' : 'ipv4' }} } meta l4proto tcp jump homeproxy_redirect
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
{# UDP tproxy #}
|
||||
{% if (match(proxy_mode, /tproxy/) && (outbound_udp_node !== 'nil' || routing_mode === 'custom')): %}
|
||||
chain homeproxy_mangle_tproxy {
|
||||
meta l4proto udp meta mark set {{ tproxy_mark }} tproxy ip to 127.0.0.1:{{ tproxy_port }} counter accept
|
||||
{% if (ipv6_support === '1'): %}
|
||||
meta l4proto udp meta mark set {{ tproxy_mark }} tproxy ip6 to [::1]:{{ tproxy_port }} counter accept
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
chain homeproxy_mangle_tproxy_port {
|
||||
{% if (routing_port): %}
|
||||
udp dport != @homeproxy_routing_port counter return
|
||||
{% endif %}
|
||||
goto homeproxy_mangle_tproxy
|
||||
}
|
||||
|
||||
chain homeproxy_mangle_mark {
|
||||
{% if (routing_port): %}
|
||||
udp dport != @homeproxy_routing_port counter return
|
||||
{% endif %}
|
||||
meta l4proto udp meta mark set {{ tproxy_mark }} counter accept
|
||||
}
|
||||
|
||||
chain homeproxy_mangle_lanac {
|
||||
{% if (control_info.listen_interfaces): %}
|
||||
meta iifname != {{ array_to_nftarr(uniq([...control_info.listen_interfaces, ...['lo']])) }} counter return
|
||||
{% endif %}
|
||||
meta iifname != lo udp dport 53 counter return
|
||||
meta mark {{ self_mark }} counter return
|
||||
|
||||
{% if (control_info.lan_proxy_mode === 'listed_only'): %}
|
||||
{% if (!isEmpty(control_info.lan_proxy_ipv4_ips)): %}
|
||||
ip saddr {{ array_to_nftarr(control_info.lan_proxy_ipv4_ips) }} counter goto homeproxy_mangle_prerouting
|
||||
{% endif /* lan_proxy_ipv4_ips */ %}
|
||||
{% for (let ipv6 in control_info.lan_proxy_ipv6_ips): %}
|
||||
ip6 saddr {{ resolve_ipv6(ipv6) }} counter goto homeproxy_mangle_prerouting
|
||||
{% endfor /* lan_proxy_ipv6_ips */ %}
|
||||
{% if (!isEmpty(control_info.lan_proxy_mac_addrs)): %}
|
||||
ether saddr {{ array_to_nftarr(control_info.lan_proxy_mac_addrs) }} counter goto homeproxy_mangle_prerouting
|
||||
{% endif /* lan_proxy_mac_addrs */ %}
|
||||
{% elif (control_info.lan_proxy_mode === 'except_listed'): %}
|
||||
{% if (!isEmpty(control_info.lan_direct_ipv4_ips)): %}
|
||||
ip saddr {{ array_to_nftarr(control_info.lan_direct_ipv4_ips) }} counter return
|
||||
{% endif /* lan_direct_ipv4_ips */ %}
|
||||
{% for (let ipv6 in control_info.lan_direct_ipv6_ips): %}
|
||||
ip6 saddr {{ resolve_ipv6(ipv6) }} counter return
|
||||
{% endfor /* lan_direct_ipv6_ips */ %}
|
||||
{% if (!isEmpty(control_info.lan_direct_mac_addrs)): %}
|
||||
ether saddr {{ array_to_nftarr(control_info.lan_direct_mac_addrs) }} counter return
|
||||
{% endif /* lan_direct_mac_addrs */ %}
|
||||
{% endif /* lan_proxy_mode */ %}
|
||||
|
||||
{% if (control_info.lan_proxy_mode !== 'listed_only'): %}
|
||||
counter goto homeproxy_mangle_prerouting
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
chain homeproxy_mangle_prerouting {
|
||||
ip daddr @homeproxy_wan_proxy_addr_v4 counter goto homeproxy_mangle_tproxy_port
|
||||
{% if (ipv6_support === '1'): %}
|
||||
ip6 daddr @homeproxy_wan_proxy_addr_v6 counter goto homeproxy_mangle_tproxy_port
|
||||
{% endif %}
|
||||
|
||||
ip daddr @homeproxy_local_addr_v4 counter return
|
||||
{% if (ipv6_support === '1'): %}
|
||||
ip6 daddr @homeproxy_local_addr_v6 counter return
|
||||
{% endif %}
|
||||
|
||||
{% if (routing_mode !== 'custom'): %}
|
||||
{% if (!isEmpty(control_info.lan_global_proxy_ipv4_ips)): %}
|
||||
ip saddr {{ array_to_nftarr(control_info.lan_global_proxy_ipv4_ips) }} counter goto homeproxy_mangle_tproxy_port
|
||||
{% endif /* lan_global_proxy_ipv4_ips */ %}
|
||||
{% for (let ipv6 in control_info.lan_global_proxy_ipv6_ips): %}
|
||||
ip6 saddr {{ resolve_ipv6(ipv6) }} counter goto homeproxy_mangle_tproxy_port
|
||||
{% endfor /* lan_global_proxy_ipv6_ips */ %}
|
||||
{% if (!isEmpty(control_info.lan_global_proxy_mac_addrs)): %}
|
||||
ether saddr {{ array_to_nftarr(control_info.lan_global_proxy_mac_addrs) }} counter goto homeproxy_mangle_tproxy_port
|
||||
{% endif /* lan_global_proxy_mac_addrs */ %}
|
||||
{% endif /* routing_mode */ %}
|
||||
|
||||
ip daddr @homeproxy_wan_direct_addr_v4 counter return
|
||||
{% if (ipv6_support === '1'): %}
|
||||
ip6 daddr @homeproxy_wan_direct_addr_v6 counter return
|
||||
{% endif /* ipv6_support */ %}
|
||||
|
||||
{% if (routing_mode === 'gfwlist'): %}
|
||||
ip daddr != @homeproxy_gfw_list_v4 counter return
|
||||
{% if (ipv6_support === '1'): %}
|
||||
ip6 daddr != @homeproxy_gfw_list_v6 counter return
|
||||
{% endif /* ipv6_support */ %}
|
||||
udp dport { 80, 443 } counter reject comment "!{{ cfgname }}: Fuck you QUIC"
|
||||
{% elif (routing_mode === 'bypass_mainland_china' || bypass_cn_traffic === '1'): %}
|
||||
ip daddr @homeproxy_mainland_addr_v4 counter return
|
||||
{% if (ipv6_support === '1'): %}
|
||||
ip6 daddr @homeproxy_mainland_addr_v6 counter return
|
||||
{% endif /* ipv6_support */ %}
|
||||
{% if (routing_mode !== 'custom'): %}
|
||||
udp dport { 80, 443 } counter reject comment "!{{ cfgname }}: Fuck you QUIC"
|
||||
{% endif /* routing_mode */ %}
|
||||
{% elif (routing_mode === 'proxy_mainland_china'): %}
|
||||
ip daddr != @homeproxy_mainland_addr_v4 counter return
|
||||
{% if (ipv6_support === '1'): %}
|
||||
ip6 daddr != @homeproxy_mainland_addr_v6 counter return
|
||||
{% endif /* ipv6_support */ %}
|
||||
{% endif /* routing_mode */ %}
|
||||
|
||||
{% if (!isEmpty(control_info.lan_gaming_mode_ipv4_ips)): %}
|
||||
ip saddr {{ array_to_nftarr(control_info.lan_gaming_mode_ipv4_ips) }} counter goto homeproxy_mangle_tproxy
|
||||
{% endif /* lan_gaming_mode_ipv4_ips */ %}
|
||||
{% for (let ipv6 in control_info.lan_gaming_mode_ipv6_ips): %}
|
||||
ip6 saddr {{ resolve_ipv6(ipv6) }} counter goto homeproxy_mangle_tproxy
|
||||
{% endfor /* lan_gaming_mode_ipv6_ips */ %}
|
||||
{% if (!isEmpty(control_info.lan_gaming_mode_mac_addrs)): %}
|
||||
ether saddr {{ array_to_nftarr(control_info.lan_gaming_mode_mac_addrs) }} counter goto homeproxy_mangle_tproxy
|
||||
{% endif /* lan_gaming_mode_mac_addrs */ %}
|
||||
|
||||
counter goto homeproxy_mangle_tproxy_port
|
||||
}
|
||||
|
||||
chain homeproxy_mangle_output {
|
||||
meta mark {{ self_mark }} counter return
|
||||
|
||||
ip daddr @homeproxy_wan_proxy_addr_v4 counter goto homeproxy_mangle_mark
|
||||
{% if (ipv6_support === '1'): %}
|
||||
ip6 daddr @homeproxy_wan_proxy_addr_v6 counter goto homeproxy_mangle_mark
|
||||
{% endif %}
|
||||
|
||||
ip daddr @homeproxy_local_addr_v4 counter return
|
||||
{% if (ipv6_support === '1'): %}
|
||||
ip6 daddr @homeproxy_local_addr_v6 counter return
|
||||
{% endif %}
|
||||
|
||||
ip daddr @homeproxy_wan_direct_addr_v4 counter return
|
||||
{% if (ipv6_support === '1'): %}
|
||||
ip6 daddr @homeproxy_wan_direct_addr_v6 counter return
|
||||
{% endif /* ipv6_support */ %}
|
||||
|
||||
{% if (routing_mode === 'gfwlist'): %}
|
||||
ip daddr != @homeproxy_gfw_list_v4 counter return
|
||||
{% if (ipv6_support === '1'): %}
|
||||
ip6 daddr != @homeproxy_gfw_list_v6 counter return
|
||||
{% endif /* ipv6_support */ %}
|
||||
{% elif (routing_mode === 'bypass_mainland_china' || bypass_cn_traffic === '1'): %}
|
||||
ip daddr @homeproxy_mainland_addr_v4 counter return
|
||||
{% if (ipv6_support === '1'): %}
|
||||
ip6 daddr @homeproxy_mainland_addr_v6 counter return
|
||||
{% endif /* ipv6_support */ %}
|
||||
{% elif (routing_mode === 'proxy_mainland_china'): %}
|
||||
ip daddr != @homeproxy_mainland_addr_v4 counter return
|
||||
{% if (ipv6_support === '1'): %}
|
||||
ip6 daddr != @homeproxy_mainland_addr_v6 counter return
|
||||
{% endif /* ipv6_support */ %}
|
||||
{% endif /* routing_mode */ %}
|
||||
|
||||
counter goto homeproxy_mangle_mark
|
||||
}
|
||||
|
||||
chain mangle_prerouting {
|
||||
meta nfproto { {{ (ipv6_support === '1') ? 'ipv4, ipv6' : 'ipv4' }} } meta l4proto udp jump homeproxy_mangle_lanac
|
||||
}
|
||||
|
||||
chain mangle_output {
|
||||
meta nfproto { {{ (ipv6_support === '1') ? 'ipv4, ipv6' : 'ipv4' }} } meta l4proto udp jump homeproxy_mangle_output
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
{# TUN #}
|
||||
{% if (match(proxy_mode, /tun/)): %}
|
||||
chain homeproxy_mangle_lanac {
|
||||
iifname {{ tun_name }} counter return
|
||||
udp dport 53 counter return
|
||||
|
||||
{% if (control_info.listen_interfaces): %}
|
||||
meta iifname != {{ array_to_nftarr(control_info.listen_interfaces) }} counter return
|
||||
{% endif %}
|
||||
|
||||
{% if (control_info.lan_proxy_mode === 'listed_only'): %}
|
||||
{% if (!isEmpty(control_info.lan_proxy_ipv4_ips)): %}
|
||||
ip saddr {{ array_to_nftarr(control_info.lan_proxy_ipv4_ips) }} counter goto homeproxy_mangle_tun
|
||||
{% endif /* lan_proxy_ipv4_ips */ %}
|
||||
{% for (let ipv6 in control_info.lan_proxy_ipv6_ips): %}
|
||||
ip6 saddr {{ resolve_ipv6(ipv6) }} counter goto homeproxy_mangle_tun
|
||||
{% endfor /* lan_proxy_ipv6_ips */ %}
|
||||
{% if (!isEmpty(control_info.lan_proxy_mac_addrs)): %}
|
||||
ether saddr {{ array_to_nftarr(control_info.lan_proxy_mac_addrs) }} counter goto homeproxy_mangle_tun
|
||||
{% endif /* lan_proxy_mac_addrs */ %}
|
||||
{% elif (control_info.lan_proxy_mode === 'except_listed'): %}
|
||||
{% if (!isEmpty(control_info.lan_direct_ipv4_ips)): %}
|
||||
ip saddr {{ array_to_nftarr(control_info.lan_direct_ipv4_ips) }} counter return
|
||||
{% endif /* lan_direct_ipv4_ips */ %}
|
||||
{% for (let ipv6 in control_info.lan_direct_ipv6_ips): %}
|
||||
ip6 saddr {{ resolve_ipv6(ipv6) }} counter return
|
||||
{% endfor /* lan_direct_ipv6_ips */ %}
|
||||
{% if (!isEmpty(control_info.lan_direct_mac_addrs)): %}
|
||||
ether saddr {{ array_to_nftarr(control_info.lan_direct_mac_addrs) }} counter return
|
||||
{% endif /* lan_direct_mac_addrs */ %}
|
||||
{% endif /* lan_proxy_mode */ %}
|
||||
|
||||
{% if (control_info.lan_proxy_mode !== 'listed_only'): %}
|
||||
counter goto homeproxy_mangle_tun
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
chain homeproxy_mangle_tun_mark {
|
||||
{% if (routing_port): %}
|
||||
{% if (proxy_mode === 'tun'): %}
|
||||
tcp dport != @homeproxy_routing_port counter return
|
||||
{% endif /* proxy_mode */ %}
|
||||
udp dport != @homeproxy_routing_port counter return
|
||||
{% endif /* routing_port */ %}
|
||||
|
||||
counter meta mark set {{ tun_mark }}
|
||||
}
|
||||
|
||||
chain homeproxy_mangle_tun {
|
||||
iifname {{ tun_name }} counter return
|
||||
|
||||
ip daddr @homeproxy_wan_proxy_addr_v4 counter goto homeproxy_mangle_tun_mark
|
||||
{% if (ipv6_support === '1'): %}
|
||||
ip6 daddr @homeproxy_wan_proxy_addr_v6 counter goto homeproxy_mangle_tun_mark
|
||||
{% endif %}
|
||||
|
||||
ip daddr @homeproxy_local_addr_v4 counter return
|
||||
{% if (ipv6_support === '1'): %}
|
||||
ip6 daddr @homeproxy_local_addr_v6 counter return
|
||||
{% endif %}
|
||||
|
||||
{% if (routing_mode !== 'custom'): %}
|
||||
{% if (!isEmpty(control_info.lan_global_proxy_ipv4_ips)): %}
|
||||
ip saddr {{ array_to_nftarr(control_info.lan_global_proxy_ipv4_ips) }} counter goto homeproxy_mangle_tun_mark
|
||||
{% endif /* lan_global_proxy_ipv4_ips */ %}
|
||||
{% for (let ipv6 in control_info.lan_global_proxy_ipv6_ips): %}
|
||||
ip6 saddr {{ resolve_ipv6(ipv6) }} counter goto homeproxy_mangle_tun_mark
|
||||
{% endfor /* lan_global_proxy_ipv6_ips */ %}
|
||||
{% if (!isEmpty(control_info.lan_global_proxy_mac_addrs)): %}
|
||||
ether saddr {{ array_to_nftarr(control_info.lan_global_proxy_mac_addrs) }} counter goto homeproxy_mangle_tun_mark
|
||||
{% endif /* lan_global_proxy_mac_addrs */ %}
|
||||
{% endif /* routing_mode */ %}
|
||||
|
||||
{% if (control_info.wan_direct_ipv4_ips): %}
|
||||
ip daddr {{ array_to_nftarr(control_info.wan_direct_ipv4_ips) }} counter return
|
||||
{% endif /* wan_direct_ipv4_ips */ %}
|
||||
{% if (control_info.wan_direct_ipv6_ips): %}
|
||||
ip6 daddr {{ array_to_nftarr(control_info.wan_direct_ipv6_ips) }} counter return
|
||||
{% endif /* wan_direct_ipv6_ips */ %}
|
||||
|
||||
{% if (routing_mode === 'gfwlist'): %}
|
||||
ip daddr != @homeproxy_gfw_list_v4 counter return
|
||||
{% if (ipv6_support === '1'): %}
|
||||
ip6 daddr != @homeproxy_gfw_list_v6 counter return
|
||||
{% endif /* ipv6_support */ %}
|
||||
udp dport { 80, 443 } counter reject comment "!{{ cfgname }}: Fuck you QUIC"
|
||||
{% elif (routing_mode === 'bypass_mainland_china' || bypass_cn_traffic === '1'): %}
|
||||
ip daddr @homeproxy_mainland_addr_v4 counter return
|
||||
{% if (ipv6_support === '1'): %}
|
||||
ip6 daddr @homeproxy_mainland_addr_v6 counter return
|
||||
{% endif /* ipv6_support */ %}
|
||||
{% if (routing_mode !== 'custom'): %}
|
||||
udp dport { 80, 443 } counter reject comment "!{{ cfgname }}: Fuck you QUIC"
|
||||
{% endif /* routing_mode */ %}
|
||||
{% elif (routing_mode === 'proxy_mainland_china'): %}
|
||||
ip daddr != @homeproxy_mainland_addr_v4 counter return
|
||||
{% if (ipv6_support === '1'): %}
|
||||
ip6 daddr != @homeproxy_mainland_addr_v6 counter return
|
||||
{% endif /* ipv6_support */ %}
|
||||
{% endif /* routing_mode */ %}
|
||||
|
||||
{% if (!isEmpty(control_info.lan_gaming_mode_ipv4_ips)): %}
|
||||
ip saddr {{ array_to_nftarr(control_info.lan_gaming_mode_ipv4_ips) }} counter meta mark set {{ tun_mark }}
|
||||
{% endif /* lan_gaming_mode_ipv4_ips */ %}
|
||||
{% for (let ipv6 in control_info.lan_gaming_mode_ipv6_ips): %}
|
||||
ip6 saddr {{ resolve_ipv6(ipv6) }} counter meta mark set {{ tun_mark }}
|
||||
{% endfor /* lan_gaming_mode_ipv6_ips */ %}
|
||||
{% if (!isEmpty(control_info.lan_gaming_mode_mac_addrs)): %}
|
||||
ether saddr {{ array_to_nftarr(control_info.lan_gaming_mode_mac_addrs) }} counter meta mark set {{ tun_mark }}
|
||||
{% endif /* lan_gaming_mode_mac_addrs */ %}
|
||||
|
||||
counter goto homeproxy_mangle_tun_mark
|
||||
}
|
||||
|
||||
chain mangle_prerouting {
|
||||
meta nfproto { {{ (ipv6_support === '1') ? 'ipv4, ipv6' : 'ipv4' }} } meta l4proto { {{ (proxy_mode === 'tun') ? 'tcp, udp' : 'udp' }} } jump homeproxy_mangle_lanac
|
||||
}
|
||||
|
||||
chain mangle_output {
|
||||
meta nfproto { {{ (ipv6_support === '1') ? 'ipv4, ipv6' : 'ipv4' }} } meta l4proto { {{ (proxy_mode === 'tun') ? 'tcp, udp' : 'udp' }} } jump homeproxy_mangle_tun
|
||||
}
|
||||
{% endif %}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
#!/usr/bin/ucode
|
||||
|
||||
'use strict';
|
||||
|
||||
import { writefile } from 'fs';
|
||||
import { cursor } from 'uci';
|
||||
import { isEmpty, RUN_DIR } from 'homeproxy';
|
||||
|
||||
const cfgname = 'homeproxy';
|
||||
const uci = cursor();
|
||||
uci.load(cfgname);
|
||||
|
||||
const routing_mode = uci.get(cfgname, 'config', 'routing_mode') || 'bypass_mainland_china',
|
||||
proxy_mode = uci.get(cfgname, 'config', 'proxy_mode') || 'redirect_tproxy';
|
||||
|
||||
let outbound_node, tun_name;
|
||||
if (match(proxy_mode, /tun/)) {
|
||||
if (routing_mode === 'custom')
|
||||
outbound_node = uci.get(cfgname, 'routing', 'default_outbound') || 'nil';
|
||||
else
|
||||
outbound_node = uci.get(cfgname, 'config', 'main_node') || 'nil';
|
||||
|
||||
if (outbound_node !== 'nil')
|
||||
tun_name = uci.get(cfgname, 'infra', 'tun_name') || 'singtun0';
|
||||
}
|
||||
|
||||
const server_enabled = uci.get(cfgname, 'server', 'enabled');
|
||||
|
||||
let forward = [],
|
||||
input = [];
|
||||
|
||||
if (tun_name) {
|
||||
push(forward, `oifname ${tun_name} counter accept comment "!${cfgname}: accept tun forward"`);
|
||||
push(input ,`iifname ${tun_name} counter accept comment "!${cfgname}: accept tun input"`);
|
||||
}
|
||||
|
||||
if (server_enabled === '1') {
|
||||
uci.foreach(cfgname, 'server', (s) => {
|
||||
if (s.enabled !== '1' || s.firewall !== '1')
|
||||
return;
|
||||
|
||||
let proto = s.network || '{ tcp, udp }';
|
||||
push(input, `meta l4proto ${proto} th dport ${s.port} counter accept comment "!${cfgname}: accept server ${s['.name']}"`);
|
||||
});
|
||||
}
|
||||
|
||||
if (!isEmpty(forward))
|
||||
writefile(RUN_DIR + '/fw4_forward.nft', join('\n', forward) + '\n');
|
||||
|
||||
if (!isEmpty(input))
|
||||
writefile(RUN_DIR + '/fw4_input.nft', join('\n', input) + '\n');
|
||||
+1031
File diff suppressed because it is too large.
Load diff
+185
@@ -0,0 +1,185 @@
|
||||
#!/usr/bin/ucode
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* Copyright (C) 2023 ImmortalWrt.org
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { writefile } from 'fs';
|
||||
import { cursor } from 'uci';
|
||||
|
||||
import {
|
||||
isEmpty, strToBool, strToInt, strToTime,
|
||||
removeBlankAttrs, HP_DIR, RUN_DIR
|
||||
} from 'homeproxy';
|
||||
|
||||
/* UCI config start */
|
||||
const uci = cursor();
|
||||
|
||||
const uciconfig = 'homeproxy';
|
||||
uci.load(uciconfig);
|
||||
|
||||
const uciserver = 'server';
|
||||
|
||||
const log_level = uci.get(uciconfig, uciserver, 'log_level') || 'warn';
|
||||
/* UCI config end */
|
||||
|
||||
const config = {};
|
||||
|
||||
/* Log */
|
||||
config.log = {
|
||||
disabled: false,
|
||||
level: log_level,
|
||||
output: RUN_DIR + '/sing-box-s.log',
|
||||
timestamp: true
|
||||
};
|
||||
|
||||
config.inbounds = [];
|
||||
|
||||
uci.foreach(uciconfig, uciserver, (cfg) => {
|
||||
if (cfg.enabled !== '1')
|
||||
return;
|
||||
|
||||
push(config.inbounds, {
|
||||
type: cfg.type,
|
||||
tag: 'cfg-' + cfg['.name'] + '-in',
|
||||
|
||||
listen: cfg.address || '::',
|
||||
listen_port: strToInt(cfg.port),
|
||||
bind_interface: cfg.bind_interface,
|
||||
reuse_addr: strToBool(cfg.reuse_addr),
|
||||
tcp_fast_open: strToBool(cfg.tcp_fast_open),
|
||||
tcp_multi_path: strToBool(cfg.tcp_multi_path),
|
||||
udp_fragment: strToBool(cfg.udp_fragment),
|
||||
udp_timeout: strToTime(cfg.udp_timeout),
|
||||
network: cfg.network,
|
||||
|
||||
/* AnyTLS */
|
||||
padding_scheme: cfg.anytls_padding_scheme,
|
||||
|
||||
/* Hysteria */
|
||||
up_mbps: strToInt(cfg.hysteria_up_mbps),
|
||||
down_mbps: strToInt(cfg.hysteria_down_mbps),
|
||||
obfs: cfg.hysteria_obfs_type ? {
|
||||
type: cfg.hysteria_obfs_type,
|
||||
password: cfg.hysteria_obfs_password
|
||||
} : cfg.hysteria_obfs_password,
|
||||
recv_window_conn: strToInt(cfg.hysteria_recv_window_conn),
|
||||
recv_window_client: strToInt(cfg.hysteria_revc_window_client),
|
||||
max_conn_client: strToInt(cfg.hysteria_max_conn_client),
|
||||
disable_mtu_discovery: strToBool(cfg.hysteria_disable_mtu_discovery),
|
||||
ignore_client_bandwidth: strToBool(cfg.hysteria_ignore_client_bandwidth),
|
||||
masquerade: cfg.hysteria_masquerade,
|
||||
|
||||
/* Shadowsocks */
|
||||
method: (cfg.type === 'shadowsocks') ? cfg.shadowsocks_encrypt_method : null,
|
||||
password: (cfg.type in ['shadowsocks', 'shadowtls']) ? cfg.password : null,
|
||||
|
||||
/* Tuic */
|
||||
congestion_control: cfg.tuic_congestion_control,
|
||||
auth_timeout: strToTime(cfg.tuic_auth_timeout),
|
||||
zero_rtt_handshake: strToBool(cfg.tuic_enable_zero_rtt),
|
||||
heartbeat: strToTime(cfg.tuic_heartbeat),
|
||||
|
||||
/* AnyTLS / HTTP / Hysteria (2) / Mixed / Socks / Trojan / Tuic / VLESS / VMess */
|
||||
users: (cfg.type !== 'shadowsocks') ? [
|
||||
{
|
||||
name: !(cfg.type in ['http', 'mixed', 'naive', 'socks']) ? 'cfg-' + cfg['.name'] + '-server' : null,
|
||||
username: cfg.username,
|
||||
password: cfg.password,
|
||||
|
||||
/* Hysteria */
|
||||
auth: (cfg.hysteria_auth_type === 'base64') ? cfg.hysteria_auth_payload : null,
|
||||
auth_str: (cfg.hysteria_auth_type === 'string') ? cfg.hysteria_auth_payload : null,
|
||||
|
||||
/* Tuic */
|
||||
uuid: cfg.uuid,
|
||||
|
||||
/* VLESS / VMess */
|
||||
flow: cfg.vless_flow,
|
||||
alterId: strToInt(cfg.vmess_alterid)
|
||||
}
|
||||
] : null,
|
||||
|
||||
multiplex: (cfg.multiplex === '1') ? {
|
||||
enabled: true,
|
||||
padding: strToBool(cfg.multiplex_padding),
|
||||
brutal: (cfg.multiplex_brutal === '1') ? {
|
||||
enabled: true,
|
||||
up_mbps: strToInt(cfg.multiplex_brutal_up),
|
||||
down_mbps: strToInt(cfg.multiplex_brutal_down)
|
||||
} : null
|
||||
} : null,
|
||||
|
||||
tls: (cfg.tls === '1') ? {
|
||||
enabled: true,
|
||||
server_name: cfg.tls_sni,
|
||||
alpn: cfg.tls_alpn,
|
||||
min_version: cfg.tls_min_version,
|
||||
max_version: cfg.tls_max_version,
|
||||
cipher_suites: cfg.tls_cipher_suites,
|
||||
certificate_path: cfg.tls_cert_path,
|
||||
key_path: cfg.tls_key_path,
|
||||
acme: (cfg.tls_acme === '1') ? {
|
||||
domain: cfg.tls_acme_domain,
|
||||
data_directory: HP_DIR + '/certs',
|
||||
default_server_name: cfg.tls_acme_dsn,
|
||||
email: cfg.tls_acme_email,
|
||||
provider: cfg.tls_acme_provider,
|
||||
disable_http_challenge: strToBool(cfg.tls_acme_dhc),
|
||||
disable_tls_alpn_challenge: (cfg.tls_acme_dtac),
|
||||
alternative_http_port: strToInt(cfg.tls_acme_ahp),
|
||||
alternative_tls_port: strToInt(cfg.tls_acme_atp),
|
||||
external_account: (cfg.tls_acme_external_account === '1') ? {
|
||||
key_id: cfg.tls_acme_ea_keyid,
|
||||
mac_key: cfg.tls_acme_ea_mackey
|
||||
} : null,
|
||||
dns01_challenge: (cfg.tls_dns01_challenge === '1') ? {
|
||||
provider: cfg.tls_dns01_provider,
|
||||
access_key_id: cfg.tls_dns01_ali_akid,
|
||||
access_key_secret: cfg.tls_dns01_ali_aksec,
|
||||
region_id: cfg.tls_dns01_ali_rid,
|
||||
api_token: cfg.tls_dns01_cf_api_token
|
||||
} : null
|
||||
} : null,
|
||||
ech: (cfg.tls_ech_key) ? {
|
||||
enabled: true,
|
||||
key: split(cfg.tls_ech_key, '\n'),
|
||||
// config: split(cfg.tls_ech_config, '\n')
|
||||
} : null,
|
||||
reality: (cfg.tls_reality === '1') ? {
|
||||
enabled: true,
|
||||
private_key: cfg.tls_reality_private_key,
|
||||
short_id: cfg.tls_reality_short_id,
|
||||
max_time_difference: strToTime(cfg.tls_reality_max_time_difference),
|
||||
handshake: {
|
||||
server: cfg.tls_reality_server_addr,
|
||||
server_port: strToInt(cfg.tls_reality_server_port)
|
||||
}
|
||||
} : null
|
||||
} : null,
|
||||
|
||||
transport: !isEmpty(cfg.transport) ? {
|
||||
type: cfg.transport,
|
||||
host: cfg.http_host || cfg.httpupgrade_host,
|
||||
path: cfg.http_path || cfg.ws_path,
|
||||
headers: cfg.ws_host ? {
|
||||
Host: cfg.ws_host
|
||||
} : null,
|
||||
method: cfg.http_method,
|
||||
max_early_data: strToInt(cfg.websocket_early_data),
|
||||
early_data_header_name: cfg.websocket_early_data_header,
|
||||
service_name: cfg.grpc_servicename,
|
||||
idle_timeout: strToTime(cfg.http_idle_timeout),
|
||||
ping_timeout: strToTime(cfg.http_ping_timeout)
|
||||
} : null
|
||||
});
|
||||
});
|
||||
|
||||
if (length(config.inbounds) === 0)
|
||||
exit(1);
|
||||
|
||||
system('mkdir -p ' + RUN_DIR);
|
||||
writefile(RUN_DIR + '/sing-box-s.json', sprintf('%.J\n', removeBlankAttrs(config)));
|
||||
+230
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* Copyright (C) 2023 ImmortalWrt.org
|
||||
*/
|
||||
|
||||
import { mkstemp } from 'fs';
|
||||
import { urldecode_params } from 'luci.http';
|
||||
|
||||
/* Global variables start */
|
||||
export const HP_DIR = '/etc/homeproxy';
|
||||
export const RUN_DIR = '/var/run/homeproxy';
|
||||
/* Global variables end */
|
||||
|
||||
/* Utilities start */
|
||||
/* Kanged from luci-app-commands */
|
||||
export function shellQuote(s) {
|
||||
return `'${replace(s, "'", "'\\''")}'`;
|
||||
};
|
||||
|
||||
export function isBinary(str) {
|
||||
for (let off = 0, byte = ord(str); off < length(str); byte = ord(str, ++off))
|
||||
if (byte <= 8 || (byte >= 14 && byte <= 31))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
export function executeCommand(...args) {
|
||||
let outfd = mkstemp();
|
||||
let errfd = mkstemp();
|
||||
|
||||
const exitcode = system(`${join(' ', args)} >&${outfd.fileno()} 2>&${errfd.fileno()}`);
|
||||
|
||||
outfd.seek(0);
|
||||
errfd.seek(0);
|
||||
|
||||
const stdout = outfd.read(1024 * 512) ?? '';
|
||||
const stderr = errfd.read(1024 * 512) ?? '';
|
||||
|
||||
outfd.close();
|
||||
errfd.close();
|
||||
|
||||
const binary = isBinary(stdout);
|
||||
|
||||
return {
|
||||
command: join(' ', args),
|
||||
stdout: binary ? null : stdout,
|
||||
stderr,
|
||||
exitcode,
|
||||
binary
|
||||
};
|
||||
};
|
||||
|
||||
export function getTime(epoch) {
|
||||
const local_time = localtime(epoch);
|
||||
return replace(replace(sprintf(
|
||||
'%d-%2d-%2d@%2d:%2d:%2d',
|
||||
local_time.year,
|
||||
local_time.mon,
|
||||
local_time.mday,
|
||||
local_time.hour,
|
||||
local_time.min,
|
||||
local_time.sec
|
||||
), ' ', '0'), '@', ' ');
|
||||
|
||||
};
|
||||
|
||||
export function wGET(url, ua) {
|
||||
if (!url || type(url) !== 'string')
|
||||
return null;
|
||||
|
||||
if (!ua)
|
||||
ua = 'Wget/1.21 (HomeProxy, like v2rayN)';
|
||||
|
||||
const output = executeCommand(`/usr/bin/wget -qO- --user-agent ${shellQuote(ua)} --timeout=10 ${shellQuote(url)}`) || {};
|
||||
return trim(output.stdout);
|
||||
};
|
||||
/* Utilities end */
|
||||
|
||||
/* String helper start */
|
||||
export function isEmpty(res) {
|
||||
return !res || res === 'nil' || (type(res) in ['array', 'object'] && length(res) === 0);
|
||||
};
|
||||
|
||||
export function strToBool(str) {
|
||||
return (str === '1') || null;
|
||||
};
|
||||
|
||||
export function strToInt(str) {
|
||||
return !isEmpty(str) ? (int(str) || null) : null;
|
||||
};
|
||||
|
||||
export function strToTime(str) {
|
||||
return !isEmpty(str) ? (str + 's') : null;
|
||||
};
|
||||
|
||||
export function removeBlankAttrs(res) {
|
||||
let content;
|
||||
|
||||
if (type(res) === 'object') {
|
||||
content = {};
|
||||
map(keys(res), (k) => {
|
||||
if (type(res[k]) in ['array', 'object'])
|
||||
content[k] = removeBlankAttrs(res[k]);
|
||||
else if (res[k] !== null && res[k] !== '')
|
||||
content[k] = res[k];
|
||||
});
|
||||
} else if (type(res) === 'array') {
|
||||
content = [];
|
||||
map(res, (k, i) => {
|
||||
if (type(k) in ['array', 'object'])
|
||||
push(content, removeBlankAttrs(k));
|
||||
else if (k !== null && k !== '')
|
||||
push(content, k);
|
||||
});
|
||||
} else
|
||||
return res;
|
||||
|
||||
return content;
|
||||
};
|
||||
|
||||
export function validateHostname(hostname) {
|
||||
return (match(hostname, /^[a-zA-Z0-9_]+$/) != null ||
|
||||
(match(hostname, /^[a-zA-Z0-9_][a-zA-Z0-9_%-.]*[a-zA-Z0-9]$/) &&
|
||||
match(hostname, /[^0-9.]/)));
|
||||
};
|
||||
|
||||
export function validation(datatype, data) {
|
||||
if (!datatype || !data)
|
||||
return null;
|
||||
|
||||
const ret = system(`/sbin/validate_data ${shellQuote(datatype)} ${shellQuote(data)} 2>/dev/null`);
|
||||
return (ret === 0);
|
||||
};
|
||||
/* String helper end */
|
||||
|
||||
/* String parser start */
|
||||
export function decodeBase64Str(str) {
|
||||
if (isEmpty(str))
|
||||
return null;
|
||||
|
||||
str = trim(str);
|
||||
str = replace(str, '_', '/');
|
||||
str = replace(str, '-', '+');
|
||||
|
||||
const padding = length(str) % 4;
|
||||
if (padding)
|
||||
str = str + substr('====', padding);
|
||||
|
||||
return b64dec(str);
|
||||
};
|
||||
|
||||
export function parseURL(url) {
|
||||
if (type(url) !== 'string')
|
||||
return null;
|
||||
|
||||
const services = {
|
||||
http: '80',
|
||||
https: '443'
|
||||
};
|
||||
|
||||
const objurl = {};
|
||||
|
||||
objurl.href = url;
|
||||
|
||||
url = replace(url, /#(.+)$/, (_, val) => {
|
||||
objurl.hash = val;
|
||||
return '';
|
||||
});
|
||||
|
||||
url = replace(url, /^(\w[A-Za-z0-9\+\-\.]+):/, (_, val) => {
|
||||
objurl.protocol = val;
|
||||
return '';
|
||||
});
|
||||
|
||||
url = replace(url, /\?(.+)/, (_, val) => {
|
||||
objurl.search = val;
|
||||
objurl.searchParams = urldecode_params(val);
|
||||
return '';
|
||||
});
|
||||
|
||||
url = replace(url, /^\/\/([^\/]+)/, (_, val) => {
|
||||
val = replace(val, /^([^@]+)@/, (_, val) => {
|
||||
objurl.userinfo = val;
|
||||
return '';
|
||||
});
|
||||
|
||||
val = replace(val, /:(\d+)$/, (_, val) => {
|
||||
objurl.port = val;
|
||||
return '';
|
||||
});
|
||||
|
||||
if (validation('ip4addr', val) ||
|
||||
validation('ip6addr', replace(val, /\[|\]/g, '')) ||
|
||||
validation('hostname', val))
|
||||
objurl.hostname = val;
|
||||
|
||||
return '';
|
||||
});
|
||||
|
||||
objurl.pathname = url || '/';
|
||||
|
||||
if (!objurl.protocol || !objurl.hostname)
|
||||
return null;
|
||||
|
||||
if (objurl.userinfo) {
|
||||
objurl.userinfo = replace(objurl.userinfo, /:(.+)$/, (_, val) => {
|
||||
objurl.password = val;
|
||||
return '';
|
||||
});
|
||||
|
||||
if (match(objurl.userinfo, /^[A-Za-z0-9\+\-\_\.]+$/)) {
|
||||
objurl.username = objurl.userinfo;
|
||||
delete objurl.userinfo;
|
||||
} else {
|
||||
delete objurl.userinfo;
|
||||
delete objurl.password;
|
||||
}
|
||||
};
|
||||
|
||||
if (!objurl.port)
|
||||
objurl.port = services[objurl.protocol];
|
||||
|
||||
objurl.host = objurl.hostname + (objurl.port ? `:${objurl.port}` : '');
|
||||
objurl.origin = `${objurl.protocol}://${objurl.host}`;
|
||||
|
||||
return objurl;
|
||||
};
|
||||
/* String parser end */
|
||||
+261
@@ -0,0 +1,261 @@
|
||||
#!/usr/bin/ucode
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* Copyright (C) 2025 ImmortalWrt.org
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { cursor } from 'uci';
|
||||
import { isEmpty, parseURL } from 'homeproxy';
|
||||
|
||||
const uci = cursor();
|
||||
|
||||
const uciconfig = 'homeproxy';
|
||||
uci.load(uciconfig);
|
||||
|
||||
const uciinfra = 'infra',
|
||||
ucimigration = 'migration',
|
||||
ucimain = 'config',
|
||||
ucinode = 'node',
|
||||
ucidns = 'dns',
|
||||
ucidnsserver = 'dns_server',
|
||||
ucidnsrule = 'dns_rule',
|
||||
ucirouting = 'routing',
|
||||
uciroutingnode = 'routing_node',
|
||||
uciroutingrule = 'routing_rule',
|
||||
uciserver = 'server';
|
||||
|
||||
/* chinadns-ng has been removed */
|
||||
if (uci.get(uciconfig, uciinfra, 'china_dns_port'))
|
||||
uci.delete(uciconfig, uciinfra, 'china_dns_port');
|
||||
|
||||
/* chinadns server now only accepts single server */
|
||||
const china_dns_server = uci.get(uciconfig, ucimain, 'china_dns_server');
|
||||
if (type(china_dns_server) === 'array') {
|
||||
uci.set(uciconfig, ucimain, 'china_dns_server', china_dns_server[0]);
|
||||
} else {
|
||||
if (match(china_dns_server, /,/))
|
||||
uci.set(uciconfig, ucimain, 'china_dns_server', split(china_dns_server, ',')[0]);
|
||||
}
|
||||
|
||||
/* github_token option has been moved to config section */
|
||||
const github_token = uci.get(uciconfig, uciinfra, 'github_token');
|
||||
if (github_token) {
|
||||
uci.set(uciconfig, ucimain, 'github_token', github_token);
|
||||
uci.delete(uciconfig, uciinfra, 'github_token')
|
||||
}
|
||||
|
||||
/* ntp_server was introduced */
|
||||
if (!uci.get(uciconfig, uciinfra, 'ntp_server'))
|
||||
uci.set(uciconfig, uciinfra, 'ntp_server', 'nil');
|
||||
|
||||
/* tun_gso was deprecated in sb 1.11 */
|
||||
if (!isEmpty(uci.get(uciconfig, uciinfra, 'tun_gso')))
|
||||
uci.delete(uciconfig, uciinfra, 'tun_gso');
|
||||
|
||||
/* create migration section */
|
||||
if (!uci.get(uciconfig, ucimigration))
|
||||
uci.set(uciconfig, ucimigration, uciconfig);
|
||||
|
||||
/* delete old crontab command */
|
||||
const migration_crontab = uci.get(uciconfig, ucimigration, 'crontab');
|
||||
if (!migration_crontab) {
|
||||
system('sed -i "/update_crond.sh/d" "/etc/crontabs/root" 2>"/dev/null"');
|
||||
uci.set(uciconfig, ucimigration, 'crontab', '1');
|
||||
}
|
||||
|
||||
/* log_level was introduced */
|
||||
if (isEmpty(uci.get(uciconfig, ucimain, 'log_level')))
|
||||
uci.set(uciconfig, ucimain, 'log_level', 'warn');
|
||||
|
||||
if (isEmpty(uci.get(uciconfig, uciserver, 'log_level')))
|
||||
uci.set(uciconfig, uciserver, 'log_level', 'warn');
|
||||
|
||||
/* empty value defaults to all ports now */
|
||||
if (uci.get(uciconfig, ucimain, 'routing_port') === 'all')
|
||||
uci.delete(uciconfig, ucimain, 'routing_port');
|
||||
|
||||
/* experimental section was removed */
|
||||
if (uci.get(uciconfig, 'experimental'))
|
||||
uci.delete(uciconfig, 'experimental');
|
||||
|
||||
/* block-dns was removed from built-in dns servers */
|
||||
const default_dns_server = uci.get(uciconfig, ucidns, 'default_server');
|
||||
if (default_dns_server === 'block-dns') {
|
||||
/* append a rule at last to block all DNS queries */
|
||||
uci.set(uciconfig, '_migration_dns_final_block', ucidnsrule);
|
||||
uci.set(uciconfig, '_migration_dns_final_block', 'label', 'migration_final_block_dns');
|
||||
uci.set(uciconfig, '_migration_dns_final_block', 'enabled', '1');
|
||||
uci.set(uciconfig, '_migration_dns_final_block', 'mode', 'default');
|
||||
uci.set(uciconfig, '_migration_dns_final_block', 'action', 'reject');
|
||||
uci.set(uciconfig, ucidns, 'default_server', 'default-dns');
|
||||
}
|
||||
|
||||
const dns_server_migration = {};
|
||||
/* DNS servers options */
|
||||
uci.foreach(uciconfig, ucidnsserver, (cfg) => {
|
||||
/* legacy format was deprecated in sb 1.12 */
|
||||
if (cfg.address) {
|
||||
const addr = parseURL((!match(cfg.address, /:\/\//) ? 'udp://' : '') + (validation('ip6addr', cfg.address) ? `[${cfg.address}]` : cfg.address));
|
||||
/* RCode was moved into DNS rules */
|
||||
if (addr.protocol === 'rcode') {
|
||||
dns_server_migration[cfg['.name']] = { action: 'predefined' };
|
||||
switch (addr.hostname) {
|
||||
case 'success':
|
||||
dns_server_migration[cfg['.name']].rcode = 'NOERROR';
|
||||
break;
|
||||
case 'format_error':
|
||||
dns_server_migration[cfg['.name']].rcode = 'FORMERR';
|
||||
break;
|
||||
case 'server_failure':
|
||||
dns_server_migration[cfg['.name']].rcode = 'SERVFAIL';
|
||||
break;
|
||||
case 'name_error':
|
||||
dns_server_migration[cfg['.name']].rcode = 'NXDOMAIN';
|
||||
break;
|
||||
case 'not_implemented':
|
||||
dns_server_migration[cfg['.name']].rcode = 'NOTIMP';
|
||||
break;
|
||||
case 'refused':
|
||||
default:
|
||||
dns_server_migration[cfg['.name']].rcode = 'REFUSED';
|
||||
break;
|
||||
}
|
||||
|
||||
uci.delete(uciconfig, cfg['.name']);
|
||||
return;
|
||||
}
|
||||
uci.set(uciconfig, cfg['.name'], 'type', addr.protocol);
|
||||
uci.set(uciconfig, cfg['.name'], 'server', addr.hostname);
|
||||
uci.set(uciconfig, cfg['.name'], 'server_port', addr.port);
|
||||
uci.set(uciconfig, cfg['.name'], 'path', (addr.pathname !== '/') ? addr.pathname : null);
|
||||
uci.delete(uciconfig, cfg['.name'], 'address');
|
||||
}
|
||||
|
||||
if (cfg.strategy) {
|
||||
if (cfg['.name'] === default_dns_server)
|
||||
uci.set(uciconfig, ucidns, 'default_strategy', cfg.strategy);
|
||||
dns_server_migration[cfg['.name']] = { strategy: cfg.strategy };
|
||||
uci.delete(uciconfig, cfg['.name'], 'strategy');
|
||||
}
|
||||
|
||||
if (cfg.client_subnet) {
|
||||
if (cfg['.name'] === default_dns_server)
|
||||
uci.set(uciconfig, ucidns, 'client_subnet', cfg.client_subnet);
|
||||
|
||||
if (isEmpty(dns_server_migration[cfg['.name']]))
|
||||
dns_server_migration[cfg['.name']] = {};
|
||||
dns_server_migration[cfg['.name']].client_subnet = cfg.client_subnet;
|
||||
uci.delete(uciconfig, cfg['.name'], 'client_subnet');
|
||||
}
|
||||
});
|
||||
|
||||
/* DNS rules options */
|
||||
uci.foreach(uciconfig, ucidnsrule, (cfg) => {
|
||||
/* outbound was removed in sb 1.12 */
|
||||
if (cfg.outbound) {
|
||||
uci.delete(uciconfig, cfg['.name']);
|
||||
if (!cfg.enabled)
|
||||
return;
|
||||
|
||||
map(cfg.outbound, (outbound) => {
|
||||
switch (outbound) {
|
||||
case 'direct-out':
|
||||
case 'block-out':
|
||||
break;
|
||||
case 'any-out':
|
||||
uci.set(uciconfig, ucirouting, 'default_outbound_dns', cfg.server);
|
||||
break;
|
||||
default:
|
||||
uci.set(uciconfig, cfg.outbound, 'domain_resolver', cfg.server);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* rule_set_ipcidr_match_source was renamed in sb 1.10 */
|
||||
if (cfg.rule_set_ipcidr_match_source === '1')
|
||||
uci.rename(uciconfig, cfg['.name'], 'rule_set_ipcidr_match_source', 'rule_set_ip_cidr_match_source');
|
||||
|
||||
/* block-dns was moved into action in sb 1.11 */
|
||||
if (cfg.server === 'block-dns') {
|
||||
uci.set(uciconfig, cfg['.name'], 'action', 'reject');
|
||||
uci.delete(uciconfig, cfg['.name'], 'server');
|
||||
} else if (!cfg.action) {
|
||||
/* add missing 'action' field */
|
||||
uci.set(uciconfig, cfg['.name'], 'action', 'route');
|
||||
}
|
||||
|
||||
/* strategy and client_subnet were moved into dns rules */
|
||||
if (dns_server_migration[cfg.server]) {
|
||||
if (dns_server_migration[cfg.server].strategy)
|
||||
uci.set(uciconfig, cfg['.name'], 'strategy', dns_server_migration[cfg.server].strategy);
|
||||
|
||||
if (dns_server_migration[cfg.server].client_subnet)
|
||||
uci.set(uciconfig, cfg['.name'], 'client_subnet', dns_server_migration[cfg.server].client_subnet);
|
||||
|
||||
if (dns_server_migration[cfg.server].rcode) {
|
||||
uci.set(uciconfig, cfg['.name'], 'action', 'predefined');
|
||||
uci.set(uciconfig, cfg['.name'], 'rcode', dns_server_migration[cfg.server].rcode);
|
||||
uci.delete(uciconfig, cfg['.name'], 'server');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/* nodes options */
|
||||
uci.foreach(uciconfig, ucinode, (cfg) => {
|
||||
/* tls_ech_tls_disable_drs is useless and deprecated in sb 1.12 */
|
||||
if (!isEmpty(cfg.tls_ech_tls_disable_drs))
|
||||
uci.delete(uciconfig, cfg['.name'], 'tls_ech_tls_disable_drs');
|
||||
|
||||
/* tls_ech_enable_pqss is useless and deprecated in sb 1.12 */
|
||||
if (!isEmpty(cfg.tls_ech_enable_pqss))
|
||||
uci.delete(uciconfig, cfg['.name'], 'tls_ech_enable_pqss');
|
||||
|
||||
/* wireguard_gso was deprecated in sb 1.11 */
|
||||
if (!isEmpty(cfg.wireguard_gso))
|
||||
uci.delete(uciconfig, cfg['.name'], 'wireguard_gso');
|
||||
});
|
||||
|
||||
/* routing rules options */
|
||||
uci.foreach(uciconfig, uciroutingrule, (cfg) => {
|
||||
/* rule_set_ipcidr_match_source was renamed in sb 1.10 */
|
||||
if (cfg.rule_set_ipcidr_match_source === '1')
|
||||
uci.rename(uciconfig, cfg['.name'], 'rule_set_ipcidr_match_source', 'rule_set_ip_cidr_match_source');
|
||||
|
||||
/* block-out was moved into action in sb 1.11 */
|
||||
if (cfg.outbound === 'block-out') {
|
||||
uci.set(uciconfig, cfg['.name'], 'action', 'reject');
|
||||
uci.delete(uciconfig, cfg['.name'], 'outbound');
|
||||
} else if (!cfg.action) {
|
||||
/* add missing 'action' field */
|
||||
uci.set(uciconfig, cfg['.name'], 'action', 'route');
|
||||
}
|
||||
});
|
||||
|
||||
/* server options */
|
||||
/* auto_firewall was moved into server options */
|
||||
const auto_firewall = uci.get(uciconfig, uciserver, 'auto_firewall');
|
||||
if (!isEmpty(auto_firewall))
|
||||
uci.delete(uciconfig, uciserver, 'auto_firewall');
|
||||
|
||||
uci.foreach(uciconfig, uciserver, (cfg) => {
|
||||
/* auto_firewall was moved into server options */
|
||||
if (auto_firewall === '1')
|
||||
uci.set(uciconfig, cfg['.name'], 'firewall' , '1');
|
||||
|
||||
/* sniff_override was deprecated in sb 1.11 */
|
||||
if (!isEmpty(cfg.sniff_override))
|
||||
uci.delete(uciconfig, cfg['.name'], 'sniff_override');
|
||||
|
||||
/* domain_strategy is now pointless without sniff override */
|
||||
if (!isEmpty(cfg.domain_strategy))
|
||||
uci.delete(uciconfig, cfg['.name'], 'domain_strategy');
|
||||
});
|
||||
|
||||
if (!isEmpty(uci.changes(uciconfig)))
|
||||
uci.commit(uciconfig);
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
#!/bin/sh
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
# Copyright (C) 2023 ImmortalWrt.org
|
||||
|
||||
SCRIPTS_DIR="/etc/homeproxy/scripts"
|
||||
|
||||
for i in "china_ip4" "china_ip6" "gfw_list" "china_list"; do
|
||||
"$SCRIPTS_DIR"/update_resources.sh "$i"
|
||||
done
|
||||
|
||||
"$SCRIPTS_DIR"/update_subscriptions.uc
|
||||
@@ -0,0 +1,89 @@
|
||||
#!/bin/sh
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
# Copyright (C) 2022-2025 ImmortalWrt.org
|
||||
|
||||
NAME="homeproxy"
|
||||
|
||||
RESOURCES_DIR="/etc/$NAME/resources"
|
||||
mkdir -p "$RESOURCES_DIR"
|
||||
|
||||
RUN_DIR="/var/run/$NAME"
|
||||
LOG_PATH="$RUN_DIR/$NAME.log"
|
||||
mkdir -p "$RUN_DIR"
|
||||
|
||||
log() {
|
||||
echo -e "$(date "+%Y-%m-%d %H:%M:%S") $*" >> "$LOG_PATH"
|
||||
}
|
||||
|
||||
to_upper() {
|
||||
echo -e "$1" | tr "[a-z]" "[A-Z]"
|
||||
}
|
||||
|
||||
check_list_update() {
|
||||
local LIST_FILE="$1"
|
||||
local REPO_NAME="$2"
|
||||
local REPO_BRANCH="$3"
|
||||
local REPO_FILE="$4"
|
||||
local LOCK_FILE="$RUN_DIR/update_resources-$LIST_FILE.lock"
|
||||
local GITHUB_TOKEN="$(uci -q get homeproxy.config.github_token)"
|
||||
|
||||
exec 200>"$LOCK_FILE"
|
||||
if ! flock -n 200 &> "/dev/null"; then
|
||||
log "[$(to_upper "$LIST_FILE")] A task is already running."
|
||||
return 2
|
||||
fi
|
||||
|
||||
local NEW_VER=$(curl -sL ${GITHUB_TOKEN:+-H "Authorization: Bearer $GITHUB_TOKEN"} "https://api.github.com/repos/$REPO_NAME/releases/latest" | jsonfilter -e "@.tag_name")
|
||||
if [ -z "$NEW_VER" ]; then
|
||||
log "[$(to_upper "$LIST_FILE")] Failed to get the latest version, please retry later."
|
||||
|
||||
return 1
|
||||
fi
|
||||
|
||||
local OLD_VER=$(cat "$RESOURCES_DIR/$LIST_FILE.ver" 2>/dev/null || echo "NOT FOUND")
|
||||
if [ "$OLD_VER" = "$NEW_VER" ]; then
|
||||
log "[$(to_upper "$LIST_FILE")] Current version: $NEW_VER."
|
||||
log "[$(to_upper "$LIST_FILE")] You're already at the latest version."
|
||||
|
||||
return 3
|
||||
else
|
||||
log "[$(to_upper "$LIST_FILE")] Local version: $OLD_VER, latest version: $NEW_VER."
|
||||
fi
|
||||
|
||||
if ! curl -sL -o "$RUN_DIR/$REPO_FILE" "https://cdn.jsdelivr.net/gh/$REPO_NAME@$REPO_BRANCH/$REPO_FILE" || [ ! -s "$RUN_DIR/$REPO_FILE" ]; then
|
||||
rm -f "$RUN_DIR/$REPO_FILE"
|
||||
log "[$(to_upper "$LIST_FILE")] Update failed."
|
||||
|
||||
return 1
|
||||
fi
|
||||
|
||||
mv -f "$RUN_DIR/$REPO_FILE" "$RESOURCES_DIR/$LIST_FILE.${REPO_FILE##*.}"
|
||||
echo -e "$NEW_VER" > "$RESOURCES_DIR/$LIST_FILE.ver"
|
||||
log "[$(to_upper "$LIST_FILE")] Successfully updated."
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
"china_ip4")
|
||||
check_list_update "$1" "Loyalsoldier/surge-rules" "release" "cncidr.txt" && \
|
||||
sed -i "/IP-CIDR6,/d; s/IP-CIDR,//g" "$RESOURCES_DIR/china_ip4.txt"
|
||||
;;
|
||||
"china_ip6")
|
||||
check_list_update "$1" "Loyalsoldier/surge-rules" "release" "cncidr.txt" && \
|
||||
sed -i "/IP-CIDR,/d; s/IP-CIDR6,//g" "$RESOURCES_DIR/china_ip6.txt"
|
||||
;;
|
||||
"gfw_list")
|
||||
check_list_update "$1" "Loyalsoldier/surge-rules" "release" "gfw.txt" && \
|
||||
sed -i "s/^\.//g" "$RESOURCES_DIR/gfw_list.txt"
|
||||
;;
|
||||
"china_list")
|
||||
check_list_update "$1" "Loyalsoldier/surge-rules" "release" "direct.txt" && \
|
||||
sed -i "s/^\.//g" "$RESOURCES_DIR/china_list.txt"
|
||||
;;
|
||||
*)
|
||||
echo -e "Usage: $0 <china_ip4 / china_ip6 / gfw_list / china_list>"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
+1156
File diff suppressed because it is too large.
Load diff
Executable
+338
@@ -0,0 +1,338 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
# Copyright (C) 2022-2023 ImmortalWrt.org
|
||||
|
||||
USE_PROCD=1
|
||||
|
||||
START=99
|
||||
STOP=10
|
||||
|
||||
CONF="homeproxy"
|
||||
PROG="/usr/bin/sing-box"
|
||||
|
||||
HP_DIR="/etc/homeproxy"
|
||||
RUN_DIR="/var/run/homeproxy"
|
||||
LOG_PATH="$RUN_DIR/homeproxy.log"
|
||||
|
||||
# we don't know which is the default server, just take the first one
|
||||
DNSMASQ_UCI_CONFIG="$(uci -q show "dhcp.@dnsmasq[0]" | awk 'NR==1 {split($0, conf, /[.=]/); print conf[2]}')"
|
||||
if [ -f "/tmp/etc/dnsmasq.conf.$DNSMASQ_UCI_CONFIG" ]; then
|
||||
DNSMASQ_DIR="$(awk -F '=' '/^conf-dir=/ {print $2}' "/tmp/etc/dnsmasq.conf.$DNSMASQ_UCI_CONFIG")/dnsmasq-homeproxy.d"
|
||||
else
|
||||
DNSMASQ_DIR="/tmp/dnsmasq.d/dnsmasq-homeproxy.d"
|
||||
fi
|
||||
|
||||
log() {
|
||||
echo -e "$(date "+%Y-%m-%d %H:%M:%S") [DAEMON] $*" >> "$LOG_PATH"
|
||||
}
|
||||
|
||||
start_service() {
|
||||
config_load "$CONF"
|
||||
|
||||
local routing_mode proxy_mode
|
||||
config_get routing_mode "config" "routing_mode" "bypass_mainland_china"
|
||||
config_get proxy_mode "config" "proxy_mode" "redirect_tproxy"
|
||||
|
||||
local outbound_node
|
||||
if [ "$routing_mode" != "custom" ]; then
|
||||
config_get outbound_node "config" "main_node" "nil"
|
||||
else
|
||||
config_get outbound_node "routing" "default_outbound" "nil"
|
||||
fi
|
||||
|
||||
local server_enabled
|
||||
config_get_bool server_enabled "server" "enabled" "0"
|
||||
|
||||
if [ "$outbound_node" = "nil" ] && [ "$server_enabled" = "0" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
mkdir -p "$RUN_DIR"
|
||||
|
||||
if [ "$outbound_node" != "nil" ]; then
|
||||
# Generate/Validate client config
|
||||
ucode -S "$HP_DIR/scripts/generate_client.uc" 2>>"$LOG_PATH"
|
||||
|
||||
if [ ! -e "$RUN_DIR/sing-box-c.json" ]; then
|
||||
log "Error: failed to generate client configuration."
|
||||
return 1
|
||||
elif ! "$PROG" check --config "$RUN_DIR/sing-box-c.json" 2>>"$LOG_PATH"; then
|
||||
log "Error: wrong client configuration detected."
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Auto update
|
||||
local auto_update auto_update_time
|
||||
config_get_bool auto_update "subscription" "auto_update" "0"
|
||||
if [ "$auto_update" = "1" ]; then
|
||||
config_get auto_update_time "subscription" "auto_update_time" "0 */6 * * *"
|
||||
sed -i "/#${CONF}_autosetup/d" "/etc/crontabs/root" 2>"/dev/null"
|
||||
echo -e "$auto_update_time $HP_DIR/scripts/update_crond.sh #${CONF}_autosetup" >> "/etc/crontabs/root"
|
||||
/etc/init.d/cron restart
|
||||
fi
|
||||
|
||||
# DNSMasq rules
|
||||
local ipv6_support dns_port
|
||||
config_get_bool ipv6_support "config" "ipv6_support" "0"
|
||||
config_get dns_port "infra" "dns_port" "5333"
|
||||
mkdir -p "$DNSMASQ_DIR"
|
||||
echo -e "conf-dir=$DNSMASQ_DIR" > "$DNSMASQ_DIR/../dnsmasq-homeproxy.conf"
|
||||
case "$routing_mode" in
|
||||
"bypass_mainland_china"|"custom"|"global")
|
||||
cat <<-EOF >> "$DNSMASQ_DIR/redirect-dns.conf"
|
||||
no-poll
|
||||
no-resolv
|
||||
server=127.0.0.1#$dns_port
|
||||
EOF
|
||||
;;
|
||||
"gfwlist")
|
||||
local gfw_nftset_v6
|
||||
[ "$ipv6_support" -eq "0" ] || gfw_nftset_v6=",6#inet#fw4#homeproxy_gfw_list_v6"
|
||||
sed -r -e "s/(.*)/server=\/\1\/127.0.0.1#$dns_port\nnftset=\/\1\\/4#inet#fw4#homeproxy_gfw_list_v4$gfw_nftset_v6/g" \
|
||||
"$HP_DIR/resources/gfw_list.txt" > "$DNSMASQ_DIR/gfw_list.conf"
|
||||
;;
|
||||
"proxy_mainland_china")
|
||||
sed -r -e "s/(.*)/server=\/\1\/127.0.0.1#$dns_port/g" \
|
||||
"$HP_DIR/resources/china_list.txt" > "$DNSMASQ_DIR/china_list.conf"
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ "$routing_mode" != "custom" ] && [ -s "$HP_DIR/resources/proxy_list.txt" ]; then
|
||||
local wan_nftset_v6
|
||||
[ "$ipv6_support" -eq "0" ] || wan_nftset_v6=",6#inet#fw4#homeproxy_wan_proxy_addr_v6"
|
||||
sed -r -e '/^\s*$/d' -e "s/(.*)/server=\/\1\/127.0.0.1#$dns_port\nnftset=\/\1\\/4#inet#fw4#homeproxy_wan_proxy_addr_v4$wan_nftset_v6/g" \
|
||||
"$HP_DIR/resources/proxy_list.txt" > "$DNSMASQ_DIR/proxy_list.conf"
|
||||
fi
|
||||
/etc/init.d/dnsmasq restart >"/dev/null" 2>&1
|
||||
|
||||
# Setup routing table
|
||||
local table_mark
|
||||
config_get table_mark "infra" "table_mark" "100"
|
||||
case "$proxy_mode" in
|
||||
"redirect_tproxy")
|
||||
local outbound_udp_node
|
||||
config_get outbound_udp_node "config" "main_udp_node" "nil"
|
||||
if [ "$outbound_udp_node" != "nil" ] || [ "$routing_mode" = "custom" ]; then
|
||||
local tproxy_mark
|
||||
config_get tproxy_mark "infra" "tproxy_mark" "101"
|
||||
|
||||
ip rule add fwmark "$tproxy_mark" table "$table_mark"
|
||||
ip route add local 0.0.0.0/0 dev lo table "$table_mark"
|
||||
|
||||
if [ "$ipv6_support" -eq "1" ]; then
|
||||
ip -6 rule add fwmark "$tproxy_mark" table "$table_mark"
|
||||
ip -6 route add local ::/0 dev lo table "$table_mark"
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
"redirect_tun"|"tun")
|
||||
local tun_name tun_mark
|
||||
config_get tun_name "infra" "tun_name" "singtun0"
|
||||
config_get tun_mark "infra" "tun_mark" "102"
|
||||
|
||||
ip tuntap add mode tun user root name "$tun_name"
|
||||
sleep 1s
|
||||
ip link set "$tun_name" up
|
||||
|
||||
ip route replace default dev "$tun_name" table "$table_mark"
|
||||
ip rule add fwmark "$tun_mark" lookup "$table_mark"
|
||||
|
||||
ip -6 route replace default dev "$tun_name" table "$table_mark"
|
||||
ip -6 rule add fwmark "$tun_mark" lookup "$table_mark"
|
||||
;;
|
||||
esac
|
||||
|
||||
# sing-box (client)
|
||||
procd_open_instance "sing-box-c"
|
||||
|
||||
procd_set_param command "$PROG"
|
||||
procd_append_param command run --config "$RUN_DIR/sing-box-c.json"
|
||||
|
||||
# QUIC-GO GSO is broken on kernel 6.6 currently
|
||||
uname -r | grep -Eq "^6\.6" && procd_set_param env "QUIC_GO_DISABLE_GSO"="true"
|
||||
|
||||
if [ -x "/sbin/ujail" ] && [ "$routing_mode" != "custom" ] && ! grep -Eq '"type": "(wireguard|tun)"' "$RUN_DIR/sing-box-c.json"; then
|
||||
procd_add_jail "sing-box-c" log procfs
|
||||
procd_add_jail_mount "$RUN_DIR/sing-box-c.json"
|
||||
procd_add_jail_mount_rw "$RUN_DIR/sing-box-c.log"
|
||||
[ "$routing_mode" != "bypass_mainland_china" ] || procd_add_jail_mount_rw "$RUN_DIR/cache.db"
|
||||
procd_add_jail_mount "$HP_DIR/certs/"
|
||||
procd_add_jail_mount "/etc/ssl/"
|
||||
procd_add_jail_mount "/etc/localtime"
|
||||
procd_add_jail_mount "/etc/TZ"
|
||||
procd_set_param capabilities "/etc/capabilities/homeproxy.json"
|
||||
procd_set_param no_new_privs 1
|
||||
procd_set_param user sing-box
|
||||
procd_set_param group sing-box
|
||||
fi
|
||||
|
||||
procd_set_param limits core="unlimited"
|
||||
procd_set_param limits nofile="1000000 1000000"
|
||||
procd_set_param stderr 1
|
||||
procd_set_param respawn
|
||||
|
||||
procd_close_instance
|
||||
fi
|
||||
|
||||
if [ "$server_enabled" = "1" ]; then
|
||||
# Generate/Validate server config
|
||||
ucode -S "$HP_DIR/scripts/generate_server.uc" 2>>"$LOG_PATH"
|
||||
|
||||
if [ ! -e "$RUN_DIR/sing-box-s.json" ]; then
|
||||
log "Error: failed to generate server configuration."
|
||||
return 1
|
||||
elif ! "$PROG" check --config "$RUN_DIR/sing-box-s.json" 2>>"$LOG_PATH"; then
|
||||
log "Error: wrong server configuration detected."
|
||||
return 1
|
||||
fi
|
||||
|
||||
# sing-box (server)
|
||||
procd_open_instance "sing-box-s"
|
||||
|
||||
procd_set_param command "$PROG"
|
||||
procd_append_param command run --config "$RUN_DIR/sing-box-s.json"
|
||||
|
||||
# QUIC-GO GSO is broken on kernel 6.6 currently
|
||||
uname -r | grep -Eq "^6\.6" && procd_set_param env "QUIC_GO_DISABLE_GSO"="true"
|
||||
|
||||
if [ -x "/sbin/ujail" ]; then
|
||||
procd_add_jail "sing-box-s" log procfs
|
||||
procd_add_jail_mount "$RUN_DIR/sing-box-s.json"
|
||||
procd_add_jail_mount_rw "$RUN_DIR/sing-box-s.log"
|
||||
procd_add_jail_mount_rw "$HP_DIR/certs/"
|
||||
procd_add_jail_mount "/etc/acme/"
|
||||
procd_add_jail_mount "/etc/ssl/"
|
||||
procd_add_jail_mount "/etc/localtime"
|
||||
procd_add_jail_mount "/etc/TZ"
|
||||
procd_set_param capabilities "/etc/capabilities/homeproxy.json"
|
||||
procd_set_param no_new_privs 1
|
||||
procd_set_param user sing-box
|
||||
procd_set_param group sing-box
|
||||
fi
|
||||
|
||||
procd_set_param limits core="unlimited"
|
||||
procd_set_param limits nofile="1000000 1000000"
|
||||
procd_set_param stderr 1
|
||||
procd_set_param respawn
|
||||
|
||||
procd_close_instance
|
||||
fi
|
||||
|
||||
# log-cleaner
|
||||
procd_open_instance "log-cleaner"
|
||||
procd_set_param command "$HP_DIR/scripts/clean_log.sh"
|
||||
procd_set_param respawn
|
||||
procd_close_instance
|
||||
|
||||
case "$routing_mode" in
|
||||
"bypass_mainland_china")
|
||||
# Prepare cache db
|
||||
[ -e "$RUN_DIR/cache.db" ] || touch "$RUN_DIR/cache.db"
|
||||
;;
|
||||
"custom")
|
||||
# Prepare ruleset directory
|
||||
[ -d "$HP_DIR/ruleset" ] || mkdir -p "$HP_DIR/ruleset"
|
||||
;;
|
||||
esac
|
||||
|
||||
[ "$outbound_node" = "nil" ] || echo > "$RUN_DIR/sing-box-c.log"
|
||||
if [ "$server_enabled" = "1" ]; then
|
||||
echo > "$RUN_DIR/sing-box-s.log"
|
||||
mkdir -p "$HP_DIR/certs"
|
||||
fi
|
||||
|
||||
# Update permissions for ujail
|
||||
chown -R sing-box:sing-box "$RUN_DIR"
|
||||
|
||||
# Setup firewall
|
||||
ucode "$HP_DIR/scripts/firewall_pre.uc"
|
||||
[ "$outbound_node" = "nil" ] || utpl -S "$HP_DIR/scripts/firewall_post.ut" > "$RUN_DIR/fw4_post.nft"
|
||||
fw4 reload >"/dev/null" 2>&1
|
||||
|
||||
log "sing-box $(sing-box version -n) started."
|
||||
}
|
||||
|
||||
stop_service() {
|
||||
sed -i "/#${CONF}_autosetup/d" "/etc/crontabs/root" 2>"/dev/null"
|
||||
/etc/init.d/cron restart >"/dev/null" 2>&1
|
||||
|
||||
# Setup firewall
|
||||
# Load config
|
||||
config_load "$CONF"
|
||||
local table_mark tproxy_mark tun_mark tun_name
|
||||
config_get table_mark "infra" "table_mark" "100"
|
||||
config_get tproxy_mark "infra" "tproxy_mark" "101"
|
||||
config_get tun_mark "infra" "tun_mark" "102"
|
||||
config_get tun_name "infra" "tun_name" "singtun0"
|
||||
|
||||
# Tproxy
|
||||
ip rule del fwmark "$tproxy_mark" table "$table_mark" 2>"/dev/null"
|
||||
ip route del local 0.0.0.0/0 dev lo table "$table_mark" 2>"/dev/null"
|
||||
ip -6 rule del fwmark "$tproxy_mark" table "$table_mark" 2>"/dev/null"
|
||||
ip -6 route del local ::/0 dev lo table "$table_mark" 2>"/dev/null"
|
||||
|
||||
# TUN
|
||||
ip route del default dev "$tun_name" table "$table_mark" 2>"/dev/null"
|
||||
ip rule del fwmark "$tun_mark" table "$table_mark" 2>"/dev/null"
|
||||
|
||||
ip -6 route del default dev "$tun_name" table "$table_mark" 2>"/dev/null"
|
||||
ip -6 rule del fwmark "$tun_mark" table "$table_mark" 2>"/dev/null"
|
||||
|
||||
# Nftables rules
|
||||
for i in "homeproxy_dstnat_redir" "homeproxy_output_redir" \
|
||||
"homeproxy_redirect" "homeproxy_redirect_proxy" \
|
||||
"homeproxy_redirect_proxy_port" "homeproxy_redirect_lanac" \
|
||||
"homeproxy_mangle_prerouting" "homeproxy_mangle_output" \
|
||||
"homeproxy_mangle_tproxy" "homeproxy_mangle_tproxy_port" \
|
||||
"homeproxy_mangle_tproxy_lanac" "homeproxy_mangle_mark" \
|
||||
"homeproxy_mangle_tun" "homeproxy_mangle_tun_mark"; do
|
||||
nft flush chain inet fw4 "$i"
|
||||
nft delete chain inet fw4 "$i"
|
||||
done 2>"/dev/null"
|
||||
for i in "homeproxy_local_addr_v4" "homeproxy_local_addr_v6" \
|
||||
"homeproxy_gfw_list_v4" "homeproxy_gfw_list_v6" \
|
||||
"homeproxy_mainland_addr_v4" "homeproxy_mainland_addr_v6" \
|
||||
"homeproxy_wan_proxy_addr_v4" "homeproxy_wan_proxy_addr_v6" \
|
||||
"homeproxy_wan_direct_addr_v4" "homeproxy_wan_direct_addr_v6" \
|
||||
"homeproxy_routing_port"; do
|
||||
nft flush set inet fw4 "$i"
|
||||
nft delete set inet fw4 "$i"
|
||||
done 2>"/dev/null"
|
||||
echo 2>"/dev/null" > "$RUN_DIR/fw4_forward.nft"
|
||||
echo 2>"/dev/null" > "$RUN_DIR/fw4_input.nft"
|
||||
echo 2>"/dev/null" > "$RUN_DIR/fw4_post.nft"
|
||||
fw4 reload >"/dev/null" 2>&1
|
||||
|
||||
# Remove DNS hijack
|
||||
rm -rf "$DNSMASQ_DIR/../dnsmasq-homeproxy.conf" "$DNSMASQ_DIR"
|
||||
/etc/init.d/dnsmasq restart >"/dev/null" 2>&1
|
||||
|
||||
rm -f "$RUN_DIR/sing-box-c.json" "$RUN_DIR/sing-box-c.log" \
|
||||
"$RUN_DIR/sing-box-s.json" "$RUN_DIR/sing-box-s.log"
|
||||
|
||||
log "Service stopped."
|
||||
}
|
||||
|
||||
service_stopped() {
|
||||
# Load config
|
||||
config_load "$CONF"
|
||||
local tun_name
|
||||
config_get tun_name "infra" "tun_name" "singtun0"
|
||||
|
||||
# TUN
|
||||
ip link set "$tun_name" down 2>"/dev/null"
|
||||
ip tuntap del mode tun name "$tun_name" 2>"/dev/null"
|
||||
}
|
||||
|
||||
reload_service() {
|
||||
log "Reloading service..."
|
||||
|
||||
stop
|
||||
start
|
||||
}
|
||||
|
||||
service_triggers() {
|
||||
procd_add_reload_trigger "$CONF"
|
||||
procd_add_interface_trigger "interface.*.up" wan /etc/init.d/$CONF reload
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
#!/bin/sh
|
||||
|
||||
[ -f "/www/luci-static/resources/icons/loading.gif" ] && \
|
||||
sed -i "s,/loading.svg,/loading.gif,g" "/www/luci-static/resources/view/homeproxy/status.js"
|
||||
|
||||
uci -q batch <<-EOF >"/dev/null"
|
||||
delete firewall.homeproxy_pre
|
||||
|
||||
delete firewall.homeproxy_forward
|
||||
set firewall.homeproxy_forward=include
|
||||
set firewall.homeproxy_forward.type=nftables
|
||||
set firewall.homeproxy_forward.path="/var/run/homeproxy/fw4_forward.nft"
|
||||
set firewall.homeproxy_forward.position="chain-pre"
|
||||
set firewall.homeproxy_forward.chain="forward"
|
||||
|
||||
delete firewall.homeproxy_input
|
||||
set firewall.homeproxy_input=include
|
||||
set firewall.homeproxy_input.type=nftables
|
||||
set firewall.homeproxy_input.path="/var/run/homeproxy/fw4_input.nft"
|
||||
set firewall.homeproxy_input.position="chain-pre"
|
||||
set firewall.homeproxy_input.chain="input"
|
||||
|
||||
delete firewall.homeproxy_post
|
||||
set firewall.homeproxy_post=include
|
||||
set firewall.homeproxy_post.type=nftables
|
||||
set firewall.homeproxy_post.path="/var/run/homeproxy/fw4_post.nft"
|
||||
set firewall.homeproxy_post.position="table-post"
|
||||
commit firewall
|
||||
EOF
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
|
||||
ucode "/etc/homeproxy/scripts/migrate_config.uc"
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"admin/services/homeproxy": {
|
||||
"title": "HomeProxy",
|
||||
"order": 10,
|
||||
"action": {
|
||||
"type": "firstchild"
|
||||
},
|
||||
"depends": {
|
||||
"acl": [ "luci-app-homeproxy" ],
|
||||
"uci": { "homeproxy": true }
|
||||
}
|
||||
},
|
||||
"admin/services/homeproxy/client": {
|
||||
"title": "Client Settings",
|
||||
"order": 10,
|
||||
"action": {
|
||||
"type": "view",
|
||||
"path": "homeproxy/client"
|
||||
}
|
||||
},
|
||||
"admin/services/homeproxy/node": {
|
||||
"title": "Node Settings",
|
||||
"order": 15,
|
||||
"action": {
|
||||
"type": "view",
|
||||
"path": "homeproxy/node"
|
||||
}
|
||||
},
|
||||
"admin/services/homeproxy/server": {
|
||||
"title": "Server Settings",
|
||||
"order": 20,
|
||||
"action": {
|
||||
"type": "view",
|
||||
"path": "homeproxy/server"
|
||||
}
|
||||
},
|
||||
"admin/services/homeproxy/status": {
|
||||
"title": "Service Status",
|
||||
"order": 30,
|
||||
"action": {
|
||||
"type": "view",
|
||||
"path": "homeproxy/status"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"luci-app-homeproxy": {
|
||||
"description": "Grant access to homeproxy configuration",
|
||||
"read": {
|
||||
"file": {
|
||||
"/etc/homeproxy/scripts/update_subscriptions.uc": [ "exec" ],
|
||||
"/var/run/homeproxy/homeproxy.log": [ "read" ],
|
||||
"/var/run/homeproxy/sing-box-c.log": [ "read" ],
|
||||
"/var/run/homeproxy/sing-box-s.log": [ "read" ]
|
||||
},
|
||||
"ubus": {
|
||||
"service": [ "list" ],
|
||||
"luci.homeproxy": [ "*" ]
|
||||
},
|
||||
"uci": [ "homeproxy" ]
|
||||
},
|
||||
"write": {
|
||||
"file": {
|
||||
"/tmp/homeproxy_certificate.tmp": [ "write" ]
|
||||
},
|
||||
"uci": [ "homeproxy" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user