update 2023-01-26 20:19:28

This commit is contained in:
github-actions[bot] 2023-01-26 20:19:28 +08:00
parent 38030555cd
commit afe81772b2
19 changed files with 1170 additions and 202 deletions

21
luci-app-aliddns/LICENSE Normal file
View File

@ -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.

View File

@ -1,24 +1,84 @@
#
# Copyright (C) 2018 chenhw2 <https://github.com/chenhw2/>
# Copyright (C) 2018-2021 chenhw2 <https://github.com/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 <https://github.com/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))

View File

@ -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

View File

@ -0,0 +1,4 @@
module("luci.controller.aliddns",package.seeall)
function index()
entry({"admin","services","aliddns"},cbi("aliddns"),_("AliDDNS"),58)
end

View File

@ -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 "主域名"

View File

@ -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")

View File

@ -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
}

View File

@ -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<string>
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<string>
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<string>
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<string> args<string>
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

View File

@ -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

View File

@ -1 +0,0 @@
zh_Hans

View File

@ -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<string>
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<string>
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<string> args<string>
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

View File

@ -1,11 +0,0 @@
{
"luci-app-aliddns": {
"description": "Grant UCI access for luci-app-aliddns",
"read": {
"uci": [ "aliddns" ]
},
"write": {
"uci": [ "aliddns" ]
}
}
}

View File

@ -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

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

View File

@ -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()