Merge pull request #1323 from yousong/shadowsocks-libev

luci-app-shadowsocks-libev: support for option dst_forward_recentrst
This commit is contained in:
Jo-Philipp Wich 2017-08-22 21:22:45 +02:00 committed by GitHub
commit d86244ab39
4 changed files with 158 additions and 91 deletions

View file

@ -9,23 +9,28 @@ m = Map("shadowsocks-libev",
translate("Redir Rules"), translate("Redir Rules"),
translate("On this page you can configure how traffics are to be \ translate("On this page you can configure how traffics are to be \
forwarded to ss-redir instances. \ forwarded to ss-redir instances. \
If enabled, packets will first have their source ip addresses checked \ If enabled, packets will first have their src ip addresses checked \
against <em>Src ip bypass</em>, <em>Src ip forward</em>, \ against <em>Src ip/net bypass</em>, <em>Src ip/net forward</em>, \
<em>Src ip checkdst</em> and if none matches <em>Src default</em> \ <em>Src ip/net checkdst</em> and if none matches <em>Src default</em> \
will give the default action to be taken. \ will give the default action to be taken. \
If the prior check results in action <em>checkdst</em>, packets will continue \ If the prior check results in action <em>checkdst</em>, packets will continue \
to have their destination addresses checked.")) to have their dst addresses checked."))
local sdata = m:get('ss_rules') local sdata = m:get('ss_rules')
if not sdata then if not sdata then
m:set('ss_rules', nil, 'ss_rules') m:set('ss_rules', nil, 'ss_rules')
m:set('ss_rules', 'disabled', true) m:set('ss_rules', 'disabled', "1")
end
function src_dst_option(s, ...)
local o = s:taboption(...)
o.datatype = "or(ip4addr,cidr4)"
end end
s = m:section(NamedSection, "ss_rules", "ss_rules") s = m:section(NamedSection, "ss_rules", "ss_rules")
s:tab("general", translate("General Settings")) s:tab("general", translate("General Settings"))
s:tab("srcip", translate("Source Settings")) s:tab("src", translate("Source Settings"))
s:tab("dstip", translate("Destination Settings")) s:tab("dst", translate("Destination Settings"))
s:taboption('general', Flag, "disabled", translate("Disable")) s:taboption('general', Flag, "disabled", translate("Disable"))
ss.option_install_package(s, 'general') ss.option_install_package(s, 'general')
@ -49,38 +54,56 @@ s:taboption('general', Value, "ipt_args",
translate("Extra arguments"), translate("Extra arguments"),
translate("Passes additional arguments to iptables. Use with care!")) translate("Passes additional arguments to iptables. Use with care!"))
s:taboption('srcip', DynamicList, "src_ips_bypass", src_dst_option(s, 'src', DynamicList, "src_ips_bypass",
translate("Src ip bypass"), translate("Src ip/net bypass"),
translate("Bypass redir action for packets with source addresses in this list")) translate("Bypass ss-redir for packets with src address in this list"))
s:taboption('srcip', DynamicList, "src_ips_forward", src_dst_option(s, 'src', DynamicList, "src_ips_forward",
translate("Src ip forward"), translate("Src ip/net forward"),
translate("Go through redir action for packets with source addresses in this list")) translate("Forward through ss-redir for packets with src address in this list"))
s:taboption('srcip', DynamicList, "src_ips_checkdst", src_dst_option(s, 'src', DynamicList, "src_ips_checkdst",
translate("Src ip checkdst"), translate("Src ip/net checkdst"),
translate("Continue to have dst address checked for packets with source addresses in this list")) translate("Continue to have dst address checked for packets with src address in this list"))
o = s:taboption('srcip', ListValue, "src_default", o = s:taboption('src', ListValue, "src_default",
translate("Src default"), translate("Src default"),
translate("Default action for packets whose source addresses do not match any of the source ip list")) translate("Default action for packets whose src address do not match any of the src ip/net list"))
ss.values_actions(o) ss.values_actions(o)
s:taboption('dstip', DynamicList, "dst_ips_bypass", src_dst_option(s, 'dst', DynamicList, "dst_ips_bypass",
translate("Dst ip bypass"), translate("Dst ip/net bypass"),
translate("Bypass redir action for packets with destination addresses in this list")) translate("Bypass ss-redir for packets with dst address in this list"))
s:taboption('dstip', DynamicList, "dst_ips_forward", src_dst_option(s, 'dst', DynamicList, "dst_ips_forward",
translate("Dst ip forward"), translate("Dst ip/net forward"),
translate("Go through redir action for packets with destination addresses in this list")) translate("Forward through ss-redir for packets with dst address in this list"))
o = s:taboption('dstip', FileBrowser, "dst_ips_bypass_file", o = s:taboption('dst', FileBrowser, "dst_ips_bypass_file",
translate("Dst ip bypass file"), translate("Dst ip/net bypass file"),
translate("File containing ip addresses for the purposes as with <em>Dst ip bypass</em>")) translate("File containing ip/net for the purposes as with <em>Dst ip/net bypass</em>"))
o.datatype = "file" o.datatype = "file"
s:taboption('dstip', FileBrowser, "dst_ips_forward_file", s:taboption('dst', FileBrowser, "dst_ips_forward_file",
translate("Dst ip forward file"), translate("Dst ip/net forward file"),
translate("File containing ip addresses for the purposes as with <em>Dst ip forward</em>")) translate("File containing ip/net for the purposes as with <em>Dst ip/net forward</em>"))
o.datatype = "file" o.datatype = "file"
o = s:taboption('dstip', ListValue, "dst_default", o = s:taboption('dst', ListValue, "dst_default",
translate("Dst default"), translate("Dst default"),
translate("Default action for packets whose destination addresses do not match any of the destination ip list")) translate("Default action for packets whose dst address do not match any of the dst ip list"))
ss.values_actions(o) ss.values_actions(o)
local installed = os.execute("iptables -m recent -h &>/dev/null") == 0
if installed then
o = s:taboption('dst', Flag, "dst_forward_recentrst")
else
m:set('ss_rules', 'dst_forward_recentrst', "0")
o = s:taboption("dst", Button, "_install")
o.inputtitle = translate("Install package iptables-mod-conntrack-extra")
o.inputstyle = "apply"
o.write = function()
return luci.http.redirect(
luci.dispatcher.build_url("admin/system/packages") ..
"?submit=1&install=iptables-mod-conntrack-extra"
)
end
end
o.title = translate("Forward recentrst")
o.description = translate("Forward those packets whose dst have recently sent to us multiple tcp-rst")
return m return m

View file

@ -3,6 +3,7 @@
local _up = getfenv(3) local _up = getfenv(3)
local ut = require("luci.util") local ut = require("luci.util")
local sys = require("luci.sys")
local ds = require("luci.dispatcher") local ds = require("luci.dispatcher")
local nw = require("luci.model.network") local nw = require("luci.model.network")
nw.init() nw.init()
@ -23,13 +24,16 @@ end
function values_redir(o, xmode) function values_redir(o, xmode)
o.map.uci.foreach("shadowsocks-libev", "ss_redir", function(sdata) o.map.uci.foreach("shadowsocks-libev", "ss_redir", function(sdata)
local disabled = ucival_to_bool(sdata["disabled"])
local sname = sdata[".name"] local sname = sdata[".name"]
local mode = sdata["mode"] or "tcp_only" local mode = sdata["mode"] or "tcp_only"
if mode and mode:find(xmode) then if not disabled and mode:find(xmode) then
local desc = "%s - %s" % {sname, mode} local desc = "%s - %s" % {sname, mode}
o:value(sname, desc) o:value(sname, desc)
end end
end) end)
o:value("", "<unset>")
o.default = ""
end end
function values_serverlist(o) function values_serverlist(o)
@ -53,10 +57,8 @@ function values_ipaddr(o)
end end
function values_ifnames(o) function values_ifnames(o)
for _, v in ipairs(nw:get_interfaces()) do for _, v in ipairs(sys.net.devices()) do
if v.dev then o:value(v)
o:value(v.dev.name)
end
end end
end end

View file

@ -118,6 +118,70 @@ var cbi_validators = {
return false; return false;
}, },
'ip4prefix': function()
{
return !isNaN(this) && this >= 0 && this <= 32;
},
'ip6prefix': function()
{
return !isNaN(this) && this >= 0 && this <= 128;
},
'cidr': function()
{
return cbi_validators.cidr4.apply(this) ||
cbi_validators.cidr6.apply(this);
},
'cidr4': function()
{
if (this.match(/^(\S+)\/(\S+)$/))
{
ip = RegExp.$1;
mask = RegExp.$2;
return cbi_validators.ip4addr.apply(ip) &&
cbi_validators.ip4prefix.apply(mask);
}
return false;
},
'cidr6': function()
{
if (this.match(/^(\S+)\/(\S+)$/))
{
ip = RegExp.$1;
mask = RegExp.$2;
return cbi_validators.ip6addr.apply(ip) &&
cbi_validators.ip6prefix.apply(mask);
}
return false;
},
'ipnet4': function()
{
if (this.match(/^(\S+)\/(\S+)$/))
{
ip = RegExp.$1;
net = RegExp.$2;
return cbi_validators.ip4addr.apply(ip) &&
cbi_validators.ip4addr.apply(net);
}
return false;
},
'ipnet6': function()
{
if (this.match(/^(\S+)\/(\S+)$/))
{
ip = RegExp.$1;
net = RegExp.$2;
return cbi_validators.ip6addr.apply(ip) &&
cbi_validators.ip6addr.apply(net);
}
return false;
},
'ipmask': function() 'ipmask': function()
{ {
return cbi_validators.ipmask4.apply(this) || return cbi_validators.ipmask4.apply(this) ||
@ -126,40 +190,16 @@ var cbi_validators = {
'ipmask4': function() 'ipmask4': function()
{ {
var ip = this, mask = 32; return cbi_validators.cidr4.apply(this) ||
cbi_validators.ipnet4.apply(this) ||
if (ip.match(/^(\S+)\/(\S+)$/)) cbi_validators.ip4addr.apply(this);
{
ip = RegExp.$1;
mask = RegExp.$2;
}
if (!isNaN(mask) && (mask < 0 || mask > 32))
return false;
if (isNaN(mask) && !cbi_validators.ip4addr.apply(mask))
return false;
return cbi_validators.ip4addr.apply(ip);
}, },
'ipmask6': function() 'ipmask6': function()
{ {
var ip = this, mask = 128; return cbi_validators.cidr6.apply(this) ||
cbi_validators.ipnet6.apply(this) ||
if (ip.match(/^(\S+)\/(\S+)$/)) cbi_validators.ip6addr.apply(this);
{
ip = RegExp.$1;
mask = RegExp.$2;
}
if (!isNaN(mask) && (mask < 0 || mask > 128))
return false;
if (isNaN(mask) && !cbi_validators.ip6addr.apply(mask))
return false;
return cbi_validators.ip6addr.apply(ip);
}, },
'port': function() 'port': function()

View file

@ -132,38 +132,40 @@ function ip6prefix(val)
return ( val and val >= 0 and val <= 128 ) return ( val and val >= 0 and val <= 128 )
end end
function cidr4(val)
local ip, mask = val:match("^([^/]+)/([^/]+)$")
return ip4addr(ip) and ip4prefix(mask)
end
function cidr6(val)
local ip, mask = val:match("^([^/]+)/([^/]+)$")
return ip6addr(ip) and ip6prefix(mask)
end
function ipnet4(val)
local ip, mask = val:match("^([^/]+)/([^/]+)$")
return ip4addr(ip) and ip4addr(mask)
end
function ipnet6(val)
local ip, mask = val:match("^([^/]+)/([^/]+)$")
return ip6addr(ip) and ip6addr(mask)
end
function ipmask(val) function ipmask(val)
return ipmask4(val) or ipmask6(val) return ipmask4(val) or ipmask6(val)
end end
function ipmask4(val) function ipmask4(val)
local ip, mask = val:match("^([^/]+)/([^/]+)$") return cidr4(val) or ipnet4(val) or ip4addr(val)
local bits = tonumber(mask)
if bits and (bits < 0 or bits > 32) then
return false
end
if not bits and mask and not ip4addr(mask) then
return false
end
return ip4addr(ip or val)
end end
function ipmask6(val) function ipmask6(val)
local ip, mask = val:match("^([^/]+)/([^/]+)$") return cidr6(val) or ipnet6(val) or ip6addr(val)
local bits = tonumber(mask)
if bits and (bits < 0 or bits > 128) then
return false
end
if not bits and mask and not ip6addr(mask) then
return false
end
return ip6addr(ip or val)
end end
function ip6hostid(val) function ip6hostid(val)