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("On this page you can configure how traffics are to be \
forwarded to ss-redir instances. \
If enabled, packets will first have their source ip addresses checked \
against <em>Src ip bypass</em>, <em>Src ip forward</em>, \
<em>Src ip checkdst</em> and if none matches <em>Src default</em> \
If enabled, packets will first have their src ip addresses checked \
against <em>Src ip/net bypass</em>, <em>Src ip/net forward</em>, \
<em>Src ip/net checkdst</em> and if none matches <em>Src default</em> \
will give the default action to be taken. \
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')
if not sdata then
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
s = m:section(NamedSection, "ss_rules", "ss_rules")
s:tab("general", translate("General Settings"))
s:tab("srcip", translate("Source Settings"))
s:tab("dstip", translate("Destination Settings"))
s:tab("src", translate("Source Settings"))
s:tab("dst", translate("Destination Settings"))
s:taboption('general', Flag, "disabled", translate("Disable"))
ss.option_install_package(s, 'general')
@ -49,38 +54,56 @@ s:taboption('general', Value, "ipt_args",
translate("Extra arguments"),
translate("Passes additional arguments to iptables. Use with care!"))
s:taboption('srcip', DynamicList, "src_ips_bypass",
translate("Src ip bypass"),
translate("Bypass redir action for packets with source addresses in this list"))
s:taboption('srcip', DynamicList, "src_ips_forward",
translate("Src ip forward"),
translate("Go through redir action for packets with source addresses in this list"))
s:taboption('srcip', DynamicList, "src_ips_checkdst",
translate("Src ip checkdst"),
translate("Continue to have dst address checked for packets with source addresses in this list"))
o = s:taboption('srcip', ListValue, "src_default",
src_dst_option(s, 'src', DynamicList, "src_ips_bypass",
translate("Src ip/net bypass"),
translate("Bypass ss-redir for packets with src address in this list"))
src_dst_option(s, 'src', DynamicList, "src_ips_forward",
translate("Src ip/net forward"),
translate("Forward through ss-redir for packets with src address in this list"))
src_dst_option(s, 'src', DynamicList, "src_ips_checkdst",
translate("Src ip/net checkdst"),
translate("Continue to have dst address checked for packets with src address in this list"))
o = s:taboption('src', ListValue, "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)
s:taboption('dstip', DynamicList, "dst_ips_bypass",
translate("Dst ip bypass"),
translate("Bypass redir action for packets with destination addresses in this list"))
s:taboption('dstip', DynamicList, "dst_ips_forward",
translate("Dst ip forward"),
translate("Go through redir action for packets with destination addresses in this list"))
src_dst_option(s, 'dst', DynamicList, "dst_ips_bypass",
translate("Dst ip/net bypass"),
translate("Bypass ss-redir for packets with dst address in this list"))
src_dst_option(s, 'dst', DynamicList, "dst_ips_forward",
translate("Dst ip/net forward"),
translate("Forward through ss-redir for packets with dst address in this list"))
o = s:taboption('dstip', FileBrowser, "dst_ips_bypass_file",
translate("Dst ip bypass file"),
translate("File containing ip addresses for the purposes as with <em>Dst ip bypass</em>"))
o = s:taboption('dst', FileBrowser, "dst_ips_bypass_file",
translate("Dst ip/net bypass file"),
translate("File containing ip/net for the purposes as with <em>Dst ip/net bypass</em>"))
o.datatype = "file"
s:taboption('dstip', FileBrowser, "dst_ips_forward_file",
translate("Dst ip forward file"),
translate("File containing ip addresses for the purposes as with <em>Dst ip forward</em>"))
s:taboption('dst', FileBrowser, "dst_ips_forward_file",
translate("Dst ip/net forward file"),
translate("File containing ip/net for the purposes as with <em>Dst ip/net forward</em>"))
o.datatype = "file"
o = s:taboption('dstip', ListValue, "dst_default",
o = s:taboption('dst', ListValue, "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)
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

View file

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

View file

@ -118,6 +118,70 @@ var cbi_validators = {
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()
{
return cbi_validators.ipmask4.apply(this) ||
@ -126,40 +190,16 @@ var cbi_validators = {
'ipmask4': function()
{
var ip = this, mask = 32;
if (ip.match(/^(\S+)\/(\S+)$/))
{
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);
return cbi_validators.cidr4.apply(this) ||
cbi_validators.ipnet4.apply(this) ||
cbi_validators.ip4addr.apply(this);
},
'ipmask6': function()
{
var ip = this, mask = 128;
if (ip.match(/^(\S+)\/(\S+)$/))
{
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);
return cbi_validators.cidr6.apply(this) ||
cbi_validators.ipnet6.apply(this) ||
cbi_validators.ip6addr.apply(this);
},
'port': function()

View file

@ -132,38 +132,40 @@ function ip6prefix(val)
return ( val and val >= 0 and val <= 128 )
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)
return ipmask4(val) or ipmask6(val)
end
function ipmask4(val)
local ip, mask = val:match("^([^/]+)/([^/]+)$")
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)
return cidr4(val) or ipnet4(val) or ip4addr(val)
end
function ipmask6(val)
local ip, mask = val:match("^([^/]+)/([^/]+)$")
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)
return cidr6(val) or ipnet6(val) or ip6addr(val)
end
function ip6hostid(val)