add NEW openwrt ssr luci to support multi-server subscription and switch (Alpha)

This commit is contained in:
coolsnowwolf 2018-09-29 10:40:15 +08:00
parent 7cedf8f3de
commit a180d3fb62
35 changed files with 25862 additions and 0 deletions

View File

@ -0,0 +1,238 @@
#
# Copyright (C) 2017 OpenWrt-ssr
# Copyright (C) 2017 yushi studio <ywb94@qq.com>
#
# This is free software, licensed under the GNU General Public License v3.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
PKG_NAME:=openwrt-ssr
PKG_VERSION:=3.1.1
# PKG_RELEASE:=1
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://github.com/shadowsocksrr/shadowsocksr-libev
PKG_SOURCE_VERSION:=d4904568c0bd7e0861c0cbfeaa43740f404db214
PKG_SOURCE_PROTO:=git
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
PKG_LICENSE:=GPLv3
PKG_LICENSE_FILES:=LICENSE
PKG_MAINTAINER:=Akkariiin
#PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)/$(BUILD_VARIANT)/$(PKG_NAME)-$(PKG_VERSION)
PKG_INSTALL:=1
PKG_FIXUP:=autoreconf
PKG_USE_MIPS16:=0
PKG_BUILD_PARALLEL:=1
include $(INCLUDE_DIR)/package.mk
define Package/openwrt-ssr/Default
SECTION:=luci
CATEGORY:=LuCI
SUBMENU:=3. Applications
TITLE:=shadowsocksR-libev LuCI interface
URL:=https://github.com/MrTheUniverse/openwrt-ssr
VARIANT:=$(1)
DEPENDS:=$(3)
PKGARCH:=all
endef
Package/luci-app-shadowsocksR = $(call Package/openwrt-ssr/Default,openssl,(OpenSSL),+libopenssl +libpthread +ipset +ip-full +iptables-mod-tproxy +libpcre +zlib)
Package/luci-app-shadowsocksR-Client = $(call Package/openwrt-ssr/Default,openssl,(OpenSSL),+libopenssl +libpthread +ipset +ip-full +iptables-mod-tproxy +libpcre +zlib)
Package/luci-app-shadowsocksR-Server = $(call Package/openwrt-ssr/Default,openssl,(OpenSSL),+libopenssl +libpthread +ipset +ip-full +iptables-mod-tproxy +libpcre +zlib)
Package/luci-app-shadowsocksR-GFW = $(call Package/openwrt-ssr/Default,openssl,(OpenSSL),+libopenssl +libpthread +ipset +ip-full +iptables-mod-tproxy +libpcre +zlib +dnsmasq-full +coreutils +coreutils-base64 +curl +bash +bind-dig +pdnsd-alt)
define Package/openwrt-ssr/description
LuCI Support for $(1).
endef
Package/luci-app-shadowsocksR/description = $(call Package/openwrt-ssr/description,shadowsocksr-libev Client and Server)
Package/luci-app-shadowsocksR-Client/description = $(call Package/openwrt-ssr/description,shadowsocksr-libev Client)
Package/luci-app-shadowsocksR-Server/description = $(call Package/openwrt-ssr/description,shadowsocksr-libev Server)
Package/luci-app-shadowsocksR-GFW/description = $(call Package/openwrt-ssr/description,shadowsocksr-libev GFW)
define Package/openwrt-ssr/prerm
#!/bin/sh
# check if we are on real system
if [ -z "$${IPKG_INSTROOT}" ]; then
echo "Removing rc.d symlink for shadowsocksr"
/etc/init.d/shadowsocksr disable
/etc/init.d/shadowsocksr stop
echo "Removing firewall rule for shadowsocksr"
uci -q batch <<-EOF >/dev/null
delete firewall.shadowsocksr
commit firewall
EOF
if [ "$(1)" = "GFW" ] ;then
sed -i '/conf-dir/d' /etc/dnsmasq.conf
/etc/init.d/dnsmasq restart
fi
fi
exit 0
endef
Package/luci-app-shadowsocksR/prerm = $(call Package/openwrt-ssr/prerm,shadowsocksr)
Package/luci-app-shadowsocksR-Client/prerm = $(call Package/openwrt-ssr/prerm,shadowsocksr)
Package/luci-app-shadowsocksR-GFW/prerm = $(call Package/openwrt-ssr/prerm,GFW)
define Package/luci-app-shadowsocksR-Server/prerm
#!/bin/sh
if [ -z "$${IPKG_INSTROOT}" ]; then
/etc/init.d/shadowsocksr disable
/etc/init.d/shadowsocksr stop
fi
exit 0
endef
define Package/openwrt-ssr/postinst
#!/bin/sh
if [ -z "$${IPKG_INSTROOT}" ]; then
uci -q batch <<-EOF >/dev/null
delete firewall.shadowsocksr
set firewall.shadowsocksr=include
set firewall.shadowsocksr.type=script
set firewall.shadowsocksr.path=/var/etc/shadowsocksr.include
set firewall.shadowsocksr.reload=1
commit firewall
EOF
fi
if [ -z "$${IPKG_INSTROOT}" ]; then
( . /etc/uci-defaults/luci-shadowsocksr ) && rm -f /etc/uci-defaults/luci-shadowsocksr
chmod 755 /etc/init.d/shadowsocksr >/dev/null 2>&1
/etc/init.d/shadowsocksr enable >/dev/null 2>&1
if [ "$(1)" = "GFW" ] ;then
if [ -f "/etc/dnsmasq.conf" ]; then
str=`cat /etc/dnsmasq.conf|grep conf-dir`
if [ -z "$str" ]; then
echo "conf-dir=/etc/dnsmasq.ssr" >> /etc/dnsmasq.conf
else
sed -i '/conf-dir/d' /etc/dnsmasq.conf
echo "conf-dir=/etc/dnsmasq.ssr" >> /etc/dnsmasq.conf
fi
else
echo "conf-dir=/etc/dnsmasq.ssr" > /etc/dnsmasq.conf
fi
/etc/init.d/dnsmasq restart
fi
fi
exit 0
endef
Package/luci-app-shadowsocksR/postinst = $(call Package/openwrt-ssr/postinst,shadowsocksr)
Package/luci-app-shadowsocksR-Client/postinst = $(call Package/openwrt-ssr/postinst,shadowsocksr)
Package/luci-app-shadowsocksR-GFW/postinst = $(call Package/openwrt-ssr/postinst,GFW)
define Package/luci-app-shadowsocksR-Server/postinst
#!/bin/sh
if [ -z "$${IPKG_INSTROOT}" ]; then
( . /etc/uci-defaults/luci-shadowsocksr ) && rm -f /etc/uci-defaults/luci-shadowsocksr
chmod 755 /etc/init.d/shadowsocksr >/dev/null 2>&1
/etc/init.d/shadowsocksr enable >/dev/null 2>&1
fi
exit 0
endef
CONFIGURE_ARGS += --disable-documentation --disable-ssp
define Install/common
$(INSTALL_DIR) $(1)/usr/lib/lua/luci/controller
$(INSTALL_DATA) ./files/luci/controller/shadowsocksr.lua $(1)/usr/lib/lua/luci/controller/shadowsocksr.lua
$(INSTALL_DIR) $(1)/usr/lib/lua/luci/i18n
$(INSTALL_DATA) ./files/luci/i18n/shadowsocksr.*.lmo $(1)/usr/lib/lua/luci/i18n
$(INSTALL_DIR) $(1)/usr/lib/lua/luci/model/cbi/shadowsocksr
$(INSTALL_DATA) ./files/luci/model/cbi/shadowsocksr/*.lua $(1)/usr/lib/lua/luci/model/cbi/shadowsocksr/
$(INSTALL_DIR) $(1)/usr/lib/lua/luci/view/shadowsocksr
$(INSTALL_DATA) ./files/luci/view/shadowsocksr/*.htm $(1)/usr/lib/lua/luci/view/shadowsocksr/
$(INSTALL_DIR) $(1)/etc/uci-defaults
$(INSTALL_BIN) ./files/root/etc/uci-defaults/luci-shadowsocksr $(1)/etc/uci-defaults/luci-shadowsocksr
$(INSTALL_DIR) $(1)/etc/config
$(INSTALL_DATA) ./files/shadowsocksr.config $(1)/etc/config/shadowsocksr
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) ./files/shadowsocksr.init $(1)/etc/init.d/shadowsocksr
endef
define Package/openwrt-ssr/install
$(call Install/common,$(1))
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/src/ss-redir $(1)/usr/bin/ssr-redir
$(INSTALL_BIN) $(PKG_BUILD_DIR)/src/ss-local $(1)/usr/bin/ssr-local
$(LN) /usr/bin/ssr-local $(1)/usr/bin/ssr-tunnel
#$(INSTALL_BIN) $(PKG_BUILD_DIR)/src/ss-server $(1)/usr/bin/ssr-server
$(INSTALL_BIN) $(PKG_BUILD_DIR)/src/ss-check $(1)/usr/bin/ssr-check
$(INSTALL_BIN) ./files/shadowsocksr.rule $(1)/usr/bin/ssr-rules
$(INSTALL_BIN) ./files/shadowsocksr.monitor $(1)/usr/bin/ssr-monitor
$(INSTALL_BIN) ./files/shadowsocksr.switch $(1)/usr/bin/ssr-switch
$(INSTALL_DIR) $(1)/etc
$(INSTALL_DATA) ./files/china_ssr.txt $(1)/etc/china_ssr.txt
$(INSTALL_DIR) $(1)/usr/share/shadowsocksr
$(INSTALL_DATA) ./files/root/usr/share/shadowsocksr/*.sh $(1)/usr/share/shadowsocksr/
endef
Package/luci-app-shadowsocksR/install = $(call Package/openwrt-ssr/install,$(1),shadowsocksr)
define Package/luci-app-shadowsocksR-Client/install
$(call Install/common,$(1))
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/src/ss-redir $(1)/usr/bin/ssr-redir
#$(INSTALL_BIN) $(PKG_BUILD_DIR)/src/ss-tunnel $(1)/usr/bin/ssr-tunnel
$(INSTALL_BIN) $(PKG_BUILD_DIR)/src/ss-local $(1)/usr/bin/ssr-local
$(INSTALL_BIN) $(PKG_BUILD_DIR)/src/ss-check $(1)/usr/bin/ssr-check
$(INSTALL_BIN) ./files/shadowsocksr.rule $(1)/usr/bin/ssr-rules
$(INSTALL_BIN) ./files/shadowsocksr.monitor $(1)/usr/bin/ssr-monitor
$(INSTALL_BIN) ./files/shadowsocksr.switch $(1)/usr/bin/ssr-switch
$(INSTALL_DIR) $(1)/etc
$(INSTALL_DATA) ./files/china_ssr.txt $(1)/etc/china_ssr.txt
endef
define Package/luci-app-shadowsocksR-Server/install
$(call Install/common,$(1))
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/src/ss-server $(1)/usr/bin/ssr-server
$(INSTALL_BIN) ./files/shadowsocksr.rule $(1)/usr/bin/ssr-rules
$(INSTALL_BIN) ./files/shadowsocksr.monitor $(1)/usr/bin/ssr-monitor
endef
define Package/luci-app-shadowsocksR-GFW/install
$(call Install/common,$(1))
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/src/ss-redir $(1)/usr/bin/ssr-redir
$(INSTALL_BIN) $(PKG_BUILD_DIR)/src/ss-local $(1)/usr/bin/ssr-local
$(LN) /usr/bin/ssr-local $(1)/usr/bin/ssr-tunnel
#$(INSTALL_BIN) $(PKG_BUILD_DIR)/src/ss-server $(1)/usr/bin/ssr-server
$(INSTALL_BIN) $(PKG_BUILD_DIR)/src/ss-check $(1)/usr/bin/ssr-check
$(INSTALL_BIN) ./files/shadowsocksr.rule $(1)/usr/bin/ssr-rules
$(INSTALL_BIN) ./files/shadowsocksr.monitor $(1)/usr/bin/ssr-monitor
$(INSTALL_BIN) ./files/shadowsocksr.gfw $(1)/usr/bin/ssr-gfw
$(INSTALL_BIN) ./files/shadowsocksr.ad $(1)/usr/bin/ssr-ad
$(INSTALL_BIN) ./files/shadowsocksr.switch $(1)/usr/bin/ssr-switch
$(INSTALL_DIR) $(1)/etc/dnsmasq.ssr
$(INSTALL_DATA) ./files/gfw_list.conf $(1)/etc/dnsmasq.ssr/gfw_list.conf
$(INSTALL_DATA) ./files/custom_forward.conf $(1)/etc/dnsmasq.ssr/custom_forward.conf
$(INSTALL_DATA) ./files/ad.conf $(1)/etc/dnsmasq.ssr/ad.conf
$(INSTALL_DIR) $(1)/etc
$(INSTALL_DATA) ./files/china_ssr.txt $(1)/etc/china_ssr.txt
$(INSTALL_DIR) $(1)/usr/share/shadowsocksr
$(INSTALL_DATA) ./files/root/usr/share/shadowsocksr/*.sh $(1)/usr/share/shadowsocksr/
endef
#$(eval $(call BuildPackage,luci-app-shadowsocksR))
#$(eval $(call BuildPackage,luci-app-shadowsocksR-Client))
#$(eval $(call BuildPackage,luci-app-shadowsocksR-Server))
$(eval $(call BuildPackage,luci-app-shadowsocksR-GFW))

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,68 @@
server=/.skype.com/127.0.0.1#5353
ipset=/.skype.com/gfwlist
server=/.buzzfeed.com/127.0.0.1#5353
ipset=/.buzzfeed.com/gfwlist
server=/.openairinterface.org/127.0.0.1#5353
ipset=/.openairinterface.org/gfwlist
server=/.apple.news/127.0.0.1#5353
ipset=/.apple.news/gfwlist
server=/.dropboxstatic.com/127.0.0.1#5353
ipset=/.dropboxstatic.com/gfwlist
server=/.github.com/127.0.0.1#5353
ipset=/.github.com/gfwlist
server=/.amazonaws.com/127.0.0.1#5353
ipset=/.amazonaws.com/gfwlist
server=/.aws.amazon.com/127.0.0.1#5353
ipset=/.aws.amazon.com/gfwlist
server=/.sublimetext.com/127.0.0.1#5353
ipset=/.sublimetext.com/gfwlist
server=/.clockwise.ee/127.0.0.1#5353
ipset=/.clockwise.ee/gfwlist
server=/.adobe.com/127.0.0.1#5353
ipset=/.adobe.com/gfwlist
server=/.nutaq.com/127.0.0.1#5353
ipset=/.nutaq.com/gfwlist
server=/.uploaded.net/127.0.0.1#5353
ipset=/.uploaded.net/gfwlist
server=/.whatsapp.com/127.0.0.1#5353
ipset=/.whatsapp.com/gfwlist
server=/.whatsapp.net/127.0.0.1#5353
ipset=/.whatsapp.net/gfwlist
server=/.backpackers.com.tw/127.0.0.1#5353
ipset=/.backpackers.com.tw/gfwlst
server=/.kknews.cc/127.0.0.1#5353
ipset=/.kknews.cc/gfwlist
server=/.eurecom.fr/127.0.0.1#5353
ipset=/.eurecom.fr/gfwlist
server=/.91smartyun.pt/127.0.0.1#5353
ipset=/.91smartyun.pt/gfwlist
server=/.gdax.com/127.0.0.1#5353
ipset=/.gdax.com/gfwlist
server=/.coinsquare.io/127.0.0.1#5353
ipset=/.coinsquare.io/gfwlist
server=/.coindesk.com/127.0.0.1#5353
ipset=/.coindesk.com/gfwlist
server=/.trouter.io/127.0.0.1#5353
ipset=/.trouter.io/gfwlist
server=/.cryptocompare.com/127.0.0.1#5353
ipset=/.cryptocompare.com/gfwlist
server=/.github.com/127.0.0.1#5353
ipset=/.github.com/gfwlist
server=/.azureedge.net/127.0.0.1#5353
ipset=/.azureedge.net/gfwlist
server=/.wsj.net/127.0.0.1#5353
ipset=/.wsj.net/gfwlist
server=/.bitfinex.com/127.0.0.1#5353
ipset=/.bitfinex.com/gfwlist
server=/.textnow.me/127.0.0.1#5353
ipset=/.textnow.me/gfwlist
server=/.textnow.com/127.0.0.1#5353
ipset=/.textnow.com/gfwlist
server=/.isnssdk.com/127.0.0.1#5353
ipset=/.isnssdk.com/gfwlist
server=/.snssdk.com/127.0.0.1#5353
ipset=/.snssdk.com/gfwlist
server=/.ampproject.org/127.0.0.1#5353
ipset=/.ampproject.org/gfwlist
server=/.cloudfront.net/127.0.0.1#5353
ipset=/.cloudfront.net/gfwlist

View File

@ -0,0 +1,38 @@
# Change the following lines if you want dnsmasq to serve SRV
# records.
# You may add multiple srv-host lines.
# The fields are <name>,<target>,<port>,<priority>,<weight>
# A SRV record sending LDAP for the example.com domain to
# ldapserver.example.com port 289
#srv-host=_ldap._tcp.example.com,ldapserver.example.com,389
# Two SRV records for LDAP, each with different priorities
#srv-host=_ldap._tcp.example.com,ldapserver.example.com,389,1
#srv-host=_ldap._tcp.example.com,ldapserver.example.com,389,2
# A SRV record indicating that there is no LDAP server for the domain
# example.com
#srv-host=_ldap._tcp.example.com
# The following line shows how to make dnsmasq serve an arbitrary PTR
# record. This is useful for DNS-SD.
# The fields are <name>,<target>
#ptr-record=_http._tcp.dns-sd-services,"New Employee Page._http._tcp.dns-sd-services"
# Change the following lines to enable dnsmasq to serve TXT records.
# These are used for things like SPF and zeroconf.
# The fields are <name>,<text>,<text>...
#Example SPF.
#txt-record=example.com,"v=spf1 a -all"
#Example zeroconf
#txt-record=_http._tcp.example.com,name=value,paper=A4
# Provide an alias for a "local" DNS name. Note that this _only_ works
# for targets which are names from DHCP or /etc/hosts. Give host
# "bert" another name, bertrand
# The fields are <cname>,<target>
#cname=bertand,bert
conf-dir=/etc/dnsmasq.ssr

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,166 @@
-- Licensed to the public under the GNU General Public License v3.
module("luci.controller.shadowsocksr", package.seeall)
function index()
if not nixio.fs.access("/etc/config/shadowsocksr") then
return
end
if nixio.fs.access("/usr/bin/ssr-redir")
then
entry({"admin", "services", "shadowsocksr"},alias("admin", "services", "shadowsocksr", "client"),_("ShadowSocksR"), 10).dependent = true
entry({"admin", "services", "shadowsocksr", "client"},arcombine(cbi("shadowsocksr/client"), cbi("shadowsocksr/client-config")),_("SSR Client"), 10).leaf = true
elseif nixio.fs.access("/usr/bin/ssr-server")
then
entry({"admin", "services", "shadowsocksr"},alias("admin", "services", "shadowsocksr", "server"),_("ShadowSocksR"), 10).dependent = true
else
return
end
entry({"admin", "services", "shadowsocksr", "servers"},cbi("shadowsocksr/servers"),_("Subscription"), 20).leaf = true
entry({"admin", "services", "shadowsocksr", "status"},cbi("shadowsocksr/status"),_("Status"), 30).leaf = true
entry({"admin", "services", "shadowsocksr", "check"}, call("check_status"))
entry({"admin", "services", "shadowsocksr", "refresh"}, call("refresh_data"))
entry({"admin", "services", "shadowsocksr", "checkport"}, call("check_port"))
end
function check_status()
local set ="/usr/bin/ssr-check www." .. luci.http.formvalue("set") .. ".com 80 3 1"
sret=luci.sys.call(set)
if sret== 0 then
retstring ="0"
else
retstring ="1"
end
luci.http.prepare_content("application/json")
luci.http.write_json({ ret=retstring })
end
function refresh_data()
local set =luci.http.formvalue("set")
local icount =0
if set == "gfw_data" then
if nixio.fs.access("/usr/bin/wget-ssl") then
refresh_cmd="wget-ssl --no-check-certificate https://raw.githubusercontent.com/gfwlist/gfwlist/master/gfwlist.txt -O /tmp/gfw.b64"
else
refresh_cmd="wget -O /tmp/gfw.b64 http://iytc.net/tools/list.b64"
end
sret=luci.sys.call(refresh_cmd .. " 2>/dev/null")
if sret== 0 then
luci.sys.call("/usr/bin/ssr-gfw")
icount = luci.sys.exec("cat /tmp/gfwnew.txt | wc -l")
if tonumber(icount)>1000 then
oldcount=luci.sys.exec("cat /etc/dnsmasq.ssr/gfw_list.conf | wc -l")
if tonumber(icount) ~= tonumber(oldcount) then
luci.sys.exec("cp -f /tmp/gfwnew.txt /etc/dnsmasq.ssr/gfw_list.conf")
retstring=tostring(math.ceil(tonumber(icount)/2))
else
retstring ="0"
end
else
retstring ="-1"
end
luci.sys.exec("rm -f /tmp/gfwnew.txt ")
else
retstring ="-1"
end
elseif set == "ip_data" then
refresh_cmd="wget -O- 'http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest' 2>/dev/null| awk -F\\| '/CN\\|ipv4/ { printf(\"%s/%d\\n\", $4, 32-log($5)/log(2)) }' > /tmp/china_ssr.txt"
sret=luci.sys.call(refresh_cmd)
icount = luci.sys.exec("cat /tmp/china_ssr.txt | wc -l")
if sret== 0 and tonumber(icount)>1000 then
oldcount=luci.sys.exec("cat /etc/china_ssr.txt | wc -l")
if tonumber(icount) ~= tonumber(oldcount) then
luci.sys.exec("cp -f /tmp/china_ssr.txt /etc/china_ssr.txt")
retstring=tostring(tonumber(icount))
else
retstring ="0"
end
else
retstring ="-1"
end
luci.sys.exec("rm -f /tmp/china_ssr.txt ")
else
local need_process = 0
if nixio.fs.access("/usr/bin/wget-ssl") then
refresh_cmd="wget-ssl --no-check-certificate -O - https://easylist-downloads.adblockplus.org/easylistchina+easylist.txt > /tmp/adnew.conf"
need_process = 1
else
refresh_cmd="wget -O /tmp/ad.conf http://iytc.net/tools/ad.conf"
end
sret=luci.sys.call(refresh_cmd .. " 2>/dev/null")
if sret== 0 then
if need_process == 1 then
luci.sys.call("/usr/bin/ssr-ad")
end
icount = luci.sys.exec("cat /tmp/ad.conf | wc -l")
if tonumber(icount)>1000 then
if nixio.fs.access("/etc/dnsmasq.ssr/ad.conf") then
oldcount=luci.sys.exec("cat /etc/dnsmasq.ssr/ad.conf | wc -l")
else
oldcount=0
end
if tonumber(icount) ~= tonumber(oldcount) then
luci.sys.exec("cp -f /tmp/ad.conf /etc/dnsmasq.ssr/ad.conf")
retstring=tostring(math.ceil(tonumber(icount)))
if oldcount==0 then
luci.sys.call("/etc/init.d/dnsmasq restart")
end
else
retstring ="0"
end
else
retstring ="-1"
end
luci.sys.exec("rm -f /tmp/ad.conf ")
else
retstring ="-1"
end
end
luci.http.prepare_content("application/json")
luci.http.write_json({ ret=retstring ,retcount=icount})
end
function check_port()
local set=""
local retstring="<br /><br />"
local s
local server_name = ""
local shadowsocksr = "shadowsocksr"
local uci = luci.model.uci.cursor()
local iret=1
uci:foreach(shadowsocksr, "servers", function(s)
if s.alias then
server_name=s.alias
elseif s.server and s.server_port then
server_name= "%s:%s" %{s.server, s.server_port}
end
iret=luci.sys.call(" ipset add ss_spec_wan_ac " .. s.server .. " 2>/dev/null")
socket = nixio.socket("inet", "stream")
socket:setopt("socket", "rcvtimeo", 3)
socket:setopt("socket", "sndtimeo", 3)
ret=socket:connect(s.server,s.server_port)
if tostring(ret) == "true" then
socket:close()
retstring =retstring .. "<font color='green'>[" .. server_name .. "] OK.</font><br />"
else
retstring =retstring .. "<font color='red'>[" .. server_name .. "] Error.</font><br />"
end
if iret== 0 then
luci.sys.call(" ipset del ss_spec_wan_ac " .. s.server)
end
end)
luci.http.prepare_content("application/json")
luci.http.write_json({ ret=retstring })
end

View File

@ -0,0 +1,374 @@
msgid ""
msgstr "Content-Type: text/plain; charset=UTF-8\n"
msgid "ShadowSocksR Client"
msgstr "ShadowSocksR 客户端"
msgid "Enable"
msgstr "启用"
msgid "Disable"
msgstr "停用"
msgid "ShadowSocksR is running"
msgstr "ShadowSocksR 客户端运行中"
msgid "ShadowSocksR is not running"
msgstr "ShadowSocksR 客户端未运行"
msgid "Global Setting"
msgstr "全局设置"
msgid "Global Server"
msgstr "全局服务器"
msgid "ShadowSocksR SOCK5 Proxy is running"
msgstr "ShadowSocksR SOCK5代理运行中"
msgid "UDP Relay Server"
msgstr "UDP中继服务器"
msgid "Same as Global Server"
msgstr "与全局服务器相同"
msgid "Servers Setting"
msgstr "服务器配置"
msgid "Alias(optional)"
msgstr "别名(可选)"
msgid "Onetime Authentication"
msgstr "一次验证"
msgid "Server Address"
msgstr "服务器地址"
msgid "Server Port"
msgstr "服务器端口"
msgid "Local Port"
msgstr "本地端口"
msgid "Connection Timeout"
msgstr "连接超时"
msgid "Password"
msgstr "密码"
msgid "Encrypt Method"
msgstr "加密方式"
msgid "Protocol"
msgstr "传输协议"
msgid "Protocol param(optional)"
msgstr "传输协议参数(可选)"
msgid "Obfs"
msgstr "混淆插件"
msgid "Obfs param(optional)"
msgstr "混淆参数(可选)"
msgid "Enable Tunnel(DNS)"
msgstr "启用隧道DNS转发"
msgid "Tunnel Port"
msgstr "隧道DNS本地端口"
msgid "Forwarding Tunnel"
msgstr "隧道DNS转发地址"
msgid "Access Control"
msgstr "访问控制"
msgid "Interfaces - WAN"
msgstr "接口 - WAN"
msgid "Bypassed IP List"
msgstr "被忽略IP列表"
msgid "NULL - As Global Proxy"
msgstr "留空 - 作为全局代理"
msgid "Bypassed IP"
msgstr "额外被忽略IP"
msgid "Forwarded IP"
msgstr "强制走代理IP"
msgid "Interfaces - LAN"
msgstr "接口 - LAN"
msgid "LAN Access Control"
msgstr "内网访问控制"
msgid "Allow listed only"
msgstr "仅允许列表内"
msgid "Allow all except listed"
msgstr "仅允许列表外"
msgid "LAN Host List"
msgstr "内网主机列表"
msgid "SSR Client"
msgstr "客户端"
msgid "SSR Server"
msgstr "服务端"
msgid "ShadowSocksR Server"
msgstr "ShadowSocksR 服务端"
msgid "ShadowSocksR Server is running"
msgstr "ShadowSocksR 服务端运行中"
msgid "ShadowSocksR Server is not running"
msgstr "ShadowSocksR 服务端未运行"
msgid "Enable Server"
msgstr "启动服务端"
msgid "Server Setting"
msgstr "服务端配置"
msgid "KcpTun Enable"
msgstr "KcpTun 启用"
msgid "bin:/usr/bin/ssr-kcptun"
msgstr "二进制文件:/usr/bin/ssr-kcptun"
msgid "KcpTun Port"
msgstr "KcpTun 端口"
msgid "KcpTun Param"
msgstr "KcpTun 参数"
msgid "KcpTun Password"
msgstr "KcpTun 密码"
msgid "Haven't a Kcptun executable file"
msgstr "不存在Kcptun可执行文件请下载Kcptun可执行文件并改名放入/usr/bin/ssr-kcptun"
msgid "Not a Kcptun executable file"
msgstr "Kcptun可执行文件格式不正确请确认是否正确下载了路由器对应的可执行文件"
msgid "Enable Process Monitor"
msgstr "启用进程监控"
msgid "Edit ShadowSocksR Server"
msgstr "编辑服务器配置"
msgid "Alias"
msgstr "别名"
msgid "SOCKS5 Proxy"
msgstr "SOCKS5代理"
msgid "Server"
msgstr "服务器"
msgid "TCP Fast Open"
msgstr "TCP快速打开"
msgid "Status"
msgstr "状态"
msgid "Unknown"
msgstr "未知"
msgid "Running Status"
msgstr "运行状态"
msgid "Global Client"
msgstr "全局客户端"
msgid "Global SSR Server"
msgstr "SSR服务端"
msgid "DNS Tunnel"
msgstr "DNS 隧道"
msgid "IPK Version"
msgstr "IPK 版本号"
msgid "KcpTun Version"
msgstr "KcpTun 版本号"
msgid "Not exist"
msgstr "未安装可执行文件"
msgid "IPK Installation Time"
msgstr "IPK 安装时间"
msgid "Project"
msgstr "项目地址"
msgid "Not Running"
msgstr "未运行"
msgid "Running"
msgstr "运行中"
msgid "Enable GFW mode"
msgstr "启用 GFW 模式"
msgid "Running Mode"
msgstr "运行模式"
msgid "IP Route Mode"
msgstr "IP路由模式"
msgid "GFW List Mode"
msgstr "GFW列表模式"
msgid "Router Proxy"
msgstr "路由器访问控制"
msgid "Normal Proxy"
msgstr "正常代理"
msgid "Bypassed Proxy"
msgstr "不走代理"
msgid "Forwarded Proxy"
msgstr "强制走代理"
msgid "UDP Relay"
msgstr "UDP中继"
msgid "Google Connectivity"
msgstr "【谷歌】连通性检查"
msgid "Baidu Connectivity"
msgstr "【百度】连通性检查"
msgid "No Check"
msgstr "未检查"
msgid "Check"
msgstr "检查"
msgid "Connect OK"
msgstr "连接正常"
msgid "Connect Error"
msgstr "连接错误"
msgid "Check..."
msgstr "正在检查.."
msgid "Proxy Check"
msgstr "代理检查"
msgid "GFW List Data"
msgstr "【GFW列表】数据库"
msgid "China IP Data"
msgstr "【国内IP段】数据库"
msgid "Records"
msgstr "条记录"
msgid "Refresh Data"
msgstr "更新数据库"
msgid "Refresh..."
msgstr "正在更新,请稍候.."
msgid "Refresh OK!"
msgstr "更新成功!"
msgid "Refresh Error!"
msgstr "更新失败!"
msgid "No new data!"
msgstr "你已经是最新数据,无需更新!"
msgid "Total Records:"
msgstr "新的总纪录数:"
msgid "Check Server Port"
msgstr "【服务器端口】检查"
msgid "Check Connect"
msgstr "检查连通性"
msgid "Check Server"
msgstr "检查服务器"
msgid "Auto Switch"
msgstr "自动切换"
msgid "Enable Auto Switch"
msgstr "启用自动切换"
msgid "Switch check cycly(second)"
msgstr "自动切换检查周期(秒)"
msgid "Check timout(second)"
msgstr "切换检查超时时间(秒)"
msgid "Advertising Data"
msgstr "【广告屏蔽】数据库"
msgid "DNS Server IP and Port"
msgstr "DNS服务器地址和端口"
msgid "Resolve Dns Mode"
msgstr "DNS解析方式"
msgid "Use SSR DNS Tunnel"
msgstr "使用SSR-DNS隧道"
msgid "Use Pdnsd"
msgstr "使用Pdnsd"
msgid "Use Other DNS Tunnel(Need to install)"
msgstr "使用其他DNS转发(需要自己安装)"
msgid "Import SSR"
msgstr "导入ssr配置信息"
msgid "Export SSR"
msgstr "导出ssr配置信息"
msgid "Import SSR successfully."
msgstr "成功导入SSR。"
msgid "Invalid SSR format."
msgstr "无效的SSR格式。"
msgid "User cancelled."
msgstr "用户已取消。"
msgid "Paste ssr url here"
msgstr "在此处粘贴ssr://网址"
msgid "Unable to copy SSR to clipboard."
msgstr "无法复制SSR网址到剪贴板。"
msgid "Copy SSR to clipboard successfully."
msgstr "成功复制SSR网址到剪贴板。"
msgid "Subscription"
msgstr "订阅"
msgid "Auto Update"
msgstr "自动更新"
msgid "Through proxy update"
msgstr "通过代理更新"
msgid "Update time (every day)"
msgstr "更新时间 (每天)"
msgid "Subscribe URL"
msgstr "订阅链接"
msgid "Update"
msgstr "更新"

View File

@ -0,0 +1,165 @@
-- Copyright (C) 2017 yushi studio <ywb94@qq.com> github.com/ywb94
-- Licensed to the public under the GNU General Public License v3.
local m, s, o,kcp_enable
local shadowsocksr = "shadowsocksr"
local uci = luci.model.uci.cursor()
local ipkg = require("luci.model.ipkg")
local fs = require "nixio.fs"
local sys = require "luci.sys"
local sid = arg[1]
local function isKcptun(file)
if not fs.access(file, "rwx", "rx", "rx") then
fs.chmod(file, 755)
end
local str = sys.exec(file .. " -v | awk '{printf $1}'")
return (str:lower() == "kcptun")
end
local server_table = {}
local encrypt_methods = {
"none",
"table",
"rc4",
"rc4-md5-6",
"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",
"cast5-cfb",
"des-cfb",
"idea-cfb",
"rc2-cfb",
"seed-cfb",
"salsa20",
"chacha20",
"chacha20-ietf",
}
local protocol = {
"origin",
"verify_deflate",
"auth_sha1_v4",
"auth_aes128_sha1",
"auth_aes128_md5",
"auth_chain_a",
"auth_chain_b",
"auth_chain_c",
"auth_chain_d",
"auth_chain_e",
"auth_chain_f",
}
obfs = {
"plain",
"http_simple",
"http_post",
"random_head",
"tls1.2_ticket_auth",
}
m = Map(shadowsocksr, translate("Edit ShadowSocksR Server"))
m.redirect = luci.dispatcher.build_url("admin/services/shadowsocksr/client")
if m.uci:get(shadowsocksr, sid) ~= "servers" then
luci.http.redirect(m.redirect)
return
end
-- [[ Servers Setting ]]--
s = m:section(NamedSection, sid, "servers")
s.anonymous = true
s.addremove = false
o = s:option(Value, "alias", translate("Alias(optional)"))
o = s:option(Flag, "auth_enable", translate("Onetime Authentication"))
o.rmempty = false
o = s:option(Flag, "switch_enable", translate("Auto Switch"))
o.rmempty = false
o = s:option(Value, "server", translate("Server Address"))
o.datatype = "host"
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 = 1234
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 _, v in ipairs(encrypt_methods) do o:value(v) end
o.rmempty = false
o = s:option(ListValue, "protocol", translate("Protocol"))
for _, v in ipairs(protocol) do o:value(v) end
o.rmempty = false
o = s:option(Value, "protocol_param", translate("Protocol param(optional)"))
o = s:option(ListValue, "obfs", translate("Obfs"))
for _, v in ipairs(obfs) do o:value(v) end
o.rmempty = false
o = s:option(Value, "obfs_param", translate("Obfs param(optional)"))
o = s:option(Flag, "fast_open", translate("TCP Fast Open"))
o.rmempty = false
kcp_enable = s:option(Flag, "kcp_enable", translate("KcpTun Enable"), translate("bin:/usr/bin/ssr-kcptun"))
kcp_enable.rmempty = false
o = s:option(Value, "kcp_port", translate("KcpTun Port"))
o.datatype = "port"
o.default = 4000
function o.validate(self, value, section)
local kcp_file="/usr/bin/ssr-kcptun"
local enable = kcp_enable:formvalue(section) or kcp_enable.disabled
if enable == kcp_enable.enabled then
if not fs.access(kcp_file) then
return nil, translate("Haven't a Kcptun executable file")
elseif not isKcptun(kcp_file) then
return nil, translate("Not a Kcptun executable file")
end
end
return value
end
o = s:option(Value, "kcp_password", translate("KcpTun Password"))
o.password = true
o = s:option(Value, "kcp_param", translate("KcpTun Param"))
o.default = "--nocomp"
o = s:option(DummyValue,"ssr_url","SSR URL")
o.rawhtml = true
o.template = "shadowsocksr/ssrurl"
o.value =sid
return m

View File

@ -0,0 +1,376 @@
-- Copyright (C) 2017 yushi studio <ywb94@qq.com> github.com/ywb94
-- Licensed to the public under the GNU General Public License v3.
local m, s, sec, o, kcp_enable
local shadowsocksr = "shadowsocksr"
local uci = luci.model.uci.cursor()
local ipkg = require("luci.model.ipkg")
local sys = require "luci.sys"
m = Map(shadowsocksr, translate("ShadowSocksR Client"))
local server_table = {}
local encrypt_methods = {
"none",
"table",
"rc4",
"rc4-md5-6",
"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",
"cast5-cfb",
"des-cfb",
"idea-cfb",
"rc2-cfb",
"seed-cfb",
"salsa20",
"chacha20",
"chacha20-ietf",
}
local protocol = {
"origin",
"verify_deflate",
"auth_sha1_v4",
"auth_aes128_sha1",
"auth_aes128_md5",
"auth_chain_a",
"auth_chain_b",
"auth_chain_c",
"auth_chain_d",
"auth_chain_e",
"auth_chain_f",
}
obfs = {
"plain",
"http_simple",
"http_post",
"random_head",
"tls1.2_ticket_auth",
}
local raw_mode = {
"faketcp",
"udp",
"icmp",
}
local seq_mode = {
"0",
"1",
"2",
"3",
"4",
}
local cipher_mode = {
"none",
"xor",
"aes128cbc",
}
local auth_mode = {
"none",
"simple",
"md5",
"crc32",
}
local speeder_mode = {
"0",
"1",
}
uci:foreach(shadowsocksr, "servers", function(s)
if s.alias then
server_table[s[".name"]] = s.alias
elseif s.server and s.server_port then
server_table[s[".name"]] = "%s:%s" %{s.server, s.server_port}
end
end)
-- [[ Servers Setting ]]--
sec = m:section(TypedSection, "servers", translate("Servers Setting"))
sec.anonymous = true
sec.addremove = true
sec.sortable = true
sec.template = "cbi/tblsection"
sec.extedit = luci.dispatcher.build_url("admin/services/shadowsocksr/client/%s")
function sec.create(...)
local sid = TypedSection.create(...)
if sid then
luci.http.redirect(sec.extedit % sid)
return
end
end
o = sec:option(DummyValue, "alias", translate("Alias"))
function o.cfgvalue(...)
return Value.cfgvalue(...) or translate("None")
end
o = sec:option(DummyValue, "server", translate("Server Address"))
function o.cfgvalue(...)
return Value.cfgvalue(...) or "?"
end
o = sec:option(DummyValue, "server_port", translate("Server Port"))
function o.cfgvalue(...)
return Value.cfgvalue(...) or "?"
end
o = sec:option(DummyValue, "encrypt_method", translate("Encrypt Method"))
function o.cfgvalue(...)
return Value.cfgvalue(...) or "?"
end
o = sec:option(DummyValue, "protocol", translate("Protocol"))
function o.cfgvalue(...)
return Value.cfgvalue(...) or "?"
end
o = sec:option(DummyValue, "obfs", translate("Obfs"))
function o.cfgvalue(...)
return Value.cfgvalue(...) or "?"
end
o = sec:option(DummyValue, "kcp_enable", translate("KcpTun"))
function o.cfgvalue(...)
return Value.cfgvalue(...) or "?"
end
o = sec:option(DummyValue, "switch_enable", translate("Auto Switch"))
function o.cfgvalue(...)
return Value.cfgvalue(...) or "0"
end
-- [[ Global Setting ]]--
s = m:section(TypedSection, "global", translate("Global Setting"))
s.anonymous = true
o = s:option(ListValue, "global_server", translate("Global Server"))
o:value("nil", translate("Disable"))
for k, v in pairs(server_table) do o:value(k, v) end
o.default = "nil"
o.rmempty = false
o = s:option(ListValue, "udp_relay_server", translate("UDP Relay Server"))
o:value("", translate("Disable"))
o:value("same", translate("Same as Global Server"))
for k, v in pairs(server_table) do o:value(k, v) end
o = s:option(Flag, "monitor_enable", translate("Enable Process Monitor"))
o.rmempty = false
o = s:option(Flag, "enable_switch", translate("Enable Auto Switch"))
o.rmempty = false
o = s:option(Value, "switch_time", translate("Switch check cycly(second)"))
o.datatype = "uinteger"
o:depends("enable_switch", "1")
o.default = 600
o = s:option(Value, "switch_timeout", translate("Check timout(second)"))
o.datatype = "uinteger"
o:depends("enable_switch", "1")
o.default = 3
if nixio.fs.access("/usr/bin/ssr-gfw") then
o = s:option(ListValue, "run_mode", translate("Running Mode"))
o:value("router", translate("IP Route Mode"))
o:value("gfw", translate("GFW List Mode"))
o = s:option(ListValue, "pdnsd_enable", translate("Resolve Dns Mode"))
o:depends("run_mode", "gfw")
o:value("0", translate("Use SSR DNS Tunnel"))
o:value("1", translate("Use Pdnsd(Need to install)"))
o:value("2", translate("Use Other DNS Tunnel(Need to install)"))
o = s:option(Flag, "tunnel_enable", translate("Enable Tunnel(DNS)"))
o:depends("run_mode", "router")
o.default = 0
o = s:option(Value, "tunnel_port", translate("Tunnel Port"))
o:depends("run_mode", "router")
o.datatype = "port"
o.default = 5300
else
o = s:option(Flag, "tunnel_enable", translate("Enable Tunnel(DNS)"))
o.default = 0
o = s:option(Value, "tunnel_port", translate("Tunnel Port"))
o.datatype = "port"
o.default = 5300
end
o = s:option(Value, "tunnel_forward", translate("DNS Server IP and Port"))
o.default = "8.8.4.4:53"
o.rmempty = false
-- [[ SOCKS5 Proxy ]]--
s = m:section(TypedSection, "socks5_proxy", translate("SOCKS5 Proxy"))
s.anonymous = true
o = s:option(ListValue, "server", translate("Server"))
o:value("nil", translate("Disable"))
for k, v in pairs(server_table) do o:value(k, v) end
o.default = "nil"
o.rmempty = false
o = s:option(Value, "local_port", translate("Local Port"))
o.datatype = "port"
o.default = 1234
o.rmempty = false
-- [[ udp2raw ]]--
if nixio.fs.access("/usr/bin/udp2raw") then
s = m:section(TypedSection, "udp2raw", translate("udp2raw tunnel"))
s.anonymous = true
o = s:option(Flag, "udp2raw_enable", translate("Enable udp2raw"))
o.default = 0
o.rmempty = false
o = s:option(Value, "server", translate("Server Address"))
o.datatype = "host"
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.rmempty = false
o = s:option(Value, "key", translate("Password"))
o.password = true
o.rmempty = false
o = s:option(ListValue, "raw_mode", translate("Raw Mode"))
for _, v in ipairs(raw_mode) do o:value(v) end
o.default = "faketcp"
o.rmempty = false
o = s:option(ListValue, "seq_mode", translate("Seq Mode"))
for _, v in ipairs(seq_mode) do o:value(v) end
o.default = "3"
o.rmempty = false
o = s:option(ListValue, "cipher_mode", translate("Cipher Mode"))
for _, v in ipairs(cipher_mode) do o:value(v) end
o.default = "xor"
o.rmempty = false
o = s:option(ListValue, "auth_mode", translate("Auth Mode"))
for _, v in ipairs(auth_mode) do o:value(v) end
o.default = "simple"
o.rmempty = false
end
-- [[ udpspeeder ]]--
if nixio.fs.access("/usr/bin/udpspeeder") then
s = m:section(TypedSection, "udpspeeder", translate("UDPspeeder"))
s.anonymous = true
o = s:option(Flag, "udpspeeder_enable", translate("Enable UDPspeeder"))
o.default = 0
o.rmempty = false
o = s:option(Value, "server", translate("Server Address"))
o.datatype = "host"
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.rmempty = false
o = s:option(Value, "key", translate("Password"))
o.password = true
o.rmempty = false
o = s:option(ListValue, "speeder_mode", translate("Speeder Mode"))
for _, v in ipairs(speeder_mode) do o:value(v) end
o.default = "0"
o.rmempty = false
o = s:option(Value, "fec", translate("Fec"))
o.default = "20:10"
o.rmempty = false
o = s:option(Value, "mtu", translate("Mtu"))
o.datatype = "uinteger"
o.default = 1250
o.rmempty = false
o = s:option(Value, "queue_len", translate("Queue Len"))
o.datatype = "uinteger"
o.default = 200
o.rmempty = false
o = s:option(Value, "timeout", translate("Fec Timeout"))
o.datatype = "uinteger"
o.default = 8
o.rmempty = false
end
-- [[ Access Control ]]--
s = m:section(TypedSection, "access_control", translate("Access Control"))
s.anonymous = true
-- Part of WAN
s:tab("wan_ac", translate("Interfaces - WAN"))
o = s:taboption("wan_ac", Value, "wan_bp_list", translate("Bypassed IP List"))
o:value("/dev/null", translate("NULL - As Global Proxy"))
o.default = "/dev/null"
o.rmempty = false
o = s:taboption("wan_ac", DynamicList, "wan_bp_ips", translate("Bypassed IP"))
o.datatype = "ip4addr"
o = s:taboption("wan_ac", DynamicList, "wan_fw_ips", translate("Forwarded IP"))
o.datatype = "ip4addr"
-- Part of LAN
s:tab("lan_ac", translate("Interfaces - LAN"))
o = s:taboption("lan_ac",ListValue, "router_proxy", translate("Router Proxy"))
o:value("1", translatef("Normal Proxy"))
o:value("0", translatef("Bypassed Proxy"))
o:value("2", translatef("Forwarded Proxy"))
o.rmempty = false
o = s:taboption("lan_ac", ListValue, "lan_ac_mode", translate("LAN Access Control"))
o:value("0", translate("Disable"))
o:value("w", translate("Allow listed only"))
o:value("b", translate("Allow all except listed"))
o.rmempty = false
o = s:taboption("lan_ac", DynamicList, "lan_ac_ips", translate("LAN Host List"))
o.datatype = "ipaddr"
luci.ip.neighbors({ family = 4 }, function(entry)
if entry.reachable then
o:value(entry.dest:string())
end
end)
return m

View File

@ -0,0 +1,108 @@
-- Copyright (C) 2017 yushi studio <ywb94@qq.com>
-- Licensed to the public under the GNU General Public License v3.
local m, s, o
local shadowsocksr = "shadowsocksr"
local sid = arg[1]
local encrypt_methods = {
"table",
"rc4",
"rc4-md5",
"rc4-md5-6",
"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",
"cast5-cfb",
"des-cfb",
"idea-cfb",
"rc2-cfb",
"seed-cfb",
"salsa20",
"chacha20",
"chacha20-ietf",
}
local protocol = {
"origin",
"verify_deflate",
"auth_sha1_v4",
"auth_aes128_sha1",
"auth_aes128_md5",
"auth_chain_a",
}
obfs = {
"plain",
"http_simple",
"http_post",
"random_head",
"tls1.2_ticket_auth",
"tls1.2_ticket_fastauth",
}
m = Map(shadowsocksr, translate("Edit ShadowSocksR Server"))
m.redirect = luci.dispatcher.build_url("admin/services/shadowsocksr/server")
if m.uci:get(shadowsocksr, sid) ~= "server_config" then
luci.http.redirect(m.redirect)
return
end
-- [[ Server Setting ]]--
s = m:section(NamedSection, sid, "server_config")
s.anonymous = true
s.addremove = false
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.default = "0.0.0.0"
o.rmempty = false
o = s:option(Value, "server_port", translate("Server Port"))
o.datatype = "port"
o.default = 8388
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 _, v in ipairs(encrypt_methods) do o:value(v) end
o.rmempty = false
o = s:option(ListValue, "protocol", translate("Protocol"))
for _, v in ipairs(protocol) do o:value(v) end
o.rmempty = false
o = s:option(ListValue, "obfs", translate("Obfs"))
for _, v in ipairs(obfs) do o:value(v) end
o.rmempty = false
o = s:option(Value, "obfs_param", translate("Obfs param(optional)"))
o = s:option(Flag, "fast_open", translate("TCP Fast Open"))
o.rmempty = false
return m

View File

@ -0,0 +1,122 @@
-- Copyright (C) 2017 yushi studio <ywb94@qq.com>
-- Licensed to the public under the GNU General Public License v3.
local m, sec, o
local shadowsocksr = "shadowsocksr"
local uci = luci.model.uci.cursor()
local ipkg = require("luci.model.ipkg")
m = Map(shadowsocksr, translate("ShadowSocksR Server"))
local encrypt_methods = {
"table",
"rc4",
"rc4-md5",
"rc4-md5-6",
"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",
"cast5-cfb",
"des-cfb",
"idea-cfb",
"rc2-cfb",
"seed-cfb",
"salsa20",
"chacha20",
"chacha20-ietf",
}
local protocol = {
"origin",
"verify_deflate",
"auth_sha1_v4",
"auth_aes128_sha1",
"auth_aes128_md5",
"auth_chain_a",
}
obfs = {
"plain",
"http_simple",
"http_post",
"random_head",
"tls1.2_ticket_auth",
"tls1.2_ticket_fastauth",
}
-- [[ Global Setting ]]--
sec = m:section(TypedSection, "server_global", translate("Global Setting"))
sec.anonymous = true
o = sec:option(Flag, "enable_server", translate("Enable Server"))
o.rmempty = false
-- [[ Server Setting ]]--
sec = m:section(TypedSection, "server_config", translate("Server Setting"))
sec.anonymous = true
sec.addremove = true
sec.sortable = true
sec.template = "cbi/tblsection"
sec.extedit = luci.dispatcher.build_url("admin/services/shadowsocksr/server/%s")
function sec.create(...)
local sid = TypedSection.create(...)
if sid then
luci.http.redirect(sec.extedit % sid)
return
end
end
o = sec:option(Flag, "enable", translate("Enable"))
function o.cfgvalue(...)
return Value.cfgvalue(...) or translate("0")
end
o.rmempty = false
o = sec:option(DummyValue, "server", translate("Server Address"))
function o.cfgvalue(...)
return Value.cfgvalue(...) or "?"
end
o = sec:option(DummyValue, "server_port", translate("Server Port"))
function o.cfgvalue(...)
return Value.cfgvalue(...) or "?"
end
o = sec:option(DummyValue, "encrypt_method", translate("Encrypt Method"))
function o.cfgvalue(...)
local v = Value.cfgvalue(...)
return v and v:upper() or "?"
end
o = sec:option(DummyValue, "protocol", translate("Protocol"))
function o.cfgvalue(...)
return Value.cfgvalue(...) or "?"
end
o = sec:option(DummyValue, "obfs", translate("Obfs"))
function o.cfgvalue(...)
return Value.cfgvalue(...) or "?"
end
return m

View File

@ -0,0 +1,40 @@
local m, s, o
local shadowsocksr = "shadowsocksr"
local function has_bin(name)
return luci.sys.call("command -v %s >/dev/null" %{name}) == 0
end
m = Map(shadowsocksr, "%s - %s" %{translate("ShadowSocksR"), translate("Servers Manage")})
-- Server Subscribe
if nixio.fs.access("/usr/share/shadowsocksr/subscribe.sh") and has_bin("base64") and has_bin("curl") and has_bin("bash") and has_bin("dig") then
s = m:section(TypedSection, "server_subscribe", translate("Server subscription"))
s.anonymous = true
o = s:option(Flag, "auto_update", translate("Auto Update"))
o.rmempty = false
o = s:option(Flag, "proxy", translate("Through proxy update"))
o.rmempty = false
o = s:option(ListValue, "auto_update_time", translate("Update time (every day)"))
for t = 0,23 do
o:value(t, t..":00")
end
o.default=2
o.rmempty = false
o = s:option(DynamicList, "subscribe_url", translate("Subscribe URL"))
o.rmempty = true
o = s:option(Button,"update",translate("Update"))
o.write = function()
luci.sys.call("/usr/share/shadowsocksr/subscribe.sh >/dev/null 2>&1")
luci.http.redirect(luci.dispatcher.build_url("admin", "services", "shadowsocksr", "servers"))
end
end
return m

View File

@ -0,0 +1,258 @@
-- Copyright (C) 2017 yushi studio <ywb94@qq.com>
-- Licensed to the public under the GNU General Public License v3.
local IPK_Version="3.1.0"
local m, s, o
local redir_run=0
local reudp_run=0
local sock5_run=0
-- local server_run=0
local kcptun_run=0
local tunnel_run=0
local udp2raw_run=0
local udpspeeder_run=0
local gfw_count=0
local ad_count=0
local ip_count=0
local gfwmode=0
if nixio.fs.access("/etc/dnsmasq.ssr/gfw_list.conf") then
gfwmode=1
end
local shadowsocksr = "shadowsocksr"
-- html constants
font_blue = [[<font color="blue">]]
font_off = [[</font>]]
bold_on = [[<strong>]]
bold_off = [[</strong>]]
local fs = require "nixio.fs"
local sys = require "luci.sys"
local kcptun_version=translate("Unknown")
local kcp_file="/usr/bin/ssr-kcptun"
if not fs.access(kcp_file) then
kcptun_version=translate("Not exist")
else
if not fs.access(kcp_file, "rwx", "rx", "rx") then
fs.chmod(kcp_file, 755)
end
kcptun_version=sys.exec(kcp_file .. " -v | awk '{printf $3}'")
if not kcptun_version or kcptun_version == "" then
kcptun_version = translate("Unknown")
end
end
local udp2raw_version=translate("Unknown")
local udp2raw_file="/usr/bin/udp2raw"
if not fs.access(udp2raw_file) then
udp2raw_version=translate("Not exist")
else
if not fs.access(udp2raw_file, "rwx", "rx", "rx") then
fs.chmod(udp2raw_file, 755)
end
udp2raw_version=sys.exec(udp2raw_file .. " -h |grep 'git version' |awk -F ':' '{print $2}'|awk '{print $1}'")
if not udp2raw_version or udp2raw_version == "" then
udp2raw_version = translate("Unknown")
end
end
local udpspeeder_version=translate("Unknown")
local udpspeeder_file="/usr/bin/udpspeeder"
if not fs.access(udpspeeder_file) then
udpspeeder_version=translate("Not exist")
else
if not fs.access(udpspeeder_file, "rwx", "rx", "rx") then
fs.chmod(udpspeeder_file, 755)
end
udpspeeder_version=sys.exec(udpspeeder_file .. " -h |grep 'git version' |awk -F ':' '{print $2}'|awk '{print $1}'")
if not udpspeeder_version or udpspeeder_version == "" then
udpspeeder_version = translate("Unknown")
end
end
if gfwmode==1 then
gfw_count = tonumber(sys.exec("cat /etc/dnsmasq.ssr/gfw_list.conf | wc -l"))/2
if nixio.fs.access("/etc/dnsmasq.ssr/ad.conf") then
ad_count=tonumber(sys.exec("cat /etc/dnsmasq.ssr/ad.conf | wc -l"))
end
end
if nixio.fs.access("/etc/china_ssr.txt") then
ip_count = sys.exec("cat /etc/china_ssr.txt | wc -l")
end
local icount=sys.exec("ps -w | grep ssr-reudp |grep -v grep| wc -l")
if tonumber(icount)>0 then
reudp_run=1
else
icount=sys.exec("ps -w | grep ssr-retcp |grep \"\\-u\"|grep -v grep| wc -l")
if tonumber(icount)>0 then
reudp_run=1
end
end
if luci.sys.call("pidof ssr-redir >/dev/null") == 0 then
redir_run=1
end
if luci.sys.call("ps -w | grep ssr-local |grep -v grep >/dev/null") == 0 then
sock5_run=1
end
if luci.sys.call("pidof ssr-kcptun >/dev/null") == 0 then
kcptun_run=1
end
-- if luci.sys.call("pidof ssr-server >/dev/null") == 0 then
-- server_run=1
-- end
if luci.sys.call("ps -w | grep ssr-tunnel |grep -v grep >/dev/null") == 0 then
tunnel_run=1
end
if luci.sys.call("pidof udp2raw >/dev/null") == 0 then
udp2raw_run=1
end
if luci.sys.call("pidof udpspeeder >/dev/null") == 0 then
udpspeeder_run=1
end
m = SimpleForm("Version", translate("Running Status"))
m.reset = false
m.submit = false
s=m:field(DummyValue,"redir_run",translate("Global Client"))
s.rawhtml = true
if redir_run == 1 then
s.value =font_blue .. bold_on .. translate("Running") .. bold_off .. font_off
else
s.value = translate("Not Running")
end
-- s=m:field(DummyValue,"server_run",translate("Global SSR Server"))
-- s.rawhtml = true
-- if server_run == 1 then
-- s.value =font_blue .. bold_on .. translate("Running") .. bold_off .. font_off
-- else
-- s.value = translate("Not Running")
-- end
s=m:field(DummyValue,"reudp_run",translate("UDP Relay"))
s.rawhtml = true
if reudp_run == 1 then
s.value =font_blue .. bold_on .. translate("Running") .. bold_off .. font_off
else
s.value = translate("Not Running")
end
s=m:field(DummyValue,"sock5_run",translate("SOCKS5 Proxy"))
s.rawhtml = true
if sock5_run == 1 then
s.value =font_blue .. bold_on .. translate("Running") .. bold_off .. font_off
else
s.value = translate("Not Running")
end
s=m:field(DummyValue,"tunnel_run",translate("DNS Tunnel"))
s.rawhtml = true
if tunnel_run == 1 then
s.value =font_blue .. bold_on .. translate("Running") .. bold_off .. font_off
else
s.value = translate("Not Running")
end
s=m:field(DummyValue,"kcptun_run",translate("KcpTun"))
s.rawhtml = true
if kcptun_run == 1 then
s.value =font_blue .. bold_on .. translate("Running") .. bold_off .. font_off
else
s.value = translate("Not Running")
end
s=m:field(DummyValue,"udp2raw_run",translate("udp2raw"))
s.rawhtml = true
if udp2raw_run == 1 then
s.value =font_blue .. bold_on .. translate("Running") .. bold_off .. font_off
else
s.value = translate("Not Running")
end
s=m:field(DummyValue,"udpspeeder_run",translate("UDPspeeder"))
s.rawhtml = true
if udpspeeder_run == 1 then
s.value =font_blue .. bold_on .. translate("Running") .. bold_off .. font_off
else
s.value = translate("Not Running")
end
s=m:field(DummyValue,"google",translate("Google Connectivity"))
s.value = translate("No Check")
s.template = "shadowsocksr/check"
s=m:field(DummyValue,"baidu",translate("Baidu Connectivity"))
s.value = translate("No Check")
s.template = "shadowsocksr/check"
if gfwmode==1 then
s=m:field(DummyValue,"gfw_data",translate("GFW List Data"))
s.rawhtml = true
s.template = "shadowsocksr/refresh"
s.value =tostring(math.ceil(gfw_count)) .. " " .. translate("Records")
s=m:field(DummyValue,"ad_data",translate("Advertising Data"))
s.rawhtml = true
s.template = "shadowsocksr/refresh"
s.value =tostring(math.ceil(ad_count)) .. " " .. translate("Records")
end
s=m:field(DummyValue,"ip_data",translate("China IP Data"))
s.rawhtml = true
s.template = "shadowsocksr/refresh"
s.value =ip_count .. " " .. translate("Records")
s=m:field(DummyValue,"check_port",translate("Check Server Port"))
s.template = "shadowsocksr/checkport"
s.value =translate("No Check")
s=m:field(DummyValue,"version",translate("IPK Version"))
s.rawhtml = true
s.value =IPK_Version
s=m:field(DummyValue,"ipk_project",translate("IPK Project"))
s.rawhtml = true
s.value =bold_on .. [[<a href="]] .. "https://github.com/ywb94/openwrt-ssr" .. [[" >]]
.. "https://github.com/ywb94/openwrt-ssr" .. [[</a>]] .. bold_off
s=m:field(DummyValue,"kcp_version",translate("KcpTun Version"))
s.rawhtml = true
s.value =kcptun_version
s=m:field(DummyValue,"kcptun_project",translate("Kcp Tun Project"))
s.rawhtml = true
s.value =bold_on .. [[<a href="]] .. "https://github.com/xtaci/kcptun" .. [[" >]]
.. "https://github.com/xtaci/kcptun" .. [[</a>]] .. bold_off
s=m:field(DummyValue,"udp2raw_version",translate("udp2raw Version"))
s.rawhtml = true
s.value =udp2raw_version
s=m:field(DummyValue,"udp2raw_project",translate("udp2raw tunnel Project"))
s.rawhtml = true
s.value =bold_on .. [[<a href="]] .. "https://github.com/wangyu-/udp2raw-tunnel" .. [[" >]]
.. "https://github.com/wangyu-/udp2raw-tunnel" .. [[</a>]] .. bold_off
s=m:field(DummyValue,"udpspeeder_version",translate("UDPspeeder Version"))
s.rawhtml = true
s.value =udpspeeder_version
s=m:field(DummyValue,"udpspeeder_project",translate("UDPspeeder Project"))
s.rawhtml = true
s.value =bold_on .. [[<a href="]] .. "https://github.com/wangyu-/UDPspeeder" .. [[" >]]
.. "https://github.com/wangyu-/UDPspeeder" .. [[</a>]] .. bold_off
return m

View File

@ -0,0 +1,38 @@
<%+cbi/valueheader%>
<script type="text/javascript">//<![CDATA[
function check_connect(btn,urlname)
{
btn.disabled = true;
btn.value = '<%:Check...%>';
murl=urlname;
XHR.get('<%=luci.dispatcher.build_url("admin", "services", "shadowsocksr","check")%>',
{ set:murl },
function(x,rv)
{
var s = document.getElementById(urlname+'-status');
if (s)
{
if (rv.ret=="0")
s.innerHTML ="<font color='green'>"+"<%:Connect OK%>"+"</font>";
else
s.innerHTML ="<font color='red'>"+"<%:Connect Error%>"+"</font>";
}
btn.disabled = false;
btn.value = '<%:Check Connect%>';
}
);
return false;
}
//]]></script>
<input type="button" class="cbi-button cbi-button-apply" value="<%:Check Connect%>" onclick="return check_connect(this,'<%=self.option%>')" />
<span id="<%=self.option%>-status"><em><%=self.value%></em></span>
<%+cbi/valuefooter%>

View File

@ -0,0 +1,36 @@
<%+cbi/valueheader%>
<script type="text/javascript">//<![CDATA[
function check_port(btn)
{
btn.disabled = true;
btn.value = '<%:Check...%>';
XHR.get('<%=luci.dispatcher.build_url("admin", "services", "shadowsocksr","checkport")%>',
null,
function(x,rv)
{
var s = document.getElementById('<%=self.option%>-status');
if (s)
{
s.innerHTML =rv.ret;
}
btn.disabled = false;
btn.value = '<%:Check Server%>';
}
);
return false;
}
//]]></script>
<input type="button" class="cbi-button cbi-button-apply" value="<%:Check Server%>" onclick="return check_port(this)" />
<span id="<%=self.option%>-status"><em><%=self.value%></em></span>
<%+cbi/valuefooter%>

View File

@ -0,0 +1,44 @@
<%+cbi/valueheader%>
<script type="text/javascript">//<![CDATA[
function refresh_data(btn,dataname)
{
btn.disabled = true;
btn.value = '<%:Refresh...%> ';
murl=dataname;
XHR.get('<%=luci.dispatcher.build_url("admin", "services", "shadowsocksr","refresh")%>',
{ set:murl },
function(x,rv)
{
var s = document.getElementById(dataname+'-status');
if (s)
{
if (rv.ret=="0")
s.innerHTML ="<font color='green'>"+"<%:No new data!%> "+"</font>";
else if(rv.ret=="-1")
{
s.innerHTML ="<font color='red'>"+"<%:Refresh Error!%> "+"</font>";
}
else
{
s.innerHTML ="<font color='green'>"+"<%:Refresh OK!%> "+"<%:Total Records:%>"+rv.ret+"</font>";
}
}
btn.disabled = false;
btn.value = '<%:Refresh Data %>';
}
);
return false;
}
//]]></script>
<input type="button" class="cbi-button cbi-input-reload" value="<%:Refresh Data%> " onclick="return refresh_data(this,'<%=self.option%>')" />
<span id="<%=self.option%>-status"><em><%=self.value%></em></span>
<%+cbi/valuefooter%>

View File

@ -0,0 +1,139 @@
<%+cbi/valueheader%>
<script type="text/javascript">//<![CDATA[
function padright(str, cnt, pad){
return str + Array(cnt+1).join(pad);
}
function b64EncodeUnicode(str) {
return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function(match, p1) {
return String.fromCharCode('0x' + p1);
}));
}
function b64encutf8safe(str) {
return b64EncodeUnicode(str).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/g,'');
}
function b64DecodeUnicode(str) {
return decodeURIComponent(Array.prototype.map.call(atob(str), function(c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
}
function b64decutf8safe(str) {
var l;
str = str.replace(/-/g,"+").replace(/_/g,"/");
l = str.length;
l = (4 - l % 4)%4;
if( l )
str = padright(str,l,"=");
return b64DecodeUnicode(str);
}
function b64encsafe(str){
return btoa(str).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/g,'')
}
function b64decsafe(str){
var l;
str = str.replace(/-/g,"+").replace(/_/g,"/");
l = str.length;
l = (4 - l % 4)%4;
if( l )
str = padright(str,l,"=");
return atob(str);
}
function dictvalue(d,key) {
var v = d[key];
if( typeof(v)=='undefined' || v=='' )
return '';
return b64decsafe(v);
}
function export_ssr_url(btn,urlname,sid) {
var s = document.getElementById(urlname+'-status');
if(!s)
return false;
var v_server = document.getElementById('cbid.shadowsocksr.'+sid+'.server');
var v_port = document.getElementById('cbid.shadowsocksr.'+sid+'.server_port');
var v_protocol = document.getElementById('cbid.shadowsocksr.'+sid+'.protocol');
var v_method = document.getElementById('cbid.shadowsocksr.'+sid+'.encrypt_method');
var v_obfs = document.getElementById('cbid.shadowsocksr.'+sid+'.obfs');
var v_password = document.getElementById('cbid.shadowsocksr.'+sid+'.password');
var v_obfs_param = document.getElementById('cbid.shadowsocksr.'+sid+'.obfs_param');
var v_protocol_param = document.getElementById('cbid.shadowsocksr.'+sid+'.protocol_param');
var v_alias = document.getElementById('cbid.shadowsocksr.'+sid+'.alias');
var ssr_str = v_server.value+":"+
v_port.value+":"+
v_protocol.value+":"+
v_method.value+":"+
v_obfs.value+":"+
b64encsafe(v_password.value)+
"/?obfsparam="+b64encsafe(v_obfs_param.value)+
"&protoparam="+b64encsafe(v_protocol_param.value)+
"&remarks="+b64encutf8safe(v_alias.value);
var textarea = document.createElement("textarea");
textarea.textContent = "ssr://"+b64encsafe(ssr_str);
textarea.style.position = "fixed";
document.body.appendChild(textarea);
textarea.select();
try {
document.execCommand("copy"); // Security exception may be thrown by some browsers.
s.innerHTML = "<font color='green'><%:Copy SSR to clipboard successfully.%></font>";
} catch (ex) {
s.innerHTML = "<font color='red'><%:Unable to copy SSR to clipboard.%></font>";
} finally {
document.body.removeChild(textarea);
}
return false;
}
function import_ssr_url(btn,urlname,sid) {
var s = document.getElementById(urlname+'-status');
if(!s)
return false;
var ssrurl = prompt("<%:Paste ssr url here%>", "ssr://");
if (ssrurl == null || ssrurl == "") {
s.innerHTML = "<font color='red'><%:User cancelled.%></font>";
return false;
}
s.innerHTML = "<font color='red'><%:Invalid SSR format.%></font>";
var ssu = ssrurl.match(/ssr:\/\/([A-Za-z0-9_-]+)/i);
if( !ssu || ssu.length<2 )
return false;
var sstr = b64decsafe(ssu[1]);
var ploc = sstr.indexOf("/?");
var url0, param="";
if( ploc>0 ) {
url0 = sstr.substr(0,ploc);
param = sstr.substr(ploc+2);
}
var ssm = url0.match(/^(.+):([^:]+):([^:]*):([^:]+):([^:]*):([^:]+)/);
if( !ssm || ssm.length<7 )
return false;
var pdict = {};
if( param.length>2 )
{
var a = param.split('&');
for( var i=0;i<a.length; i++ ) {
var b = a[i].split('=');
pdict[decodeURIComponent(b[0])] = decodeURIComponent(b[1] || '');
}
}
document.getElementById('cbid.shadowsocksr.'+sid+'.server').value = ssm[1];
document.getElementById('cbid.shadowsocksr.'+sid+'.server_port').value = ssm[2];
document.getElementById('cbid.shadowsocksr.'+sid+'.protocol').value = ssm[3];
document.getElementById('cbid.shadowsocksr.'+sid+'.encrypt_method').value = ssm[4];
document.getElementById('cbid.shadowsocksr.'+sid+'.obfs').value = ssm[5];
document.getElementById('cbid.shadowsocksr.'+sid+'.password').value = b64decsafe(ssm[6]);
document.getElementById('cbid.shadowsocksr.'+sid+'.obfs_param').value = dictvalue(pdict,'obfsparam');
document.getElementById('cbid.shadowsocksr.'+sid+'.protocol_param').value = dictvalue(pdict,'protoparam');
var rem = pdict['remarks'];
if( typeof(rem)!='undefined' && rem!='' && rem.length>0 )
document.getElementById('cbid.shadowsocksr.'+sid+'.alias').value = b64decutf8safe(rem);
s.innerHTML = "<font color='green'><%:Import SSR successfully.%></font>";
return false;
}
//]]></script>
<input type="button" class="cbi-button cbi-button-apply" value="<%:Import SSR%>" onclick="return import_ssr_url(this,'<%=self.option%>','<%=self.value%>')" />
<input type="button" class="cbi-button cbi-button-apply" value="<%:Export SSR%>" onclick="return export_ssr_url(this,'<%=self.option%>','<%=self.value%>')" />
<span id="<%=self.option%>-status"><%:ssr://%></span>
<%+cbi/valuefooter%>

View File

@ -0,0 +1,17 @@
#!/bin/sh
uci -q batch <<-EOF >/dev/null
delete ucitrack.@shadowsocksr[-1]
add ucitrack shadowsocksr
set ucitrack.@shadowsocksr[-1].init=shadowsocksr
commit ucitrack
delete firewall.shadowsocksr
set firewall.shadowsocksr=include
set firewall.shadowsocksr.type=script
set firewall.shadowsocksr.path=/var/etc/shadowsocksr.include
set firewall.shadowsocksr.reload=1
commit firewall
EOF
rm -f /tmp/luci-indexcache
exit 0

Binary file not shown.

View File

@ -0,0 +1,169 @@
#!/bin/bash
# Copyright (C) 2017 XiaoShan https://www.mivm.cn
urlsafe_b64decode() {
local d="====" data=$(echo $1 | sed 's/_/\//g; s/-/+/g')
local mod4=$((${#data}%4))
[ $mod4 -gt 0 ] && data=${data}${d:mod4}
echo $data | base64 -d
}
CheckIPAddr() {
echo $1 | grep "^[0-9]\{1,3\}\.\([0-9]\{1,3\}\.\)\{2\}[0-9]\{1,3\}$" >/dev/null 2>&1
[ $? -ne 0 ] && return 1
local ipaddr=($(echo $1 | sed 's/\./ /g'))
[ ${#ipaddr[@]} -ne 4 ] && return 1
for ((i=0;i<${#ipaddr[@]};i++))
do
[ ${ipaddr[i]} -gt 255 -a ${ipaddr[i]} -lt 0 ] && return 1
done
return 0
}
Server_Update() {
local uci_set="uci -q set $name.$1."
${uci_set}alias="[$ssr_group] $ssr_remarks"
${uci_set}auth_enable="0"
${uci_set}switch_enable="0"
${uci_set}server="$ssr_host"
${uci_set}server_port="$ssr_port"
${uci_set}local_port="1234"
uci -q get $name.@servers[$1].timeout >/dev/null || ${uci_set}timeout="60"
${uci_set}password="$ssr_passwd"
${uci_set}encrypt_method="$ssr_method"
${uci_set}protocol="$ssr_protocol"
${uci_set}protocol_param="$ssr_protoparam"
${uci_set}obfs="$ssr_obfs"
${uci_set}obfs_param="$ssr_obfsparam"
${uci_set}fast_open="0"
${uci_set}kcp_enable="0"
${uci_set}kcp_port="0"
${uci_set}kcp_param="--nocomp"
}
name=shadowsocksr
subscribe_url=($(uci get $name.@server_subscribe[0].subscribe_url))
[ ${#subscribe_url[@]} -eq 0 ] && exit 1
[ $(uci -q get $name.@server_subscribe[0].proxy || echo 0) -eq 0 ] && /etc/init.d/$name stop >/dev/null 2>&1
log_name=${name}_subscribe
for ((o=0;o<${#subscribe_url[@]};o++))
do
subscribe_data=$(curl -s -L --connect-timeout 3 ${subscribe_url[o]})
curl_code=$?
if [ $curl_code -eq 0 ];then
ssr_url=($(echo $subscribe_data | base64 -d | sed 's/\r//g')) # 解码数据并删除 \r 换行符
subscribe_max=$(echo ${ssr_url[0]} | grep -i MAX= | awk -F = '{print $2}')
subscribe_max_x=()
if [ -n "$subscribe_max" ]; then
while [ ${#subscribe_max_x[@]} -ne $subscribe_max ]
do
if [ ${#ssr_url[@]} -ge 10 ]; then
if [ $((${RANDOM:0:2}%2)) -eq 0 ]; then
temp_x=${RANDOM:0:1}
else
temp_x=${RANDOM:0:2}
fi
else
temp_x=${RANDOM:0:1}
fi
[ $temp_x -lt ${#ssr_url[@]} -a -z "$(echo "${subscribe_max_x[*]}" | grep -w ${temp_x})" ] && subscribe_max_x[${#subscribe_max_x[@]}]="$temp_x"
done
else
subscribe_max=${#ssr_url[@]}
fi
ssr_group=$(urlsafe_b64decode $(urlsafe_b64decode ${ssr_url[$((${#ssr_url[@]} - 1))]//ssr:\/\//} | sed 's/&/\n/g' | grep group= | awk -F = '{print $2}'))
if [ -n "$ssr_group" ]; then
subscribe_i=0
subscribe_n=0
subscribe_o=0
subscribe_x=""
temp_host_o=()
curr_ssr=$(uci show $name | grep @servers | grep -c server=)
for ((x=0;x<$curr_ssr;x++)) # 循环已有服务器信息,匹配当前订阅群组
do
temp_alias=$(uci -q get $name.@servers[$x].alias | grep "\[$ssr_group\]")
[ -n "$temp_alias" ] && temp_host_o[${#temp_host_o[@]}]=$(uci get $name.@servers[$x].server)
done
for ((x=0;x<$subscribe_max;x++)) # 循环链接
do
[ ${#subscribe_max_x[@]} -eq 0 ] && temp_x=$x || temp_x=${subscribe_max_x[x]}
temp_info=$(urlsafe_b64decode ${ssr_url[temp_x]//ssr:\/\//}) # 解码 SSR 链接
# 依次获取基本信息
info=${temp_info///?*/}
temp_info_array=(${info//:/ })
ssr_host=${temp_info_array[0]}
ssr_port=${temp_info_array[1]}
ssr_protocol=${temp_info_array[2]}
ssr_method=${temp_info_array[3]}
ssr_obfs=${temp_info_array[4]}
ssr_passwd=$(urlsafe_b64decode ${temp_info_array[5]})
info=${temp_info:$((${#info} + 2))}
info=(${info//&/ })
ssr_protoparam=""
ssr_obfsparam=""
ssr_remarks="$temp_x"
for ((i=0;i<${#info[@]};i++)) # 循环扩展信息
do
temp_info=($(echo ${info[i]} | sed 's/=/ /g'))
case "${temp_info[0]}" in
protoparam)
ssr_protoparam=$(urlsafe_b64decode ${temp_info[1]})
;;
obfsparam)
ssr_obfsparam=$(urlsafe_b64decode ${temp_info[1]})
;;
remarks)
ssr_remarks=$(urlsafe_b64decode ${temp_info[1]})
;;
esac
done
CheckIPAddr $ssr_host
if [ $? -ne 0 ]; then # 如果地址不是IP 则解析IP
ssr_hosts=($(dig $ssr_host a +short))
for ((i=0;i<${#ssr_hosts[@]};i++))
do
ssr_host=${ssr_hosts[i]}
CheckIPAddr $ssr_host
[ $? -eq 0 ] && continue
ssr_host=""
done
[ -z "$ssr_host" ] && continue
fi
uci_name_tmp=$(uci show $name | grep -w $ssr_host | awk -F . '{print $2}')
if [ -z "$uci_name_tmp" ]; then # 判断当前服务器信息是否存在
uci_name_tmp=$(uci add $name servers)
subscribe_n=$(($subscribe_n + 1))
fi
Server_Update $uci_name_tmp
subscribe_x=${subscribe_x}$ssr_host" "
# echo "服务器地址: $ssr_host"
# echo "服务器端口 $ssr_port"
# echo "密码: $ssr_passwd"
# echo "加密: $ssr_method"
# echo "协议: $ssr_protocol"
# echo "协议参数: $ssr_protoparam"
# echo "混淆: $ssr_obfs"
# echo "混淆参数: $ssr_obfsparam"
# echo "备注: $ssr_remarks"
done
for ((x=0;x<${#temp_host_o[@]};x++)) # 新旧服务器信息匹配,如果旧服务器信息不存在于新服务器信息则删除
do
if [ -z "$(echo "$subscribe_x" | grep -w ${temp_host_o[x]})" ]; then
uci_name_tmp=$(uci show $name | grep ${temp_host_o[x]} | awk -F . '{print $2}')
uci delete $name.$uci_name_tmp
subscribe_o=$(($subscribe_o + 1))
fi
done
subscribe_log="$ssr_group 服务器订阅更新成功 服务器数量: ${#ssr_url[@]} 新增服务器: $subscribe_n 删除服务器: $subscribe_o"
logger -st $log_name[$$] -p6 "$subscribe_log"
uci commit $name
else
logger -st $log_name[$$] -p3 "${subscribe_url[$o]} 订阅数据解析失败 无法获取 Group"
fi
else
logger -st $log_name[$$] -p3 "${subscribe_url[$o]} 订阅数据获取失败 错误代码: $curl_code"
fi
done
/etc/init.d/$name restart >/dev/null 2>&1

View File

@ -0,0 +1,6 @@
#!/bin/sh -e
if [ -f /tmp/adnew.conf ]; then
cat /tmp/adnew.conf | grep ^\|\|[^\*]*\^$ | sed -e 's:||:address\=\/:' -e 's:\^:/0\.0\.0\.0:' > /tmp/ad.conf
fi

View File

@ -0,0 +1,76 @@
config global
option global_server 'nil'
option monitor_enable '1'
option tunnel_enable '0'
option tunnel_port '5300'
option tunnel_forward '8.8.4.4:53'
option tunnel_address '0.0.0.0'
option pdnsd_enable '0'
option run_mode 'router'
config servers
option auth_enable '0'
option fast_open '0'
option server '127.0.0.1'
option server_port '8388'
option local_port '1234'
option password 'hello!!'
option timeout '60'
option encrypt_method 'rc4-md5'
option protocol 'origin'
option obfs 'plain'
option obfs_param ''
option kcp_enable '0'
option kcp_port '4000'
option kcp_password ''
option kcp_param '--nocomp'
config socks5_proxy
option server 'nil'
option local_port '1080'
option local_address '0.0.0.0'
config access_control
option lan_ac_mode '0'
option router_proxy '1'
option wan_bp_list '/etc/china_ssr.txt'
config server_global
option enable_server '0'
config server_config
option server '0.0.0.0'
option server_port '8388'
option password 'hello!!'
option timeout '60'
option encrypt_method 'rc4-md5'
option protocol 'origin'
option obfs 'plain'
option obfs_param ''
option fast_open '0'
option enable '1'
config server_subscribe
option auto_update '0'
config udp2raw
option server '127.0.0.1'
option server_port '600'
option local_port '400'
option key 'passwd'
option raw_mode 'faketcp'
option seq_mode '3'
option cipher_mode 'xor'
option auth_mode 'simple'
config udpspeeder
option server '127.0.0.1'
option server_port '400'
option local_port '500'
option key 'passwd'
option speeder_mode '0'
option fec '2:4'
option mtu '1250'
option queue_len '1'
option timeout '8'

View File

@ -0,0 +1,33 @@
#!/bin/sh -e
generate_china_banned()
{
cat $1 | base64 -d > /tmp/gfwlist.txt
rm -f $1
cat /tmp/gfwlist.txt | sort -u |
sed 's#!.\+##; s#|##g; s#@##g; s#http:\/\/##; s#https:\/\/##;' |
sed '/\*/d; /apple\.com/d; /sina\.cn/d; /sina\.com\.cn/d; /baidu\.com/d; /byr\.cn/d; /jlike\.com/d; /weibo\.com/d; /zhongsou\.com/d; /youdao\.com/d; /sogou\.com/d; /so\.com/d; /soso\.com/d; /aliyun\.com/d; /taobao\.com/d; /jd\.com/d; /qq\.com/d' |
sed '/^[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+$/d' |
grep '^[0-9a-zA-Z\.-]\+$' | grep '\.' | sed 's#^\.\+##' | sort -u |
awk '
BEGIN { prev = "________"; } {
cur = $0;
if (index(cur, prev) == 1 && substr(cur, 1 + length(prev) ,1) == ".") {
} else {
print cur;
prev = cur;
}
}' | sort -u
}
generate_china_banned /tmp/gfw.b64 > /tmp/gfw.txt
rm -f /tmp/gfwlist.txt
datestr=`date`
echo -e "# gfw list ipset rules for dnsmasq\n# updated on $datestr\n#">/tmp/gfwnew.txt
sed '/.*/s/.*/server=\/\.&\/127.0.0.1#5353\nipset=\/\.&\/gfwlist/' /tmp/gfw.txt >>/tmp/gfwnew.txt
rm -f /tmp/gfw.txt

View File

@ -0,0 +1,503 @@
#!/bin/sh /etc/rc.common
#
# Copyright (C) 2017 openwrt-ssr
# Copyright (C) 2017 yushi studio <ywb94@qq.com>
#
# This is free software, licensed under the GNU General Public License v3.
# See /LICENSE for more information.
#
START=90
STOP=15
SERVICE_DAEMONIZE=1
NAME=shadowsocksr
EXTRA_COMMANDS=rules
CONFIG_FILE=/var/etc/${NAME}.json
CONFIG_UDP_FILE=/var/etc/${NAME}_u.json
CONFIG_SOCK5_FILE=/var/etc/${NAME}_s.json
server_count=0
redir_tcp=0
redir_udp=0
tunnel_enable=0
local_enable=0
kcp_enable_flag=0
kcp_flag=0
pdnsd_enable_flag=0
switch_enable=0
switch_server=$1
MAXFD=32768
uci_get_by_name() {
local ret=$(uci get $NAME.$1.$2 2>/dev/null)
echo ${ret:=$3}
}
uci_get_by_type() {
local ret=$(uci get $NAME.@$1[0].$2 2>/dev/null)
echo ${ret:=$3}
}
run_mode=$(uci_get_by_type global run_mode)
gen_config_file() {
local host=$(uci_get_by_name $1 server)
if echo $host|grep -E "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$">/dev/null; then
hostip=${host}
elif [ "$host" != "${host#*:[0-9a-fA-F]}" ] ;then
hostip=${host}
else
hostip=`ping ${host} -s 1 -c 1 | grep PING | cut -d'(' -f 2 | cut -d')' -f1`
if echo $hostip|grep -E "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$">/dev/null; then
hostip=${hostip}
else
hostip=`cat /etc/ssr_ip`
fi
fi
[ $2 = "0" -a $kcp_flag = "1" ] && hostip="127.0.0.1"
if [ $2 = "0" ] ;then
config_file=$CONFIG_FILE
elif [ $2 = "1" ]; then
config_file=$CONFIG_UDP_FILE
else
config_file=$CONFIG_SOCK5_FILE
fi
if [ $(uci_get_by_name $1 fast_open) = "1" ] ;then
fastopen="true";
else
fastopen="false";
fi
cat <<-EOF >$config_file
{
"server": "$hostip",
"server_port": $(uci_get_by_name $1 server_port),
"local_address": "0.0.0.0",
"local_port": $(uci_get_by_name $1 local_port),
"password": "$(uci_get_by_name $1 password)",
"timeout": $(uci_get_by_name $1 timeout 60),
"method": "$(uci_get_by_name $1 encrypt_method)",
"protocol": "$(uci_get_by_name $1 protocol)",
"protocol_param": "$(uci_get_by_name $1 protocol_param)",
"obfs": "$(uci_get_by_name $1 obfs)",
"obfs_param": "$(uci_get_by_name $1 obfs_param)",
"fast_open": $fastopen
}
EOF
}
get_arg_out() {
case "$(uci_get_by_type access_control router_proxy 1)" in
1) echo "-o";;
2) echo "-O";;
esac
}
start_rules() {
local server=$(uci_get_by_name $GLOBAL_SERVER server)
#resolve name
if echo $server|grep -E "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$">/dev/null; then
server=${server}
elif [ "$server" != "${server#*:[0-9a-fA-F]}" ] ;then
server=${server}
else
server=`ping ${server} -s 1 -c 1 | grep PING | cut -d'(' -f 2 | cut -d')' -f1`
if echo $server|grep -E "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$">/dev/null; then
echo $server >/etc/ssr_ip
else
server=`cat /etc/ssr_ip`
fi
fi
kcp_server=$server
local kcp_enable=$(uci_get_by_name $GLOBAL_SERVER kcp_enable)
if [ $kcp_enable = "1" ] ;then
kcp_flag=1
fi
local local_port=$(uci_get_by_name $GLOBAL_SERVER local_port)
local lan_ac_ips=$(uci_get_by_type access_control lan_ac_ips)
local lan_ac_mode=$(uci_get_by_type access_control lan_ac_mode)
local router_proxy=$(uci_get_by_type access_control router_proxy)
if [ "$GLOBAL_SERVER" = "$UDP_RELAY_SERVER" -a $kcp_flag = 0 ]; then
ARG_UDP="-u"
elif [ -n "$UDP_RELAY_SERVER" ]; then
ARG_UDP="-U"
local udp_server=$(uci_get_by_name $UDP_RELAY_SERVER server)
local udp_local_port=$(uci_get_by_name $UDP_RELAY_SERVER local_port)
fi
if [ -n "$lan_ac_ips" ]; then
case "$lan_ac_mode" in
w|W|b|B) local ac_ips="$lan_ac_mode$lan_ac_ips";;
esac
fi
#deal gfw firewall rule
local gfwmode=""
if [ "$run_mode" = "gfw" ]; then
gfwmode="-g"
fi
/usr/bin/ssr-rules \
-s "$server" \
-l "$local_port" \
-S "$udp_server" \
-L "$udp_local_port" \
-a "$ac_ips" \
-i "$(uci_get_by_type access_control wan_bp_list)" \
-b "$(uci_get_by_type access_control wan_bp_ips)" \
-w "$(uci_get_by_type access_control wan_fw_ips)" \
$(get_arg_out) $gfwmode $ARG_UDP
return $?
}
start_pdnsd() {
local usr_dns="$1"
local usr_port="$2"
local tcp_dns_list="208.67.222.222, 208.67.220.220"
[ -z "$usr_dns" ] && usr_dns="8.8.8.8"
[ -z "$usr_port" ] && usr_port="53"
mkdir -p /var/etc /var/pdnsd
if ! test -f "/var/pdnsd/pdnsd.cache"; then
dd if=/dev/zero of="/var/pdnsd/pdnsd.cache" bs=1 count=4 2> /dev/null
chown -R nobody.nogroup /var/pdnsd
fi
cat > /var/etc/pdnsd.conf <<EOF
global {
perm_cache=10240;
cache_dir="/var/pdnsd";
pid_file = /var/run/pdnsd.pid;
run_as="nobody";
server_ip = 127.0.0.1;
server_port = 5353;
status_ctl = on;
query_method = tcp_only;
min_ttl=1h;
max_ttl=1w;
timeout=10;
neg_domain_pol=on;
proc_limit=2;
procq_limit=8;
}
server {
label= "ssr-usrdns";
ip = $usr_dns;
port = $usr_port;
timeout=6;
uptest=none;
interval=10m;
purge_cache=off;
}
server {
label= "ssr-pdnsd";
ip = $tcp_dns_list;
port = 5353;
timeout=6;
uptest=none;
interval=10m;
purge_cache=off;
}
EOF
/usr/sbin/pdnsd -c /var/etc/pdnsd.conf -d
}
start_tunnel() {
local tunnel_config_file=$CONFIG_FILE
if [ "$ARG_UDP" = "-U" ]; then
tunnel_config_file=$CONFIG_UDP_FILE
fi
local local_dns_port=$(uci_get_by_type global tunnel_port)
if [ "$run_mode" = "gfw" ] ;then
local_dns_port=5353
fi
/usr/bin/ssr-tunnel \
-c $tunnel_config_file $ARG_OTA -u \
-l $local_dns_port \
-b $(uci_get_by_type global tunnel_address 0.0.0.0) \
-L $(uci_get_by_type global tunnel_forward 8.8.4.4:53) \
-f /var/run/ssr-tunnel.pid
tunnel_enable=1
return $?
}
start_redir() {
case "$(uci_get_by_name $GLOBAL_SERVER auth_enable)" in
1|on|true|yes|enabled) ARG_OTA="-A";;
*) ARG_OTA="";;
esac
#deal kcp
local kcp_enable=$(uci_get_by_name $GLOBAL_SERVER kcp_enable)
if [ $kcp_enable = "1" ] ;then
[ ! -f "/usr/bin/ssr-kcptun" ] && return 1
local kcp_str=`/usr/bin/ssr-kcptun -v |grep kcptun|wc -l`
[ "0" = $kcp_str ] && return 1
local kcp_port=$(uci_get_by_name $GLOBAL_SERVER kcp_port)
local server_port=$(uci_get_by_name $GLOBAL_SERVER server_port)
local password=$(uci_get_by_name $GLOBAL_SERVER kcp_password)
local kcp_param=$(uci_get_by_name $GLOBAL_SERVER kcp_param)
[ "$password" != "" ] && password="--key "${password}
service_start /usr/bin/ssr-kcptun \
-r $kcp_server:$kcp_port \
-l :$server_port $password $kcp_param
kcp_enable_flag=1
fi
gen_config_file $GLOBAL_SERVER 0
redir_tcp=1
local last_config_file=$CONFIG_FILE
local pid_file="/var/run/ssr-retcp.pid"
if [ "$ARG_UDP" = "-U" ]; then
/usr/bin/ssr-redir \
-c $CONFIG_FILE $ARG_OTA \
-f /var/run/ssr-retcp.pid
case "$(uci_get_by_name $UDP_RELAY_SERVER auth_enable)" in
1|on|true|yes|enabled) ARG_OTA="-A";;
*) ARG_OTA="";;
esac
gen_config_file $UDP_RELAY_SERVER 1
last_config_file=$CONFIG_UDP_FILE
pid_file="/var/run/ssr-reudp.pid"
redir_udp=1
fi
/usr/bin/ssr-redir \
-c $last_config_file $ARG_OTA $ARG_UDP \
-f $pid_file
#deal with dns
if [ "$run_mode" = "gfw" ] ;then
if [ "$(uci_get_by_type global pdnsd_enable)" = "0" ] ;then
start_tunnel
fi
if [ "$(uci_get_by_type global pdnsd_enable)" = "1" ] ;then
local dnsstr="$(uci_get_by_type global tunnel_forward 8.8.4.4:53)"
local dnsserver=`echo "$dnsstr"|awk -F ':' '{print $1}'`
local dnsport=`echo "$dnsstr"|awk -F ':' '{print $2}'`
ipset add gfwlist $dnsserver 2>/dev/null
start_pdnsd $dnsserver $dnsport
pdnsd_enable_flag=1
fi
fi
if [ "$(uci_get_by_type global enable_switch)" = "1" ] ;then
if [ "$(uci_get_by_name $GLOBAL_SERVER switch_enable)" = "1" ] ;then
if [ -z "$switch_server" ] ;then
local switch_time=$(uci_get_by_type global switch_time)
local switch_timeout=$(uci_get_by_type global switch_timeout)
service_start /usr/bin/ssr-switch start $switch_time $switch_timeout
switch_enable=1
fi
fi
fi
return $?
}
start_udp2raw() {
cat > /var/etc/udp2raw.conf <<EOF
# udp2raw config file
-c
-l0.0.0.0:$(uci_get_by_type udp2raw local_port)
-r$(uci_get_by_type udp2raw server):$(uci_get_by_type udp2raw server_port)
-a
-k $(uci_get_by_type udp2raw key)
--raw-mode $(uci_get_by_type udp2raw raw_mode)
--seq-mode $(uci_get_by_type udp2raw seq_mode)
--cipher-mode $(uci_get_by_type udp2raw cipher_mode)
--auth-mode $(uci_get_by_type udp2raw auth_mode)
EOF
/usr/bin/udp2raw --conf-file /var/etc/udp2raw.conf >/dev/null 2>&1 &
}
start_udpspeeeder() {
/usr/bin/udpspeeder -c -l0.0.0.0:$(uci_get_by_type udpspeeder local_port) \
-r$(uci_get_by_type udpspeeder server):$(uci_get_by_type udpspeeder server_port) \
-k $(uci_get_by_type udpspeeder key) \
--mode $(uci_get_by_type udpspeeder speeder_mode) \
--mtu $(uci_get_by_type udpspeeder mtu) \
-f$(uci_get_by_type udpspeeder fec) \
-q$(uci_get_by_type udpspeeder queue_len) \
--timeout $(uci_get_by_type udpspeeder timeout) \
>/dev/null 2>&1 &
}
gen_service_file() {
if [ $(uci_get_by_name $1 fast_open) = "1" ] ;then
fastopen="true";
else
fastopen="false";
fi
cat <<-EOF >$2
{
"server": "$(uci_get_by_name $1 server)",
"server_port": $(uci_get_by_name $1 server_port),
"password": "$(uci_get_by_name $1 password)",
"timeout": $(uci_get_by_name $1 timeout 60),
"method": "$(uci_get_by_name $1 encrypt_method)",
"protocol": "$(uci_get_by_name $1 protocol)",
"protocol_param": "$(uci_get_by_name $1 protocol_param)",
"obfs": "$(uci_get_by_name $1 obfs)",
"obfs_param": "$(uci_get_by_name $1 obfs_param)",
"fast_open": $fastopen
}
EOF
}
start_service() {
[ $(uci_get_by_name $1 enable) = "0" ] && return 1
let server_count=server_count+1
if [ $server_count = 1 ] ;then
iptables -N SSR-SERVER-RULE && \
iptables -t filter -I INPUT -j SSR-SERVER-RULE
fi
gen_service_file $1 /var/etc/${NAME}_${server_count}.json
/usr/bin/ssr-server -c /var/etc/${NAME}_${server_count}.json -u -f /var/run/ssr-server${server_count}.pid
iptables -t filter -A SSR-SERVER-RULE -p tcp --dport $(uci_get_by_name $1 server_port) -j ACCEPT
iptables -t filter -A SSR-SERVER-RULE -p udp --dport $(uci_get_by_name $1 server_port) -j ACCEPT
return 0
}
gen_serv_include() {
FWI=$(uci get firewall.shadowsocksr.path 2>/dev/null)
[ -n "$FWI" ] || return 0
if [ ! -f $FWI ] ;then
echo '#!/bin/sh' >$FWI
fi
extract_rules() {
echo "*filter"
iptables-save -t filter | grep SSR-SERVER-RULE|sed -e "s/^-A INPUT/-I INPUT/"
echo 'COMMIT'
}
cat <<-EOF >>$FWI
iptables-save -c | grep -v "SSR-SERVER" | iptables-restore -c
iptables-restore -n <<-EOT
$(extract_rules)
EOT
EOF
}
start_server() {
SERVER_ENABLE=$(uci_get_by_type server_global enable_server)
[ "$SERVER_ENABLE" = 0 ] && return 0
mkdir -p /var/run /var/etc
config_load $NAME
config_foreach start_service server_config
gen_serv_include
return 0
}
start_local() {
local local_server=$(uci_get_by_type socks5_proxy server)
[ "$local_server" = "nil" ] && return 1
mkdir -p /var/run /var/etc
gen_config_file $local_server 2
/usr/bin/ssr-local -c $CONFIG_SOCK5_FILE -u \
-l $(uci_get_by_type socks5_proxy local_port 1080) \
-b $(uci_get_by_type socks5_proxy local_address 0.0.0.0) \
-f /var/run/ssr-local.pid
local_enable=1
}
rules() {
[ "$GLOBAL_SERVER" = "nil" ] && return 1
mkdir -p /var/run /var/etc
UDP_RELAY_SERVER=$(uci_get_by_type global udp_relay_server)
[ "$UDP_RELAY_SERVER" = "same" ] && UDP_RELAY_SERVER=$GLOBAL_SERVER
if start_rules ;then
return 0
else
return 1
fi
}
start() {
case "$(uci_get_by_type udp2raw udp2raw_enable)" in
1|on|true|yes|enabled)
start_udp2raw
;;
esac
case "$(uci_get_by_type udpspeeder udpspeeder_enable)" in
1|on|true|yes|enabled)
start_udpspeeeder
;;
esac
if [ -z "$switch_server" ] ;then
GLOBAL_SERVER=$(uci_get_by_type global global_server)
else
GLOBAL_SERVER=$switch_server
switch_enable=1
fi
if rules ;then
start_redir
if ! [ "$run_mode" = "gfw" ] ;then
case "$(uci_get_by_type global tunnel_enable)" in
1|on|true|yes|enabled)
start_tunnel
;;
esac
fi
fi
start_server
start_local
if [ $(uci_get_by_type global monitor_enable) = 1 ] ;then
let total_count=server_count+redir_tcp+redir_udp+tunnel_enable+kcp_enable_flag+local_enable+pdnsd_enable_flag+switch_enable
if [ $total_count -gt 0 ] ;then
#param:server(count) redir_tcp(0:no,1:yes) redir_udp tunnel kcp local gfw
service_start /usr/bin/ssr-monitor \
$server_count $redir_tcp $redir_udp $tunnel_enable \
$kcp_enable_flag $local_enable $pdnsd_enable_flag $switch_enable
fi
fi
}
boot() {
(sleep 5 && start >/dev/null 2>&1) &
}
stop() {
/usr/bin/ssr-rules -f
srulecount=`iptables -L|grep SSR-SERVER-RULE|wc -l`
if [ $srulecount -gt 0 ] ;then
iptables -F SSR-SERVER-RULE
iptables -t filter -D INPUT -j SSR-SERVER-RULE
iptables -X SSR-SERVER-RULE 2>/dev/null
fi
killall -q -9 ssr-monitor
killall -q -9 udp2raw
killall -q -9 udpspeeder
/usr/bin/udp2raw --clear >/dev/null
if [ -z "$switch_server" ] ;then
killall -q -9 ssr-switch
fi
killall -q -9 ssr-redir
killall -q -9 ssr-tunnel
killall -q -9 ssr-server
killall -q -9 ssr-kcptun
killall -q -9 ssr-local
killall -q pdnsd
}

View File

@ -0,0 +1,151 @@
#!/bin/sh
#
# Copyright (C) 2017 openwrt-ssr
# Copyright (C) 2017 yushi studio <ywb94@qq.com>
#
# This is free software, licensed under the GNU General Public License v3.
# See /LICENSE for more information.
#
NAME=shadowsocksr
uci_get_by_name() {
local ret=$(uci get $NAME.$1.$2 2>/dev/null)
echo ${ret:=$3}
}
uci_get_by_type() {
local ret=$(uci get $NAME.@$1[0].$2 2>/dev/null)
echo ${ret:=$3}
}
server_process_count=$1
redir_tcp_process=$2
redir_udp_process=$3
tunnel_process=$4
kcp_process=$5
local_process=$6
pdnsd_process=$7
if [ -z "$pdnsd_process" ] ;then
pdnsd_process=0
fi
i=0
GLOBAL_SERVER=$(uci_get_by_type global global_server)
local server=$(uci_get_by_name $GLOBAL_SERVER server)
local kcp_port=$(uci_get_by_name $GLOBAL_SERVER kcp_port)
local server_port=$(uci_get_by_name $GLOBAL_SERVER server_port)
local password=$(uci_get_by_name $GLOBAL_SERVER kcp_password)
local kcp_param=$(uci_get_by_name $GLOBAL_SERVER kcp_param)
[ "$password" != "" ] && password="--key "${password}
local sock5_port=$(uci_get_by_type socks5_proxy local_port 1080)
if echo $server|grep -E "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$">/dev/null; then
server=${server}
else
server=`cat /etc/ssr_ip`
fi
while [ "1" = "1" ] #死循环
do
sleep 30
#redir tcp
if [ $redir_tcp_process -gt 0 ] ;then
icount=`ps -w | grep ssr-retcp |grep -v grep| wc -l`
if [ $icount = 0 ] ;then
logger -t "$NAME" "ssr redir tcp error.restart!"
/etc/init.d/shadowsocksr restart
exit 0
fi
fi
#redir udp
if [ $redir_udp_process -gt 0 ] ;then
icount=`ps -w | grep ssr-reudp|grep -v grep| wc -l`
if [ $icount = 0 ] ;then
logger -t "$NAME" "ssr redir udp error.restart!"
/etc/init.d/shadowsocksr restart
exit 0
fi
fi
#ssr-dns tunnel
if [ $tunnel_process -gt 0 ] ;then
icount=`ps -w | grep ssr-tunnel |grep -v grep| wc -l`
if [ $icount = 0 ] ;then
logger -t "$NAME" "ssr tunnel error.restart!"
/etc/init.d/shadowsocksr restart
exit 0
fi
fi
#server
if [ $server_process_count -gt 0 ] ;then
icount=`ps -w | grep ssr-server |grep -v grep| wc -l`
if [ $icount -lt $server_process_count ] #如果进程挂掉就重启它
then
logger -t "$NAME" "ssr server error.restart!"
killall -q -9 ssr-server
for i in `seq $server_process_count`
do
/usr/bin/ssr-server -c /var/etc/shadowsocksr_$i.json -u -f /var/run/ssr-server$i.pid
done
fi
fi
#kcptun
if [ $kcp_process -gt 0 ] ;then
icount=`ps -w | grep ssr-kcptun |grep -v grep| wc -l`
if [ $icount -lt $kcp_process ] #如果进程挂掉就重启它
then
logger -t "$NAME" "ssr kcptun error.restart!"
killall -q -9 ssr-kcptun
( /usr/bin/ssr-kcptun -r $server:$kcp_port -l :$server_port $password $kcp_param &)
fi
fi
#local
if [ $local_process -gt 0 ] ;then
icount=`ps -w | grep ssr-local |grep -v grep| wc -l`
if [ $icount -lt $local_process ] #如果进程挂掉就重启它
then
logger -t "$NAME" "ssr local error.restart!"
killall -q -9 ssr-local
( /usr/bin/ssr-local -c /var/etc/shadowsocksr_s.json -u -l $sock5_port -f /var/run/ssr-local.pid &)
fi
fi
#pdnsd
if [ $pdnsd_process -gt 0 ] ;then
icount=`ps -w | grep pdnsd |grep -v grep| wc -l`
if [ $icount -lt $pdnsd_process ] #如果进程挂掉就重启它
then
logger -t "$NAME" "pdnsd tunnel error.restart!"
killall -q -9 pdnsd
( /usr/sbin/pdnsd -c /var/etc/pdnsd.conf -d &)
fi
fi
#udp2raw
if [ $(uci_get_by_type udp2raw udp2raw_enable) = 1 ] ;then
ucount=`ps -w | grep udp2raw |grep -v grep| wc -l`
if [ $ucount = 0 ] ;then
/usr/bin/udp2raw --clear >/dev/null
/usr/bin/udp2raw --conf-file /var/etc/udp2raw.conf >/dev/null 2>&1 &
fi
fi
#udpspeeder
if [ $(uci_get_by_type udpspeeder udpspeeder_enable) = 1 ] ;then
scount=`ps -w | grep udpspeeder |grep -v grep| wc -l`
if [ $scount = 0 ] ;then
/usr/bin/udpspeeder -c -l0.0.0.0:$(uci_get_by_type udpspeeder local_port) \
-r$(uci_get_by_type udpspeeder server):$(uci_get_by_type udpspeeder server_port) \
-k $(uci_get_by_type udpspeeder key) \
--mode $(uci_get_by_type udpspeeder speeder_mode) \
--mtu $(uci_get_by_type udpspeeder mtu) \
-f$(uci_get_by_type udpspeeder fec) \
-q$(uci_get_by_type udpspeeder queue_len) \
--timeout $(uci_get_by_type udpspeeder timeout) \
>/dev/null 2>&1 &
fi
fi
done

View File

@ -0,0 +1,291 @@
#!/bin/sh
#
# Copyright (C) 2017 openwrt-ssr
# Copyright (C) 2017 yushi studio <ywb94@qq.com>
#
# This is free software, licensed under the GNU General Public License v3.
# See /LICENSE for more information.
#
TAG="_SS_SPEC_RULE_" # comment tag
IPT="iptables -t nat" # alias of iptables
FWI=$(uci get firewall.shadowsocksr.path 2>/dev/null) # firewall include file
usage() {
cat <<-EOF
Usage: ssr-rules [options]
Valid options are:
-s <server_ip> ip address of shadowsocksr remote server
-l <local_port> port number of shadowsocksr local server
-S <server_ip> ip address of shadowsocksr remote UDP server
-L <local_port> port number of shadowsocksr local UDP server
-i <ip_list_file> a file content is bypassed ip list
-a <lan_ips> lan ip of access control, need a prefix to
define access control mode
-b <wan_ips> wan ip of will be bypassed
-w <wan_ips> wan ip of will be forwarded
-e <extra_options> extra options for iptables
-o apply the rules to the OUTPUT chain
-O apply the global rules to the OUTPUT chain
-u enable udprelay mode, TPROXY is required
-U enable udprelay mode, using different IP
and ports for TCP and UDP
-f flush the rules
-g gfw list mode
-h show this help message and exit
EOF
exit $1
}
loger() {
# 1.alert 2.crit 3.err 4.warn 5.notice 6.info 7.debug
logger -st ssr-rules[$$] -p$1 $2
}
flush_r() {
flush_iptables() {
local ipt="iptables -t $1"
local DAT=$(iptables-save -t $1)
eval $(echo "$DAT" | grep "$TAG" | sed -e 's/^-A/$ipt -D/' -e 's/$/;/')
for chain in $(echo "$DAT" | awk '/^:SS_SPEC/{print $1}'); do
$ipt -F ${chain:1} 2>/dev/null && $ipt -X ${chain:1}
done
}
flush_iptables nat
flush_iptables mangle
ip rule del fwmark 0x01/0x01 table 100 2>/dev/null
ip route del local 0.0.0.0/0 dev lo table 100 2>/dev/null
ipset -X ss_spec_lan_ac 2>/dev/null
ipset -X ss_spec_wan_ac 2>/dev/null
ipset -X ssr_gen_router 2>/dev/null
[ -n "$FWI" ] && echo '#!/bin/sh' >$FWI
return 0
}
ipset_r() {
if [ -z "$GFWMODE" ] ;then
ipset -! -R <<-EOF || return 1
create ss_spec_wan_ac hash:net
$(gen_iplist | sed -e "s/^/add ss_spec_wan_ac /")
$(for ip in $WAN_FW_IP; do echo "add ss_spec_wan_ac $ip nomatch"; done)
EOF
$IPT -N SS_SPEC_WAN_AC && \
$IPT -A SS_SPEC_WAN_AC -m set --match-set ss_spec_wan_ac dst -j RETURN && \
$IPT -A SS_SPEC_WAN_AC -j SS_SPEC_WAN_FW
else
ipset -N gfwlist iphash 2>/dev/null
for ip in $WAN_FW_IP; do ipset add gfwlist $ip ; done
$IPT -N SS_SPEC_WAN_AC
$IPT -A SS_SPEC_WAN_AC -m set --match-set gfwlist dst -j SS_SPEC_WAN_FW
fi
return $?
}
fw_rule() {
$IPT -N SS_SPEC_WAN_FW && \
$IPT -A SS_SPEC_WAN_FW -p tcp \
-j REDIRECT --to-ports $local_port 2>/dev/null || {
loger 3 "Can't redirect, please check the iptables."
exit 1
}
return $?
}
ac_rule() {
if [ -n "$LAN_AC_IP" ]; then
case "${LAN_AC_IP:0:1}" in
w|W)
MATCH_SET="-m set --match-set ss_spec_lan_ac src"
;;
b|B)
MATCH_SET="-m set ! --match-set ss_spec_lan_ac src"
;;
*)
loger 3 "Bad argument \`-a $LAN_AC_IP\`."
return 2
;;
esac
fi
IFNAME=$(uci get -P/var/state network.lan.ifname 2>/dev/null)
ipset -! -R <<-EOF || return 1
create ss_spec_lan_ac hash:net
$(for ip in ${LAN_AC_IP:1}; do echo "add ss_spec_lan_ac $ip"; done)
EOF
$IPT -I PREROUTING 1 ${IFNAME:+-i $IFNAME} -p tcp $EXT_ARGS $MATCH_SET \
-m comment --comment "$TAG" -j SS_SPEC_WAN_AC
if [ "$OUTPUT" = 1 ]; then
$IPT -I OUTPUT 1 -p tcp $EXT_ARGS \
-m comment --comment "$TAG" -j SS_SPEC_WAN_AC
elif [ "$OUTPUT" = 2 ]; then
ipset -! -R <<-EOF || return 1
create ssr_gen_router hash:net
$(gen_spec_iplist | sed -e "s/^/add ssr_gen_router /")
EOF
$IPT -N SS_SPEC_ROUTER && \
$IPT -A SS_SPEC_ROUTER -m set --match-set ssr_gen_router dst -j RETURN && \
$IPT -A SS_SPEC_ROUTER -j SS_SPEC_WAN_FW
$IPT -I OUTPUT 1 -p tcp -m comment --comment "$TAG" -j SS_SPEC_ROUTER
fi
return $?
}
tp_rule() {
[ -n "$TPROXY" ] || return 0
ip rule add fwmark 0x01/0x01 table 100
ip route add local 0.0.0.0/0 dev lo table 100
local ipt="iptables -t mangle"
$ipt -N SS_SPEC_TPROXY
if [ -z "$GFWMODE" ] ;then
$ipt -A SS_SPEC_TPROXY -p udp -m set ! --match-set ss_spec_wan_ac dst \
-j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01
else
$ipt -A SS_SPEC_TPROXY -p udp -m set --match-set gfwlist dst \
-j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01
fi
$ipt -I PREROUTING 1 ${IFNAME:+-i $IFNAME} -p udp $EXT_ARGS $MATCH_SET \
-m comment --comment "$TAG" -j SS_SPEC_TPROXY
return $?
}
get_wan_ip() {
cat <<-EOF | grep -E "^([0-9]{1,3}\.){3}[0-9]{1,3}"
$server
$SERVER
$WAN_BP_IP
EOF
}
gen_iplist() {
cat <<-EOF
0.0.0.0/8
10.0.0.0/8
100.64.0.0/10
127.0.0.0/8
169.254.0.0/16
172.16.0.0/12
192.0.0.0/24
192.0.2.0/24
192.88.99.0/24
192.168.0.0/16
198.18.0.0/15
198.51.100.0/24
203.0.113.0/24
224.0.0.0/4
240.0.0.0/4
255.255.255.255
$(get_wan_ip)
$(cat ${IGNORE_LIST:=/dev/null} 2>/dev/null)
EOF
}
gen_spec_iplist() {
cat <<-EOF
0.0.0.0/8
10.0.0.0/8
100.64.0.0/10
127.0.0.0/8
169.254.0.0/16
172.16.0.0/12
192.0.0.0/24
192.0.2.0/24
192.88.99.0/24
192.168.0.0/16
198.18.0.0/15
198.51.100.0/24
203.0.113.0/24
224.0.0.0/4
240.0.0.0/4
255.255.255.255
$(get_wan_ip)
EOF
}
gen_include() {
[ -n "$FWI" ] || return 0
extract_rules() {
echo "*$1"
iptables-save -t $1 | grep SS_SPEC_ |\
sed -e "s/^-A \(OUTPUT\|PREROUTING\)/-I \1 1/"
echo 'COMMIT'
}
cat <<-EOF >>$FWI
iptables-save -c | grep -v "SS_SPEC" | iptables-restore -c
iptables-restore -n <<-EOT
$(extract_rules nat)
$(extract_rules mangle)
EOT
EOF
return 0
}
while getopts ":s:l:S:L:i:e:a:b:w:oOuUfgh" arg; do
case "$arg" in
s)
server=$OPTARG
;;
l)
local_port=$OPTARG
;;
S)
SERVER=$OPTARG
;;
L)
LOCAL_PORT=$OPTARG
;;
i)
IGNORE_LIST=$OPTARG
;;
e)
EXT_ARGS=$OPTARG
;;
a)
LAN_AC_IP=$OPTARG
;;
b)
WAN_BP_IP=$(for ip in $OPTARG; do echo $ip; done)
;;
w)
WAN_FW_IP=$OPTARG
;;
o)
OUTPUT=1
;;
O)
OUTPUT=2
;;
u)
TPROXY=1
;;
U)
TPROXY=2
;;
g)
GFWMODE=1
;;
f)
flush_r
exit 0
;;
h)
usage 0
;;
esac
done
if [ -z "$server" -o -z "$local_port" ]; then
usage 2
fi
if [ "$TPROXY" = 1 ]; then
SERVER=$server
LOCAL_PORT=$local_port
elif [ "$TPROXY" = 2 ]; then
: ${SERVER:?"You must assign an ip for the udp relay server."}
: ${LOCAL_PORT:?"You must assign a port for the udp relay server."}
fi
flush_r && fw_rule && ipset_r && ac_rule && tp_rule && gen_include
[ "$?" = 0 ] || loger 3 "Start failed!"
exit $?

View File

@ -0,0 +1,165 @@
#!/bin/sh /etc/rc.common
#
# Copyright (C) 2017 openwrt-ssr
# Copyright (C) 2017 yushi studio <ywb94@qq.com>
#
# This is free software, licensed under the GNU General Public License v3.
# See /LICENSE for more information.
#
local cycle_time=60
local switch_time=3
local normal_flag=0
local server_locate=0
local server_count=0
NAME=shadowsocksr
ENABLE_SERVER=nil
CONFIG_SWTICH_FILE=/var/etc/${NAME}_t.json
[ -n "$1" ] && cycle_time=$1
[ -n "$2" ] && switch_time=$2
uci_get_by_name() {
local ret=$(uci get $NAME.$1.$2 2>/dev/null)
echo ${ret:=$3}
}
uci_get_by_type() {
local ret=$(uci get $NAME.@$1[0].$2 2>/dev/null)
echo ${ret:=$3}
}
DEFAULT_SERVER=$(uci_get_by_type global global_server)
CURRENT_SERVER=$DEFAULT_SERVER
#判断代理是否正常
check_proxy() {
/usr/bin/ssr-check www.google.com 80 $switch_time 1
if [ "$?" == "0" ]; then
return 0
else
/usr/bin/ssr-check www.baidu.com 80 $switch_time 1
if [ "$?" == "0" ]; then
#goole不通baidu通则不正常
return 1
else
return 2
fi
fi
return 0
}
test_proxy() {
local servername=$(uci_get_by_name $1 server)
local serverport=$(uci_get_by_name $1 server_port)
ret=$(ping -c 3 $servername | grep 'loss' | awk -F ',' '{ print $3 }' | awk -F "%" '{ print $1 }')
[ -z "$ret" ] && return 1
[ "$ret" -gt "50" ] && return 1
ipset add ss_spec_wan_ac $servername 2>/dev/null
ret=$?
/usr/bin/ssr-check $servername $serverport $switch_time
local ret2=$?
if [ "$ret" = "0" ] ;then
ipset del ss_spec_wan_ac $servername 2>/dev/null
fi
if [ "$ret2" = "0" ] ;then
return 0
else
return 1
fi
}
search_proxy() {
let server_count=server_count+1
[ "$normal_flag" = "1" -a "$server_count" -le "$server_locate" ] && return 0
[ "$(uci_get_by_name $1 switch_enable)" != "1" ] && return 1
[ $ENABLE_SERVER != nil ] && return 0
[ "$1" = "$CURRENT_SERVER" ] && return 0
local servername=$(uci_get_by_name $1 server)
local serverport=$(uci_get_by_name $1 server_port)
ipset add ss_spec_wan_ac $servername 2>/dev/null
ret=$?
/usr/bin/ssr-check $servername $serverport $switch_time
local ret2=$?
if [ "$ret" = "0" ] ;then
ipset del ss_spec_wan_ac $servername 2>/dev/null
fi
if [ "$ret2" = "0" ] ;then
server_locate=$server_count
ENABLE_SERVER=$1
return 0
else
return 1
fi
}
#选择可用的代理
select_proxy() {
config_load $NAME
ENABLE_SERVER=nil
mkdir -p /var/run /var/etc
server_count=0
config_foreach search_proxy servers
}
#切换代理
switch_proxy() {
/etc/init.d/shadowsocksr restart $1
return 0
}
start() {
#不支持kcptun启用时的切换
[ $(uci_get_by_name $DEFAULT_SERVER kcp_enable) = "1" ] && return 1
while [ "1" = "1" ] #死循环
do
sleep $cycle_time
#判断当前代理是否为缺省服务器
if [ "$CURRENT_SERVER" != "$DEFAULT_SERVER" ] ;then
#echo "not default proxy"
#检查缺省服务器是否正常
if test_proxy $DEFAULT_SERVER ;then
#echo "switch to default proxy"
#缺省服务器正常,切换回来
CURRENT_SERVER=$DEFAULT_SERVER
switch_proxy $CURRENT_SERVER
logger -t "$NAME" "switch to default ["$(uci_get_by_name $CURRENT_SERVER server)"] proxy!"
continue
fi
fi
#判断当前代理是否正常
check_proxy
current_ret=$?
if [ "$current_ret" = "1" ] ;then
#当前代理错误,判断有无可用的服务器
#echo "current error"
select_proxy
if [ "$ENABLE_SERVER" != nil ] ;then
#有其他服务器可用,进行切换
#echo $(uci_get_by_name $new_proxy server)
CURRENT_SERVER=$ENABLE_SERVER
switch_proxy $CURRENT_SERVER
normal_flag=1
logger -t "$NAME" "switch proxy ["$(uci_get_by_name $CURRENT_SERVER server)"] success!"
#echo "switch ok"
else
normal_flag=0
fi
else
normal_flag=0
fi
done
}

View File

@ -0,0 +1,315 @@
From 4a153bc0bb8ed20517871bddbf92ba69057bef97 Mon Sep 17 00:00:00 2001
From: WouldChar <wouldchar@gmail.com>
Date: Mon, 18 Dec 2017 19:33:51 +0800
Subject: [PATCH 1/7] Backport ss-check
* from https://github.com/ywb94/shadowsocks-libev
---
src/Makefile.am | 5 ++
src/check.c | 242 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/redir.c | 2 +-
3 files changed, 248 insertions(+), 1 deletion(-)
create mode 100644 src/check.c
diff --git a/src/Makefile.am b/src/Makefile.am
index eea1300..d2c6d24 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -22,7 +22,7 @@ SS_COMMON_LIBS += $(top_builddir)/libev/libev.la \
$(top_builddir)/libsodium/src/libsodium/libsodium.la
endif
-bin_PROGRAMS = ss-local
+bin_PROGRAMS = ss-local ss-check
#bin_PROGRAMS += ss-tunnel
if !BUILD_WINCOMPAT
#bin_PROGRAMS += ss-server ss-manager
@@ -42,6 +43,8 @@ ss_local_SOURCES = utils.c \
local.c \
$(sni_src)
+ss_check_SOURCES = check.c
+
#ss_tunnel_SOURCES = utils.c \
# jconf.c \
# json.c \
@@ -69,6 +72,7 @@ ss_local_SOURCES = utils.c \
# manager.c
ss_local_LDADD = $(SS_COMMON_LIBS)
+ss_check_LDADD = $(SS_COMMON_LIBS)
#ss_tunnel_LDADD = $(SS_COMMON_LIBS)
#ss_server_LDADD = $(SS_COMMON_LIBS)
#ss_manager_LDADD = $(SS_COMMON_LIBS)
@@ -83,6 +87,7 @@ ss_local_LDADD += $(top_builddir)/libudns/libudns.la
endif
ss_local_CFLAGS = $(AM_CFLAGS) -DMODULE_LOCAL
+ss_check_CFLAGS = $(AM_CFLAGS) -DMODULE_CHECK
#ss_tunnel_CFLAGS = $(AM_CFLAGS) -DMODULE_TUNNEL
#ss_server_CFLAGS = $(AM_CFLAGS) -DMODULE_REMOTE
#ss_manager_CFLAGS = $(AM_CFLAGS) -DMODULE_MANAGER
diff --git a/src/check.c b/src/check.c
new file mode 100644
index 0000000..9243686
--- /dev/null
+++ b/src/check.c
@@ -0,0 +1,242 @@
+/*
+ * check.c - check remote shadowsocks server port
+ *
+ * Copyright (C) 2017, yushi studio <ywb94@qq.com>
+ *
+ * This file is part of the shadowsocks-libev.
+ *
+ * shadowsocks-libev is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * shadowsocks-libev is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with shadowsocks-libev; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <time.h>
+#include <arpa/inet.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <string.h>
+
+//#define __DEBUG__
+#ifdef __DEBUG__
+#define DEBUG(format,...) printf("File: "__FILE__", Line: %05d: "format"/n", __LINE__, ##__VA_ARGS__)
+#else
+#define DEBUG(format,...)
+#endif
+
+static sigjmp_buf jmpbuf;
+
+static void alarm_func()
+{
+ siglongjmp(jmpbuf, 1);
+}
+
+static struct hostent *timeGethostbyname(const char *domain, int timeout)
+{
+ struct hostent *ipHostent = NULL;
+ signal(SIGALRM, alarm_func);
+ if (sigsetjmp(jmpbuf, 1) != 0) {
+ alarm(0); //timout
+ signal(SIGALRM, SIG_IGN);
+ return NULL;
+ }
+ alarm(timeout); //setting alarm
+ ipHostent = gethostbyname(domain);
+ signal(SIGALRM, SIG_IGN);
+ return ipHostent;
+}
+
+
+#define MY_HTTP_DEFAULT_PORT 80
+#define BUFFER_SIZE 1024
+#define HTTP_POST "POST /%s HTTP/1.1\r\nHOST: %s:%d\r\nAccept: */*\r\n"\
+ "Content-Type:application/x-www-form-urlencoded\r\nContent-Length: %d\r\n\r\n%s"
+#define HTTP_GET "GET /%s HTTP/1.1\r\nHOST: %s:%d\r\nAccept: */*\r\n\r\n"
+
+static int http_parse_url(const char *url, char *host, char *file, int *port)
+{
+ char *ptr1, *ptr2;
+ int len = 0;
+ if (!url || !host || !file || !port)
+ return 1;
+
+ ptr1 = (char *)url;
+
+ if (!strncmp(ptr1, "http://", strlen("http://")))
+ ptr1 += strlen("http://");
+ else
+ return 1;
+
+ ptr2 = strchr(ptr1, '/');
+ if (ptr2) {
+ len = strlen(ptr1) - strlen(ptr2);
+ memcpy(host, ptr1, len);
+ host[len] = '\0';
+ if (*(ptr2 + 1)) {
+ memcpy(file, ptr2 + 1, strlen(ptr2) - 1);
+ file[strlen(ptr2) - 1] = '\0';
+ }
+ }
+ else {
+ memcpy(host,ptr1,strlen(ptr1));
+ host[strlen(ptr1)] = '\0';
+ }
+
+ //get host and ip
+ ptr1 = strchr(host, ':');
+ if (ptr1) {
+ *ptr1++ = '\0';
+ *port = atoi(ptr1);
+ }
+ else
+ *port = MY_HTTP_DEFAULT_PORT;
+
+ return 0;
+}
+
+static int http_tcpclient_recv(int socket, char *lpbuff)
+{
+ int recvnum = 0;
+
+ recvnum = recv(socket, lpbuff, BUFFER_SIZE*4, 0);
+
+ return recvnum;
+}
+
+static int http_tcpclient_send(int socket, char *buff, int size)
+{
+ int sent = 0, tmpres = 0;
+
+ while (sent < size) {
+ tmpres = send(socket, buff + sent, size - sent, 0);
+ if (tmpres == -1)
+ return 1;
+ sent += tmpres;
+ }
+ return sent;
+}
+
+int http_get(const char *url, int socket_fd)
+{
+ char lpbuf[BUFFER_SIZE * 4] = {'\0'};
+
+ char host_addr[BUFFER_SIZE] = {'\0'};
+ char file[BUFFER_SIZE] = {'\0'};
+ int port = 0;
+
+ if (!url) {
+ DEBUG("url failed\n");
+ return 1;
+ }
+
+ if (http_parse_url(url, host_addr, file, &port)) {
+ DEBUG("http_parse_url failed\n");
+ return 1;
+ }
+ DEBUG("url: %s\thost_addr: %s\tfile: %s\t, %d\n", url, host_addr, file, port);
+
+ if (socket_fd < 0) {
+ DEBUG("http_tcpclient_create failed\n");
+ return 1;
+ }
+
+ sprintf(lpbuf, HTTP_GET, file, host_addr, port);
+
+ if (http_tcpclient_send(socket_fd, lpbuf, strlen(lpbuf)) < 0) {
+ DEBUG("http_tcpclient_send failed\n");
+ return 1;
+ }
+ DEBUG("request:\n%s\n", lpbuf);
+
+ if (http_tcpclient_recv(socket_fd, lpbuf) <= 0) {
+ DEBUG("http_tcpclient_recv failed\n");
+ close(socket_fd);
+ return 1;
+ }
+ DEBUG("rec:\n%s\n", lpbuf);
+ close(socket_fd);
+
+ //return http_parse_result(lpbuf);
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int fd, http_flag = 0, http_ret = 1;
+ struct sockaddr_in addr;
+ struct hostent *host;
+ struct timeval timeo = {3, 0};
+ socklen_t len = sizeof(timeo);
+
+ char http_url[100] = "http://";
+
+ fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (argc >= 4)
+ timeo.tv_sec = atoi(argv[3]);
+ if (argc >= 5)
+ http_flag=1;
+
+ if ((host = timeGethostbyname(argv[1], timeo.tv_sec)) == NULL) {
+ DEBUG("gethostbyname err\n");
+ return 1;
+ }
+
+ if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeo, len) == -1) {
+ DEBUG("setsockopt send err\n");
+ return 1;
+ }
+
+ if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeo, len) == -1) {
+ DEBUG("setsockopt recv err\n");
+ return 1;
+ }
+
+ addr.sin_family = AF_INET;
+ addr.sin_addr = *((struct in_addr *)host->h_addr);
+ //addr.sin_addr.s_addr = inet_addr(argv[1]);
+ addr.sin_port = htons(atoi(argv[2]));
+
+ if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+ if (errno == EINPROGRESS) {
+ DEBUG("timeout err\n");
+ return 1;
+ }
+ DEBUG("connect err\n");
+ return 1;
+ }
+
+ if (http_flag == 0) {
+ close(fd);
+ return 0;
+ }
+
+ strcat(http_url, argv[1]);
+ http_ret = http_get(http_url, fd);
+
+ if (http_ret == 1) {
+ DEBUG("recv err");
+ return 1;
+ }
+ else {
+ DEBUG("recv ok");
+ return 0;
+ }
+}
diff --git a/src/redir.c b/src/redir.c
index 4345a36..e2bdd0e 100644
--- a/src/redir.c
+++ b/src/redir.c
@@ -203,7 +203,7 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
// continue to wait for recv
return;
} else {
- ERROR("server recv");
+ //ERROR("server recv");
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
return;
--
2.7.4

View File

@ -0,0 +1,12 @@
INSTALL = install
PREFIX = /usr/bin
po2lmo: src/po2lmo.o src/template_lmo.o
$(CC) -o src/po2lmo src/po2lmo.o src/template_lmo.o
install:
$(INSTALL) -m 755 src/po2lmo $(PREFIX)
clean:
$(RM) src/po2lmo src/*.o

Binary file not shown.

View File

@ -0,0 +1,247 @@
/*
* lmo - Lua Machine Objects - PO to LMO conversion tool
*
* Copyright (C) 2009-2012 Jo-Philipp Wich <xm@subsignal.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "template_lmo.h"
static void die(const char *msg)
{
fprintf(stderr, "Error: %s\n", msg);
exit(1);
}
static void usage(const char *name)
{
fprintf(stderr, "Usage: %s input.po output.lmo\n", name);
exit(1);
}
static void print(const void *ptr, size_t size, size_t nmemb, FILE *stream)
{
if( fwrite(ptr, size, nmemb, stream) == 0 )
die("Failed to write stdout");
}
static int extract_string(const char *src, char *dest, int len)
{
int pos = 0;
int esc = 0;
int off = -1;
for( pos = 0; (pos < strlen(src)) && (pos < len); pos++ )
{
if( (off == -1) && (src[pos] == '"') )
{
off = pos + 1;
}
else if( off >= 0 )
{
if( esc == 1 )
{
switch (src[pos])
{
case '"':
case '\\':
off++;
break;
}
dest[pos-off] = src[pos];
esc = 0;
}
else if( src[pos] == '\\' )
{
dest[pos-off] = src[pos];
esc = 1;
}
else if( src[pos] != '"' )
{
dest[pos-off] = src[pos];
}
else
{
dest[pos-off] = '\0';
break;
}
}
}
return (off > -1) ? strlen(dest) : -1;
}
static int cmp_index(const void *a, const void *b)
{
uint32_t x = ((const lmo_entry_t *)a)->key_id;
uint32_t y = ((const lmo_entry_t *)b)->key_id;
if (x < y)
return -1;
else if (x > y)
return 1;
return 0;
}
static void print_uint32(uint32_t x, FILE *out)
{
uint32_t y = htonl(x);
print(&y, sizeof(uint32_t), 1, out);
}
static void print_index(void *array, int n, FILE *out)
{
lmo_entry_t *e;
qsort(array, n, sizeof(*e), cmp_index);
for (e = array; n > 0; n--, e++)
{
print_uint32(e->key_id, out);
print_uint32(e->val_id, out);
print_uint32(e->offset, out);
print_uint32(e->length, out);
}
}
int main(int argc, char *argv[])
{
char line[4096];
char key[4096];
char val[4096];
char tmp[4096];
int state = 0;
int offset = 0;
int length = 0;
int n_entries = 0;
void *array = NULL;
lmo_entry_t *entry = NULL;
uint32_t key_id, val_id;
FILE *in;
FILE *out;
if( (argc != 3) || ((in = fopen(argv[1], "r")) == NULL) || ((out = fopen(argv[2], "w")) == NULL) )
usage(argv[0]);
memset(line, 0, sizeof(key));
memset(key, 0, sizeof(val));
memset(val, 0, sizeof(val));
while( (NULL != fgets(line, sizeof(line), in)) || (state >= 2 && feof(in)) )
{
if( state == 0 && strstr(line, "msgid \"") == line )
{
switch(extract_string(line, key, sizeof(key)))
{
case -1:
die("Syntax error in msgid");
case 0:
state = 1;
break;
default:
state = 2;
}
}
else if( state == 1 || state == 2 )
{
if( strstr(line, "msgstr \"") == line || state == 2 )
{
switch(extract_string(line, val, sizeof(val)))
{
case -1:
state = 4;
break;
default:
state = 3;
}
}
else
{
switch(extract_string(line, tmp, sizeof(tmp)))
{
case -1:
state = 2;
break;
default:
strcat(key, tmp);
}
}
}
else if( state == 3 )
{
switch(extract_string(line, tmp, sizeof(tmp)))
{
case -1:
state = 4;
break;
default:
strcat(val, tmp);
}
}
if( state == 4 )
{
if( strlen(key) > 0 && strlen(val) > 0 )
{
key_id = sfh_hash(key, strlen(key));
val_id = sfh_hash(val, strlen(val));
if( key_id != val_id )
{
n_entries++;
array = realloc(array, n_entries * sizeof(lmo_entry_t));
entry = (lmo_entry_t *)array + n_entries - 1;
if (!array)
die("Out of memory");
entry->key_id = key_id;
entry->val_id = val_id;
entry->offset = offset;
entry->length = strlen(val);
length = strlen(val) + ((4 - (strlen(val) % 4)) % 4);
print(val, length, 1, out);
offset += length;
}
}
state = 0;
memset(key, 0, sizeof(key));
memset(val, 0, sizeof(val));
}
memset(line, 0, sizeof(line));
}
print_index(array, n_entries, out);
if( offset > 0 )
{
print_uint32(offset, out);
fsync(fileno(out));
fclose(out);
}
else
{
fclose(out);
unlink(argv[2]);
}
fclose(in);
return(0);
}

View File

@ -0,0 +1,328 @@
/*
* lmo - Lua Machine Objects - Base functions
*
* Copyright (C) 2009-2010 Jo-Philipp Wich <xm@subsignal.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "template_lmo.h"
/*
* Hash function from http://www.azillionmonkeys.com/qed/hash.html
* Copyright (C) 2004-2008 by Paul Hsieh
*/
uint32_t sfh_hash(const char *data, int len)
{
uint32_t hash = len, tmp;
int rem;
if (len <= 0 || data == NULL) return 0;
rem = len & 3;
len >>= 2;
/* Main loop */
for (;len > 0; len--) {
hash += sfh_get16(data);
tmp = (sfh_get16(data+2) << 11) ^ hash;
hash = (hash << 16) ^ tmp;
data += 2*sizeof(uint16_t);
hash += hash >> 11;
}
/* Handle end cases */
switch (rem) {
case 3: hash += sfh_get16(data);
hash ^= hash << 16;
hash ^= data[sizeof(uint16_t)] << 18;
hash += hash >> 11;
break;
case 2: hash += sfh_get16(data);
hash ^= hash << 11;
hash += hash >> 17;
break;
case 1: hash += *data;
hash ^= hash << 10;
hash += hash >> 1;
}
/* Force "avalanching" of final 127 bits */
hash ^= hash << 3;
hash += hash >> 5;
hash ^= hash << 4;
hash += hash >> 17;
hash ^= hash << 25;
hash += hash >> 6;
return hash;
}
uint32_t lmo_canon_hash(const char *str, int len)
{
char res[4096];
char *ptr, prev;
int off;
if (!str || len >= sizeof(res))
return 0;
for (prev = ' ', ptr = res, off = 0; off < len; prev = *str, off++, str++)
{
if (isspace(*str))
{
if (!isspace(prev))
*ptr++ = ' ';
}
else
{
*ptr++ = *str;
}
}
if ((ptr > res) && isspace(*(ptr-1)))
ptr--;
return sfh_hash(res, ptr - res);
}
lmo_archive_t * lmo_open(const char *file)
{
int in = -1;
uint32_t idx_offset = 0;
struct stat s;
lmo_archive_t *ar = NULL;
if (stat(file, &s) == -1)
goto err;
if ((in = open(file, O_RDONLY)) == -1)
goto err;
if ((ar = (lmo_archive_t *)malloc(sizeof(*ar))) != NULL)
{
memset(ar, 0, sizeof(*ar));
ar->fd = in;
ar->size = s.st_size;
fcntl(ar->fd, F_SETFD, fcntl(ar->fd, F_GETFD) | FD_CLOEXEC);
if ((ar->mmap = mmap(NULL, ar->size, PROT_READ, MAP_SHARED, ar->fd, 0)) == MAP_FAILED)
goto err;
idx_offset = ntohl(*((const uint32_t *)
(ar->mmap + ar->size - sizeof(uint32_t))));
if (idx_offset >= ar->size)
goto err;
ar->index = (lmo_entry_t *)(ar->mmap + idx_offset);
ar->length = (ar->size - idx_offset - sizeof(uint32_t)) / sizeof(lmo_entry_t);
ar->end = ar->mmap + ar->size;
return ar;
}
err:
if (in > -1)
close(in);
if (ar != NULL)
{
if ((ar->mmap != NULL) && (ar->mmap != MAP_FAILED))
munmap(ar->mmap, ar->size);
free(ar);
}
return NULL;
}
void lmo_close(lmo_archive_t *ar)
{
if (ar != NULL)
{
if ((ar->mmap != NULL) && (ar->mmap != MAP_FAILED))
munmap(ar->mmap, ar->size);
close(ar->fd);
free(ar);
ar = NULL;
}
}
lmo_catalog_t *_lmo_catalogs = NULL;
lmo_catalog_t *_lmo_active_catalog = NULL;
int lmo_load_catalog(const char *lang, const char *dir)
{
DIR *dh = NULL;
char pattern[16];
char path[PATH_MAX];
struct dirent *de = NULL;
lmo_archive_t *ar = NULL;
lmo_catalog_t *cat = NULL;
if (!lmo_change_catalog(lang))
return 0;
if (!dir || !(dh = opendir(dir)))
goto err;
if (!(cat = malloc(sizeof(*cat))))
goto err;
memset(cat, 0, sizeof(*cat));
snprintf(cat->lang, sizeof(cat->lang), "%s", lang);
snprintf(pattern, sizeof(pattern), "*.%s.lmo", lang);
while ((de = readdir(dh)) != NULL)
{
if (!fnmatch(pattern, de->d_name, 0))
{
snprintf(path, sizeof(path), "%s/%s", dir, de->d_name);
ar = lmo_open(path);
if (ar)
{
ar->next = cat->archives;
cat->archives = ar;
}
}
}
closedir(dh);
cat->next = _lmo_catalogs;
_lmo_catalogs = cat;
if (!_lmo_active_catalog)
_lmo_active_catalog = cat;
return 0;
err:
if (dh) closedir(dh);
if (cat) free(cat);
return -1;
}
int lmo_change_catalog(const char *lang)
{
lmo_catalog_t *cat;
for (cat = _lmo_catalogs; cat; cat = cat->next)
{
if (!strncmp(cat->lang, lang, sizeof(cat->lang)))
{
_lmo_active_catalog = cat;
return 0;
}
}
return -1;
}
static lmo_entry_t * lmo_find_entry(lmo_archive_t *ar, uint32_t hash)
{
unsigned int m, l, r;
uint32_t k;
l = 0;
r = ar->length - 1;
while (1)
{
m = l + ((r - l) / 2);
if (r < l)
break;
k = ntohl(ar->index[m].key_id);
if (k == hash)
return &ar->index[m];
if (k > hash)
{
if (!m)
break;
r = m - 1;
}
else
{
l = m + 1;
}
}
return NULL;
}
int lmo_translate(const char *key, int keylen, char **out, int *outlen)
{
uint32_t hash;
lmo_entry_t *e;
lmo_archive_t *ar;
if (!key || !_lmo_active_catalog)
return -2;
hash = lmo_canon_hash(key, keylen);
for (ar = _lmo_active_catalog->archives; ar; ar = ar->next)
{
if ((e = lmo_find_entry(ar, hash)) != NULL)
{
*out = ar->mmap + ntohl(e->offset);
*outlen = ntohl(e->length);
return 0;
}
}
return -1;
}
void lmo_close_catalog(const char *lang)
{
lmo_archive_t *ar, *next;
lmo_catalog_t *cat, *prev;
for (prev = NULL, cat = _lmo_catalogs; cat; prev = cat, cat = cat->next)
{
if (!strncmp(cat->lang, lang, sizeof(cat->lang)))
{
if (prev)
prev->next = cat->next;
else
_lmo_catalogs = cat->next;
for (ar = cat->archives; ar; ar = next)
{
next = ar->next;
lmo_close(ar);
}
free(cat);
break;
}
}
}

View File

@ -0,0 +1,92 @@
/*
* lmo - Lua Machine Objects - General header
*
* Copyright (C) 2009-2012 Jo-Philipp Wich <xm@subsignal.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _TEMPLATE_LMO_H_
#define _TEMPLATE_LMO_H_
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>
#include <fnmatch.h>
#include <dirent.h>
#include <ctype.h>
#include <limits.h>
#if (defined(__GNUC__) && defined(__i386__))
#define sfh_get16(d) (*((const uint16_t *) (d)))
#else
#define sfh_get16(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\
+(uint32_t)(((const uint8_t *)(d))[0]) )
#endif
struct lmo_entry {
uint32_t key_id;
uint32_t val_id;
uint32_t offset;
uint32_t length;
} __attribute__((packed));
typedef struct lmo_entry lmo_entry_t;
struct lmo_archive {
int fd;
int length;
uint32_t size;
lmo_entry_t *index;
char *mmap;
char *end;
struct lmo_archive *next;
};
typedef struct lmo_archive lmo_archive_t;
struct lmo_catalog {
char lang[6];
struct lmo_archive *archives;
struct lmo_catalog *next;
};
typedef struct lmo_catalog lmo_catalog_t;
uint32_t sfh_hash(const char *data, int len);
uint32_t lmo_canon_hash(const char *data, int len);
lmo_archive_t * lmo_open(const char *file);
void lmo_close(lmo_archive_t *ar);
extern lmo_catalog_t *_lmo_catalogs;
extern lmo_catalog_t *_lmo_active_catalog;
int lmo_load_catalog(const char *lang, const char *dir);
int lmo_change_catalog(const char *lang);
int lmo_translate(const char *key, int keylen, char **out, int *outlen);
void lmo_close_catalog(const char *lang);
#endif