diff --git a/luci-app-aliddns/LICENSE b/luci-app-aliddns/LICENSE
new file mode 100644
index 000000000..e09a55e37
--- /dev/null
+++ b/luci-app-aliddns/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2017 chenhw2
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/luci-app-aliddns/Makefile b/luci-app-aliddns/Makefile
index aeb95408b..356f58d73 100644
--- a/luci-app-aliddns/Makefile
+++ b/luci-app-aliddns/Makefile
@@ -1,24 +1,84 @@
#
-# Copyright (C) 2018 chenhw2
+# Copyright (C) 2018-2021 chenhw2
#
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
-LUCI_TITLE:=LuCI Support for aliddns
-LUCI_DESCRIPTION:=LuCI Support for ALiDDNS.
-LUCI_DEPENDS:=+openssl-util +curl
-LUCI_PKGARCH:=all
-
PKG_NAME:=luci-app-aliddns
-PKG_VERSION:=0.3.0
+PKG_VERSION:=0.4.0
PKG_RELEASE:=1
PKG_LICENSE:=MIT
PKG_LICENSE_FILES:=LICENSE
PKG_MAINTAINER:=chenhw2
-include $(TOPDIR)/feeds/luci/luci.mk
+PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
-# call BuildPackage - OpenWrt buildroot signature
+include $(INCLUDE_DIR)/package.mk
+
+define Package/luci-app-aliddns
+ SECTION:=luci
+ CATEGORY:=LuCI
+ SUBMENU:=3. Applications
+ TITLE:=LuCI Support for aliddns
+ PKGARCH:=all
+ DEPENDS:=+openssl-util +curl
+endef
+
+define Package/luci-app-aliddns/description
+ LuCI Support for ALiDDNS.
+endef
+
+define Build/Prepare
+ $(foreach po,$(wildcard ${CURDIR}/files/luci/i18n/*.po), \
+ po2lmo $(po) $(PKG_BUILD_DIR)/$(patsubst %.po,%.lmo,$(notdir $(po)));)
+endef
+
+define Build/Configure
+endef
+
+define Build/Compile
+endef
+
+define Package/luci-app-aliddns/postinst
+#!/bin/sh
+if [ -z "$${IPKG_INSTROOT}" ]; then
+ if [ -f /etc/uci-defaults/luci-aliddns ]; then
+ ( . /etc/uci-defaults/luci-aliddns ) && \
+ rm -f /etc/uci-defaults/luci-aliddns
+ fi
+ rm -rf /tmp/luci-indexcache /tmp/luci-modulecache
+fi
+exit 0
+endef
+
+define Package/luci-app-aliddns/prerm
+#!/bin/sh
+/etc/init.d/aliddns stop
+exit 0
+endef
+
+define Package/luci-app-aliddns/conffiles
+/etc/config/aliddns
+endef
+
+define Package/luci-app-aliddns/install
+ $(INSTALL_DIR) $(1)/usr/lib/lua/luci/i18n
+ $(INSTALL_DATA) $(PKG_BUILD_DIR)/aliddns.*.lmo $(1)/usr/lib/lua/luci/i18n/
+ $(INSTALL_DIR) $(1)/usr/lib/lua/luci/controller
+ $(INSTALL_DATA) ./files/luci/controller/*.lua $(1)/usr/lib/lua/luci/controller/
+ $(INSTALL_DIR) $(1)/usr/lib/lua/luci/model/cbi/aliddns
+ $(INSTALL_DATA) ./files/luci/model/cbi/*.lua $(1)/usr/lib/lua/luci/model/cbi/
+ $(INSTALL_DIR) $(1)/etc/config
+ $(INSTALL_DATA) ./files/root/etc/config/aliddns $(1)/etc/config/aliddns
+ $(INSTALL_DIR) $(1)/etc/init.d
+ $(INSTALL_BIN) ./files/root/etc/init.d/aliddns $(1)/etc/init.d/aliddns
+ $(INSTALL_DIR) $(1)/etc/uci-defaults
+ $(INSTALL_BIN) ./files/root/etc/uci-defaults/luci-aliddns $(1)/etc/uci-defaults/luci-aliddns
+ $(INSTALL_DIR) $(1)/usr/sbin
+ $(INSTALL_BIN) ./files/root/usr/sbin/aliddns $(1)/usr/sbin/aliddns
+endef
+
+$(eval $(call BuildPackage,luci-app-aliddns))
diff --git a/luci-app-aliddns/README.md b/luci-app-aliddns/README.md
new file mode 100644
index 000000000..62ed84d48
--- /dev/null
+++ b/luci-app-aliddns/README.md
@@ -0,0 +1,68 @@
+# luci-app-aliddns
+LEDE/OpenWrt LuCI for AliDDNS
+===
+
+简介
+---
+
+本软件包是 AliDDNS 的 LuCI 控制界面,
+
+软件包文件结构:
+```
+/
+├── etc/
+│ ├── config/
+│ │ └── aliddns // UCI 配置文件
+│ │── init.d/
+│ │ └── aliddns // init 脚本
+│ └── uci-defaults/
+│ └── luci-aliddns // uci-defaults 脚本
+└── usr/
+ ├── sbin/
+ │ └── aliddns // 主程序
+ └── lib/
+ └── lua/
+ └── luci/ // LuCI 部分
+ ├── controller/
+ │ └── aliddns.lua // LuCI 菜单配置
+ ├── i18n/ // LuCI 语言文件目录
+ │ └── aliddns.zh-cn.lmo
+ └── model/
+ └── cbi/
+ └── aliddns.lua // LuCI 基本设置
+```
+
+依赖
+---
+
+软件包的正常使用需要依赖 `openssl-util` 和 `curl`.
+
+配置
+---
+
+软件包的配置文件路径: `/etc/config/aliddns`
+此文件为 UCI 配置文件, 配置方式可参考 [Wiki][uci]
+
+编译
+---
+
+从 LEDE 的 [SDK][lede-sdk] 编译
+```bash
+# 解压下载好的 SDK
+tar axvf lede-sdk-17.01.*-ar71xx-generic_gcc-5.4.0_musl-1.1.16.Linux-x86_64.tar.xz
+cd lede-sdk-17.01.*-ar71xx-*
+# Clone 项目
+mkdir -p package/feeds
+git clone https://github.com/chenhw2/luci-app-aliddns.git package/feeds/luci-app-aliddns
+# 编译 po2lmo (如果有po2lmo可跳过)
+pushd package/feeds/luci-app-aliddns/tools/po2lmo
+make && sudo make install
+popd
+# 选择要编译的包 LuCI -> 3. Applications
+make menuconfig
+# 开始编译
+make package/feeds/luci-app-aliddns/compile V=s
+```
+
+ [lede-sdk]: https://lede-project.org/docs/guide-developer/compile_packages_for_lede_with_the_sdk
+ [uci]: https://lede-project.org/docs/user-guide/introduction_to_lede_configuration
diff --git a/luci-app-aliddns/files/luci/controller/aliddns.lua b/luci-app-aliddns/files/luci/controller/aliddns.lua
new file mode 100644
index 000000000..9a169ef20
--- /dev/null
+++ b/luci-app-aliddns/files/luci/controller/aliddns.lua
@@ -0,0 +1,4 @@
+module("luci.controller.aliddns",package.seeall)
+function index()
+entry({"admin","services","aliddns"},cbi("aliddns"),_("AliDDNS"),58)
+end
diff --git a/luci-app-aliddns/po/zh_Hans/aliddns.po b/luci-app-aliddns/files/luci/i18n/aliddns.zh-cn.po
similarity index 77%
rename from luci-app-aliddns/po/zh_Hans/aliddns.po
rename to luci-app-aliddns/files/luci/i18n/aliddns.zh-cn.po
index e1f8b7faf..f0be976bc 100644
--- a/luci-app-aliddns/po/zh_Hans/aliddns.po
+++ b/luci-app-aliddns/files/luci/i18n/aliddns.zh-cn.po
@@ -10,6 +10,9 @@ msgstr "启用"
msgid "Clean Before Update"
msgstr "清除所有同名记录"
+msgid "Enabled IPv6"
+msgstr "启用 IPv6"
+
msgid "Base"
msgstr "基本设置"
@@ -22,6 +25,15 @@ msgstr "选择WAN-IP来源"
msgid "Select the WAN-IP Source for AliDDNS, like wan/internet"
msgstr "动态域名的IP来源,如wan/internet"
+msgid "WAN6-IP Source"
+msgstr "WAN6-IP来源"
+
+msgid "Select WAN6-IP Source"
+msgstr "选择WAN6-IP来源"
+
+msgid "Select the WAN6-IP Source for AliDDNS, like wan6/internet"
+msgstr "动态域名的IPv6来源,如wan6/internet"
+
msgid "Main Domain"
msgstr "主域名"
diff --git a/luci-app-aliddns/luasrc/model/cbi/aliddns.lua b/luci-app-aliddns/files/luci/model/cbi/aliddns.lua
similarity index 82%
rename from luci-app-aliddns/luasrc/model/cbi/aliddns.lua
rename to luci-app-aliddns/files/luci/model/cbi/aliddns.lua
index af69efbe4..f04ffbcd8 100644
--- a/luci-app-aliddns/luasrc/model/cbi/aliddns.lua
+++ b/luci-app-aliddns/files/luci/model/cbi/aliddns.lua
@@ -15,19 +15,32 @@ enable.rmempty = false
enable = e:option(Flag, "clean", translate("Clean Before Update"))
enable.rmempty = false
+ipv6 = e:option(Flag,"ipv6",translate("Enabled IPv6"))
+ipv6.rmempty=false
+
token = e:option(Value, "app_key", translate("Access Key ID"))
+
email = e:option(Value, "app_secret", translate("Access Key Secret"))
iface = e:option(ListValue, "interface", translate("WAN-IP Source"), translate("Select the WAN-IP Source for AliDDNS, like wan/internet"))
iface:value("", translate("Select WAN-IP Source"))
iface:value("internet")
iface:value("wan")
-
iface.rmempty = false
+
+iface6 = e:option(ListValue, "interface6", translate("WAN6-IP Source"),translate("Select the WAN6-IP Source for AliDDNS, like wan6/internet"))
+iface6:value("",translate("Select WAN6-IP Source"))
+iface6:value("internet")
+iface6:value("wan")
+iface6:value("wan6")
+iface6.rmempty = true
+
main = e:option(Value, "main_domain", translate("Main Domain"), translate("For example: test.github.com -> github.com"))
main.rmempty = false
+
sub = e:option(Value, "sub_domain", translate("Sub Domain"), translate("For example: test.github.com -> test"))
sub.rmempty = false
+
time = e:option(Value, "time", translate("Inspection Time"), translate("Unit: Minute, Range: 1-59"))
time.rmempty = false
@@ -49,6 +62,7 @@ end
tvlog.write = function(e,e,e)
end
+
local e = luci.http.formvalue("cbi.apply")
if e then
io.popen("/etc/init.d/aliddns restart")
diff --git a/luci-app-aliddns/root/etc/config/aliddns b/luci-app-aliddns/files/root/etc/config/aliddns
similarity index 100%
rename from luci-app-aliddns/root/etc/config/aliddns
rename to luci-app-aliddns/files/root/etc/config/aliddns
diff --git a/luci-app-aliddns/root/etc/init.d/aliddns b/luci-app-aliddns/files/root/etc/init.d/aliddns
old mode 100755
new mode 100644
similarity index 74%
rename from luci-app-aliddns/root/etc/init.d/aliddns
rename to luci-app-aliddns/files/root/etc/init.d/aliddns
index f6c7029da..8740c0c05
--- a/luci-app-aliddns/root/etc/init.d/aliddns
+++ b/luci-app-aliddns/files/root/etc/init.d/aliddns
@@ -2,6 +2,8 @@
START=80
NAME=aliddns
+EXTRA_COMMANDS="status"
+EXTRA_HELP=" status Service status"
NE_TIPS='AliDDNS NOT ENABLED'
@@ -51,7 +53,9 @@ start() {
[ -f /etc/crontabs/root ] || mkdir -p /etc/crontabs && touch /etc/crontabs/root
sed -i '/aliddns/d' /etc/crontabs/root
echo "*/$time * * * * /usr/sbin/aliddns >> /var/log/aliddns.log 2>&1" >> /etc/crontabs/root
- /etc/init.d/cron restart
+ if [ "$(/etc/init.d/cron status)" = "running" ]; then
+ /etc/init.d/cron reload
+ fi
( /usr/sbin/aliddns >> /var/log/aliddns.log 2>&1 ) &
}
@@ -59,6 +63,16 @@ start() {
stop() {
rm -rf "/etc/hotplug.d/iface/${START}-${NAME}"
sed -i '/aliddns/d' /etc/crontabs/root >/dev/null 2>&1
- /etc/init.d/cron restart
+ if [ "$(/etc/init.d/cron status)" = "running" ]; then
+ /etc/init.d/cron reload
+ fi
echo "${NE_TIPS}" > /var/log/aliddns.log
}
+
+status() {
+ if [ "$(/etc/init.d/cron status)" != "running" ]; then
+ echo "inactive" && false
+ else
+ grep -q aliddns /etc/crontabs/root && echo "running" || echo "inactive" && false
+ fi
+}
diff --git a/luci-app-aliddns/root/etc/uci-defaults/luci-aliddns b/luci-app-aliddns/files/root/etc/uci-defaults/luci-aliddns
old mode 100755
new mode 100644
similarity index 100%
rename from luci-app-aliddns/root/etc/uci-defaults/luci-aliddns
rename to luci-app-aliddns/files/root/etc/uci-defaults/luci-aliddns
diff --git a/luci-app-aliddns/files/root/usr/sbin/aliddns b/luci-app-aliddns/files/root/usr/sbin/aliddns
new file mode 100755
index 000000000..50a0f1c50
--- /dev/null
+++ b/luci-app-aliddns/files/root/usr/sbin/aliddns
@@ -0,0 +1,283 @@
+#!/bin/sh
+
+NAME=aliddns
+log_file=/var/log/$NAME.log
+
+uci_get_by_name() {
+ local ret=$(uci get $NAME.$1.$2 2>/dev/null)
+ echo ${ret:=$3}
+}
+
+uci_bool_by_name() {
+ case "$(uci_get_by_name $1 $2)" in
+ 1|on|true|yes|enabled) return 0;;
+ esac
+ return 1
+}
+
+intelnetip() {
+ tmp_ip=`curl -sL --connect-timeout 3 members.3322.org/dyndns/getip`
+ if [ "Z$tmp_ip" == "Z" ]; then
+ tmp_ip=`curl -sL --connect-timeout 3 api-ipv4.ip.sb/ip`
+ fi
+ if [ "Z$tmp_ip" == "Z" ]; then
+ tmp_ip=`curl -sL --connect-timeout 3 v4.myip.la`
+ fi
+ if [ "Z$tmp_ip" == "Z" ]; then
+ tmp_ip=`curl -sL --connect-timeout 3 whatismyip.akamai.com`
+ fi
+ echo -n $tmp_ip
+}
+
+intelnetip6() {
+ tmp_ip6=`curl -sL --connect-timeout 3 ipv6.whatismyip.akamai.com`
+ if [ "Z$tmp_ip6" == "Z" ]; then
+ tmp_ip6=`curl -sL --connect-timeout 3 speed.neu6.edu.cn/getIP.php`
+ fi
+ if [ "Z$tmp_ip6" == "Z" ]; then
+ tmp_ip6=`curl -sL --connect-timeout 3 v6.ident.me`
+ fi
+ if [ "Z$tmp_ip6" == "Z" ]; then
+ tmp_ip6=`curl -sL --connect-timeout 3 api-ipv6.ip.sb/ip`
+ fi
+ echo -n $tmp_ip6
+}
+
+resolve2ip() {
+ # resolve2ip domain
+ domain=$1
+ tmp_ip=`nslookup $domain ns1.alidns.com 2>/dev/null | sed '/^Server/d; /#53$/d' | grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | tail -n1`
+ if [ "Z$tmp_ip" == "Z" ]; then
+ tmp_ip=`nslookup $domain ns2.alidns.com 2>/dev/null | sed '/^Server/d; /#53$/d' | grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | tail -n1`
+ fi
+ if [ "Z$tmp_ip" == "Z" ]; then
+ tmp_ip=`nslookup $domain 114.114.115.115 2>/dev/null | sed '/^Server/d; /#53$/d' | grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | tail -n1`
+ fi
+ if [ "Z$tmp_ip" == "Z" ]; then
+ tmp_ip=`curl -sL --connect-timeout 3 "119.29.29.29/d?dn=$domain"`
+ fi
+ echo -n $tmp_ip
+}
+
+resolve2ip6() {
+ # resolve2ip6 domain
+ domain=$1
+ tmp_ip6=`nslookup $domain ns1.alidns.com 2>/dev/null | sed '/^Server/d; /#53$/d' | grep -oE '([0-9A-Fa-f]{0,4}:){2,7}([0-9A-Fa-f]{1,4}$|((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4})' | tail -n1`
+ if [ "Z$tmp_ip6" == "Z" ]; then
+ tmp_ip6=`nslookup $domain ns2.alidns.com 2>/dev/null | sed '/^Server/d; /#53$/d' | grep -oE '([0-9A-Fa-f]{0,4}:){2,7}([0-9A-Fa-f]{1,4}$|((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4})' | tail -n1`
+ fi
+ if [ "Z$tmp_ip6" == "Z" ]; then
+ tmp_ip6=`nslookup $domain 114.114.115.115 2>/dev/null | sed '/^Server/d; /#53$/d' | grep -oE '([0-9A-Fa-f]{0,4}:){2,7}([0-9A-Fa-f]{1,4}$|((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4})' | tail -n1`
+ fi
+ if [ "Z$tmp_ip6" == "Z" ]; then
+ tmp_ip6=`curl -sL --connect-timeout 3 "119.29.29.29/d?dn=$domain&type=AAAA"`
+ fi
+ echo -n $tmp_ip6
+}
+
+check_aliddns() {
+ echo "$DATE WAN-IP: ${ip}"
+ if [ "Z$ip" == "Z" ]; then
+ echo "$DATE ERROR, cant get WAN-IP..."
+ return 0
+ fi
+ current_ip=$(resolve2ip "$dm_real")
+ if [ "Z$current_ip" == "Z" ]; then
+ rrid='' # NO Resolve IP Means new Record_ID
+ fi
+ echo "$DATE DOMAIN-IP: ${current_ip}"
+ if [ "Z$ip" == "Z$current_ip" ]; then
+ echo "$DATE IP dont need UPDATE..."
+ return 0
+ else
+ echo "$DATE UPDATING..."
+ return 1
+ fi
+}
+
+check_aliddns6() {
+ echo "$DATE WAN6-IP: ${ip6}"
+ if [ "Z$ip6" == "Z" ]; then
+ echo "$DATE ERROR, cant get WAN6-IP..."
+ return 0
+ fi
+ current_ip6=$(resolve2ip6 "$dm_real")
+ if [ "Z$current_ip6" == "Z" ]; then
+ rrid6='' # NO Resolve IP Means new Record_ID
+ fi
+ echo "$DATE DOMAIN-IP6: ${current_ip6}"
+ if [ "Z$ip6" == "Z$current_ip6" ]; then
+ echo "$DATE IPv6 dont need UPDATE..."
+ return 0
+ else
+ echo "$DATE UPDATING AAAA..."
+ return 1
+ fi
+}
+
+
+urlencode() {
+ # urlencode url
+ out=''
+ for c in $(echo -n $1 | sed 's/[^\n]/&\n/g'); do
+ case $c in
+ [a-zA-Z0-9._-]) out="$out$c" ;;
+ *) out="$out$(printf '%%%02X' "'$c")" ;;
+ esac
+ done
+ echo -n $out
+}
+
+send_request() {
+ # send_request action args
+ local args="AccessKeyId=$ak_id&Action=$1&Format=json&$2&Version=2015-01-09"
+ local hash=$(urlencode $(echo -n "GET&%2F&$(urlencode $args)" | openssl dgst -sha1 -hmac "$ak_sec&" -binary | openssl base64))
+ curl -sSL --connect-timeout 10 "http://alidns.aliyuncs.com/?$args&Signature=$hash"
+}
+
+get_recordid() {
+ sed 's/RR/\n/g' | sed -n 's/.*RecordId[^0-9]*\([0-9]*\).*/\1\n/p' | sort -ru | sed /^$/d
+}
+
+query_recordid() {
+ send_request "DescribeSubDomainRecords" "SignatureMethod=HMAC-SHA1&SignatureNonce=$timestamp&SignatureVersion=1.0&SubDomain=$dm_escape&Timestamp=$timestamp&Type=A"
+}
+
+query_recordid6() {
+ send_request "DescribeSubDomainRecords" "SignatureMethod=HMAC-SHA1&SignatureNonce=$timestamp&SignatureVersion=1.0&SubDomain=$dm_escape&Timestamp=$timestamp&Type=AAAA"
+}
+
+update_record() {
+ send_request "UpdateDomainRecord" "RR=$sub_dm_escape&RecordId=$1&SignatureMethod=HMAC-SHA1&SignatureNonce=$timestamp&SignatureVersion=1.0&Timestamp=$timestamp&Type=A&Value=$ip"
+}
+
+add_record() {
+ send_request "AddDomainRecord&DomainName=$main_dm" "RR=$sub_dm_escape&SignatureMethod=HMAC-SHA1&SignatureNonce=$timestamp&SignatureVersion=1.0&Timestamp=$timestamp&Type=A&Value=$ip"
+}
+
+update_record6() {
+ send_request "UpdateDomainRecord" "RR=$sub_dm_escape&RecordId=$1&SignatureMethod=HMAC-SHA1&SignatureNonce=$timestamp&SignatureVersion=1.0&Timestamp=$timestamp&Type=AAAA&Value=$ip6_escape"
+}
+
+add_record6() {
+ send_request "AddDomainRecord&DomainName=$main_dm" "RR=$sub_dm_escape&SignatureMethod=HMAC-SHA1&SignatureNonce=$timestamp&SignatureVersion=1.0&Timestamp=$timestamp&Type=AAAA&Value=$ip6_escape"
+}
+
+del_record() {
+ send_request "DeleteDomainRecord" "RecordId=$1&SignatureMethod=HMAC-SHA1&SignatureNonce=$timestamp&SignatureVersion=1.0&Timestamp=$timestamp"
+}
+
+do_ddns_record() {
+ if uci_bool_by_name base clean ; then
+ query_recordid | get_recordid | while read rr; do
+ echo "$DATE Clean record $dm_show: $rr"
+ del_record $rr >/dev/null
+ timestamp=$(date -u "+%Y-%m-%dT%H%%3A%M%%3A%SZ")
+ done
+ rrid=''
+ fi
+ if [ "Z$rrid" == "Z" ]; then
+ rrid=`query_recordid | get_recordid`
+ fi
+ if [ "Z$rrid" == "Z" ]; then
+ rrid=`add_record | get_recordid`
+ echo "$DATE ADD record $rrid"
+ else
+ update_record $rrid >/dev/null 2>&1
+ echo "$DATE UPDATE record $rrid"
+ fi
+ if [ "Z$rrid" == "Z" ]; then
+ # failed
+ echo "$DATE # ERROR, Please Check Config/Time"
+ else
+ # save rrid
+ uci set aliddns.base.record_id=$rrid
+ uci commit aliddns
+ echo "$DATE # UPDATED($ip)"
+ fi
+}
+
+do_ddns_record6() {
+ if uci_bool_by_name base clean ; then
+ query_recordid6 | get_recordid | while read rr; do
+ echo "$DATE Clean record $dm_show: $rr"
+ del_record $rr >/dev/null
+ timestamp=$(date -u "+%Y-%m-%dT%H%%3A%M%%3A%SZ")
+ done
+ rrid6=''
+ fi
+ if [ "Z$rrid6" == "Z" ]; then
+ rrid6=`query_recordid6 | get_recordid`
+ fi
+ if [ "Z$rrid6" == "Z" ]; then
+ rrid6=`add_record6 | get_recordid`
+ echo "$DATE ADD record $rrid6"
+ else
+ update_record6 $rrid6 >/dev/null 2>&1
+ echo "$DATE UPDATE record $rrid6"
+ fi
+ if [ "Z$rrid6" == "Z" ]; then
+ # failed
+ echo "$DATE # ERROR, Please Check Config/Time"
+ else
+ # save rrid6
+ uci set aliddns.base.record_id6=$rrid6
+ uci commit aliddns
+ echo "$DATE # UPDATED($ip6)"
+ fi
+}
+
+clean_log() {
+ if [ $(cat $log_file 2>/dev/null | wc -l) -ge 16 ]; then
+ rm -f $log_file && touch $log_file
+ echo "$DATE Log Cleaned"
+ fi
+}
+
+[ -x /usr/bin/openssl -a -x /usr/bin/curl -a -x /bin/sed ] || {
+ echo "Need [ openssl + curl + sed ]"
+ exit 1
+}
+
+ak_id=$(uci_get_by_name base app_key)
+ak_sec=$(uci_get_by_name base app_secret)
+rrid=$(uci_get_by_name base record_id)
+rrid6=$(uci_get_by_name base record_id6)
+main_dm=$(uci_get_by_name base main_domain)
+sub_dm=$(uci_get_by_name base sub_domain)
+
+if [ "Z$sub_dm" == "Z@" -o "Z$sub_dm" == "Z" ]; then
+ dm_real="$main_dm"
+else
+ dm_real="$sub_dm.$main_dm"
+fi
+dm_show="$sub_dm.$main_dm"
+dm_escape=`urlencode "$sub_dm.$main_dm"`
+sub_dm_escape=`urlencode "$sub_dm"`
+
+iface=$(uci_get_by_name base interface)
+if [ "Z$iface" == "Zinternet" -o "Z$iface" == "Z" ]; then
+ ip=$(intelnetip)
+else
+ ip=$(ubus call network.interface.$iface status | grep '"address"' | grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | head -1)
+fi
+
+DATE=$(date +'%Y-%m-%d %H:%M:%S')
+timestamp=$(date -u "+%Y-%m-%dT%H%%3A%M%%3A%SZ")
+
+clean_log
+check_aliddns || do_ddns_record
+
+# exit if ipv6 not-enabled
+uci_bool_by_name base ipv6 || exit 0
+
+iface6=$(uci_get_by_name base interface6)
+if [ "Z$iface6" == "Zinternet" -o "Z$iface6" == "Z" ]; then
+ ip6=$(intelnetip6)
+else
+ ip6=$(ubus call network.interface.$iface6 status | grep '"address"' | grep -oE '([0-9A-Fa-f]{0,4}:){2,7}([0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){4})' | head -1)
+fi
+ip6_escape=`urlencode "$ip6"`
+
+clean_log
+check_aliddns6 || do_ddns_record6
diff --git a/luci-app-aliddns/luasrc/controller/aliddns.lua b/luci-app-aliddns/luasrc/controller/aliddns.lua
deleted file mode 100644
index 6ecc2eacf..000000000
--- a/luci-app-aliddns/luasrc/controller/aliddns.lua
+++ /dev/null
@@ -1,11 +0,0 @@
-module("luci.controller.aliddns", package.seeall)
-
-function index()
- if not nixio.fs.access("/etc/config/aliddns") then
- return
- end
-
- local page = entry({"admin", "services", "aliddns"}, cbi("aliddns"), _("AliDDNS"), 58)
- page.dependent = true
- page.acl_depends = { "luci-app-aliddns" }
-end
diff --git a/luci-app-aliddns/po/zh-cn b/luci-app-aliddns/po/zh-cn
deleted file mode 120000
index 8d69574dd..000000000
--- a/luci-app-aliddns/po/zh-cn
+++ /dev/null
@@ -1 +0,0 @@
-zh_Hans
\ No newline at end of file
diff --git a/luci-app-aliddns/root/usr/sbin/aliddns b/luci-app-aliddns/root/usr/sbin/aliddns
deleted file mode 100755
index 3d74c7a0e..000000000
--- a/luci-app-aliddns/root/usr/sbin/aliddns
+++ /dev/null
@@ -1,164 +0,0 @@
-#!/bin/sh
-
-NAME=aliddns
-log_file=/var/log/$NAME.log
-
-uci_get_by_name() {
- local ret=$(uci get $NAME.$1.$2 2>/dev/null)
- echo ${ret:=$3}
-}
-
-uci_bool_by_name() {
- case "$(uci_get_by_name $1 $2)" in
- 1|on|true|yes|enabled) return 0;;
- esac
- return 1
-}
-
-intelnetip() {
- tmp_ip=`curl -sL --connect-timeout 3 ns1.dnspod.net:6666`
- if [ "Z$tmp_ip" == "Z" ]; then
- tmp_ip=`curl -sL --connect-timeout 3 members.3322.org/dyndns/getip`
- fi
- if [ "Z$tmp_ip" == "Z" ]; then
- tmp_ip=`curl -sL --connect-timeout 3 14.215.150.17:6666`
- fi
- if [ "Z$tmp_ip" == "Z" ]; then
- tmp_ip=`curl -sL --connect-timeout 3 whatismyip.akamai.com`
- fi
- echo -n $tmp_ip
-}
-
-resolve2ip() {
- # resolve2ip domain
- domain=$1
- tmp_ip=`nslookup $domain ns1.alidns.com 2>/dev/null | sed '/^Server/d; /#53$/d' | grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | tail -n1`
- if [ "Z$tmp_ip" == "Z" ]; then
- tmp_ip=`nslookup $domain ns2.alidns.com 2>/dev/null | sed '/^Server/d; /#53$/d' | grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | tail -n1`
- fi
- if [ "Z$tmp_ip" == "Z" ]; then
- tmp_ip=`nslookup $domain 114.114.115.115 2>/dev/null | sed '/^Server/d; /#53$/d' | grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | tail -n1`
- fi
- if [ "Z$tmp_ip" == "Z" ]; then
- tmp_ip=`curl -sL --connect-timeout 3 "119.29.29.29/d?dn=$domain"`
- fi
- echo -n $tmp_ip
-}
-
-check_aliddns() {
- echo "$DATE WAN-IP: ${ip}"
- if [ "Z$ip" == "Z" ]; then
- echo "$DATE ERROR, cant get WAN-IP..."
- return 0
- fi
- current_ip=$(resolve2ip "$sub_dm.$main_dm")
- if [ "Z$current_ip" == "Z" ]; then
- rrid='' # NO Resolve IP Means new Record_ID
- fi
- echo "$DATE DOMAIN-IP: ${current_ip}"
- if [ "Z$ip" == "Z$current_ip" ]; then
- echo "$DATE IP dont need UPDATE..."
- return 0
- else
- echo "$DATE UPDATING..."
- return 1
- fi
-}
-
-urlencode() {
- # urlencode url
- out=''
- for c in $(echo -n $1 | sed 's/[^\n]/&\n/g'); do
- case $c in
- [a-zA-Z0-9._-]) out="$out$c" ;;
- *) out="$out$(printf '%%%02X' "'$c")" ;;
- esac
- done
- echo -n $out
-}
-
-send_request() {
- # send_request action args
- local args="AccessKeyId=$ak_id&Action=$1&Format=json&$2&Version=2015-01-09"
- local hash=$(urlencode $(echo -n "GET&%2F&$(urlencode $args)" | openssl dgst -sha1 -hmac "$ak_sec&" -binary | openssl base64))
- curl -sSL --connect-timeout 5 "http://alidns.aliyuncs.com/?$args&Signature=$hash"
-}
-
-get_recordid() {
- sed 's/RR/\n/g' | sed -n 's/.*RecordId[^0-9]*\([0-9]*\).*/\1\n/p' | sort -ru | sed /^$/d
-}
-
-query_recordid() {
- send_request "DescribeSubDomainRecords" "SignatureMethod=HMAC-SHA1&SignatureNonce=$timestamp&SignatureVersion=1.0&SubDomain=$sub_dm.$main_dm&Timestamp=$timestamp"
-}
-
-update_record() {
- send_request "UpdateDomainRecord" "RR=$sub_dm&RecordId=$1&SignatureMethod=HMAC-SHA1&SignatureNonce=$timestamp&SignatureVersion=1.0&Timestamp=$timestamp&Type=A&Value=$ip"
-}
-
-add_record() {
- send_request "AddDomainRecord&DomainName=$main_dm" "RR=$sub_dm&SignatureMethod=HMAC-SHA1&SignatureNonce=$timestamp&SignatureVersion=1.0&Timestamp=$timestamp&Type=A&Value=$ip"
-}
-
-del_record() {
- send_request "DeleteDomainRecord" "RecordId=$1&SignatureMethod=HMAC-SHA1&SignatureNonce=$timestamp&SignatureVersion=1.0&Timestamp=$timestamp"
-}
-
-do_ddns_record() {
- if uci_bool_by_name base clean ; then
- query_recordid | get_recordid | while read rr; do
- echo "$DATE Clean record $sub_dm.$main_dm: $rr"
- del_record $rr >/dev/null
- timestamp=$(date -u "+%Y-%m-%dT%H%%3A%M%%3A%SZ")
- done
- rrid=''
- fi
- if [ "Z$rrid" == "Z" ]; then
- rrid=`query_recordid | get_recordid`
- fi
- if [ "Z$rrid" == "Z" ]; then
- rrid=`add_record | get_recordid`
- echo "$DATE ADD record $rrid"
- else
- update_record $rrid >/dev/null 2>&1
- echo "$DATE UPDATE record $rrid"
- fi
- if [ "Z$rrid" == "Z" ]; then
- # failed
- echo "$DATE # ERROR, Please Check Config/Time"
- else
- # save rrid
- uci set aliddns.base.record_id=$rrid
- uci commit aliddns
- echo "$DATE # UPDATED($ip)"
- fi
-}
-
-clean_log() {
- if [ $(cat $log_file 2>/dev/null | wc -l) -ge 16 ]; then
- rm -f $log_file && touch $log_file
- echo "$DATE Log Cleaned"
- fi
-}
-
-[ -x /usr/bin/openssl -a -x /usr/bin/curl -a -x /bin/sed ] ||
- ( echo "Need [ openssl + curl + sed ]" && exit 1 )
-
-ak_id=$(uci_get_by_name base app_key)
-ak_sec=$(uci_get_by_name base app_secret)
-rrid=$(uci_get_by_name base record_id)
-main_dm=$(uci_get_by_name base main_domain)
-sub_dm=$(uci_get_by_name base sub_domain)
-
-iface=$(uci_get_by_name base interface)
-if [ "Z$iface" == "Zinternet" -o "Z$iface" == "Z" ]; then
- ip=$(intelnetip)
-else
- ip=$(ubus call network.interface.$iface status | grep '"address"' | grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}')
-fi
-
-DATE=$(date +'%Y-%m-%d %H:%M:%S')
-timestamp=$(date -u "+%Y-%m-%dT%H%%3A%M%%3A%SZ")
-
-clean_log
-check_aliddns || do_ddns_record
diff --git a/luci-app-aliddns/root/usr/share/rpcd/acl.d/luci-app-aliddns.json b/luci-app-aliddns/root/usr/share/rpcd/acl.d/luci-app-aliddns.json
deleted file mode 100644
index 448ce8290..000000000
--- a/luci-app-aliddns/root/usr/share/rpcd/acl.d/luci-app-aliddns.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "luci-app-aliddns": {
- "description": "Grant UCI access for luci-app-aliddns",
- "read": {
- "uci": [ "aliddns" ]
- },
- "write": {
- "uci": [ "aliddns" ]
- }
- }
-}
diff --git a/luci-app-aliddns/tools/po2lmo/Makefile b/luci-app-aliddns/tools/po2lmo/Makefile
new file mode 100644
index 000000000..ad2c13320
--- /dev/null
+++ b/luci-app-aliddns/tools/po2lmo/Makefile
@@ -0,0 +1,12 @@
+
+INSTALL = install
+PREFIX = /usr/bin
+
+po2lmo: src/po2lmo.o src/template_lmo.o
+ $(CC) $(LDFLAGS) -o src/po2lmo src/po2lmo.o src/template_lmo.o
+
+install:
+ $(INSTALL) -m 755 src/po2lmo $(PREFIX)
+
+clean:
+ $(RM) src/po2lmo src/*.o
diff --git a/luci-app-aliddns/tools/po2lmo/src/po2lmo.c b/luci-app-aliddns/tools/po2lmo/src/po2lmo.c
new file mode 100644
index 000000000..0da792b68
--- /dev/null
+++ b/luci-app-aliddns/tools/po2lmo/src/po2lmo.c
@@ -0,0 +1,247 @@
+/*
+ * lmo - Lua Machine Objects - PO to LMO conversion tool
+ *
+ * Copyright (C) 2009-2012 Jo-Philipp Wich
+ *
+ * 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);
+}
diff --git a/luci-app-aliddns/tools/po2lmo/src/template_lmo.c b/luci-app-aliddns/tools/po2lmo/src/template_lmo.c
new file mode 100644
index 000000000..27205a722
--- /dev/null
+++ b/luci-app-aliddns/tools/po2lmo/src/template_lmo.c
@@ -0,0 +1,328 @@
+/*
+ * lmo - Lua Machine Objects - Base functions
+ *
+ * Copyright (C) 2009-2010 Jo-Philipp Wich
+ *
+ * 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;
+ }
+ }
+}
diff --git a/luci-app-aliddns/tools/po2lmo/src/template_lmo.h b/luci-app-aliddns/tools/po2lmo/src/template_lmo.h
new file mode 100644
index 000000000..57f59aa56
--- /dev/null
+++ b/luci-app-aliddns/tools/po2lmo/src/template_lmo.h
@@ -0,0 +1,92 @@
+/*
+ * lmo - Lua Machine Objects - General header
+ *
+ * Copyright (C) 2009-2012 Jo-Philipp Wich
+ *
+ * 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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#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
diff --git a/luci-app-gpsysupgrade/luasrc/model/cbi/gpsysupgrade/sysupgrade.lua b/luci-app-gpsysupgrade/luasrc/model/cbi/gpsysupgrade/sysupgrade.lua
index bcc54b17b..f37d64b73 100644
--- a/luci-app-gpsysupgrade/luasrc/model/cbi/gpsysupgrade/sysupgrade.lua
+++ b/luci-app-gpsysupgrade/luasrc/model/cbi/gpsysupgrade/sysupgrade.lua
@@ -123,15 +123,15 @@ function to_check()
elseif board_name:match("redmi,ax6$") then
model = "ipq807x_generic/redmi_ax6"
check_update()
- download_url = "https://op.supes.top/firmware/" ..model.. "/" ..remote_version.. "-openwrt-ipq807x-generic-redmi_ax6-squashfs-sysupgrade.bin"
+ download_url = "https://op.supes.top/firmware/" ..model.. "/" ..remote_version.. "-openwrt-ipq807x-generic-redmi_ax6-squashfs-nand-sysupgrade.bin"
elseif board_name:match("xiaomi,ax9000$") then
model = "ipq807x_generic/xiaomi_ax9000"
check_update()
- download_url = "https://op.supes.top/firmware/" ..model.. "/" ..remote_version.. "-openwrt-ipq807x-generic-xiaomi_ax9000-squashfs-sysupgrade.bin"
+ download_url = "https://op.supes.top/firmware/" ..model.. "/" ..remote_version.. "-openwrt-ipq807x-generic-xiaomi_ax9000-squashfs-nand-sysupgrade.bin"
elseif board_name:match("xiaomi,ax3600$") then
model = "ipq807x_generic/xiaomi_ax3600"
check_update()
- download_url = "https://op.supes.top/firmware/" ..model.. "/" ..remote_version.. "-openwrt-ipq807x-generic-xiaomi_ax3600-squashfs-sysupgrade.bin"
+ download_url = "https://op.supes.top/firmware/" ..model.. "/" ..remote_version.. "-openwrt-ipq807x-generic-xiaomi_ax3600-squashfs-nand-sysupgrade.bin"
elseif board_name:match("xy%-c5$") then
model = "ramips_mt7621/xiaoyu_xy-c5"
check_update()