mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-10-30 11:55:13 +08:00
🌴 Sync 2026-03-05 23:51:42
This commit is contained in:
1 parent
97c049ed0a
commit
0acff03804
14253 files changed
+3893239
No files matched your search
@@ -0,0 +1,80 @@
|
||||
config general
|
||||
option transparent_proxy_enable '1'
|
||||
option tproxy_enable_udp '1'
|
||||
option server 'clashmeta'
|
||||
|
||||
option tproxy_port '7892'
|
||||
option packet_mark_id '255'
|
||||
list whitelist_process_uids '346'
|
||||
list whitelist_process_gids '346'
|
||||
option lan_interface 'br-lan'
|
||||
|
||||
# file descriptor limit
|
||||
option rlimit_nofile '8192 16384'
|
||||
# memory limit
|
||||
option rlimit_data '314572800 314572800'
|
||||
|
||||
option dnsmasq_takeover_enable '0'
|
||||
option dns_port '5353'
|
||||
# option dns_count '0'
|
||||
|
||||
list wan_bypass_rules '114.114.114.114'
|
||||
list wan_forward_rules '8.8.8.8'
|
||||
|
||||
option wan_forward_rule_file '/etc/mihomo/forwardlist.txt'
|
||||
option wan_bypass_rule_file '/etc/mihomo/chnlist.txt'
|
||||
|
||||
|
||||
config server 'clashmeta'
|
||||
option alias 'Clash Meta (mihomo)'
|
||||
option server_type 'mihomo'
|
||||
option executable_path '/usr/bin/mihomo'
|
||||
|
||||
option config_type 'directory'
|
||||
# option config_type 'file'
|
||||
|
||||
option config_directory '/etc/mihomo'
|
||||
option config_file '/etc/mihomo/config.yml'
|
||||
|
||||
|
||||
config server 'clash'
|
||||
option alias 'Clash / Clash Premium'
|
||||
option server_type 'mihomo'
|
||||
option executable_path '/usr/bin/clash'
|
||||
|
||||
option config_type 'directory'
|
||||
# option config_type 'file'
|
||||
|
||||
option config_directory '/etc/clash'
|
||||
option config_file '/etc/clash/config.yml'
|
||||
|
||||
|
||||
config server 'xray'
|
||||
option server_type 'xray'
|
||||
option executable_path '/usr/bin/xray'
|
||||
|
||||
option config_type 'directory'
|
||||
# option config_type 'file'
|
||||
|
||||
option config_directory '/etc/xray'
|
||||
option config_file '/etc/xray/config.json'
|
||||
|
||||
|
||||
config server 'v2ray'
|
||||
option server_type 'xray'
|
||||
option executable_path '/usr/bin/v2ray'
|
||||
|
||||
option config_type 'directory'
|
||||
# option config_type 'file'
|
||||
|
||||
option config_directory '/etc/v2ray'
|
||||
option config_file '/etc/v2ray/config.json'
|
||||
|
||||
|
||||
config lan_hosts 'example_bypass'
|
||||
option macaddr '22:11:33:44:55:66'
|
||||
option bypassed '1'
|
||||
|
||||
config lan_hosts 'example_forward'
|
||||
option macaddr '66:55:44:33:22:11'
|
||||
option bypassed '0'
|
||||
+138
@@ -0,0 +1,138 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
|
||||
START=90
|
||||
STOP=15
|
||||
USE_PROCD=1
|
||||
NAME=jederproxy
|
||||
|
||||
. $IPKG_INSTROOT/lib/functions/jederproxy.sh
|
||||
|
||||
uci_get_global_config() {
|
||||
local key="$1"
|
||||
local default_value="$2"
|
||||
local value=$(uci -q get ${NAME}.@general[0].$key)
|
||||
echo ${value:=$default_value}
|
||||
}
|
||||
|
||||
start_jederproxy_process() {
|
||||
process=$1
|
||||
cwd=$2
|
||||
cmd=$3
|
||||
shift 3
|
||||
|
||||
log "Starting $process from $cmd inside $cwd"
|
||||
procd_open_instance
|
||||
procd_set_param respawn 1 1 0
|
||||
|
||||
procd_set_param env JP_TARGET_WD="$cwd"
|
||||
procd_set_param command "/usr/libexec/jederproxy/jederproxy_jail"
|
||||
procd_append_param command "$cmd"
|
||||
for arg in "$@"; do
|
||||
procd_append_param command "$arg"
|
||||
done
|
||||
|
||||
local rlimit_nofile
|
||||
local rlimit_data
|
||||
rlimit_nofile="$(uci_get_global_config rlimit_nofile)"
|
||||
rlimit_data="$(uci_get_global_config rlimit_data)"
|
||||
|
||||
if [ ! -z "${rlimit_nofile}" ] ; then
|
||||
log "set limit nofile=${rlimit_nofile}"
|
||||
procd_set_param limits "nofile=${rlimit_nofile}"
|
||||
fi
|
||||
if [ ! -z "${rlimit_data}" ] ; then
|
||||
log "set limit data=${rlimit_data}"
|
||||
procd_set_param limits "data=${rlimit_data}"
|
||||
fi
|
||||
|
||||
procd_set_param stdout 1
|
||||
procd_set_param stderr 1
|
||||
procd_set_param file /etc/config/jederproxy
|
||||
procd_set_param pidfile /var/run/jederproxy.pid
|
||||
procd_close_instance
|
||||
}
|
||||
|
||||
setup_dnsmasq() {
|
||||
local dns_port=$(uci_get_global_config dns_port)
|
||||
local dns_count=$(uci_get_global_config dns_count 0)
|
||||
|
||||
echo "# Generated dnsmasq configurations by luci-app-jederproxy" > /tmp/dnsmasq.d/jederproxy.conf
|
||||
echo "strict-order" >> /tmp/dnsmasq.d/jederproxy.conf
|
||||
echo "server=/#/127.0.0.1#${dns_port}" >> /tmp/dnsmasq.d/jederproxy.conf
|
||||
local cur_port
|
||||
for cur_port in $(seq ${dns_port} $(expr ${dns_port} + ${dns_count})); do
|
||||
echo "server=127.0.0.1#${cur_port}" >> /tmp/dnsmasq.d/jederproxy.conf
|
||||
done
|
||||
|
||||
log $(cat /tmp/dnsmasq.d/jederproxy.conf)
|
||||
/etc/init.d/dnsmasq restart > /dev/null 2>&1
|
||||
}
|
||||
|
||||
flush_dnsmasq() {
|
||||
[ -f "/tmp/dnsmasq.d/jederproxy.conf" ] && rm /tmp/dnsmasq.d/jederproxy.conf
|
||||
/etc/init.d/dnsmasq restart > /dev/null 2>&1
|
||||
}
|
||||
|
||||
system_configure() {
|
||||
[ "$(uci_get_global_config transparent_proxy_enable)" == "1" ] || return 0
|
||||
log "Setting dnsmasq and firewall for transparent proxy..."
|
||||
[ "$(uci_get_global_config dnsmasq_takeover_enable)" == "1" ] && setup_dnsmasq
|
||||
setup_firewall
|
||||
}
|
||||
|
||||
system_deconfigure() {
|
||||
log "Resetting dnsmasq and firewall configurations..."
|
||||
[ "$(uci_get_global_config dnsmasq_takeover_enable)" == "1" ] && flush_dnsmasq
|
||||
flush_firewall
|
||||
}
|
||||
|
||||
start_service() {
|
||||
local active_server server_type executable_path config_type config_directory config_file
|
||||
config_load $NAME
|
||||
|
||||
mkdir -p /var/etc/jederproxy
|
||||
|
||||
active_server=$(uci_get_global_config server)
|
||||
|
||||
config_get server_type "$active_server" server_type
|
||||
config_get executable_path "$active_server" executable_path
|
||||
config_get config_type "$active_server" config_type
|
||||
config_get config_directory "$active_server" config_directory
|
||||
config_get config_file "$active_server" config_file
|
||||
|
||||
local working_directory=""
|
||||
if [ "$config_type" = "directory" ]; then
|
||||
working_directory="$config_directory"
|
||||
elif [ "$config_type" = "file" ]; then
|
||||
working_directory=$(dirname "$config_file")
|
||||
fi
|
||||
|
||||
if [ "$server_type" = "mihomo" ]; then
|
||||
if [ "$config_type" = "directory" ]; then
|
||||
start_jederproxy_process mihomo "$working_directory" "$executable_path" -d "$config_directory"
|
||||
elif [ "$config_type" = "file" ]; then
|
||||
start_jederproxy_process mihomo "$working_directory" "$executable_path" -f "$config_file"
|
||||
fi
|
||||
elif [ "$server_type" = "xray" ]; then
|
||||
if [ "$config_type" = "directory" ]; then
|
||||
start_jederproxy_process xray "$working_directory" "$executable_path" -confdir "$config_directory"
|
||||
elif [ "$config_type" = "file" ]; then
|
||||
start_jederproxy_process xray "$working_directory" "$executable_path" run -c "$config_file"
|
||||
fi
|
||||
|
||||
fi
|
||||
system_configure || system_deconfigure
|
||||
}
|
||||
|
||||
stop_service() {
|
||||
system_deconfigure
|
||||
}
|
||||
|
||||
reload_service() {
|
||||
stop
|
||||
start
|
||||
}
|
||||
|
||||
service_triggers() {
|
||||
procd_add_reload_trigger "jederproxy"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
include "/var/etc/jederproxy/*.nft"
|
||||
@@ -0,0 +1,29 @@
|
||||
FIREWALL_INCLUDE="/usr/share/jederproxy/firewall_include.lua"
|
||||
|
||||
log() {
|
||||
logger -st jederproxy[$$] -p4 "$@"
|
||||
}
|
||||
|
||||
setup_firewall() {
|
||||
log "Setting ipset rules..."
|
||||
lua /usr/share/jederproxy/gen_ipset_rules.lua | ipset -! restore
|
||||
|
||||
log "Generating firewall rules..."
|
||||
/usr/bin/lua ${FIREWALL_INCLUDE} enable > $(uci get firewall.xray.path)
|
||||
|
||||
log "Triggering firewall restart..."
|
||||
/etc/init.d/firewall reload 2>/dev/null
|
||||
}
|
||||
|
||||
flush_firewall() {
|
||||
log "Flushing firewall rules..."
|
||||
/usr/bin/lua ${FIREWALL_INCLUDE} flush > $(uci get firewall.xray.path)
|
||||
|
||||
log "Triggering firewall restart..."
|
||||
/etc/init.d/firewall reload 2>/dev/null
|
||||
|
||||
log "Flushing ipset rules..."
|
||||
for setname in $(ipset -n list | grep "tp_spec"); do
|
||||
ipset -! destroy $setname
|
||||
done
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
FIREWALL_INCLUDE="/usr/share/jederproxy/firewall_include.ut"
|
||||
|
||||
log() {
|
||||
logger -st jederproxy[$$] -p4 "$@"
|
||||
}
|
||||
|
||||
setup_firewall() {
|
||||
ip route add local default dev lo table 100
|
||||
ip rule add fwmark 0x2333 table 100
|
||||
|
||||
log "Generating firewall4 rules..."
|
||||
/usr/bin/utpl ${FIREWALL_INCLUDE} > /var/etc/jederproxy/firewall_include.nft
|
||||
|
||||
log "Triggering firewall4 reload..."
|
||||
/etc/init.d/firewall reload 2>/dev/null
|
||||
}
|
||||
|
||||
flush_firewall() {
|
||||
ip rule del table 100
|
||||
ip route flush table 100
|
||||
|
||||
log "Flushing firewall4 rules..."
|
||||
rm /var/etc/jederproxy/firewall_include.nft 2>/dev/null || log ".. but fw4 rule file not exists"
|
||||
|
||||
log "Triggering firewall4 reload..."
|
||||
/etc/init.d/firewall reload 2>/dev/null
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#!/bin/sh
|
||||
|
||||
# mihomo/clash search for geoip.dat in $HOME/.config/mihomo
|
||||
export HOME="$JP_TARGET_WD"
|
||||
# xray search for geoip.dat in $PWD
|
||||
cd "$JP_TARGET_WD"
|
||||
|
||||
# $HOME is unset by procd and $PWD is reset to / by procd,
|
||||
# that's why we need this mini "jail"
|
||||
exec "$@"
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
#!/bin/sh
|
||||
|
||||
main() {
|
||||
case "$1" in
|
||||
list)
|
||||
echo '{"statsquery":{},"statssys":{},"restartlogger":{}}'
|
||||
;;
|
||||
call)
|
||||
shift
|
||||
xray api $@
|
||||
esac
|
||||
}
|
||||
|
||||
main "$@"
|
||||
@@ -0,0 +1,92 @@
|
||||
#!/usr/bin/lua
|
||||
local ucursor = require "luci.model.uci"
|
||||
|
||||
local flush = [[# firewall include file to stop transparent proxy
|
||||
ip rule del table 100
|
||||
ip route flush table 100
|
||||
iptables-save -c | grep -v "JPROXY" | iptables-restore -c]]
|
||||
local header = [[# firewall include file to start transparent proxy
|
||||
ip route add local default dev lo table 100
|
||||
ip rule add fwmark 0x2333 table 100
|
||||
|
||||
iptables-restore -n <<-EOF
|
||||
*mangle
|
||||
:JPROXY_RULES - [0:0]
|
||||
:JPROXY_MARK_CONNECTIONS - [0:0]
|
||||
]]
|
||||
local rules = [[
|
||||
##### JPROXY_RULES #####
|
||||
# ignore traffic marked by JPROXY outbound
|
||||
-A JPROXY_RULES -m mark --mark 0x%x -j RETURN
|
||||
# connection-mark -> packet-mark
|
||||
-A JPROXY_RULES -j CONNMARK --restore-mark
|
||||
# ignore established connections
|
||||
-A JPROXY_RULES -m mark --mark 0x2333 -j RETURN
|
||||
|
||||
# ignore traffic sent to reserved addresses
|
||||
-A JPROXY_RULES -m set --match-set jp_ipv4_rfc1918 dst -j RETURN
|
||||
|
||||
# route traffic depends on whitelist/blacklists
|
||||
-A JPROXY_RULES -m set --match-set jp_ether_src_bypass src -j RETURN
|
||||
-A JPROXY_RULES -m set --match-set jp_ether_src_forward src -j JPROXY_MARK_CONNECTIONS
|
||||
|
||||
-A JPROXY_RULES -m set --match-set jp_ipv4_dst_forward dst -j JPROXY_MARK_CONNECTIONS
|
||||
-A JPROXY_RULES -m set --match-set jp_ipv4_dst_bypass dst -j RETURN
|
||||
-A JPROXY_RULES -j JPROXY_MARK_CONNECTIONS
|
||||
|
||||
##### JPROXY_MARK_CONNECTIONS #####
|
||||
# mark the first packet of the connection
|
||||
-A JPROXY_MARK_CONNECTIONS -p tcp --syn -j MARK --set-mark 0x2333
|
||||
-A JPROXY_MARK_CONNECTIONS -p udp -m conntrack --ctstate NEW -j MARK --set-mark 0x2333
|
||||
|
||||
# packet-mark -> connection-mark
|
||||
-A JPROXY_MARK_CONNECTIONS -j CONNMARK --save-mark
|
||||
|
||||
##### OUTPUT #####
|
||||
-A OUTPUT -p tcp -m addrtype --src-type LOCAL ! --dst-type LOCAL -j JPROXY_RULES
|
||||
|
||||
##### PREROUTING #####
|
||||
# proxy traffic passing through this machine (other->other)
|
||||
-A PREROUTING -i %s -p tcp -m addrtype ! --src-type LOCAL ! --dst-type LOCAL -j JPROXY_RULES
|
||||
|
||||
# hand over the marked package to TPROXY for processing
|
||||
-A PREROUTING -p tcp -m mark --mark 0x2333 -j TPROXY --on-ip 127.0.0.1 --on-port %d
|
||||
]]
|
||||
|
||||
local rules_udp = [[
|
||||
##### OUTPUT #####
|
||||
-A OUTPUT -p udp -m addrtype --src-type LOCAL ! --dst-type LOCAL -j JPROXY_RULES
|
||||
|
||||
##### PREROUTING #####
|
||||
# proxy traffic passing through this machine (other->other)
|
||||
-A PREROUTING -i %s -p udp -m addrtype ! --src-type LOCAL ! --dst-type LOCAL -j JPROXY_RULES
|
||||
|
||||
# hand over the marked package to TPROXY for processing
|
||||
-A PREROUTING -p udp -m mark --mark 0x2333 -j TPROXY --on-ip 127.0.0.1 --on-port %d
|
||||
]]
|
||||
|
||||
local footer = [[
|
||||
COMMIT
|
||||
EOF]]
|
||||
|
||||
local proxy_section = ucursor:get_first("jederproxy", "general")
|
||||
local proxy = ucursor:get_all("jederproxy", proxy_section)
|
||||
|
||||
print(flush)
|
||||
if proxy.transparent_proxy_enable ~= "1" then
|
||||
do
|
||||
return
|
||||
end
|
||||
end
|
||||
if arg[1] == "enable" then
|
||||
print(header)
|
||||
print(string.format(rules, tonumber(proxy.mark),
|
||||
proxy.lan_interface, proxy.tproxy_port))
|
||||
if proxy.tproxy_enable_udp ~= "1" then
|
||||
print(string.format(rules_udp
|
||||
proxy.lan_interface, proxy.tproxy_port))
|
||||
end
|
||||
print(footer)
|
||||
else
|
||||
print("# arg[1] == " .. arg[1] .. ", not enable")
|
||||
end
|
||||
@@ -0,0 +1,144 @@
|
||||
#!/usr/bin/utpl
|
||||
{%
|
||||
const uci = require("uci");
|
||||
const fs = require("fs");
|
||||
|
||||
function iterate_file(filename, cb) {
|
||||
let fd = fs.open(filename, "r");
|
||||
if (!fd) {
|
||||
warn(`Unable to open '${filename}': ${fs.error()}\n`);
|
||||
return;
|
||||
}
|
||||
|
||||
let line = null, count = 0;
|
||||
while (!!(line = trim(fd.read("line")))) {
|
||||
if (ord(line) == 35) // skip lines which start with '#'
|
||||
continue;
|
||||
|
||||
cb(line);
|
||||
|
||||
count++;
|
||||
}
|
||||
fd.close();
|
||||
return count;
|
||||
}
|
||||
|
||||
const cursor = uci.cursor();
|
||||
cursor.load("jederproxy");
|
||||
const config = cursor.get_all("jederproxy");
|
||||
const general = config[filter(keys(config), k => config[k][".type"] == "general")[0]];
|
||||
const jp_ether_src_forward = uniq(map(filter(keys(config), k => config[k][".type"] == "lan_hosts" && config[k].bypassed == "0"), k => config[k].macaddr) || []);
|
||||
const jp_ether_src_bypass = uniq(map(filter(keys(config), k => config[k][".type"] == "lan_hosts" && config[k].bypassed == "1"), k => config[k].macaddr) || []);
|
||||
const uids_direct = uniq(general.whitelist_process_uids || []);
|
||||
const gids_direct = uniq(general.whitelist_process_gids || []);
|
||||
const wan_bypass_rules = general.wan_bypass_rules || [];
|
||||
const wan_forward_rules = general.wan_forward_rules || [];
|
||||
const enable_udp = general.tproxy_enable_udp || "";
|
||||
iterate_file(general.wan_bypass_rule_file || "/dev/null", line => push(wan_bypass_rules, line));
|
||||
iterate_file(general.wan_forward_rule_file || "/dev/null", line => push(wan_forward_rules, line));
|
||||
// push(wan_bypass_rules, split(general.fast_dns, ":")[0]);
|
||||
// push(wan_forward_rules, split(general.secure_dns, ":")[0]);
|
||||
%}
|
||||
set jp_ether_src_bypass {
|
||||
type ether_addr
|
||||
size 65536
|
||||
{% if (length(jp_ether_src_bypass) > 0): %}
|
||||
elements = { {{ join(", ", jp_ether_src_bypass) }} }
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
set jp_ether_src_forward {
|
||||
type ether_addr
|
||||
size 65536
|
||||
{% if (length(jp_ether_src_forward) > 0): %}
|
||||
elements = { {{ join(", ", jp_ether_src_forward) }} }
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
set jp_ipv4_rfc1918 {
|
||||
type ipv4_addr
|
||||
size 65536
|
||||
flags interval
|
||||
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.88.99.0/24,
|
||||
192.168.0.0/16,
|
||||
198.18.0.0/15,
|
||||
198.51.100.0/24,
|
||||
203.0.113.0/24,
|
||||
224.0.0.0/4,
|
||||
233.252.0.0/24,
|
||||
240.0.0.0/4
|
||||
}
|
||||
auto-merge
|
||||
}
|
||||
|
||||
set jp_ipv4_dst_bypass {
|
||||
type ipv4_addr
|
||||
size 65536
|
||||
flags interval
|
||||
elements = { {{ join(", ", wan_bypass_rules)}} }
|
||||
auto-merge
|
||||
}
|
||||
|
||||
set jp_ipv4_dst_forward {
|
||||
type ipv4_addr
|
||||
size 65536
|
||||
flags interval
|
||||
elements = { {{ join(", ", wan_forward_rules)}} }
|
||||
auto-merge
|
||||
}
|
||||
|
||||
chain jproxy_rules {
|
||||
{% if (length(uids_direct) > 0): %}
|
||||
meta skuid { {{ join(", ", uids_direct) }} } return comment "ignore traffic from processes owned by specific UIDs"
|
||||
{% endif %}
|
||||
{% if (length(gids_direct) > 0): %}
|
||||
meta skgid { {{ join(", ", gids_direct) }} } return comment "ignore traffic from processes owned by specific GIDs"
|
||||
{% endif %}
|
||||
|
||||
mark {{ sprintf("0x%08x", general.packet_mark_id) }} counter return comment "ignore outbound connections initiated by jederproxy"
|
||||
counter meta mark set ct mark comment "connection-mark -> packet-mark"
|
||||
mark 0x2333 counter return comment "ignore established connections"
|
||||
|
||||
ip daddr @jp_ipv4_rfc1918 return comment "ignore traffic sent to reserved IP address/networks"
|
||||
ether saddr @jp_ether_src_bypass return comment "ignore traffic from specific sources (by macaddr)"
|
||||
ether saddr @jp_ether_src_forward jump jproxy_mark_connection comment "enforce proxy from specific sources (by macaddr)"
|
||||
ip daddr @jp_ipv4_dst_forward jump jproxy_mark_connection comment "enforce proxy to specific IP address/networks"
|
||||
ip daddr @jp_ipv4_dst_bypass return comment "ignore traffic sent to specific IP address/networks"
|
||||
|
||||
jump jproxy_mark_connection
|
||||
}
|
||||
|
||||
chain jproxy_mark_connection {
|
||||
tcp flags & (fin|syn|rst|ack) == syn counter meta mark set 0x2333 comment "mark the first packet of TCP connections"
|
||||
ip protocol udp ct state new counter meta mark set 0x2333 comment "mark the first packet of UDP connections"
|
||||
counter ct mark set mark comment "packet-mark -> connection-mark"
|
||||
}
|
||||
|
||||
chain jproxy_prerouting {
|
||||
type filter hook prerouting priority filter; policy accept;
|
||||
|
||||
iifname "{{ general.lan_interface }}" ip protocol {tcp, udp} fib saddr type != local fib daddr type != local counter jump jproxy_rules comment "proxy TCP/UDP traffic passing through this router (other->other)"
|
||||
|
||||
meta l4proto tcp meta mark 0x2333 tproxy ip to 127.0.0.1:{{ general.tproxy_port }} counter accept comment "send marked TCP packets to jederproxy"
|
||||
{% if (enable_udp == "1"): %}
|
||||
meta l4proto udp meta mark 0x2333 tproxy ip to 127.0.0.1:{{ general.tproxy_port }} counter accept comment "send marked UDP packets to jederproxy"
|
||||
{% endif %}
|
||||
|
||||
}
|
||||
|
||||
chain jproxy_output {
|
||||
type route hook output priority filter; policy accept;
|
||||
ip protocol tcp fib saddr type local fib daddr type != local counter jump jproxy_rules comment "Proxy TCP traffic from router itself"
|
||||
{% if (enable_udp == "1"): %}
|
||||
ip protocol udp fib saddr type local fib daddr type != local counter jump jproxy_rules comment "Proxy UDP traffic from router itself"
|
||||
{% endif %}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,78 @@
|
||||
#!/usr/bin/lua
|
||||
|
||||
local io = require("io")
|
||||
local ucursor = require "luci.model.uci"
|
||||
local proxy_section = ucursor:get_first("jederproxy", "general")
|
||||
local proxy = ucursor:get_all("jederproxy", proxy_section)
|
||||
local gen_ipset_rules_extra = dofile("/usr/share/jederproxy/gen_ipset_rules_extra.lua")
|
||||
|
||||
local create_ipset_rules = [[create jp_ether_src_bypass hash:mac hashsize 64
|
||||
create jp_ether_src_forward hash:mac hashsize 64
|
||||
create jp_ipv4_rfc1918 hash:net hashsize 64
|
||||
create jp_ipv4_dst_bypass hash:net hashsize 64
|
||||
create jp_ipv4_dst_forward hash:net hashsize 64]]
|
||||
|
||||
local function create_ipset()
|
||||
print(create_ipset_rules)
|
||||
end
|
||||
|
||||
local function split_ipv4_host_port(val, port_default)
|
||||
local found, _, ip, port = val:find("([%d.]+):(%d+)")
|
||||
if found == nil then
|
||||
return val, tonumber(port_default)
|
||||
else
|
||||
return ip, tonumber(port)
|
||||
end
|
||||
end
|
||||
|
||||
local function lan_access_control()
|
||||
ucursor:foreach("xray", "lan_hosts", function(v)
|
||||
if v.bypassed == '0' then
|
||||
print(string.format("add jp_ether_src_forward %s", v.macaddr))
|
||||
else
|
||||
print(string.format("add jp_ether_src_bypass %s", v.macaddr))
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
local function iterate_list(ln, set_name)
|
||||
local ip_list = proxy[ln]
|
||||
if ip_list == nil then
|
||||
return
|
||||
end
|
||||
for _, line in ipairs(ip_list) do
|
||||
print(string.format("add %s %s", set_name, line))
|
||||
end
|
||||
end
|
||||
|
||||
local function iterate_file(fn, set_name)
|
||||
if fn == nil then
|
||||
return
|
||||
end
|
||||
local f = io.open(fn)
|
||||
if f == nil then
|
||||
return
|
||||
end
|
||||
for line in io.lines(fn) do
|
||||
if line ~= "" then
|
||||
print(string.format("add %s %s", set_name, line))
|
||||
end
|
||||
end
|
||||
f:close()
|
||||
end
|
||||
|
||||
local function dns_ips()
|
||||
local fast_dns_ip, fast_dns_port = split_ipv4_host_port(proxy.fast_dns, 53)
|
||||
local secure_dns_ip, secure_dns_port = split_ipv4_host_port(proxy.secure_dns, 53)
|
||||
print(string.format("add jp_ipv4_dst_bypass %s", fast_dns_ip))
|
||||
print(string.format("add jp_ipv4_dst_forward %s", secure_dns_ip))
|
||||
end
|
||||
|
||||
create_ipset()
|
||||
dns_ips()
|
||||
lan_access_control()
|
||||
iterate_list("wan_bypass_rules", "jp_ipv4_dst_bypass")
|
||||
iterate_file(proxy.wan_bypass_rule_file or "/dev/null", "jp_ipv4_dst_bypass")
|
||||
iterate_list("wan_forward_rules", "jp_ipv4_dst_forward")
|
||||
iterate_file(proxy.wan_forward_rule_file or "/dev/null", "jp_ipv4_dst_forward")
|
||||
gen_ipset_rules_extra(proxy)
|
||||
@@ -0,0 +1,23 @@
|
||||
#!/usr/bin/lua
|
||||
|
||||
local special_purpose_rules = [[add jp_ipv4_rfc1918 255.255.255.255
|
||||
add jp_ipv4_rfc1918 0.0.0.0/8
|
||||
add jp_ipv4_rfc1918 10.0.0.0/8
|
||||
add jp_ipv4_rfc1918 100.64.0.0/10
|
||||
add jp_ipv4_rfc1918 127.0.0.0/8
|
||||
add jp_ipv4_rfc1918 169.254.0.0/16
|
||||
add jp_ipv4_rfc1918 172.16.0.0/12
|
||||
add jp_ipv4_rfc1918 192.0.0.0/24
|
||||
add jp_ipv4_rfc1918 192.0.2.0/24
|
||||
add jp_ipv4_rfc1918 192.88.99.0/24
|
||||
add jp_ipv4_rfc1918 192.168.0.0/16
|
||||
add jp_ipv4_rfc1918 198.18.0.0/15
|
||||
add jp_ipv4_rfc1918 198.51.100.0/24
|
||||
add jp_ipv4_rfc1918 203.0.113.0/24
|
||||
add jp_ipv4_rfc1918 224.0.0.0/4
|
||||
add jp_ipv4_rfc1918 233.252.0.0/24
|
||||
add jp_ipv4_rfc1918 240.0.0.0/4]]
|
||||
|
||||
return function(proxy)
|
||||
print(special_purpose_rules)
|
||||
end
|
||||
Binary file not shown.
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"admin/services/jederproxy": {
|
||||
"title": "Jederproxy",
|
||||
"action": {
|
||||
"type": "view",
|
||||
"path": "jederproxy"
|
||||
},
|
||||
"depends": {
|
||||
"acl": [
|
||||
"luci-app-jederproxy"
|
||||
],
|
||||
"uci": {
|
||||
"jederproxy": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"luci-app-jederproxy": {
|
||||
"description": "Grant access to jederproxy configurations",
|
||||
"read": {
|
||||
"ubus": {
|
||||
"luci": [
|
||||
"getInitList",
|
||||
"setInitAction"
|
||||
]
|
||||
},
|
||||
"uci": [
|
||||
"jederproxy"
|
||||
],
|
||||
"file": {
|
||||
"/etc/init.d/jederproxy": [ "exec" ],
|
||||
"/var/run/jederproxy.pid": [ "read" ]
|
||||
}
|
||||
},
|
||||
"write": {
|
||||
"uci": [
|
||||
"jederproxy"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,323 @@
|
||||
'use strict';
|
||||
'require view';
|
||||
'require uci';
|
||||
'require rpc';
|
||||
'require form';
|
||||
'require fs';
|
||||
'require ui';
|
||||
'require network';
|
||||
'require tools.widgets as widgets';
|
||||
|
||||
var callInitList, callInitAction, ServiceController;
|
||||
|
||||
const FEATURE_FLAGS = {
|
||||
have_fw3: false, // %FLAG_NO_FW3% managed by build system
|
||||
have_fw4: false, // %FLAG_NO_FW4% managed by build system
|
||||
// %FLAG_FW3% have_fw3: true, // uncomment by build system on fw3
|
||||
// %FLAG_FW4% have_fw4: true, // uncomment by build system on fw4
|
||||
};
|
||||
|
||||
callInitList = rpc.declare({
|
||||
object: 'luci',
|
||||
method: 'getInitList',
|
||||
params: [ 'name' ],
|
||||
expect: { '': {} }
|
||||
}),
|
||||
|
||||
callInitAction = rpc.declare({
|
||||
object: 'luci',
|
||||
method: 'setInitAction',
|
||||
params: [ 'name', 'action' ],
|
||||
expect: { result: false }
|
||||
});
|
||||
|
||||
|
||||
function check_resource_files(load_result) {
|
||||
let geoip_existence = false;
|
||||
let geoip_size = 0;
|
||||
let geosite_existence = false;
|
||||
let geosite_size = 0;
|
||||
let firewall4 = false;
|
||||
let xray_bin_default = false;
|
||||
let optional_features = {};
|
||||
for (const f of load_result) {
|
||||
if (f.name == "xray") {
|
||||
xray_bin_default = true;
|
||||
}
|
||||
if (f.name == "geoip.dat") {
|
||||
geoip_existence = true;
|
||||
geoip_size = '%.2mB'.format(f.size);
|
||||
}
|
||||
if (f.name == "geosite.dat") {
|
||||
geosite_existence = true;
|
||||
geosite_size = '%.2mB'.format(f.size);
|
||||
}
|
||||
if (f.name == "firewall_include.ut") {
|
||||
firewall4 = true;
|
||||
}
|
||||
if (f.name.startsWith("optional_feature_")) {
|
||||
optional_features[f.name] = true;
|
||||
}
|
||||
}
|
||||
return {
|
||||
geoip_existence: geoip_existence,
|
||||
geoip_size: geoip_size,
|
||||
geosite_existence: geosite_existence,
|
||||
geosite_size: geosite_size,
|
||||
optional_features: optional_features,
|
||||
firewall4: firewall4,
|
||||
xray_bin_default: xray_bin_default,
|
||||
}
|
||||
}
|
||||
|
||||
function check_dns_format(_, dns) {
|
||||
if (/^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)(\.(?!$)|$)){4}$/.test(dns)) {
|
||||
// IPv4 Address
|
||||
return true;
|
||||
}
|
||||
if (/(https|tcp|quic)(\+local)?:\/\/([-\w\d@:%._\+~#=]{1,256}\.[\w\d()]{1,6}\b)(:(\d+))?([-\w\d()@:%_\+.~#?&\/=]*)/.test(dns)) {
|
||||
// DoH/TCP/QUIC Server Address
|
||||
return true;
|
||||
}
|
||||
|
||||
if (dns === "localhost") {
|
||||
return true;
|
||||
}
|
||||
return "Invalid DNS address";
|
||||
}
|
||||
|
||||
ServiceController = form.DummyValue.extend({
|
||||
handleAction: function(name, action, ev) {
|
||||
return callInitAction(name, action).then(function(success) {
|
||||
ui.addNotification(null, E('p', _('Service %s success.').format(action)), 'info');
|
||||
}).catch(function (e) {
|
||||
ui.addNotification(null, E("p", _('Unable to perform service %s: %s').format(action, e.message)), "error");
|
||||
});
|
||||
},
|
||||
|
||||
renderWidget: function(section_id, option_id, cfgvalue) {
|
||||
return E([], [
|
||||
E('span', { 'class': 'control-group' }, [
|
||||
E('button', {
|
||||
class: 'btn cbi-button-%s'.format(this.service_enabled ? 'positive' : 'negative'),
|
||||
click: ui.createHandlerFn(this, function() {
|
||||
return callInitAction(this.service_name, this.service_enabled ? "disable": "enable").then(rc => ui.addNotification(null, E('p', _('Toggle startup success.')), 'info'));
|
||||
}),
|
||||
disabled: this.control_disabled
|
||||
}, this.service_enabled ? _('Enabled') : _('Disabled')),
|
||||
E('button', { 'class': 'btn cbi-button-action', 'click': ui.createHandlerFn(this, 'handleAction', this.service_name, 'start'), 'disabled': this.control_disabled }, _('Start')),
|
||||
E('button', { 'class': 'btn cbi-button-action', 'click': ui.createHandlerFn(this, 'handleAction', this.service_name, 'restart'), 'disabled': this.control_disabled }, _('Restart')),
|
||||
E('button', { 'class': 'btn cbi-button-action', 'click': ui.createHandlerFn(this, 'handleAction', this.service_name, 'stop'), 'disabled': this.control_disabled }, _('Stop'))
|
||||
])
|
||||
]);
|
||||
},
|
||||
});
|
||||
|
||||
return view.extend({
|
||||
handleServiceReload: function (ev) {
|
||||
return callInitAction("jederproxy", "restart").then(function(rc) {
|
||||
ui.addNotification(null, E('p', _('Reload service success.')), 'info');
|
||||
}).catch(function (e) {
|
||||
ui.addNotification(null, E("p", _('Unable to reload service: %s').format(e.message)), "error");
|
||||
});
|
||||
},
|
||||
|
||||
handleSaveApply: function (ev, mode) {
|
||||
return this.__base__.handleSaveApply(ev, mode).then(this.handleServiceReload);
|
||||
},
|
||||
|
||||
load: function () {
|
||||
return Promise.all([
|
||||
uci.load("jederproxy"), // config_data
|
||||
fs.list("/usr/share/jederproxy"), // xray_dir
|
||||
network.getHostHints(), // network_hosts
|
||||
L.resolveDefault(fs.read("/var/run/jederproxy.pid"), null), // xray_pid
|
||||
callInitList("jederproxy"), // xray_service_status
|
||||
])
|
||||
},
|
||||
|
||||
render: function (load_result) {
|
||||
const config_data = load_result[0];
|
||||
const xray_dir = load_result[1];
|
||||
const network_hosts = load_result[2];
|
||||
const xray_pid = load_result[3];
|
||||
const xray_service_status = load_result[4]["jederproxy"];
|
||||
const geoip_direct_code = uci.get_first(config_data, "general", "geoip_direct_code");
|
||||
const { geoip_existence, geoip_size, geosite_existence, geosite_size, optional_features, firewall4, xray_bin_default } = check_resource_files(xray_dir);
|
||||
const status_text = xray_pid ? (_("[Xray is running]") + `[PID:${xray_pid.trim()}]`) : _("[Xray is stopped]");
|
||||
|
||||
let asset_file_status = _('WARNING: at least one of asset files (geoip.dat, geosite.dat) is not found under /usr/share/jederproxy. Xray may not work properly. See <a href="https://github.com/ttimasdf/luci-app-jederproxy">here</a> for help.')
|
||||
if (geoip_existence) {
|
||||
if (geosite_existence) {
|
||||
asset_file_status = _('Asset files check: ') + `geoip.dat ${geoip_size}; geosite.dat ${geosite_size}. ` + _('Report issues or request for features <a href="https://github.com/ttimasdf/luci-app-jederproxy">here</a>.')
|
||||
}
|
||||
}
|
||||
|
||||
const m = new form.Map('jederproxy', _('Xray'), status_text + " " + asset_file_status);
|
||||
|
||||
var s, o, ss;
|
||||
|
||||
s = m.section(form.TypedSection, 'general');
|
||||
s.addremove = false;
|
||||
s.anonymous = true;
|
||||
|
||||
s.tab('general', _('General Settings'));
|
||||
|
||||
o = s.taboption('general', form.ListValue, 'server', _('Server Instance'))
|
||||
o.datatype = "uciname"
|
||||
// o.value("disabled", _("Disabled"))
|
||||
for (const v of uci.sections(config_data, "server")) {
|
||||
o.value(v[".name"], v.alias || v[".name"])
|
||||
}
|
||||
|
||||
o = s.taboption('general', ServiceController, "_service", _("Service Control"), _("Refresh the page manually for actions to take effect"));
|
||||
o.service_name = "jederproxy"
|
||||
o.service_enabled = xray_service_status.enabled;
|
||||
o.service_index = xray_service_status.index;
|
||||
|
||||
o = s.taboption('general', form.Flag, 'dnsmasq_takeover_enable', _('Enable dnsmasq Takeover'), _('Enable this option force using xray dns inbound port as dnsmasq\'s upstream server.'))
|
||||
|
||||
o = s.taboption('general', form.Flag, 'transparent_proxy_enable', _('Enable Transparent Proxy'), _('This enables DNS query forwarding and TProxy for both TCP and optionally UDP connections.'))
|
||||
|
||||
o = s.taboption('general', form.Flag, 'tproxy_enable_udp', _('Enable UDP Forward'), _('UDP Forward could be switched off for better compatibility with some service providers'))
|
||||
o.depends("transparent_proxy_enable", "1")
|
||||
|
||||
o = s.taboption('general', form.SectionValue, "jederproxy_servers", form.GridSection, 'server', _('Proxy Servers'), _("Servers are referenced by index (order in the following list). Deleting servers may result in changes of upstream servers actually used by proxy and bridge."))
|
||||
ss = o.subsection
|
||||
ss.sortable = false
|
||||
ss.anonymous = true
|
||||
ss.addremove = true
|
||||
|
||||
ss.tab('general', _('General Settings'));
|
||||
|
||||
o = ss.taboption('general', form.Value, "alias", _("Alias"))
|
||||
o.rmempty = true
|
||||
|
||||
o = ss.taboption('general', form.Value, 'executable_path', _('Proxy Executable Path'))
|
||||
o.rmempty = false
|
||||
|
||||
o = ss.taboption('general', form.ListValue, 'server_type', _('Server Type'))
|
||||
o.value("mihomo")
|
||||
o.value("xray")
|
||||
o.default = "mihomo"
|
||||
|
||||
o = ss.taboption('general', form.ListValue, 'config_type', _('Config file type'))
|
||||
o.value("directory")
|
||||
o.value("file")
|
||||
o.default = "file"
|
||||
|
||||
o = ss.taboption('general', form.Value, 'config_directory', _('Config directory path'))
|
||||
o.depends("config_type", "directory")
|
||||
o.rmempty = false
|
||||
|
||||
o = ss.taboption('general', form.Value, 'config_file', _('Config file path'))
|
||||
o.depends("config_type", "file")
|
||||
o.rmempty = false
|
||||
|
||||
s.tab('proxy', _('iptables/nftables Settings'));
|
||||
|
||||
o = s.taboption('proxy', form.Value, 'tproxy_port', _('Transparent Proxy Port'), _('The <code>tproxy-port</code> value in mihomo/clash or <code>port</code> value of dokodemo inbound in v2ray/xray'))
|
||||
o.datatype = 'port'
|
||||
o.default = 7892
|
||||
|
||||
o = s.taboption('proxy', form.Value, 'packet_mark_id', _('Packet Mark Number'), _('The <code>routing-mark</code> value in mihomo/clash or <code>streamSettings.sockopt.mark</code> value in v2ray/xray'))
|
||||
o.datatype = 'range(1, 255)'
|
||||
o.default = 255
|
||||
|
||||
// if (firewall4) {
|
||||
// o = s.taboption('proxy', form.DynamicList, 'uids_direct', _('Skip Proxy for uids'), _("Processes started by users with these uids won't be forwarded through Xray."))
|
||||
// o.datatype = "integer"
|
||||
|
||||
// o = s.taboption('proxy', form.DynamicList, 'gids_direct', _('Skip Proxy for gids'), _("Processes started by users in groups with these gids won't be forwarded through Xray."))
|
||||
// o.datatype = "integer"
|
||||
// }
|
||||
|
||||
o = s.taboption('proxy', form.DynamicList, 'whitelist_process_uids', _('Whitelist UIDs'), _('Ignore local traffic of specific UIDs'))
|
||||
o.rmempty = true
|
||||
|
||||
o = s.taboption('proxy', form.DynamicList, 'whitelist_process_gids', _('Whitelist GIDs'), _('Ignore local traffic of specific GIDs'))
|
||||
o.rmempty = true
|
||||
|
||||
|
||||
o = s.taboption('proxy', widgets.DeviceSelect, 'lan_interface', _("LAN Interface"))
|
||||
o.noaliases = true
|
||||
o.rmempty = false
|
||||
o.nocreate = true
|
||||
|
||||
o = s.taboption('proxy', form.SectionValue, "access_control_lan_hosts", form.TableSection, 'lan_hosts', _('LAN Hosts Access Control'), _("Will not enable transparent proxy for these MAC addresses."))
|
||||
|
||||
ss = o.subsection;
|
||||
ss.sortable = false
|
||||
ss.anonymous = true
|
||||
ss.addremove = true
|
||||
|
||||
o = ss.option(form.Value, "macaddr", _("MAC Address"))
|
||||
L.sortedKeys(network_hosts.hosts).forEach(function (mac) {
|
||||
o.value(mac, E([], [mac, ' (', E('strong', [network_hosts.hosts[mac].name || L.toArray(network_hosts.hosts[mac].ipaddrs || network_hosts.hosts[mac].ipv4)[0] || L.toArray(network_hosts.hosts[mac].ip6addrs || network_hosts.hosts[mac].ipv6)[0] || '?']), ')']));
|
||||
});
|
||||
|
||||
o.datatype = "macaddr"
|
||||
o.rmempty = false
|
||||
|
||||
o = ss.option(form.ListValue, "bypassed", _("Access Control Strategy"))
|
||||
o.value("0", "Always forwarded")
|
||||
o.value("1", "Always bypassed")
|
||||
o.rmempty = false
|
||||
|
||||
s.tab('dns', _('DNS Settings'));
|
||||
|
||||
o = s.taboption('dns', form.Value, 'dns_port', _('Xray DNS Server Port'), _("Do not use port 53 (dnsmasq), port 5353 (mDNS) or other common ports"))
|
||||
o.datatype = 'port'
|
||||
o.default = 5300
|
||||
|
||||
o = s.taboption('dns', form.Value, 'dns_count', _('Extra DNS Server Ports'), _('Listen for DNS Requests on multiple ports (all of which serves as dnsmasq upstream servers).<br/>For example if Xray DNS Server Port is 5300 and use 3 extra ports, 5300 - 5303 will be used for DNS requests.<br/>Increasing this value may help reduce the possibility of temporary DNS lookup failures.'))
|
||||
o.datatype = 'range(0, 50)'
|
||||
o.default = 0
|
||||
|
||||
s.tab('transparent_proxy_rules', _('Transparent Proxy Rules'));
|
||||
|
||||
o = s.taboption('transparent_proxy_rules', form.DynamicList, "wan_bypass_rules", _("Bypassed IP"), _("Requests to these IPs won't be forwarded through your proxy."))
|
||||
o.datatype = "ip4addr"
|
||||
o.rmempty = true
|
||||
|
||||
o = s.taboption('transparent_proxy_rules', form.Value, 'wan_bypass_rule_file', _('Bypassed IP list file'))
|
||||
o.rmempty = false
|
||||
|
||||
o = s.taboption('transparent_proxy_rules', form.DynamicList, "wan_forward_rules", _("Forwarded IP"))
|
||||
o.datatype = "ip4addr"
|
||||
o.rmempty = true
|
||||
|
||||
o = s.taboption('transparent_proxy_rules', form.Value, 'wan_forward_rule_file', _('Forwarded IP list file'))
|
||||
o.rmempty = false
|
||||
|
||||
|
||||
s.tab('procd_options', _('Process Options'))
|
||||
|
||||
function rlimit_validate(section_id, value) {
|
||||
let rlimit_regex = new RegExp("^[0-9]+ [0-9]+$","g");
|
||||
if (value == "" || rlimit_regex.test(value)) {
|
||||
return true
|
||||
} else {
|
||||
return "rlimit format: [soft] [hard]"
|
||||
}
|
||||
}
|
||||
o = s.taboption('procd_options', form.Value, 'rlimit_nofile', _('Max Open Files'), _('Set xray process resource limit <code>RLIMIT_NOFILE</code>: max number of open file descriptors.'))
|
||||
o.value("", "[unset]")
|
||||
o.value("1024 4096", "1024 4096 (system default)")
|
||||
o.value("8192 16384")
|
||||
o.value("102400 204800")
|
||||
o.default = ""
|
||||
o.validate = rlimit_validate
|
||||
|
||||
o = s.taboption('procd_options', form.Value, 'rlimit_data', _('Max Allocated Memory'), _('Set xray process resource limit <code>RLIMIT_DATA</code>: max memory usage.'))
|
||||
o.value("", "[unset]")
|
||||
o.value("52428800 52428800", "50 MiB")
|
||||
o.value("104857600 104857600", "100 MiB")
|
||||
o.value("209715200 209715200", "200 MiB")
|
||||
o.value("419430400 419430400", "400 MiB")
|
||||
o.default = ""
|
||||
o.validate = rlimit_validate
|
||||
|
||||
return m.render();
|
||||
}
|
||||
});
|
||||
Reference in new issue
Block a user