From 4171d8e07a297f715795d7ee3fe667fbe549d053 Mon Sep 17 00:00:00 2001 From: Ycarus Date: Fri, 5 Oct 2018 17:13:38 +0200 Subject: [PATCH] Choose interface used for each domains, ips, networks or protocols that bypass OMR --- .../luasrc/controller/omr-bypass.lua | 46 +---- .../luasrc/model/cbi/omr-bypass.lua | 72 +++++++ .../luasrc/view/omr-bypass/bypass.htm | 176 +++++++----------- .../root/etc/config/omr-bypass | 5 +- .../root/etc/init.d/omr-bypass | 130 ++++++++++--- .../root/etc/uci-defaults/41_omr-bypass | 50 ++++- .../share/omr/post-tracking.d/post-tracking | 13 +- 7 files changed, 296 insertions(+), 196 deletions(-) create mode 100644 luci-app-omr-bypass/luasrc/model/cbi/omr-bypass.lua diff --git a/luci-app-omr-bypass/luasrc/controller/omr-bypass.lua b/luci-app-omr-bypass/luasrc/controller/omr-bypass.lua index 9169a1c68..46ba4fabf 100644 --- a/luci-app-omr-bypass/luasrc/controller/omr-bypass.lua +++ b/luci-app-omr-bypass/luasrc/controller/omr-bypass.lua @@ -4,48 +4,6 @@ module("luci.controller.omr-bypass", package.seeall) function index() entry({"admin", "services", "omr-bypass"}, alias("admin", "services", "omr-bypass", "index"), _("OMR-Bypass")) - entry({"admin", "services", "omr-bypass", "index"}, template("omr-bypass/bypass")) - entry({"admin", "services", "omr-bypass", "add"}, post("bypass_add")) + --entry({"admin", "services", "omr-bypass", "index"}, template("omr-bypass/bypass")) + entry({"admin", "services", "omr-bypass", "index"}, cbi("omr-bypass")) end - -function bypass_add() - local hosts = luci.http.formvalue("cbid.omr-bypass.hosts") - if (type(hosts) ~= "table") then - hosts = {hosts} - end - local domains_ipset = "" - local ip_ipset = {} - for _, k in pairs(hosts) do - if k ~= "" then - if dt.ipmask(k) then - table.insert(ip_ipset, k) - else - domains_ipset = domains_ipset .. '/' .. k - end - end - end - ucic:set_list("omr-bypass","ips","ip",ip_ipset) - - local dpi = luci.http.formvalue("cbid.omr-bypass.dpi") - if dpi ~= "" then - if (type(dpi) ~= "table") then - dpi = {dpi} - end - ucic:set_list("omr-bypass","dpi","proto",dpi) - else - ucic:delete("omr-bypass","dpi","proto") - end - - local interface = luci.http.formvalue("cbid.omr-bypass.interface") or "" - ucic:set("omr-bypass","defaults","ifname",interface) - - ucic:save("omr-bypass") - ucic:commit("omr-bypass") - ucic:set_list("dhcp",ucic:get_first("dhcp","dnsmasq"),"ipset",domains_ipset .. "/ss_rules_dst_bypass_all") - ucic:save("dhcp") - ucic:commit("dhcp") - luci.sys.exec("/etc/init.d/dnsmasq reload") - luci.sys.exec("/etc/init.d/omr-bypass restart") - luci.http.redirect(luci.dispatcher.build_url("admin/services/omr-bypass")) - return -end \ No newline at end of file diff --git a/luci-app-omr-bypass/luasrc/model/cbi/omr-bypass.lua b/luci-app-omr-bypass/luasrc/model/cbi/omr-bypass.lua new file mode 100644 index 000000000..e7da2ed95 --- /dev/null +++ b/luci-app-omr-bypass/luasrc/model/cbi/omr-bypass.lua @@ -0,0 +1,72 @@ +-- Copyright 2018 Ycarus (Yannick Chabanois) +-- Licensed to the public under the Apache License 2.0. + +local ipc = require "luci.ip" +local sys = require "luci.sys" +local net = require "luci.model.network".init() +local ifaces = net:get_interfaces() or { net:get_interface() } + +m = Map("omr-bypass", translate("Bypass")) + +s = m:section(TypedSection, "domains", translate("Domains")) +s.addremove = true +s.anonymous = true +s.template = "cbi/tblsection" + +hn = s:option(Value, "name", translate("Domain")) +hn.datatype = "hostname" +hn.optional = false +hn.rmempty = true + +ifd = s:option(Value, "interface", translate("Interface")) +ifd.rmempty = true + +s = m:section(TypedSection, "ip", translate("IPs and Networks")) +s.addremove = true +s.anonymous = true +s.template = "cbi/tblsection" + +ip = s:option(Value, "ips", translate("IP")) +ip.datatype = "ipaddr" +ip.rmempty = true +ip.optional = false + +ifi = s:option(Value, "interface", translate("Interface")) +ifi.rmempty = true + +s = m:section(TypedSection, "dpis", translate("Protocols")) +s.addremove = true +s.anonymous = true +s.template = "cbi/tblsection" + +dpi = s:option(Value, "proto", translate("Protocol")) +dpi.rmempty = true +dpi.optional = false +local protos = {} +for l in io.lines("/proc/net/xt_ndpi/proto") do + local a,b,c,d = l:match('(%w+) (%w+)') + if b ~= "2" and not string.match(b,"custom") then + table.insert(protos,b) + end +end +table.sort(protos) +for _,b in ipairs(protos) do + dpi:value(b,"%s" % tostring(b)) +end + +ifp = s:option(ListValue, "interface", translate("Interface")) +ifp.rmempty = true + +ifd.default = "all" +ifi.default = "all" +ifp.default = "all" +ifd:value("all",translate("Master interface")) +ifi:value("all",translate("Master interface")) +ifp:value("all",translate("Master interface")) +for _, iface in ipairs(ifaces) do + ifd:value(iface:name(),"%s" % iface:name()) + ifi:value(iface:name(),"%s" % iface:name()) + ifp:value(iface:name(),"%s" % iface:name()) +end + +return m diff --git a/luci-app-omr-bypass/luasrc/view/omr-bypass/bypass.htm b/luci-app-omr-bypass/luasrc/view/omr-bypass/bypass.htm index 1ee44e742..605b4fac7 100644 --- a/luci-app-omr-bypass/luasrc/view/omr-bypass/bypass.htm +++ b/luci-app-omr-bypass/luasrc/view/omr-bypass/bypass.htm @@ -1,6 +1,6 @@ <%+header%> - + <% local uci = require("luci.model.uci").cursor() @@ -17,114 +17,82 @@

<%:Bypass%>

-
-
<%:Set domains name, ips or networks you want to bypass.%>
-
- -
-
-<% - local j = 1 - for _ , host in pairs(hosts) do - j = j+1 - for hst in string.gmatch(host,"([^/]*)/") do - if hst ~= "" then -%> - -
-<% - end - end - end - for _ , ip in pairs(ips) do - j = j+1 -%> -
-
-
- <%:You need to use OpenMPTCProuter as DNS server when you want to bypass a domain%> -
-<% - end - if j == 1 then -%> - -
-
-
- <%:You need to use OpenMPTCProuter as DNS server when you want to bypass a domain%> -
-<% - end -%> +
+

<%:Domains, ips or networks%>

+
+
+
+
<%:Domain, IP or network%>
+
<%:Output interface%>
+
-
-
-
-
<%:Set protocols you want to bypass.%>
-
- -
-<% - local allprt="""" - local protos = {} - for l in io.lines("/proc/net/xt_ndpi/proto") do - local a,b,c,d = l:match('(%w+) (%w+)') - if b ~= "2" and not string.match(b,"custom") then - table.insert(protos,b) - end +
+
+
+ +
+
+
+
-<% - end - if k == 1 then -%> -
-<% - end -%> -
-
-
-
- -
-
<%:Set interface you want to use for bypassed traffic.%>
-
- -
- -
-
- <%:If empty, multipath master interface is used if up else any other up interface.%> + end + %> +
-
+
+ +
+
+
+

<%:Protocols%>

+
+
+
+
<%:Protocols%>
+
<%:Output interface%>
+
+
+
+
+<% + local allprt="""" + local protos = {} + for l in io.lines("/proc/net/xt_ndpi/proto") do + local a,b,c,d = l:match('(%w+) (%w+)') + if b ~= "2" and not string.match(b,"custom") then + table.insert(protos,b) + end + end + table.sort(protos) + for _,b in ipairs(protos) do + allprt=allprt .. ","" .. b .. """ + end +%> +
+
+ +
+
+
+ +
+
+
+
+ +
+
diff --git a/luci-app-omr-bypass/root/etc/config/omr-bypass b/luci-app-omr-bypass/root/etc/config/omr-bypass index f62f6b418..c6f3e90a5 100644 --- a/luci-app-omr-bypass/root/etc/config/omr-bypass +++ b/luci-app-omr-bypass/root/etc/config/omr-bypass @@ -1,5 +1,2 @@ -config defaults 'defaults' +config interface 'all' -config bypass 'ips' - -config bypass 'dpi' diff --git a/luci-app-omr-bypass/root/etc/init.d/omr-bypass b/luci-app-omr-bypass/root/etc/init.d/omr-bypass index f43229984..af11af4b4 100755 --- a/luci-app-omr-bypass/root/etc/init.d/omr-bypass +++ b/luci-app-omr-bypass/root/etc/init.d/omr-bypass @@ -8,52 +8,119 @@ USE_PROCD=1 . /usr/lib/unbound/iptools.sh _bypass_ip() { - local ip="$1" + local ip=$1 + local type=$2 + [ -z "$type" ] && type="all" valid_ip4=$( valid_subnet4 $ip) valid_ip6=$( valid_subnet6 $ip) if [ "$valid_ip4" = "ok" ]; then - ipset add ss_rules_dst_bypass_all $ip + ipset add ss_rules_dst_bypass_$type $ip elif [ "$valid_ip6" = "ok" ]; then - ipset add ss_rules6_dst_bypass_all $ip + ipset add ss_rules6_dst_bypass_$type $ip fi } _bypass_domain() { - # Bypass domain even if OMR DNS is not used - domains=$(uci -q get dhcp.@dnsmasq[0].ipset) - for domain in ${domains//\// }; do - if [ -n "$domain" ] && [ "$domain" != "ss_rules_dst_bypass_all" ]; then - resolve=$(dig a +nocmd +noall +answer $domain | awk '{print $5}') - for ip in $resolve; do - _bypass_ip $ip - done - resolve=$(dig aaaa +nocmd +noall +answer $domain | awk '{print $5}') - for ip in $resolve; do - _bypass_ip $ip - done - fi - done + local domain + local intf + config_get domain $1 name + config_get intf $1 interface + + [ -z "$intf" ] && intf="all" + if [ -n "$domain" ]; then + resolve=$(dig a +nocmd +noall +answer $domain | awk '{print $5}') + for ip in $resolve; do + _bypass_ip $ip $intf + done + resolve=$(dig aaaa +nocmd +noall +answer $domain | awk '{print $5}') + for ip in $resolve; do + _bypass_ip $ip $intf + done + uci -q add_list dhcp.@dnsmasq[0].ipset="/$domain/ss_rules_dst_bypass_$intf,ss_rules6_dst_bypass_$intf" + fi } _bypass_proto() { - local proto="$1" + local proto + local intf + config_get proto $1 proto + config_get intf $1 interface + local intfid="$(uci -q get omr-bypass.$intf.id)" + + [ -z "$intf" ] && intf="all" [ -z "$proto" ] && return - ndpi_rules="-A omr-bypass-dpi -m ndpi --$proto -j MARK --set-mark 0x539 - $ndpi_rules" + if [ "$intf" = "all" ]; then + ndpi_rules="-A omr-bypass-dpi -m ndpi --$proto -j MARK --set-mark 0x539 + $ndpi_rules" + else + local intfid="$(uci -q get omr-bypass.$intf.id)" + ndpi_rules="-A omr-bypass-dpi -m ndpi --$proto -j MARK --set-mark 0x539$intfid + $ndpi_rules" + fi +} + +_intf_rule() { + local intf="$1" + local mode + count=$((count+1)) + ipset -q flush ss_rules_dst_bypass_$intf > /dev/null 2>&1 + ipset -q flush ss_rules6_dst_bypass_$intf > /dev/null 2>&1 + ipset -q --exist restore <<-EOF + create ss_rules_dst_bypass_$intf hash:net hashsize 64 + create ss_rules6_dst_bypass_$intf hash:net family inet6 hashsize 64 + EOF + ip rule add prio 1 fwmark 0x539$count lookup $count > /dev/null 2>&1 + ip -6 rule add prio 1 fwmark 0x539$count lookup $count > /dev/null 2>&1 + if [ "$(iptables -w 40 -t mangle -L | grep ss_rules_dst_bypass_$intf)" = "" ]; then + iptables-restore --wait=60 --noflush <<-EOF + *mangle + -A PREROUTING -m set --match-set ss_rules_dst_bypass_$intf dst -j MARK --set-mark 0x539$count + COMMIT + EOF + fi + if [ "$(ip6tables -w 40 -t mangle -L | grep ss_rules6_dst_bypass_$intf)" = "" ]; then + ip6tables-restore --wait=60 --noflush <<-EOF + *mangle + -A PREROUTING -m set --match-set ss_rules6_dst_bypass_$intf dst -j MARK --set-mark 0x539$count + COMMIT + EOF + fi + uci -q set omr-bypass.$intf=interface + uci -q set omr-bypass.$intf.id=$count +} + +_bypass_ip_set() { + local ip + local interface + config_get ip $1 ip + config_get interface $1 interface + _bypass_ip $ip $interface } start_service() { + local count + + uci -q del omr-bypass + ipset -q flush ss_rules_dst_bypass_all > /dev/null 2>&1 + ipset -q flush ss_rules6_dst_bypass_all > /dev/null 2>&1 ipset -q --exist restore <<-EOF create ss_rules_dst_bypass_all hash:net hashsize 64 + create ss_rules6_dst_bypass_all hash:net family inet6 hashsize 64 EOF - config_load omr-bypass - config_list_foreach ips "ip" _bypass_ip + config_load network + config_foreach _intf_rule interface - _bypass_domain + local ndpi_rules="" + config_load omr-bypass + config_foreach _bypass_ip_set ips + uci -q del dhcp.@dnsmasq[0].ipset + config_foreach _bypass_domain domains + config_foreach _bypass_proto dpis ip rule add prio 1 fwmark 0x539 lookup 991337 > /dev/null 2>&1 + ip -6 rule add prio 1 fwmark 0x539 lookup 991337 > /dev/null 2>&1 if [ "$(iptables -w 40 -t mangle -L | grep 'match-set ss_rules_dst_bypass_all dst MARK set')" = "" ]; then iptables-restore --wait=60 --noflush <<-EOF @@ -62,10 +129,16 @@ start_service() { COMMIT EOF fi + if [ "$(ip6tables -w 40 -t mangle -L | grep 'match-set ss_rules6_dst_bypass_all dst MARK set')" = "" ]; then + ip6tables-restore --wait=60 --noflush <<-EOF + *mangle + -A PREROUTING -m set --match-set ss_rules6_dst_bypass_all dst -j MARK --set-mark 0x539 + COMMIT + EOF + fi iptables-save --counters | grep -v omr-bypass-dpi | iptables-restore --counters - local ndpi_rules="" - config_list_foreach dpi "proto" _bypass_proto + ip6tables-save --counters | grep -v omr-bypass-dpi | ip6tables-restore --counters ndpi_rules=$(echo $ndpi_rules | awk 'NF') if [ "$ndpi_rules" != "" ]; then iptables-restore --wait=60 --noflush <<-EOF @@ -75,6 +148,13 @@ start_service() { $ndpi_rules COMMIT EOF + ip6tables-restore --wait=60 --noflush <<-EOF + *mangle + :omr-bypass-dpi - + -A PREROUTING -m addrtype ! --dst-type LOCAL -j omr-bypass-dpi + $ndpi_rules + COMMIT + EOF fi } diff --git a/luci-app-omr-bypass/root/etc/uci-defaults/41_omr-bypass b/luci-app-omr-bypass/root/etc/uci-defaults/41_omr-bypass index 89a1eec76..c3367a552 100644 --- a/luci-app-omr-bypass/root/etc/uci-defaults/41_omr-bypass +++ b/luci-app-omr-bypass/root/etc/uci-defaults/41_omr-bypass @@ -7,21 +7,51 @@ uci -q batch <<-EOF >/dev/null commit ucitrack EOF -if [ "$(uci -q get omr-bypass.dpi)" = "" ]; then - uci -q batch <<-EOF >/dev/null - set omr-bypass.dpi=bypass - EOF +if [ -n "$(uci -q get omr-bypass.dpi)" ]; then + proto=$(uci -q get omr-bypass.dpi.proto) + [ -n "$proto" ] && { + for pro in $proto; do + uci -q batch <<-EOF >/dev/null + set omr-bypass.dpi[-1]=dpi + set omr-bypass.dpi[-1].proto=$pro + set omr-bypass.dpi[-1].interface=all + EOF + done + uci -q commit omr-bypass + } fi -if [ "$(uci -q get omr-bypass.default)" = "" ]; then - uci -q batch <<-EOF >/dev/null - set omr-bypass.defaults=defaults - EOF +if [ -n "$(uci -q get omr-bypass.ips)" ]; then + ips=$(uci -q get omr-bypass.ips.ip) + [ -n "$ips" ] && { + for ip in $ips; do + uci -q batch <<-EOF >/dev/null + set omr-bypass.ips[-1]=ips + set omr-bypass.ips[-1].name=$ip + set omr-bypass.ips[-1].interface=all + EOF + done + uci -q commit omr-bypass + } fi -if [ "$(uci -q get ucitrack.@shadowsocks-libev[-1].affects)" = "" ]; then +if [ -n "$(uci -q get dhcp.dnsmasq[0].ipset)" ]; then + domains="$(uci -q get dhcp.dnsmasq[0].ipset | sed -e 's:/::' -e 's:/ss_rules_dst_bypass_all::' -e 's:/: :g')" + [ -n "$domains" ] && { + for domain in $domains; do + uci -q batch <<-EOF >/dev/null + set omr-bypass.domains[-1]=domains + set omr-bypass.domains[-1].name=$domain + set omr-bypass.domains[-1].interface=all + EOF + done + uci -q commit omr-bypass + } +fi + +if [ "$(uci -q get ucitrack.@shadowsocks-libev[-1].affects | grep omr-bypass)" != "" ]; then uci -q batch <<-EOF >/dev/null - set ucitrack.@shadowsocks-libev[-1].affects=omr-bypass + del_list ucitrack.@shadowsocks-libev[-1].affects=omr-bypass EOF fi rm -f /tmp/luci-indexcache diff --git a/mptcp/files/usr/share/omr/post-tracking.d/post-tracking b/mptcp/files/usr/share/omr/post-tracking.d/post-tracking index 46049be59..a3c2fad64 100755 --- a/mptcp/files/usr/share/omr/post-tracking.d/post-tracking +++ b/mptcp/files/usr/share/omr/post-tracking.d/post-tracking @@ -26,9 +26,7 @@ set_route() { if [ "$interface_gw" != "" ]; then _log "$PREVINTERFACE down. Replace default route by $interface_gw dev $interface_if" ip route replace default scope global nexthop via $interface_gw dev $interface_if && SETROUTE=true - if [ "$(uci -q get omr-bypass.defaults.ifname)" = "" ]; then - ip route replace default via $interface_gw dev $interface_if table 991337 - fi + ip route replace default via $interface_gw dev $interface_if table 991337 fi fi } @@ -168,6 +166,7 @@ if [ "$OMR_TRACKER_STATUS" = "ERROR" ]; then uci -q set shadowsocks-libev.ss_rules.redir_udp='hi2' /etc/init.d/shadowsocks-libev rules_down /etc/init.d/shadowsocks-libev rules_up + /etc/init.d/omr-bypass reload >/dev/null 2>&1 fi fi exit 0 @@ -183,6 +182,7 @@ if [ "$OMR_TRACKER_INTERFACE" = "glorytun" ] || [ "$OMR_TRACKER_INTERFACE" = "om uci -q delete shadowsocks-libev.ss_rules.redir_udp /etc/init.d/shadowsocks-libev rules_down /etc/init.d/shadowsocks-libev rules_up + /etc/init.d/omr-bypass reload >/dev/null 2>&1 fi # Set VPN MTU @@ -223,9 +223,7 @@ if [ "$multipath_config" = "master" ]; then config_load shadowsocks-libev config_foreach set_ss_route server 1 fi - if [ "$(uci -q get omr-bypass.defaults.ifname)" = "" ]; then - ip route replace default via $OMR_TRACKER_DEVICE_GATEWAY dev $OMR_TRACKER_DEVICE table 991337 - fi + ip route replace default via $OMR_TRACKER_DEVICE_GATEWAY dev $OMR_TRACKER_DEVICE table 991337 fi if [ -n "$OMR_TRACKER_DEVICE_IP" ] && [ -n "$OMR_TRACKER_DEVICE_GATEWAY" ]; then local metric=$(ip rule show | grep -m 1 "$OMR_TRACKER_DEVICE_IP" | awk '{print $5}') @@ -244,9 +242,6 @@ else } fi fi -if [ "$(uci -q get omr-bypass.defaults.ifname)" = "$OMR_TRACKER_DEVICE" ] && [ "$(ip route show table 991337 | grep $OMR_TRACKER_DEVICE_GATEWAY)" = "" ]; then - ip route replace default via $OMR_TRACKER_DEVICE_GATEWAY dev $OMR_TRACKER_DEVICE table 991337 -fi [ "$multipath_config" = "on" ] && glorytun-udp path $OMR_TRACKER_DEVICE_IP dev tun0 up > /dev/null 2>&1 [ "$multipath_config" = "backup" ] && glorytun-udp path $OMR_TRACKER_DEVICE_IP dev tun0 backup > /dev/null 2>&1