update.lua 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. #!/usr/bin/lua
  2. ------------------------------------------------
  3. -- This file is part of the luci-app-ssr-plus update.lua
  4. -- By Mattraks
  5. ------------------------------------------------
  6. require "luci.sys"
  7. require "luci.model.uci"
  8. local icount = 0
  9. local args = arg[1]
  10. local uci = require "luci.model.uci".cursor()
  11. -- 以下设置更新数据库至 DNSMASQ 配置路径
  12. -- 获取 DNSMASQ 配置 ID
  13. local DNSMASQ_UCI_CONFIG = uci:get_first("dhcp", "dnsmasq", ".name")
  14. -- 获取 DNSMASQ 默认配置文件
  15. local DNSMASQ_CONF_PATH = "/tmp/etc/dnsmasq.conf." .. DNSMASQ_UCI_CONFIG
  16. -- 检查 DNSMASQ 配置文件是否存在,如果存在则提取 conf-dir
  17. for line in io.lines(DNSMASQ_CONF_PATH) do
  18. local conf_dir = line:match("^conf%-dir=(.+)")
  19. if conf_dir then
  20. DNSMASQ_CONF_DIR = conf_dir:gsub("%s+", "") -- 去除空白字符
  21. break
  22. end
  23. end
  24. -- 设置 dnsmasq-ssrplus.d 目录路径,并去除路径末尾的斜杠
  25. local TMP_DNSMASQ_PATH = DNSMASQ_CONF_DIR:match("^(.-)/?$") .. "/dnsmasq-ssrplus.d"
  26. local TMP_PATH = "/var/etc/ssrplus"
  27. -- match comments/title/whitelist/ip address/excluded_domain
  28. local comment_pattern = "^[!\\[@]+"
  29. local ip_pattern = "^%d+%.%d+%.%d+%.%d+"
  30. local domain_pattern = "([%w%-%_]+%.[%w%.%-%_]+)[%/%*]*"
  31. local excluded_domain = {
  32. "apple.com", "sina.cn", "sina.com.cn", "baidu.com", "byr.cn", "jlike.com",
  33. "weibo.com", "zhongsou.com", "youdao.com", "sogou.com", "so.com", "soso.com",
  34. "aliyun.com", "taobao.com", "jd.com", "qq.com"
  35. }
  36. -- gfwlist parameter
  37. local mydnsip = '127.0.0.1'
  38. local mydnsport = '5335'
  39. local ipsetname = 'gfwlist'
  40. local new_appledns = uci:get_first("shadowsocksr", "global", "apple_dns")
  41. local bc = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
  42. -- base64decoding
  43. local function base64_dec(data)
  44. data = string.gsub(data, '[^' .. bc .. '=]', '')
  45. return (data:gsub('.', function(x)
  46. if (x == '=') then
  47. return ''
  48. end
  49. local r, f = '', (bc:find(x) - 1)
  50. for i = 6, 1, -1 do
  51. r = r .. (f % 2 ^ i - f % 2 ^ (i - 1) > 0 and '1' or '0')
  52. end
  53. return r;
  54. end):gsub('%d%d%d?%d?%d?%d?%d?%d?', function(x)
  55. if (#x ~= 8) then
  56. return ''
  57. end
  58. local c = 0
  59. for i = 1, 8 do
  60. c = c + (x:sub(i, i) == '1' and 2 ^ (8 - i) or 0)
  61. end
  62. return string.char(c)
  63. end))
  64. end
  65. -- check if domain is excluded
  66. local function check_excluded_domain(value)
  67. for _, domain in ipairs(excluded_domain) do
  68. if value:find(domain) then
  69. return true
  70. end
  71. end
  72. end
  73. -- gfwlist转码至dnsmasq格式
  74. local function generate_gfwlist(type)
  75. local domains, domains_map = {}, {}
  76. local out = io.open("/tmp/ssr-update." .. type, "w")
  77. for line in io.lines("/tmp/ssr-update.tmp") do
  78. if not (string.find(line, comment_pattern) or string.find(line, ip_pattern) or check_excluded_domain(line)) then
  79. local start, finish, match = string.find(line, domain_pattern)
  80. if start and not domains_map[match] then
  81. domains_map[match] = true
  82. table.insert(domains, match)
  83. end
  84. end
  85. end
  86. for _, domain in ipairs(domains) do
  87. out:write(string.format("server=/%s/%s#%s\n", domain, mydnsip, mydnsport))
  88. out:write(string.format("ipset=/%s/%s\n", domain, ipsetname))
  89. end
  90. out:close()
  91. os.remove("/tmp/ssr-update.tmp")
  92. end
  93. -- 更换 Apple dns
  94. local function generate_apple(type)
  95. local domains, domains_map = {}, {}
  96. local out = io.open("/tmp/ssr-update." .. type, "w")
  97. for line in io.lines("/tmp/ssr-update.tmp") do
  98. if not (string.find(line, comment_pattern)) then
  99. local start, finish, match = string.find(line, domain_pattern)
  100. if start and not domains_map[match] then
  101. domains_map[match] = true
  102. match = string.gsub(match, "%s", "") --从域名中去除所有空白字符
  103. table.insert(domains, match)
  104. end
  105. end
  106. end
  107. for _, domain in ipairs(domains) do
  108. if new_appledns and new_appledns ~= "" then
  109. out:write(string.format("server=/%s/%s\n", domain, new_appledns))
  110. end
  111. end
  112. out:close()
  113. os.remove("/tmp/ssr-update.tmp")
  114. end
  115. -- adblock转码至dnsmasq格式
  116. local function generate_adblock(type)
  117. local domains, domains_map = {}, {}
  118. local out = io.open("/tmp/ssr-update." .. type, "w")
  119. for line in io.lines("/tmp/ssr-update.tmp") do
  120. if not (string.find(line, comment_pattern)) then
  121. local start, finish, match = string.find(line, domain_pattern)
  122. if start and not domains_map[match] then
  123. domains_map[match] = true
  124. table.insert(domains, match)
  125. end
  126. end
  127. end
  128. for _, domain in ipairs(domains) do
  129. out:write(string.format("address=/%s/\n", domain))
  130. end
  131. out:close()
  132. os.remove("/tmp/ssr-update.tmp")
  133. end
  134. local log = function(...)
  135. if args then
  136. print("{ret=" .. table.concat({...}, ",retcount=") .. "}")
  137. else
  138. print(os.date("%Y-%m-%d %H:%M:%S ") .. table.concat({...}, " "))
  139. end
  140. end
  141. local function update(url, file, type, file2)
  142. local Num = 1
  143. local refresh_cmd = "curl -sSL --insecure -o /tmp/ssr-update." .. type .. " " .. url
  144. local sret = luci.sys.call(refresh_cmd)
  145. if sret == 0 then
  146. if type == "gfw_data" then
  147. local gfwlist = io.open("/tmp/ssr-update." .. type, "r")
  148. local decode = gfwlist:read("*a")
  149. if not decode:find("google") then
  150. decode = base64_dec(decode)
  151. end
  152. gfwlist:close()
  153. -- 写回gfwlist
  154. gfwlist = io.open("/tmp/ssr-update.tmp", "w")
  155. gfwlist:write(decode)
  156. gfwlist:close()
  157. generate_gfwlist(type)
  158. Num = 2
  159. end
  160. if type == "apple_data" then
  161. local apple = io.open("/tmp/ssr-update." .. type, "r")
  162. local decode = apple:read("*a")
  163. if not decode:find("apple") then
  164. decode = base64_dec(decode)
  165. end
  166. apple:close()
  167. -- 写回applechina
  168. apple = io.open("/tmp/ssr-update.tmp", "w")
  169. apple:write(decode)
  170. apple:close()
  171. if new_appledns and new_appledns ~= "" then
  172. generate_apple(type)
  173. end
  174. end
  175. if type == "ad_data" then
  176. local adblock = io.open("/tmp/ssr-update." .. type, "r")
  177. local decode = adblock:read("*a")
  178. if decode:find("address=") then
  179. adblock:close()
  180. else
  181. adblock:close()
  182. -- 写回adblock
  183. adblock = io.open("/tmp/ssr-update.tmp", "w")
  184. adblock:write(decode)
  185. adblock:close()
  186. generate_adblock(type)
  187. end
  188. end
  189. local new_md5 = luci.sys.exec("echo -n $([ -f '/tmp/ssr-update." .. type .. "' ] && md5sum /tmp/ssr-update." .. type .. " | awk '{print $1}')")
  190. local old_md5 = luci.sys.exec("echo -n $([ -f '" .. file .. "' ] && md5sum " .. file .. " | awk '{print $1}')")
  191. if new_md5 == old_md5 then
  192. if args then
  193. log(1)
  194. else
  195. log("你已经是最新数据,无需更新!")
  196. end
  197. else
  198. icount = luci.sys.exec("cat /tmp/ssr-update." .. type .. " | wc -l")
  199. luci.sys.exec("cp -f /tmp/ssr-update." .. type .. " " .. file)
  200. if file2 then
  201. luci.sys.exec("cp -f /tmp/ssr-update." .. type .. " " .. file2)
  202. end
  203. if type == "gfw_data" or type == "ad_data" then
  204. luci.sys.call("/usr/share/shadowsocksr/gfw2ipset.sh")
  205. else
  206. luci.sys.call("/usr/share/shadowsocksr/chinaipset.sh " .. TMP_PATH .. "/china_ssr.txt")
  207. end
  208. if args then
  209. log(0, tonumber(icount) / Num)
  210. else
  211. log("更新成功! 新的总记录数:" .. tostring(tonumber(icount) / Num))
  212. end
  213. end
  214. else
  215. if args then
  216. log(-1)
  217. else
  218. log("更新失败!")
  219. end
  220. end
  221. os.remove("/tmp/ssr-update." .. type)
  222. end
  223. if args then
  224. if args == "gfw_data" then
  225. update(uci:get_first("shadowsocksr", "global", "gfwlist_url"), "/etc/ssrplus/gfw_list.conf", args, TMP_DNSMASQ_PATH .. "/gfw_list.conf")
  226. os.exit(0)
  227. end
  228. if args == "ip_data" then
  229. update(uci:get_first("shadowsocksr", "global", "chnroute_url"), "/etc/ssrplus/china_ssr.txt", args, TMP_PATH .. "/china_ssr.txt")
  230. os.exit(0)
  231. end
  232. if args == "apple_data" then
  233. update(uci:get_first("shadowsocksr", "global", "apple_url"), "/etc/ssrplus/applechina.conf", args, TMP_DNSMASQ_PATH .. "/applechina.conf")
  234. os.exit(0)
  235. end
  236. if args == "ad_data" then
  237. update(uci:get_first("shadowsocksr", "global", "adblock_url"), "/etc/ssrplus/ad.conf", args, TMP_DNSMASQ_PATH .. "/ad.conf")
  238. os.exit(0)
  239. end
  240. if args == "nfip_data" then
  241. update(uci:get_first("shadowsocksr", "global", "nfip_url"), "/etc/ssrplus/netflixip.list", args, TMP_DNSMASQ_PATH .. "/netflixip.list")
  242. os.exit(0)
  243. end
  244. else
  245. log("正在更新【GFW列表】数据库")
  246. update(uci:get_first("shadowsocksr", "global", "gfwlist_url"), "/etc/ssrplus/gfw_list.conf", "gfw_data", TMP_DNSMASQ_PATH .. "/gfw_list.conf")
  247. log("正在更新【国内IP段】数据库")
  248. update(uci:get_first("shadowsocksr", "global", "chnroute_url"), "/etc/ssrplus/china_ssr.txt", "ip_data", TMP_PATH .. "/china_ssr.txt")
  249. if uci:get_first("shadowsocksr", "global", "apple_optimization", "0") == "1" then
  250. log("正在更新【Apple域名】数据库")
  251. update(uci:get_first("shadowsocksr", "global", "apple_url"), "/etc/ssrplus/applechina.conf", "apple_data", TMP_DNSMASQ_PATH .. "/applechina.conf")
  252. end
  253. if uci:get_first("shadowsocksr", "global", "adblock", "0") == "1" then
  254. log("正在更新【广告屏蔽】数据库")
  255. update(uci:get_first("shadowsocksr", "global", "adblock_url"), "/etc/ssrplus/ad.conf", "ad_data", TMP_DNSMASQ_PATH .. "/ad.conf")
  256. end
  257. if uci:get_first("shadowsocksr", "global", "netflix_enable", "0") == "1" then
  258. log("正在更新【Netflix IP段】数据库")
  259. update(uci:get_first("shadowsocksr", "global", "nfip_url"), "/etc/ssrplus/netflixip.list", "nfip_data", TMP_DNSMASQ_PATH .. "/netflixip.list")
  260. end
  261. -- log("正在更新【Netflix IP段】数据库")
  262. -- update(uci:get_first("shadowsocksr", "global", "nfip_url"), "/etc/ssrplus/netflixip.list", "nfip_data")
  263. end