#
-# Copyright (C) 2008-2014 The LuCI Team <luci@lists.subsignal.org>
+# Copyright (C) 2017 Yousong Zhou <yszhou4tech@gmail.com>
#
# This is free software, licensed under the Apache License, Version 2.0 .
#
include $(TOPDIR)/rules.mk
-LUCI_TITLE:=LuCI Support for Shadowsocks-libev
+LUCI_TITLE:=LuCI Support for shadowsocks-libev
LUCI_DEPENDS:=
+PKG_LICENSE:=Apache-2.0
+
include ../../luci.mk
# call BuildPackage - OpenWrt buildroot signature
--- Copyright 2015 Jian Chang <aa65535@live.com>
+-- Copyright 2017 Yousong Zhou <yszhou4tech@gmail.com>
-- Licensed to the public under the Apache License 2.0.
-
+--
module("luci.controller.shadowsocks-libev", package.seeall)
function index()
- if not nixio.fs.access("/etc/config/shadowsocks-libev") then
- return
- end
+ entry({"admin", "services", "shadowsocks-libev"},
+ alias("admin", "services", "shadowsocks-libev", "instances"),
+ _("Shadowsocks-libev"), 59)
+
+ entry({"admin", "services", "shadowsocks-libev", "instances"},
+ arcombine(cbi("shadowsocks-libev/instances"), cbi("shadowsocks-libev/instance-details")),
+ _("Local Instances"), 10).leaf = true
+
+ entry({"admin", "services", "shadowsocks-libev", "servers"},
+ cbi("shadowsocks-libev/servers"),
+ _("Remote Servers"), 20).leaf = true
- entry({"admin", "services", "shadowsocks-libev"}, cbi("shadowsocks-libev"), _("ShadowSocks-libev"), 74).dependent = true
+ entry({"admin", "services", "shadowsocks-libev", "rules"},
+ cbi("shadowsocks-libev/rules"),
+ _("Redir Rules"), 30).leaf = true
end
+++ /dev/null
--- Copyright 2015 Jian Chang <aa65535@live.com>
--- Licensed to the public under the Apache License 2.0.
-
-local m, s, o, e, a
-
-if luci.sys.call("pidof ss-redir >/dev/null") == 0 then
- m = Map("shadowsocks-libev", translate("ShadowSocks-libev"), translate("ShadowSocks-libev is running"))
-else
- m = Map("shadowsocks-libev", translate("ShadowSocks-libev"), translate("ShadowSocks-libev is not running"))
-end
-
-e = {
- "table",
- "rc4",
- "rc4-md5",
- "aes-128-cfb",
- "aes-192-cfb",
- "aes-256-cfb",
- "bf-cfb",
- "camellia-128-cfb",
- "camellia-192-cfb",
- "camellia-256-cfb",
- "cast5-cfb",
- "des-cfb",
- "idea-cfb",
- "rc2-cfb",
- "seed-cfb",
- "salsa20",
- "chacha20",
-}
-
--- Global Setting
-s = m:section(TypedSection, "shadowsocks-libev", translate("Global Setting"))
-s.anonymous = true
-
-o = s:option(Flag, "enable", translate("Enable"))
-o.default = 1
-o.rmempty = false
-
-o = s:option(Value, "server", translate("Server Address"))
-o.datatype = "ipaddr"
-o.rmempty = false
-
-o = s:option(Value, "server_port", translate("Server Port"))
-o.datatype = "port"
-o.rmempty = false
-
-o = s:option(Value, "local_port", translate("Local Port"))
-o.datatype = "port"
-o.default = 1080
-o.rmempty = false
-
-o = s:option(Value, "timeout", translate("Connection Timeout"))
-o.datatype = "uinteger"
-o.default = 60
-o.rmempty = false
-
-o = s:option(Value, "password", translate("Password"))
-o.password = true
-o.rmempty = false
-
-o = s:option(ListValue, "encrypt_method", translate("Encrypt Method"))
-for i,v in ipairs(e) do
- o:value(v)
-end
-o.rmempty = false
-
-o = s:option(Value, "ignore_list", translate("Ignore List"))
-o:value("/dev/null", translate("Disabled"))
-o.default = "/dev/null"
-o.rmempty = false
-
--- UDP Relay
-s = m:section(TypedSection, "shadowsocks-libev", translate("UDP Relay"))
-s.anonymous = true
-
-o = s:option(ListValue, "udp_mode", translate("Relay Mode"))
-o:value("0", translate("Disabled"))
-o:value("1", translate("Enabled"))
-o:value("2", translate("Custom"))
-o.default = 0
-o.rmempty = false
-
-o = s:option(Value, "udp_server", translate("Server Address"))
-o.datatype = "ipaddr"
-o:depends("udp_mode", 2)
-
-o = s:option(Value, "udp_server_port", translate("Server Port"))
-o.datatype = "port"
-o:depends("udp_mode", 2)
-
-o = s:option(Value, "udp_local_port", translate("Local Port"))
-o.datatype = "port"
-o.default = 1081
-o:depends("udp_mode", 2)
-
-o = s:option(Value, "udp_timeout", translate("Connection Timeout"))
-o.datatype = "uinteger"
-o.default = 60
-o:depends("udp_mode", 2)
-
-o = s:option(Value, "udp_password", translate("Password"))
-o.password = true
-o:depends("udp_mode", 2)
-
-o = s:option(ListValue, "udp_encrypt_method", translate("Encrypt Method"))
-for i,v in ipairs(e) do
- o:value(v)
-end
-o:depends("udp_mode", 2)
-
--- UDP Forward
-s = m:section(TypedSection, "shadowsocks-libev", translate("UDP Forward"))
-s.anonymous = true
-
-o = s:option(Flag, "tunnel_enable", translate("Enable"))
-o.default = 1
-o.rmempty = false
-
-o = s:option(Value, "tunnel_port", translate("UDP Local Port"))
-o.datatype = "port"
-o.default = 5300
-
-o = s:option(Value, "tunnel_forward", translate("Forwarding Tunnel"))
-o.default = "8.8.4.4:53"
-
--- Access Control
-s = m:section(TypedSection, "shadowsocks-libev", translate("Access Control"))
-s.anonymous = true
-
-s:tab("lan_ac", translate("LAN"))
-
-o = s:taboption("lan_ac", ListValue, "lan_ac_mode", translate("Access Control"))
-o:value("0", translate("Disabled"))
-o:value("1", translate("Allow listed only"))
-o:value("2", translate("Allow all except listed"))
-o.default = 0
-o.rmempty = false
-
-o = s:taboption("lan_ac", DynamicList, "lan_ac_ip", translate("LAN IP List"))
-o.datatype = "ipaddr"
-
-luci.ip.neighbors({ family = 4 }, function(entry)
- if entry.reachable then
- o:value(entry.dest:string())
- end
-end)
-
-s:tab("wan_ac", translate("WAN"))
-
-o = s:taboption("wan_ac", DynamicList, "wan_bp_ip", translate("Bypassed IP"))
-o.datatype = "ip4addr"
-
-o = s:taboption("wan_ac", DynamicList, "wan_fw_ip", translate("Forwarded IP"))
-o.datatype = "ip4addr"
-
-return m
--- /dev/null
+-- Copyright 2017 Yousong Zhou <yszhou4tech@gmail.com>
+-- Licensed to the public under the Apache License 2.0.
+
+local ds = require "luci.dispatcher"
+local ss = require "luci.model.shadowsocks-libev"
+
+local sname = arg[1]
+local redirect_url = ds.build_url("admin/services/shadowsocks-libev/instances")
+local s, o
+
+local m = Map("shadowsocks-libev")
+local sdata = m:get(sname)
+if not sdata then
+ luci.http.redirect(redirect_url)
+ return
+end
+local stype = sdata[".type"]
+m.redirect = redirect_url
+m.title = "shadowsocks-libev - %s - %s" % {stype, sname}
+
+
+s = m:section(NamedSection, sname, stype)
+s:tab("general", translate("General Settings"))
+s:tab("advanced", translate("Advanced Settings"))
+s:taboption("general", Flag, "disabled", translate("Disable"))
+ss.option_install_package(s, "general")
+
+if stype == "ss_server" then
+ ss.options_server(s, "general")
+ o = s:taboption("general", Value, "bind_address",
+ translate("Bind address"),
+ translate("The address ss-server will initiate connection from"))
+ o.datatype = "ipaddr"
+ o.placeholder = "0.0.0.0"
+ ss.values_ipaddr(o)
+ o = s:taboption("general", Value, "manager_address", translate("Manager address"))
+ o.datatype = "hostport"
+else
+ ss.options_client(s, "general")
+ if stype == "ss_tunnel" then
+ o = s:taboption("general", Value, "tunnel_address",
+ translate("Tunnel address"),
+ translate("The address ss-tunnel will forward traffic to"))
+ o.datatype = "hostport"
+ end
+end
+ss.options_common(s, "advanced")
+
+return m
--- /dev/null
+-- Copyright 2017 Yousong Zhou <yszhou4tech@gmail.com>
+-- Licensed to the public under the Apache License 2.0.
+
+local ds = require "luci.dispatcher"
+local ss = require "luci.model.shadowsocks-libev"
+local ut = require "luci.util"
+local m, s, o
+
+m = Map("shadowsocks-libev",
+ translate("Local Instances"),
+ translate("Instances of shadowsocks-libev components, e.g. ss-local, \
+ ss-redir, ss-tunnel, ss-server, etc. To enable an instance it \
+ is required to enable both the instance itself and the remote \
+ server it refers to."))
+
+local instances = {}
+local cfgtypes = { "ss_local", "ss_redir", "ss_server", "ss_tunnel" }
+local instances_data = ut.ubus("service", "list", {name = "shadowsocks-libev"})["shadowsocks-libev"]
+if instances_data ~= nil then
+ instances_data = instances_data["instances"]
+end
+
+for sname, sdata in pairs(m:get()) do
+ local key, value = ss.cfgvalue_overview(sdata)
+ if key ~= nil then
+ if instances_data and instances_data[key] and instances_data[key]["running"] then
+ value["running"] = "yes"
+ else
+ value["running"] = "no"
+ end
+ instances[key] = value
+ end
+end
+
+s = m:section(Table, instances)
+s.addremove = true
+s.template_addremove = "shadowsocks-libev/add_instance"
+s.extedit = function(self, section)
+ local value = instances[section]
+ if type(value) == "table" then
+ return ds.build_url(unpack(ds.context.requestpath),
+ "services/shadowsocks-libev/instances",
+ value[".name"])
+ end
+end
+s.parse = function(self, ...)
+ Table.parse(self, ...)
+
+ local crval = REMOVE_PREFIX .. self.config
+ local name = self.map:formvaluetable(crval)
+ for k,v in pairs(name) do
+ local value = instances[k]
+ local sname = value[".name"]
+ if type(value) == "table" then
+ m:del(sname)
+ instances[k] = nil
+ for _, oname in ipairs({"redir_tcp", "redir_udp"}) do
+ local ovalue = m:get("ss_rules", oname)
+ if ovalue == sname then
+ m:del("ss_rules", oname)
+ end
+ end
+ end
+ end
+
+ local stype = m:formvalue("_newinst.type")
+ local sname = m:formvalue("_newinst.name")
+ if ut.contains(cfgtypes, stype) then
+ local created
+ if sname and #sname > 0 then
+ created = m:set(sname, nil, stype)
+ else
+ created = m:add(stype)
+ sname = created
+ end
+ if created then
+ m.uci:save("shadowsocks-libev")
+ luci.http.redirect(ds.build_url(
+ "admin/services/shadowsocks-libev/instances", sname
+ ))
+ end
+ end
+end
+
+o = s:option(DummyValue, "name", translate("Name"))
+o.rawhtml = true
+o = s:option(DummyValue, "overview", translate("Overview"))
+o.rawhtml = true
+
+s:option(DummyValue, "running", translate("Running"))
+
+o = s:option(Button, "disabled", translate("Enable/Disable"))
+o.render = function(self, section, scope)
+ if instances[section].disabled then
+ self.title = translate("Disabled")
+ self.inputstyle = "reset"
+ else
+ self.title = translate("Enabled")
+ self.inputstyle = "save"
+ end
+ Button.render(self, section, scope)
+end
+o.write = function(self, section)
+ local sdata = instances[section]
+ if type(sdata) == "table" then
+ local sname = sdata[".name"]
+ local disabled = not sdata["disabled"]
+ sdata["disabled"] = disabled
+ m:set(sname, "disabled", tostring(disabled))
+ end
+end
+
+return m
--- /dev/null
+-- Copyright 2017 Yousong Zhou <yszhou4tech@gmail.com>
+-- Licensed to the public under the Apache License 2.0.
+
+local ss = require("luci.model.shadowsocks-libev")
+
+local m, s, o
+
+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> \
+ 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."))
+
+
+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:taboption('general', Flag, "disabled", translate("Disable"))
+ss.option_install_package(s, 'general')
+
+o = s:taboption('general', ListValue, "redir_tcp",
+ translate("ss-redir for TCP"))
+ss.values_redir(o, 'tcp')
+o = s:taboption('general', ListValue, "redir_udp",
+ translate("ss-redir for UDP"))
+ss.values_redir(o, 'udp')
+
+o = s:taboption('general', ListValue, "local_default",
+ translate("Local-out default"),
+ translate("Default action for locally generated packets"))
+ss.values_actions(o)
+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",
+ translate("Src default"),
+ translate("Default action for packets whose source addresses do not match any of the source ip 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"))
+
+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.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>"))
+o.datatype = "file"
+
+return m
--- /dev/null
+-- Copyright 2017 Yousong Zhou <yszhou4tech@gmail.com>
+-- Licensed to the public under the Apache License 2.0.
+
+local ds = require "luci.dispatcher"
+local ss = require("luci.model.shadowsocks-libev")
+
+local m, s
+
+m = Map("shadowsocks-libev",
+ translate("Remote Servers"),
+ translate("Definition of remote shadowsocks servers. \
+ Disable any of them will also disable instances refering to it."))
+
+local sname = arg[1]
+if sname then
+ if not m:get(sname) then
+ luci.http.redirect(ds.build_url("admin/services/shadowsocks-libev/servers"))
+ return
+ end
+ s = m:section(NamedSection, sname, "server")
+ m.title = m.title .. ' - ' .. sname
+else
+ s = m:section(TypedSection, "server")
+ s.template = 'cbi/tblsection'
+ s.addremove = true
+end
+
+s:option(Flag, "disabled", translate("Disable"))
+ss.options_server(s)
+
+return m
--- /dev/null
+-- Copyright 2017 Yousong Zhou <yszhou4tech@gmail.com>
+-- Licensed to the public under the Apache License 2.0.
+
+local _up = getfenv(3)
+local ut = require("luci.util")
+local ds = require("luci.dispatcher")
+local nw = require("luci.model.network")
+nw.init()
+module("luci.model.shadowsocks-libev", function(m)
+ setmetatable(m, {__index=function (self, k)
+ local tb = _up
+ return rawget(self, k) or _up[k]
+ end})
+end)
+
+function values_actions(o)
+ for _, a in ipairs(actions) do
+ o:value(a)
+ end
+end
+
+function values_redir(o, xmode)
+ o.map.uci.foreach("shadowsocks-libev", "ss_redir", function(sdata)
+ local sname = sdata[".name"]
+ local mode = sdata["mode"]
+ if mode and mode:find(xmode) then
+ local desc = "%s - %s" % {sname, mode}
+ o:value(sname, desc)
+ end
+ end)
+end
+
+function values_serverlist(o)
+ o.map.uci.foreach("shadowsocks-libev", "server", function(sdata)
+ local sname = sdata[".name"]
+ local server = sdata["server"]
+ local server_port = sdata["server_port"]
+ if server and server_port then
+ local desc = "%s - %s:%s" % {sname, sdata["server"], sdata["server_port"]}
+ o:value(sname, desc)
+ end
+ end)
+end
+
+function values_ipaddr(o)
+ local keys, vals = {}, {}
+ for _, v in ipairs(nw:get_interfaces()) do
+ for _, a in ipairs(v:ipaddrs()) do
+ o:value(a:host():string(), '%s (%s)' %{ a:host(), v:shortname() })
+ end
+ end
+end
+
+function options_client(s, tab)
+ local o
+
+ o = s:taboption(tab, ListValue, "server", translate("Remote server"))
+ values_serverlist(o)
+ o = s:taboption(tab, Value, "local_address", translate("Local address"))
+ o.datatype = "ipaddr"
+ o.placeholder = "0.0.0.0"
+ values_ipaddr(o)
+ o = s:taboption(tab, Value, "local_port", translate("Local port"))
+ o.datatype = "port"
+end
+
+function options_server(s, tab)
+ local o
+ local optfunc
+
+ if tab == nil then
+ optfunc = function(...) return s:option(...) end
+ else
+ optfunc = function(...) return s:taboption(tab, ...) end
+ end
+
+ o = optfunc(Value, "server", translate("Server"))
+ o.datatype = "host"
+ o.size = 16
+ o = optfunc(Value, "server_port", translate("Server port"))
+ o.datatype = "port"
+ o.size = 5
+ o = optfunc(ListValue, "method", translate("Method"))
+ for _, m in ipairs(methods) do
+ o:value(m)
+ end
+ o = optfunc(Value, "key", translate("Key (base64 encoding)"))
+ o.datatype = "base64"
+ o.password = true
+ o.size = 12
+ o = optfunc(Value, "password", translate("Password"))
+ o.password = true
+ o.size = 12
+end
+
+function options_common(s, tab)
+ local o
+
+ o = s:taboption(tab, ListValue, "mode", translate("Mode of operation"))
+ for _, m in ipairs(modes) do
+ o:value(m)
+ end
+ o.default = "tcp_and_udp"
+ o = s:taboption(tab, Value, "mtu", translate("MTU"))
+ o.datatype = "uinteger"
+ o = s:taboption(tab, Value, "timeout", translate("Timeout (sec)"))
+ o.datatype = "uinteger"
+ s:taboption(tab, Value, "user", translate("Run as"))
+
+ s:taboption(tab, Flag, "verbose", translate("Verbose"))
+ s:taboption(tab, Flag, "fast_open", translate("Enable TCP Fast Open"))
+ s:taboption(tab, Flag, "reuse_port", translate("Enable SO_REUSEPORT"))
+end
+
+function ucival_to_bool(val)
+ return val == "true" or val == "1" or val == "yes" or val == "on"
+end
+
+function cfgvalue_overview(sdata)
+ local stype = sdata[".type"]
+ local lines = {}
+
+ if stype == "ss_server" then
+ cfgvalue_overview_(sdata, lines, names_options_server)
+ cfgvalue_overview_(sdata, lines, names_options_common)
+ cfgvalue_overview_(sdata, lines, {
+ "bind_address",
+ "manager_address",
+ })
+ elseif stype == "ss_local" or stype == "ss_redir" or stype == "ss_tunnel" then
+ cfgvalue_overview_(sdata, lines, names_options_client)
+ if stype == "ss_tunnel" then
+ cfgvalue_overview_(sdata, lines, {"tunnel_address"})
+ end
+ cfgvalue_overview_(sdata, lines, names_options_common)
+ else
+ return nil, nil
+ end
+ local sname = sdata[".name"]
+ local key = "%s.%s" % {stype, sname}
+ local value = {
+ [".name"] = sname,
+ name = '%s.<var>%s</var>' % {stype, sname},
+ overview = table.concat(lines, "</br>"),
+ disabled = ucival_to_bool(sdata["disabled"]),
+ }
+ return key, value
+end
+
+function cfgvalue_overview_(sdata, lines, names)
+ local line
+
+ for _, n in ipairs(names) do
+ local v = sdata[n]
+ if v ~= nil then
+ local fv = "<var>%s</var>" % ut.pcdata(v)
+ if sdata[".type"] ~= "ss_server" and n == "server" then
+ fv = '<a class="label" href="%s">%s</a>' % {
+ ds.build_url("admin/services/shadowsocks-libev/servers", v), fv}
+ end
+ line = n .. ": " .. fv
+ table.insert(lines, line)
+ end
+ end
+end
+
+function option_install_package(s, tab)
+ local bin = s.sectiontype:gsub("_", "-", 1)
+ local installed = nixio.fs.access("/usr/bin/" .. bin)
+ if installed then
+ return
+ end
+ local opkg_package = "shadowsocks-libev-" .. bin
+ local p_install
+ if tab then
+ p_install = s:taboption(tab, Button, "_install")
+ else
+ p_install = s:option(Button, "_install")
+ end
+ p_install.title = translate("Package is not installed")
+ p_install.inputtitle = translate("Install package %q" % opkg_package)
+ p_install.inputstyle = "apply"
+
+ function p_install.write()
+ return luci.http.redirect(
+ luci.dispatcher.build_url("admin/system/packages") ..
+ "?submit=1&install=%s" % opkg_package
+ )
+ end
+end
+
+names_options_server = {
+ "server",
+ "server_port",
+ "method",
+ "key",
+ "password",
+}
+
+names_options_client = {
+ "server",
+ "local_address",
+ "local_port",
+}
+
+names_options_common = {
+ "verbose",
+ "fast_open",
+ "reuse_port",
+ "mode",
+ "mtu",
+ "timeout",
+ "user",
+}
+
+modes = {
+ "tcp_only",
+ "tcp_and_udp",
+ "udp_only",
+}
+
+actions = {
+ "bypass",
+ "forward",
+ "checkdst",
+}
+
+methods = {
+ -- aead
+ "aes-128-gcm",
+ "aes-192-gcm",
+ "aes-256-gcm",
+ -- stream
+ "table",
+ "rc4",
+ "rc4-md5",
+ "aes-128-cfb",
+ "aes-192-cfb",
+ "aes-256-cfb",
+ "aes-128-ctr",
+ "aes-192-ctr",
+ "aes-256-ctr",
+ "bf-cfb",
+ "camellia-128-cfb",
+ "camellia-192-cfb",
+ "camellia-256-cfb",
+ "salsa20",
+ "chacha20",
+ "chacha20-ietf",
+ "aes-128-gcm",
+ "aes-192-gcm",
+ "aes-256-gcm",
+}
--- /dev/null
+<div class="cbi-section-create cbi-tblsection-create">
+ <br />
+ <table class="cbi-section-table">
+ <tr class="cbi-section-table-row">
+ <td class="cbi-section-table-cell" style="width:140px">
+ <select class="cbi-input-select" id="_newinst.type" name="_newinst.type">
+ <option value="_dummy">-- instance type --</option>
+ <option value="ss_local">ss-local</option>
+ <option value="ss_tunnel">ss-tunnel</option>
+ <option value="ss_redir">ss-redir</option>
+ <option value="ss_server">ss-server</option>
+ </select>
+ </td>
+ <td class="cbi-section-table-cell" style="width:110px">
+ <input type="text" class="cbi-input-text" id="_newinst.name" name="_newinst.name" placeholder="<%:Name%>"/>
+ </td>
+ <td class="cbi-section-table-cell left">
+ <input type="submit" class="cbi-button cbi-button-add" name="cbi.cts.<%=self.config%>" value="<%:Add%>" />
+ </td>
+ </tr>
+ </table>
+</div>
+++ /dev/null
-msgid ""
-msgstr ""
-"Content-Type: text/plain; charset=UTF-8\n"
-"Project-Id-Version: \n"
-"POT-Creation-Date: \n"
-"PO-Revision-Date: \n"
-"Language-Team: \n"
-"MIME-Version: 1.0\n"
-"Content-Transfer-Encoding: 8bit\n"
-"X-Generator: Poedit 1.8.11\n"
-"Last-Translator: Luiz Angelo Daros de Luca <luizluca@gmail.com>\n"
-"Plural-Forms: nplurals=2; plural=(n > 1);\n"
-"Language: pt_BR\n"
-
-msgid "Access Control"
-msgstr "Controle de Acesso"
-
-msgid "Allow all except listed"
-msgstr "Permitir todos, exceto os listados"
-
-msgid "Allow listed only"
-msgstr "Permitir somente os listados"
-
-msgid "Bypassed IP"
-msgstr "Endereços IP Ignorados"
-
-msgid "Connection Timeout"
-msgstr "Tempo limite de conexão"
-
-msgid "Custom"
-msgstr "Personalizado"
-
-msgid "Disabled"
-msgstr "Desabilitado"
-
-msgid "Enable"
-msgstr "Ativar"
-
-msgid "Enabled"
-msgstr "Ativado"
-
-msgid "Encrypt Method"
-msgstr "Método de Cifragem"
-
-msgid "Forwarded IP"
-msgstr "Endereço IP Encaminhado"
-
-msgid "Forwarding Tunnel"
-msgstr "Tunel para Encaminhamento"
-
-msgid "Global Setting"
-msgstr "Opções Globais"
-
-msgid "Ignore List"
-msgstr "Lista de Ignorados"
-
-msgid "LAN"
-msgstr "LAN"
-
-msgid "LAN IP List"
-msgstr "Lista de endereços IP da LAN"
-
-msgid "Local Port"
-msgstr "Porta Local"
-
-msgid "Password"
-msgstr "Senha"
-
-msgid "Relay Mode"
-msgstr "Modo de Retransmissor"
-
-msgid "Server Address"
-msgstr "Endereço do Servidor"
-
-msgid "Server Port"
-msgstr "Porta do servidor"
-
-msgid "ShadowSocks-libev"
-msgstr "ShadowSocks-libev"
-
-msgid "ShadowSocks-libev is not running"
-msgstr "O serviço ShadowSocks-libev está parado"
-
-msgid "ShadowSocks-libev is running"
-msgstr "O serviço ShadowSocks-libev está em execução."
-
-msgid "UDP Forward"
-msgstr "Encaminhamento UDP"
-
-msgid "UDP Local Port"
-msgstr "Porta Local UDP"
-
-msgid "UDP Relay"
-msgstr "Retransmissão UDP"
-
-msgid "WAN"
-msgstr "WAN"
+++ /dev/null
-msgid ""
-msgstr ""
-"Content-Type: text/plain; charset=UTF-8\n"
-"Project-Id-Version: PACKAGE VERSION\n"
-"Last-Translator: Automatically generated\n"
-"Language-Team: none\n"
-"Language: sv\n"
-"MIME-Version: 1.0\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-
-msgid "Access Control"
-msgstr ""
-
-msgid "Allow all except listed"
-msgstr ""
-
-msgid "Allow listed only"
-msgstr ""
-
-msgid "Bypassed IP"
-msgstr ""
-
-msgid "Connection Timeout"
-msgstr ""
-
-msgid "Custom"
-msgstr ""
-
-msgid "Disabled"
-msgstr ""
-
-msgid "Enable"
-msgstr ""
-
-msgid "Enabled"
-msgstr ""
-
-msgid "Encrypt Method"
-msgstr ""
-
-msgid "Forwarded IP"
-msgstr ""
-
-msgid "Forwarding Tunnel"
-msgstr ""
-
-msgid "Global Setting"
-msgstr ""
-
-msgid "Ignore List"
-msgstr ""
-
-msgid "LAN"
-msgstr ""
-
-msgid "LAN IP List"
-msgstr ""
-
-msgid "Local Port"
-msgstr ""
-
-msgid "Password"
-msgstr ""
-
-msgid "Relay Mode"
-msgstr ""
-
-msgid "Server Address"
-msgstr ""
-
-msgid "Server Port"
-msgstr ""
-
-msgid "ShadowSocks-libev"
-msgstr ""
-
-msgid "ShadowSocks-libev is not running"
-msgstr ""
-
-msgid "ShadowSocks-libev is running"
-msgstr ""
-
-msgid "UDP Forward"
-msgstr ""
-
-msgid "UDP Local Port"
-msgstr ""
-
-msgid "UDP Relay"
-msgstr ""
-
-msgid "WAN"
-msgstr ""
-
-#~ msgid "Broadcast on all interfaces"
-#~ msgstr "Sänd i alla gränssnitt"
-
-#~ msgid "Choose the host to wake up or enter a custom MAC address to use"
-#~ msgstr ""
-#~ "Välj värden som ska väckas upp eller fyll i en anpassad MAC-adress att "
-#~ "använda"
-
-#~ msgid "Host to wake up"
-#~ msgstr "Värd som ska väckas upp"
-
-#~ msgid "Network interface to use"
-#~ msgstr "Nätverksgränssnitt som ska användas"
-
-#~ msgid ""
-#~ "Sometimes only one of the two tools works. If one fails, try the other one"
-#~ msgstr ""
-#~ "Ibland så fungerar bara en av de två verktygen. Prova med den andra om "
-#~ "den första misslyckades"
-
-#~ msgid "Specifies the interface the WoL packet is sent on"
-#~ msgstr "Anger gränssnittet som fjärrstartspaketet skickas med"
-
-#~ msgid "Starting WoL utility:"
-#~ msgstr "Startar hjälpprogrammet för fjärrstyrning av uppstart:"
-
-#~ msgid "Wake on LAN"
-#~ msgstr "Fjärrstyrning av uppstart"
-
-#~ msgid ""
-#~ "Wake on LAN is a mechanism to remotely boot computers in the local "
-#~ "network."
-#~ msgstr ""
-#~ "Fjärrstyrning av uppstart är en mekanism för att starta upp datorer via "
-#~ "fjärrstyrning i det lokala nätverket."
-
-#~ msgid "Wake up host"
-#~ msgstr "Väck upp värden"
-
-#~ msgid "WoL program"
-#~ msgstr "Program för fjärrstart"
+++ /dev/null
-msgid ""
-msgstr "Content-Type: text/plain; charset=UTF-8"
-
-msgid "Access Control"
-msgstr ""
-
-msgid "Allow all except listed"
-msgstr ""
-
-msgid "Allow listed only"
-msgstr ""
-
-msgid "Bypassed IP"
-msgstr ""
-
-msgid "Connection Timeout"
-msgstr ""
-
-msgid "Custom"
-msgstr ""
-
-msgid "Disabled"
-msgstr ""
-
-msgid "Enable"
-msgstr ""
-
-msgid "Enabled"
-msgstr ""
-
-msgid "Encrypt Method"
-msgstr ""
-
-msgid "Forwarded IP"
-msgstr ""
-
-msgid "Forwarding Tunnel"
-msgstr ""
-
-msgid "Global Setting"
-msgstr ""
-
-msgid "Ignore List"
-msgstr ""
-
-msgid "LAN"
-msgstr ""
-
-msgid "LAN IP List"
-msgstr ""
-
-msgid "Local Port"
-msgstr ""
-
-msgid "Password"
-msgstr ""
-
-msgid "Relay Mode"
-msgstr ""
-
-msgid "Server Address"
-msgstr ""
-
-msgid "Server Port"
-msgstr ""
-
-msgid "ShadowSocks-libev"
-msgstr ""
-
-msgid "ShadowSocks-libev is not running"
-msgstr ""
-
-msgid "ShadowSocks-libev is running"
-msgstr ""
-
-msgid "UDP Forward"
-msgstr ""
-
-msgid "UDP Local Port"
-msgstr ""
-
-msgid "UDP Relay"
-msgstr ""
-
-msgid "WAN"
-msgstr ""
+++ /dev/null
-msgid ""
-msgstr ""
-"Project-Id-Version: PACKAGE VERSION\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2014-11-12 14:12+0800\n"
-"PO-Revision-Date: 2015-07-02 14:26+0800\n"
-"Last-Translator: Jian Chang <aa65535@live.com>\n"
-"Language: zh_CN\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Pootle 2.0.6\n"
-
-msgid "Access Control"
-msgstr "访问控制"
-
-msgid "Allow all except listed"
-msgstr "仅允许列表外"
-
-msgid "Allow listed only"
-msgstr "仅允许列表内"
-
-msgid "Bypassed IP"
-msgstr "被忽略的IP"
-
-msgid "Connection Timeout"
-msgstr "连接超时"
-
-msgid "Custom"
-msgstr "自定义"
-
-msgid "Disabled"
-msgstr "已禁用"
-
-msgid "Enable"
-msgstr "启用"
-
-msgid "Enabled"
-msgstr "已启用"
-
-msgid "Encrypt Method"
-msgstr "加密方式"
-
-msgid "Forwarded IP"
-msgstr "走代理的IP"
-
-msgid "Forwarding Tunnel"
-msgstr "UDP转发地址"
-
-msgid "Global Setting"
-msgstr "全局设置"
-
-msgid "Ignore List"
-msgstr "忽略列表"
-
-msgid "LAN"
-msgstr ""
-
-msgid "LAN IP List"
-msgstr "内网IP列表"
-
-msgid "Local Port"
-msgstr "本地端口"
-
-msgid "Password"
-msgstr "密码"
-
-msgid "Relay Mode"
-msgstr "中继模式"
-
-msgid "Server Address"
-msgstr "服务器地址"
-
-msgid "Server Port"
-msgstr "服务器端口"
-
-msgid "ShadowSocks-libev"
-msgstr "ShadowSocks-libev"
-
-msgid "ShadowSocks-libev is not running"
-msgstr "ShadowSocks-libev 未运行"
-
-msgid "ShadowSocks-libev is running"
-msgstr "ShadowSocks-libev 运行中"
-
-msgid "UDP Forward"
-msgstr "UDP转发"
-
-msgid "UDP Local Port"
-msgstr "UDP本地端口"
-
-msgid "UDP Relay"
-msgstr "UDP中继"
-
-msgid "WAN"
-msgstr ""