1 #!/bin/sh /etc/rc.common
2 # Copyright 2017-2020 Stan Grishin (stangri@melmac.net)
3 # shellcheck disable=SC2039,SC1091,SC2086,SC3043,SC3057,SC3060
6 # shellcheck disable=SC2034
8 # shellcheck disable=SC2034
11 if type extra_command
1>/dev
/null
2>&1; then
12 extra_command
'version' 'Show version information'
14 # shellcheck disable=SC2034
15 EXTRA_COMMANDS
='version'
18 version
() { echo "$PKG_VERSION"; }
20 readonly __ERROR__
='\033[0;31mERROR\033[0m'
22 # shellcheck disable=SC2034
32 readonly packageName
='vpnbypass'
33 readonly serviceName
="$packageName $PKG_VERSION"
34 readonly sharedMemoryOutput
="/dev/shm/$packageName-output"
37 # Can take a single parameter (text) to be output at any verbosity
38 # Or target verbosity level and text to be output at specifc verbosity
39 local msg memmsg logmsg
41 if [ $
((verbosity
& $1)) -gt 0 ] ||
[ "$verbosity" = "$1" ]; then shift; else return 0; fi
43 [ -t 1 ] && printf "%b" "$1"
44 msg
="${1//$serviceName /service }";
45 if [ "$(printf "%b
" "$msg" | wc -l)" -gt 0 ]; then
46 [ -s "$sharedMemoryOutput" ] && memmsg
="$(cat "$sharedMemoryOutput")"
47 logmsg
="$(printf "%b
" "${memmsg}${msg}" | sed 's/\x1b\[[0-9;]*m//g')"
48 logger
-t "${packageName:-service} [$$]" "$(printf "%b
" "$logmsg")"
49 rm -f "$sharedMemoryOutput"
51 printf "%b" "$msg" >> "$sharedMemoryOutput"
54 load_package_config
() {
55 config_load
"$packageName"
56 config_get_bool serviceEnabled
'config' 'enabled' 1
57 config_get verbosity
'config' 'verbosity' '2'
58 if [ -z "${verbosity##*[!0-9]*}" ] ||
[ "$verbosity" -lt 0 ] ||
[ "$verbosity" -gt 2 ]; then
61 .
/lib
/functions
/network.sh
68 network_find_wan wan_if4
69 [ "$serviceEnabled" -gt 0 ] ||
return 1
70 [ -n "$wan_if4" ] && network_get_gateway wan_gw
"$wan_if4"
71 if [ $sleepCount -ge 25 ] ||
[ -n "$wan_gw" ]; then break; fi
72 output
"$serviceName waiting for wan gateway...\\n"
73 sleep 2; network_flush_cache
; sleepCount
=$
((sleepCount
+1));
75 [ -n "$wan_gw" ] && return 0
76 output
"$__ERROR__: $serviceName failed to discover WAN gateway.\\n"; return 1;
79 is_ovpn
() { local dev i
; for i
in ifname device
; do [ -z "$dev" ] && dev
="$(uci -q get "network.
${1}.${i}")"; done; if [ "${dev:0:3}" = "tun" ] || [ "${dev:0:3}" = "tap" ] || [ -f "/sys/devices/virtual/net/${dev}/tun_flags" ]; then return 0; else return 1; fi; }
80 is_wan
() { if [ -n "$wan_if4" ] && [ "$1" = "$wan_if4" ]; then return 0; else return 1; fi; }
81 is_supported_interface
() { if is_wan
"$1" || is_ovpn
"$1"; then return 0; else return 1; fi; }
85 d
="${*//-A/-D}"; [ "$d" != "$*" ] && iptables
$d >/dev
/null
2>&1
86 d
="${*//-I/-D}"; [ "$d" != "$*" ] && iptables
$d >/dev
/null
2>&1
87 d
="${*//-N/-F}"; [ "$d" != "$*" ] && iptables
$d >/dev
/null
2>&1
88 d
="${*//-N/-X}"; [ "$d" != "$*" ] && iptables
$d >/dev
/null
2>&1
89 d
="$*"; iptables
$d >/dev
/null
2>&1 || output
"\\n$__ERROR__: iptables $d\\n"
93 local ll lports rports routes ranges
94 is_enabled ||
return 1
95 config_get lports
'config' 'localport'
96 config_get rports
'config' 'remoteport'
97 config_get routes
'config' 'remotesubnet'
98 config_get ranges
'config' 'localsubnet'
100 procd_open_instance
"main"
101 procd_set_param
command /bin
/true
102 procd_set_param stdout
1
103 procd_set_param stderr
1
106 ip rule del fwmark
"$FW_MARK" table
"$TID" >/dev
/null
2>&1;
107 ipset
-q flush
"$IPSET"; ipset
-q destroy
"$IPSET";
108 ip route flush table
"$TID"; ip route flush cache
;
109 ip route add default via
"$wan_gw" table
"$TID"; ip route flush cache
;
110 ip rule add fwmark
"$FW_MARK" table
"$TID"
111 ipset
-q -exist create
"$IPSET" hash:ip
; ipset
-q flush
"$IPSET"
112 { modprobe xt_set
; modprobe ip_set
; modprobe ip_set_hash_ip
; } >/dev
/null
2>&1
113 ipt
-t mangle
-D PREROUTING
-m mark
--mark 0x00/${FW_MASK} -g VPNBYPASS
>/dev
/null
2>&1
114 { ipt
-t mangle
-N VPNBYPASS
; ipt
-t mangle
-A PREROUTING
-m mark
--mark 0x00/${FW_MASK} -g VPNBYPASS
; } >/dev
/null
2>&1
115 ipt
-t mangle
-A VPNBYPASS
-m set --match-set $IPSET dst
-j MARK
--set-mark ${FW_MARK}/${FW_MASK} >/dev
/null
2>&1
116 for ll
in ${ranges}; do ipt -t mangle -A VPNBYPASS -j MARK --set-mark ${FW_MARK}/${FW_MASK} -s "$ll"; done
117 for ll
in ${lports}; do ipt -t mangle -A VPNBYPASS -j MARK --set-mark ${FW_MARK}/${FW_MASK} -p tcp -m multiport --sport "${ll//-/:}"; done
118 for ll in ${routes}; do ipt -t mangle -A VPNBYPASS -j MARK --set-mark ${FW_MARK}/${FW_MASK} -d "$ll"; done
119 for ll in ${rports}; do ipt -t mangle -A VPNBYPASS -j MARK --set-mark ${FW_MARK}/${FW_MASK} -p tcp -m multiport --dport "${ll//-/:}"; done
120 output
"$serviceName started with TID: $TID; FW_MARK: $FW_MARK\\n"
125 ip rule del fwmark
"$FW_MARK" table
"$TID" >/dev
/null
2>&1;
126 ipset
-q flush
"$IPSET"; ipset
-q destroy
"$IPSET";
127 ip route flush table
"$TID"; ip route flush cache
;
128 ipt
-t mangle
-D PREROUTING
-m mark
--mark 0x00/${FW_MASK} -g VPNBYPASS
>/dev
/null
2>&1
129 { ipt
-t mangle
-F VPNBYPASS
; ipt
-t mangle
-X VPNBYPASS
; } >/dev
/null
2>&1
130 output
"$serviceName stopped\\n"
133 service_triggers_load_interface
() { is_supported_interface
"$1" && ifaces
="${ifaces}${1} "; }
136 config_load network; config_foreach service_triggers_load_interface 'interface';
138 procd_add_reload_trigger 'openvpn'
139 if type procd_add_service_trigger 1>/dev/null 2>&1; then
140 procd_add_service_trigger "service.restart
" "firewall
" /etc/init.d/${packageName} reload
142 procd_add_config_trigger "config.change
" "${packageName}" /etc/init.d/${packageName} reload
143 for n in $ifaces; do procd_add_reload_interface_trigger "$n"; procd_add_interface_trigger "interface.
*" "$n" /etc/init.d/vpnbypass reload; done;
144 output "$serviceName monitoring interfaces
: $ifaces\\n
"