mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-10-30 01:45:13 +08:00
🗽 Sync 2026-05-20 20:54:52
This commit is contained in:
1 parent
269a29c77c
commit
0c67fa5e72
17 files changed
+202
-154
No files matched your search
+38
-11
@@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (C) 2015-2016 OpenWrt.org
|
||||
# Copyright (C) 2015-2024 OpenWrt.org
|
||||
# Copyright (C) 2020 jjm2473@gmail.com
|
||||
#
|
||||
# This is free software, licensed under the GNU General Public License v3.
|
||||
@@ -10,9 +10,17 @@ include $(TOPDIR)/rules.mk
|
||||
PKG_ARCH_DDNSTO:=$(ARCH)
|
||||
|
||||
PKG_NAME:=ddnsto
|
||||
# use PKG_SOURCE_DATE instead of PKG_VERSION for compitable
|
||||
PKG_SOURCE_DATE:=3.0.4
|
||||
PKG_RELEASE:=1
|
||||
# use PKG_SOURCE_DATE instead of PKG_VERSION for compatible
|
||||
PKG_SOURCE_DATE:=4.2.0
|
||||
PKG_RELEASE:=2
|
||||
|
||||
# 构建类型:standard 或 lite
|
||||
DDNSTO_TYPE?=standard
|
||||
|
||||
# 调试信息
|
||||
$(info DDNSTO_TYPE is set to: $(DDNSTO_TYPE))
|
||||
|
||||
# 架构名称映射
|
||||
ARCH_HEXCODE:=
|
||||
ifeq ($(ARCH),x86_64)
|
||||
ARCH_HEXCODE=8664
|
||||
@@ -24,29 +32,49 @@ else ifeq ($(ARCH),mipsel)
|
||||
ARCH_HEXCODE=1b0c
|
||||
endif
|
||||
PKG_SOURCE_VERSION:=$(ARCH_HEXCODE)
|
||||
PKG_SOURCE:=$(PKG_NAME)-binary-$(PKG_SOURCE_DATE).tar.gz
|
||||
PKG_SOURCE_URL:=https://dl.istoreos.com/binary/ddnsto/
|
||||
PKG_HASH:=skip
|
||||
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-binary-$(PKG_SOURCE_DATE)
|
||||
|
||||
# 根据类型选择下载地址和文件名
|
||||
ifeq ($(DDNSTO_TYPE),lite)
|
||||
PKG_SOURCE:=$(PKG_NAME)-binary-lite-$(PKG_SOURCE_DATE).tar.gz
|
||||
PKG_SOURCE_URL:=https://github.com/linkease/ddnsto-openwrt-package/raw/refs/heads/main/
|
||||
PKG_HASH:=skip
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-binary-lite-$(PKG_SOURCE_DATE)
|
||||
else
|
||||
PKG_SOURCE:=$(PKG_NAME)-binary-$(PKG_SOURCE_DATE).tar.gz
|
||||
PKG_SOURCE_URL:=https://github.com/linkease/ddnsto-openwrt-package/raw/refs/heads/main/
|
||||
PKG_HASH:=skip
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-binary-$(PKG_SOURCE_DATE)
|
||||
endif
|
||||
|
||||
PKG_BUILD_PARALLEL:=1
|
||||
PKG_USE_MIPS16:=0
|
||||
|
||||
# 禁用 strip,保持二进制文件原样
|
||||
STRIP:=true
|
||||
RSTRIP:=:
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/$(PKG_NAME)
|
||||
SECTION:=net
|
||||
CATEGORY:=Network
|
||||
SUBMENU:=Web Servers/Proxies
|
||||
TITLE:=DDNS.to - the reverse proxy
|
||||
TITLE:=DDNS.to - the reverse proxy ($(DDNSTO_TYPE))
|
||||
DEPENDS:=
|
||||
PKGARCH:=all
|
||||
URL:=https://www.ddnsto.com/
|
||||
endef
|
||||
|
||||
define Package/$(PKG_NAME)/description
|
||||
DDNS.to is a reverse proxy
|
||||
DDNS.to is a reverse proxy service that allows you to access
|
||||
your devices from anywhere without public IP or port forwarding.
|
||||
|
||||
Build type: $(DDNSTO_TYPE)
|
||||
Features:
|
||||
- Multi-device index support
|
||||
- WebDAV file sharing
|
||||
- Intranet penetration
|
||||
endef
|
||||
|
||||
define Package/$(PKG_NAME)/conffiles
|
||||
@@ -70,7 +98,6 @@ endef
|
||||
define Package/$(PKG_NAME)/install
|
||||
$(INSTALL_DIR) $(1)/usr/sbin $(1)/etc/config $(1)/etc/init.d $(1)/etc/uci-defaults
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/ddnsto.$(PKG_ARCH_DDNSTO) $(1)/usr/sbin/ddnstod
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/ddwebdav.$(PKG_ARCH_DDNSTO) $(1)/usr/sbin/ddwebdav
|
||||
$(INSTALL_CONF) ./files/ddnsto.config $(1)/etc/config/ddnsto
|
||||
$(INSTALL_BIN) ./files/ddnsto.init $(1)/etc/init.d/ddnsto
|
||||
$(INSTALL_BIN) ./files/ddnsto.uci-default $(1)/etc/uci-defaults/ddnsto
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
DEVICE_IDX=0
|
||||
LOG_LEVEL=2
|
||||
while getopts u:x:l: flag
|
||||
do
|
||||
case "${flag}" in
|
||||
u) TOKEN=${OPTARG};;
|
||||
x) DEVICE_IDX=${OPTARG};;
|
||||
l) LOG_LEVEL=${OPTARG};;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ -z "${TOKEN}" ]; then
|
||||
logger "ddnsto: the token is empty, get token from https://www.ddnsto.com/ "
|
||||
exit 2
|
||||
fi
|
||||
|
||||
echo "ddnsto version device_id is is:"
|
||||
/usr/sbin/ddnsto -u ${TOKEN} -w
|
||||
|
||||
_term() {
|
||||
logger "ddnsto: SIGTERM"
|
||||
killall ddnsto 2>/dev/null
|
||||
killall ddwebdav 2>/dev/null
|
||||
|
||||
rm -f /tmp/.ddnsto.pid
|
||||
rm -f /tmp/.ddnsto.status
|
||||
rm -f /tmp/.ddnsto.up
|
||||
exit
|
||||
}
|
||||
|
||||
trap "_term;" SIGTERM
|
||||
|
||||
while true ; do
|
||||
if ! pidof "ddnsto" > /dev/null ; then
|
||||
logger "ddnsto try running"
|
||||
/usr/sbin/ddnsto -u ${TOKEN} -x ${DEVICE_IDX} &
|
||||
PID=$!
|
||||
wait $PID
|
||||
RET=$?
|
||||
logger "ddnsto EXIT CODE: ${RET}"
|
||||
if [ "${RET}" == "100" ]; then
|
||||
logger "ddnsto token error, please set a correct token from https://www.ddnsto.com/ "
|
||||
exit 100
|
||||
fi
|
||||
fi
|
||||
sleep 20
|
||||
done
|
||||
@@ -1,5 +1,11 @@
|
||||
config ddnsto
|
||||
option enabled '0'
|
||||
option feat_port '3033'
|
||||
option feat_enabled '0'
|
||||
# option token ''
|
||||
option index '0'
|
||||
option logger '0'
|
||||
option feat_enabled '0'
|
||||
option feat_port '3033'
|
||||
# option feat_username ''
|
||||
# option feat_password ''
|
||||
# option feat_disk_path_selected ''
|
||||
# option address ''
|
||||
Executable → Regular
+30
-26
@@ -4,45 +4,49 @@ START=99
|
||||
USE_PROCD=1
|
||||
|
||||
get_config() {
|
||||
config_get_bool enabled $1 enabled 1
|
||||
config_get_bool logger $1 logger 0
|
||||
config_get token $1 token
|
||||
config_get index $1 index 0
|
||||
config_get_bool feat_enabled $1 feat_enabled 1
|
||||
config_get_bool enabled $1 enabled 0
|
||||
config_get_bool logger $1 logger 0
|
||||
config_get token $1 token
|
||||
config_get index $1 index 0
|
||||
config_get_bool feat_enabled $1 feat_enabled 0
|
||||
}
|
||||
|
||||
ddnsto_prepare() {
|
||||
killall ddnstod 2>/dev/null
|
||||
killall ddwebdav 2>/dev/null
|
||||
killall ddnstod 2>/dev/null
|
||||
}
|
||||
|
||||
stop_service() {
|
||||
ddnsto_prepare
|
||||
ddnsto_prepare
|
||||
}
|
||||
|
||||
start_service() {
|
||||
ddnsto_prepare
|
||||
config_load ddnsto
|
||||
config_foreach get_config ddnsto
|
||||
if [ $enabled != 1 ]; then
|
||||
return 1
|
||||
fi
|
||||
ddnsto_prepare
|
||||
config_load ddnsto
|
||||
config_foreach get_config ddnsto
|
||||
|
||||
if [ "$enabled" != "1" ]; then
|
||||
logger -t ddnsto -p daemon.info "ddnsto service disabled"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -z "$token" ]; then
|
||||
logger -t ddnsto -p warn "token not set"
|
||||
return 1
|
||||
fi
|
||||
|
||||
procd_open_instance
|
||||
procd_set_param command /usr/sbin/ddnstod -u "$token" -x $index -F
|
||||
[ "$logger" == 1 ] && procd_set_param stderr 1
|
||||
procd_set_param respawn
|
||||
procd_close_instance
|
||||
if [ -z "$token" ]; then
|
||||
logger -t ddnsto -p daemon.warn "token not set"
|
||||
return 1
|
||||
fi
|
||||
|
||||
procd_open_instance
|
||||
procd_set_param command /usr/sbin/ddnstod -u "$token" -x "$index" -F
|
||||
[ "$logger" == "1" ] && procd_set_param stderr 1
|
||||
procd_set_param respawn
|
||||
procd_close_instance
|
||||
}
|
||||
|
||||
service_triggers() {
|
||||
procd_add_reload_trigger "ddnsto"
|
||||
procd_add_reload_trigger "ddnsto"
|
||||
}
|
||||
|
||||
reload_service() {
|
||||
restart
|
||||
stop
|
||||
sleep 1
|
||||
start
|
||||
}
|
||||
@@ -17,4 +17,4 @@ EOF
|
||||
|
||||
/etc/init.d/ddnsto enable
|
||||
|
||||
exit 0
|
||||
exit 0
|
||||
+1
-1
@@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=ipv6-neigh
|
||||
PKG_VERSION:=0.1.0
|
||||
PKG_RELEASE:=11
|
||||
PKG_RELEASE:=12
|
||||
|
||||
PKG_BUILD_DEPENDS:=rust/host
|
||||
PKG_BUILD_PARALLEL:=1
|
||||
|
||||
+50
-35
@@ -30,7 +30,7 @@ mod types;
|
||||
use filter::{if_ipv4_in_private_subnet, if_ipv6_in_private_subnet, ipv6_in_prefix, ipv6_passes_active_prefix, is_gua_ipv6};
|
||||
use iface::{get_active_lan_prefixes, register_router_addresses, wait_for_dns_server};
|
||||
use probe::{probe_gua_keepalive, probe_registered_neighbours, prune_gua_keepalive, send_icmpv4_echo, send_icmpv6_echo};
|
||||
use reconcile::{do_delete_dns, process_new_neigh, prune_ula_for_mac, reconcile_dns};
|
||||
use reconcile::{do_delete_dns, process_new_neigh, prune_ula_for_host, reconcile_dns};
|
||||
use types::{
|
||||
DEFAULT_TTL, RTNLGRP_NEIGH, GuaKeepaliveEntry, Neigh, RegisteredEntry, nl_mgrp,
|
||||
};
|
||||
@@ -253,16 +253,17 @@ async fn main() -> Result<(), ()> {
|
||||
}
|
||||
}
|
||||
|
||||
let key = (neigh.mac.clone(), inet_to_string(&neigh.inet));
|
||||
let ip_str = inet_to_string(&neigh.inet);
|
||||
match neigh.state {
|
||||
NeighbourState::Reachable => {
|
||||
// Confirmed online — register in DNS immediately.
|
||||
if !registered.contains_key(&key) {
|
||||
if let Some(hostname) = leases.get(&neigh.mac) {
|
||||
if let Some(hostname) = leases.get(&neigh.mac) {
|
||||
let key = (hostname.clone(), ip_str.clone());
|
||||
if !registered.contains_key(&key) {
|
||||
// Enforce per-host ULA limit before adding a new one.
|
||||
if let NeighbourAddress::Inet6(addr) = &neigh.inet {
|
||||
if if_ipv6_in_private_subnet(addr) {
|
||||
prune_ula_for_mac(&neigh.mac, max_ula_per_host, &mut registered, &updater).await;
|
||||
prune_ula_for_host(hostname, max_ula_per_host, &mut registered, &updater).await;
|
||||
}
|
||||
}
|
||||
let result = match &neigh.inet {
|
||||
@@ -281,9 +282,9 @@ async fn main() -> Result<(), ()> {
|
||||
}
|
||||
Err(e) => error!("DNS update failed for {}: {}", hostname, e),
|
||||
}
|
||||
} else {
|
||||
debug!("no lease for mac {}, skipping DNS update", neigh.mac);
|
||||
}
|
||||
} else {
|
||||
debug!("no lease for mac {}, skipping DNS update", neigh.mac);
|
||||
}
|
||||
}
|
||||
NeighbourState::Stale | NeighbourState::Delay | NeighbourState::Probe => {
|
||||
@@ -409,29 +410,39 @@ async fn main() -> Result<(), ()> {
|
||||
}
|
||||
}
|
||||
|
||||
let key = (neigh.mac.clone(), inet_to_string(&neigh.inet));
|
||||
let ip_str = inet_to_string(&neigh.inet);
|
||||
if is_failed_state(neigh.state) {
|
||||
// Neighbour confirmed unreachable — remove DNS record
|
||||
if let Some(entry) = registered.remove(&key) {
|
||||
debug!("Neighbour failed: {:?}", neigh);
|
||||
if !do_delete_dns(&entry.hostname, &neigh.inet, &updater).await {
|
||||
// DNS delete failed, put back so we retry
|
||||
registered.insert(key, entry);
|
||||
// Neighbour confirmed unreachable — remove DNS record.
|
||||
// Resolve key by hostname (handles MAC changes: new MAC in leases
|
||||
// can now evict entries registered under an old MAC).
|
||||
// Fall back to scanning registered by IP if MAC is no longer in leases.
|
||||
let key_opt: Option<(String, String)> = leases
|
||||
.get(&neigh.mac)
|
||||
.map(|h| (h.clone(), ip_str.clone()))
|
||||
.or_else(|| registered.keys().find(|(_, ip)| ip == &ip_str).cloned());
|
||||
if let Some(key) = key_opt {
|
||||
if let Some(entry) = registered.remove(&key) {
|
||||
debug!("Neighbour failed: {:?}", neigh);
|
||||
if !do_delete_dns(&entry.hostname, &neigh.inet, &updater).await {
|
||||
// DNS delete failed, put back so we retry
|
||||
registered.insert(key, entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if neigh.state == NeighbourState::Reachable {
|
||||
if let Some(entry) = registered.get_mut(&key) {
|
||||
// Already registered, just update timestamp and ifindex
|
||||
entry.last_confirmed = Instant::now();
|
||||
entry.ifindex = neigh.ifindex;
|
||||
} else {
|
||||
// New reachable neighbour — register in DNS
|
||||
debug!("New neighbour: {:?}", neigh);
|
||||
if let Some(hostname) = leases.get(&neigh.mac) {
|
||||
if let Some(hostname) = leases.get(&neigh.mac) {
|
||||
let key = (hostname.clone(), ip_str.clone());
|
||||
if let Some(entry) = registered.get_mut(&key) {
|
||||
// Already registered, just update timestamp and ifindex
|
||||
entry.last_confirmed = Instant::now();
|
||||
entry.ifindex = neigh.ifindex;
|
||||
} else {
|
||||
// New reachable neighbour — register in DNS
|
||||
debug!("New neighbour: {:?}", neigh);
|
||||
// Enforce per-host ULA limit before adding.
|
||||
if let NeighbourAddress::Inet6(addr) = &neigh.inet {
|
||||
if if_ipv6_in_private_subnet(addr) {
|
||||
prune_ula_for_mac(&neigh.mac, max_ula_per_host, &mut registered, &updater).await;
|
||||
prune_ula_for_host(hostname, max_ula_per_host, &mut registered, &updater).await;
|
||||
}
|
||||
}
|
||||
if process_new_neigh(&neigh, &updater, &leases, private_subnet_v6).await {
|
||||
@@ -441,17 +452,20 @@ async fn main() -> Result<(), ()> {
|
||||
ifindex: neigh.ifindex,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
debug!("no lease for mac {}, skipping DNS update", neigh.mac);
|
||||
}
|
||||
} else {
|
||||
debug!("no lease for mac {}, skipping DNS update", neigh.mac);
|
||||
}
|
||||
} else if matches!(neigh.state, NeighbourState::Stale | NeighbourState::Delay | NeighbourState::Probe) {
|
||||
// Uncertain state: update ifindex only so the next probe uses
|
||||
// the right interface, but do NOT refresh last_confirmed —
|
||||
// STALE/DELAY/PROBE is not confirmed reachable and refreshing
|
||||
// the timestamp would suppress the periodic probe.
|
||||
if let Some(entry) = registered.get_mut(&key) {
|
||||
entry.ifindex = neigh.ifindex;
|
||||
if let Some(hostname) = leases.get(&neigh.mac) {
|
||||
let key = (hostname.clone(), ip_str.clone());
|
||||
if let Some(entry) = registered.get_mut(&key) {
|
||||
entry.ifindex = neigh.ifindex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -474,15 +488,16 @@ async fn main() -> Result<(), ()> {
|
||||
}
|
||||
}
|
||||
}
|
||||
let key = (neigh.mac.clone(), inet_to_string(&neigh.inet));
|
||||
let stored_hostname = registered.remove(&key).map(|e| e.hostname);
|
||||
let ip_str = inet_to_string(&neigh.inet);
|
||||
// Resolve key by hostname; fall back to scanning by IP if MAC gone from leases.
|
||||
let key_opt: Option<(String, String)> = leases
|
||||
.get(&neigh.mac)
|
||||
.map(|h| (h.clone(), ip_str.clone()))
|
||||
.or_else(|| registered.keys().find(|(_, ip)| ip == &ip_str).cloned());
|
||||
debug!("Del neighbour: {:?}", neigh);
|
||||
// Use stored hostname if available, fall back to leases for records
|
||||
// that survived a program restart (not in registered).
|
||||
let hostname_opt = stored_hostname
|
||||
.or_else(|| leases.get(&neigh.mac).cloned());
|
||||
if let Some(ref hostname) = hostname_opt {
|
||||
do_delete_dns(hostname, &neigh.inet, &updater).await;
|
||||
if let Some(key) = key_opt {
|
||||
registered.remove(&key);
|
||||
do_delete_dns(&key.0, &neigh.inet, &updater).await;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
||||
+10
-10
@@ -67,20 +67,20 @@ pub(crate) async fn do_delete_dns(
|
||||
}
|
||||
}
|
||||
|
||||
/// Enforce the per-host ULA AAAA limit. If `mac` already has `max` or more ULA AAAA
|
||||
/// Enforce the per-host ULA AAAA limit. If `host` already has `max` or more ULA AAAA
|
||||
/// records in `registered`, remove the oldest (by `last_confirmed`) and delete from DNS.
|
||||
/// Returns the number of existing ULA AAAA records for this MAC (after pruning).
|
||||
pub(crate) async fn prune_ula_for_mac(
|
||||
mac: &str,
|
||||
/// Returns the number of existing ULA AAAA records for this host (after pruning).
|
||||
pub(crate) async fn prune_ula_for_host(
|
||||
host: &str,
|
||||
max: usize,
|
||||
registered: &mut HashMap<(String, String), RegisteredEntry>,
|
||||
updater: &DnsUpdater,
|
||||
) -> usize {
|
||||
// Collect existing ULA AAAA keys for this MAC.
|
||||
// Collect existing ULA AAAA keys for this host.
|
||||
let mut ula_keys: Vec<((String, String), Instant)> = registered
|
||||
.iter()
|
||||
.filter(|((m, ip_str), _)| {
|
||||
m == mac && ip_str.parse::<Ipv6Addr>().map_or(false, |a| if_ipv6_in_private_subnet(&a))
|
||||
.filter(|((h, ip_str), _)| {
|
||||
h == host && ip_str.parse::<Ipv6Addr>().map_or(false, |a| if_ipv6_in_private_subnet(&a))
|
||||
})
|
||||
.map(|(k, e)| (k.clone(), e.last_confirmed))
|
||||
.collect();
|
||||
@@ -99,15 +99,15 @@ pub(crate) async fn prune_ula_for_mac(
|
||||
let addr: Ipv6Addr = key.1.parse().unwrap();
|
||||
let inet = NeighbourAddress::Inet6(addr);
|
||||
do_delete_dns(&entry.hostname, &inet, updater).await;
|
||||
info!("ULA pruning: removed oldest {} -> {} for mac {}", entry.hostname, key.1, mac);
|
||||
info!("ULA pruning: removed oldest {} -> {} for host {}", entry.hostname, key.1, host);
|
||||
}
|
||||
}
|
||||
|
||||
// Return count after pruning.
|
||||
registered
|
||||
.iter()
|
||||
.filter(|((m, ip_str), _)| {
|
||||
m == mac && ip_str.parse::<Ipv6Addr>().map_or(false, |a| if_ipv6_in_private_subnet(&a))
|
||||
.filter(|((h, ip_str), _)| {
|
||||
h == host && ip_str.parse::<Ipv6Addr>().map_or(false, |a| if_ipv6_in_private_subnet(&a))
|
||||
})
|
||||
.count()
|
||||
}
|
||||
|
||||
@@ -8,8 +8,8 @@ include $(TOPDIR)/rules.mk
|
||||
LUCI_TITLE:=LuCI support for ddnsto
|
||||
LUCI_DEPENDS:=+ddnsto +block-mount
|
||||
LUCI_PKGARCH:=all
|
||||
PKG_VERSION:=3.2.0-r5
|
||||
PKG_RELEASE:=1
|
||||
PKG_VERSION:=4.0.3-r1
|
||||
PKG_RELEASE:=2
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
--wulishui <wulishui@gmail.com> ,20200911
|
||||
--jjm2473 <jjm2473@gmail.com> ,20210127
|
||||
|
||||
local m, s
|
||||
local m, s, o
|
||||
|
||||
m = Map("ddnsto", translate("DDNS.to"), translate("DDNS.to is a reverse proxy.")
|
||||
m = Map("ddnsto", translate("DDNS.to"), translate("DDNS.to is a reverse proxy service.")
|
||||
.. " <a href=\"https://www.ddnsto.com/\" onclick=\"void(0)\" target=\"_blank\">"
|
||||
.. translate("Official Website")
|
||||
.. "</a>")
|
||||
@@ -18,6 +18,41 @@ s:option(Flag, "enabled", translate("Enable")).rmempty=false
|
||||
|
||||
s:option(Value, "token", translate("Token")).rmempty=false
|
||||
|
||||
o = s:option(Value, "index", translate("Device Index"))
|
||||
o.default = "0"
|
||||
o.datatype = "uinteger"
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(Flag, "logger", translate("Enable Logging"))
|
||||
o.default = "0"
|
||||
o.rmempty = false
|
||||
|
||||
-- WebDAV/File Sharing settings
|
||||
s2=m:section(TypedSection, "ddnsto", translate("WebDAV File Sharing"))
|
||||
s2.addremove=false
|
||||
s2.anonymous=true
|
||||
|
||||
o = s2:option(Flag, "feat_enabled", translate("Enable WebDAV"))
|
||||
o.default = "0"
|
||||
o.rmempty = false
|
||||
|
||||
o = s2:option(Value, "feat_port", translate("WebDAV Port"))
|
||||
o.default = "3033"
|
||||
o.datatype = "port"
|
||||
o.rmempty = false
|
||||
o:depends("feat_enabled", "1")
|
||||
|
||||
o = s2:option(Value, "feat_username", translate("Username"))
|
||||
o.rmempty = false
|
||||
o:depends("feat_enabled", "1")
|
||||
|
||||
o = s2:option(Value, "feat_password", translate("Password"))
|
||||
o.password = true
|
||||
o.rmempty = false
|
||||
o:depends("feat_enabled", "1")
|
||||
|
||||
o = s2:option(Value, "feat_disk_path_selected", translate("Shared Path"))
|
||||
o.rmempty = false
|
||||
o:depends("feat_enabled", "1")
|
||||
|
||||
return m
|
||||
|
||||
|
||||
@@ -97,6 +97,6 @@ Error generating stack: `+o.message+`
|
||||
*
|
||||
* This source code is licensed under the ISC license.
|
||||
* See the LICENSE file in the root directory of this source tree.
|
||||
*/const vf=[["rect",{width:"14",height:"20",x:"5",y:"2",rx:"2",ry:"2",key:"1yt0o3"}],["path",{d:"M12 18h.01",key:"mhygvu"}]],Vu=Gt("smartphone",vf);function yf(){return m.jsx("div",{className:"bg-white rounded-lg border border-slate-200 p-6 mb-4",children:m.jsx("div",{className:"flex items-start",children:m.jsxs("div",{className:"flex-1",children:[m.jsxs("div",{className:"flex items-center gap-3 mb-3",children:[m.jsx("div",{className:"w-10 h-10 rounded-full bg-blue-50 flex items-center justify-center",children:m.jsx(Bu,{className:"w-6 h-6 text-blue-600"})}),m.jsx("h2",{className:"text-slate-800",children:"DDNSTO 远程访问"})]}),m.jsx("p",{className:"text-slate-600 text-sm mb-2",children:"DDNSTO 远程访问,不需要公网 IP、不需要开放端口。只需一个链接,即可从任何地方安全访问您的 NAS、路由器和桌面。"}),m.jsxs("a",{href:"https://www.ddnsto.com",target:"_blank",rel:"noopener noreferrer",className:"inline-flex items-center gap-1 text-sm text-blue-600 hover:underline",children:["了解更多",m.jsx(Al,{className:"w-3 h-3"})]})]})})})}function wf({isRunning:y,isConfigured:E,hostname:d,address:U,deviceId:T,version:L,featEnabled:B,tunnelOk:G,onRefreshStatus:A}){const[Q,Z]=C.useState(!1),W={label:y?"运行中":"已停止",bgColor:y?"bg-green-100":"bg-slate-200",textColor:y?"text-green-700":"text-slate-600"},H=U&&U.trim().length>0?U:"未配置",q=Q,ae=G===!0,V=q?"检查中...":G===!0?"正常":G===!1?"无法连接服务器":"未知",Y=B==="1"||B===!0?"已开启":"未开启",we=T||"-",ze=async()=>{if(A){Z(!0);try{await A()}finally{Z(!1)}}};return m.jsxs("div",{className:"bg-white rounded-lg border border-slate-200 p-6 mb-4",children:[m.jsx("h3",{className:"text-slate-800 mb-4",children:"运行状态"}),m.jsxs("div",{className:"flex items-center justify-between pb-6 border-b border-slate-100",children:[m.jsxs("div",{className:"flex items-center gap-4",children:[m.jsx("span",{className:`px-3 py-1 rounded-full text-sm ${W.bgColor} ${W.textColor}`,children:W.label}),E&&m.jsxs("div",{className:"flex items-center gap-2",children:[m.jsx("span",{className:"text-sm text-slate-500",children:"远程访问域名:"}),U&&U.trim().length>0?m.jsxs("a",{href:H,target:"_blank",rel:"noopener noreferrer",className:"text-sm text-blue-600 hover:underline flex items-center gap-1",children:[H,m.jsx(Al,{className:"w-3 h-3"})]}):m.jsx("span",{className:"text-sm text-slate-500",children:H})]})]}),m.jsx("div",{className:"flex items-center gap-2",children:m.jsxs("button",{onClick:ze,className:"px-3 py-2 rounded-md text-blue-600 text-sm hover:bg-blue-50 transition-colors flex items-center gap-1",children:[m.jsx(hf,{className:"w-4 h-4"}),"刷新状态"]})})]}),m.jsx("div",{className:"mt-6",children:m.jsxs("div",{className:"flex items-center gap-2 text-sm text-slate-700",children:[m.jsx(Bu,{className:"w-4 h-4 text-slate-400"}),q&&m.jsx("div",{className:"w-4 h-4 rounded-full border-2 border-slate-300 border-t-blue-600 animate-spin"}),m.jsxs("h4",{className:"text-sm text-slate-700",children:["服务器连接:",ae?m.jsx("span",{className:"text-green-600",children:V}):m.jsx("span",{children:V}),"| 设备 ID:",we," | 拓展功能:",Y,L?` | 版本:${L}`:""]})]})})]})}function Qu({checked:y,onChange:E,label:d,id:U,disabled:T,containerClassName:L,...B}){return m.jsxs("div",{className:`ddnsto-toggle-container ${L||""}`,children:[d&&m.jsx("label",{htmlFor:U,className:"text-sm text-slate-700 mr-3 whitespace-nowrap",children:d}),m.jsxs("label",{className:"ddnsto-toggle-switch","aria-label":d||"toggle",children:[m.jsx("input",{id:U,type:"checkbox",checked:y,disabled:T,onChange:G=>E(G.target.checked),...B}),m.jsx("span",{className:"ddnsto-toggle-slider","aria-hidden":!0})]})]})}function kf({onSave:y,isInTab:E,token:d,enabled:U,advancedConfig:T,onRegisterSave:L,onTokenChange:B,onEnabledChange:G}){const[A,Q]=C.useState(d||""),[Z,W]=C.useState(U);C.useEffect(()=>{Q(d||"")},[d]),C.useEffect(()=>{W(U)},[T,U]);const H=()=>{A.trim()&&y(A,Z?"1":"0",T)};return C.useEffect(()=>{L&&L(()=>H())},[L,A,Z,T]),m.jsxs("div",{className:E?"":"bg-white rounded-lg border border-slate-200 p-6 mb-4",children:[!E&&m.jsxs(m.Fragment,{children:[m.jsx("h3",{className:"text-slate-800 mb-2",children:"手动配置"}),m.jsx("p",{className:"text-xs text-slate-400 mb-6",children:"如果您已经在 DDNSTO 控制台获取了令牌,可以直接在此填写并启动插件。"})]}),m.jsxs("div",{className:"space-y-5",children:[m.jsx("div",{className:"pb-4",children:m.jsxs("div",{className:"flex items-center gap-2",children:[m.jsx("h4",{className:"text-sm text-slate-700",children:"启用 DDNSTO"}),m.jsx(Qu,{checked:Z,onChange:q=>{W(q),G?.(q)},"aria-label":"启用 DDNSTO",containerClassName:"ml-6"})]})}),m.jsxs("div",{children:[m.jsxs("div",{className:"flex items-center gap-2 mb-2",children:[m.jsxs("label",{className:"text-sm text-slate-700",children:["用户令牌(Token) ",m.jsx("span",{className:"text-red-500",children:"*"})]}),m.jsLine truncated
|
||||
*/const vf=[["rect",{width:"14",height:"20",x:"5",y:"2",rx:"2",ry:"2",key:"1yt0o3"}],["path",{d:"M12 18h.01",key:"mhygvu"}]],Vu=Gt("smartphone",vf);function yf(){return m.jsx("div",{className:"bg-white rounded-lg border border-slate-200 p-6 mb-4",children:m.jsx("div",{className:"flex items-start",children:m.jsxs("div",{className:"flex-1",children:[m.jsxs("div",{className:"flex items-center gap-3 mb-3",children:[m.jsx("div",{className:"w-10 h-10 rounded-full bg-blue-50 flex items-center justify-center",children:m.jsx(Bu,{className:"w-6 h-6 text-blue-600"})}),m.jsx("h2",{className:"text-slate-800",children:"DDNSTO 远程访问"})]}),m.jsx("p",{className:"text-slate-600 text-sm mb-2",children:"DDNSTO 远程访问,不需要公网 IP、不需要开放端口。只需一个链接,即可从任何地方安全访问您的 NAS、路由器和桌面。"}),m.jsxs("a",{href:"https://www.ddnsto.com",target:"_blank",rel:"noopener noreferrer",className:"inline-flex items-center gap-1 text-sm text-blue-600 hover:underline",children:["了解更多",m.jsx(Al,{className:"w-3 h-3"})]})]})})})}function wf({isRunning:y,isConfigured:E,hostname:d,address:U,deviceId:T,version:L,featEnabled:B,tunnelOk:G,onRefreshStatus:A}){const[Q,Z]=C.useState(!1),W={label:y?"运行中":"已停止",bgColor:y?"bg-green-100":"bg-slate-200",textColor:y?"text-green-700":"text-slate-600"},H=U&&U.trim().length>0?U:"未配置",q=Q,ae=G===!0,V=q?"检查中...":G===!0?"正常":G===!1?"无法连接服务器":"未知",Y=B==="1"||B===!0?"已开启":"未开启",we=T||"-",ze=async()=>{if(A){Z(!0);try{await A()}finally{Z(!1)}}};return m.jsxs("div",{className:"bg-white rounded-lg border border-slate-200 p-6 mb-4",children:[m.jsx("h3",{className:"text-slate-800 mb-4",children:"运行状态"}),m.jsxs("div",{className:"flex items-center justify-between pb-6 border-b border-slate-100",children:[m.jsxs("div",{className:"flex items-center gap-4",children:[m.jsx("span",{className:`px-3 py-1 rounded-full text-sm ${W.bgColor} ${W.textColor}`,children:W.label}),E&&m.jsxs("div",{className:"flex items-center gap-2",children:[m.jsx("span",{className:"text-sm text-slate-500",children:"远程访问域名:"}),U&&U.trim().length>0?m.jsxs("div",{className:"flex items-center gap-2",children:[m.jsxs("a",{href:H,target:"_blank",rel:"noopener noreferrer",className:"text-sm text-blue-600 hover:underline flex items-center gap-1",children:[H,m.jsx(Al,{className:"w-3 h-3"})]}),m.jsx("span",{className:"text-xs text-amber-600",title:"如域名已失效,请重新运行快速向导",children:"(如失效请重新运行快速向导)"})]}):m.jsx("span",{className:"text-sm text-slate-500",children:H})]})]}),m.jsx("div",{className:"flex items-center gap-2",children:m.jsxs("button",{onClick:ze,className:"px-3 py-2 rounded-md text-blue-600 text-sm hover:bg-blue-50 transition-colors flex items-center gap-1",children:[m.jsx(hf,{className:"w-4 h-4"}),"刷新状态"]})})]}),m.jsx("div",{className:"mt-6",children:m.jsxs("div",{className:"flex items-center gap-2 text-sm text-slate-700",children:[m.jsx(Bu,{className:"w-4 h-4 text-slate-400"}),q&&m.jsx("div",{className:"w-4 h-4 rounded-full border-2 border-slate-300 border-t-blue-600 animate-spin"}),m.jsxs("h4",{className:"text-sm text-slate-700",children:["服务器连接:",ae?m.jsx("span",{className:"text-green-600",children:V}):m.jsx("span",{children:V}),"| 设备 ID:",we," | 拓展功能:",Y,L?` | 版本:${L}`:""]})]})})]})}function Qu({checked:y,onChange:E,label:d,id:U,disabled:T,containerClassName:L,...B}){return m.jsxs("div",{className:`ddnsto-toggle-container ${L||""}`,children:[d&&m.jsx("label",{htmlFor:U,className:"text-sm text-slate-700 mr-3 whitespace-nowrap",children:d}),m.jsxs("label",{className:"ddnsto-toggle-switch","aria-label":d||"toggle",children:[m.jsx("input",{id:U,type:"checkbox",checked:y,disabled:T,onChange:G=>E(G.target.checked),...B}),m.jsx("span",{className:"ddnsto-toggle-slider","aria-hidden":!0})]})]})}function kf({onSave:y,isInTab:E,token:d,enabled:U,advancedConfig:T,onRegisterSave:L,onTokenChange:B,onEnabledChange:G}){const[A,Q]=C.useState(d||""),[Z,W]=C.useState(U);C.useEffect(()=>{Q(d||"")},[d]),C.useEffect(()=>{W(U)},[T,U]);const H=()=>{A.trim()&&y(A,Z?"1":"0",T)};return C.useEffect(()=>{L&&L(()=>H())},[L,A,Z,T]),m.jsxs("div",{className:E?"":"bg-white rounded-lg border border-slate-200 p-6 mb-4",children:[!E&&m.jsxs(m.Fragment,{children:[m.jsx("h3",{className:"text-slate-800 mb-2",children:"手动配置"}),m.jsx("p",{className:"text-xs text-slate-400 mb-6",children:"如果您已经在 DDNSTO 控制台获取了令牌,可以直接在此填写并启动插件。"})]}),m.jsxs("div",{className:"space-y-5",children:[m.jsx("div",{className:"pb-4",children:m.jsxs("div",{className:"flex items-center gap-2",children:[m.jsx("h4",{className:"text-sm text-slate-700",children:"启用 DDNSTO"}),m.jsx(Qu,{checked:Z,onChange:q=>{W(q),G?.(q)},"aria-label":"启用 DDNSTO",containerClassName:"ml-6"})]})}),m.jsxs("div",Line truncated
|
||||
${jf}
|
||||
${zf}`;if(Mf&>.attachShadow){const E=gt.shadowRoot||gt.attachShadow({mode:"open"});if(!E.querySelector("style[data-ddnsto-style]")){const d=document.createElement("style");d.setAttribute("data-ddnsto-style","true"),d.textContent=y,E.appendChild(d)}Ui=E,bl(gt,Ul),bl(gt.parentElement,Ul)}else{if(!document.head.querySelector("style[data-ddnsto-style]")){const E=document.createElement("style");E.setAttribute("data-ddnsto-style","true"),E.textContent=y,document.head.appendChild(E)}bl(gt,Ul),bl(gt.parentElement,Ul)}Ui&&qd.createRoot(Ui).render(m.jsx(Kd.StrictMode,{children:m.jsx(Ef,{config:Lf})}))}
|
||||
@@ -7,8 +7,8 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-passwall
|
||||
PKG_VERSION:=26.5.11
|
||||
PKG_RELEASE:=129
|
||||
PKG_VERSION:=26.5.20
|
||||
PKG_RELEASE:=130
|
||||
PKG_PO_VERSION:=$(PKG_VERSION)
|
||||
|
||||
PKG_CONFIG_DEPENDS:= \
|
||||
|
||||
@@ -78,6 +78,7 @@ if not arg_select_proto:find("_") then
|
||||
load_normal_options = true
|
||||
end
|
||||
|
||||
local netdev_list = api.get_network_devices()
|
||||
local node_list = api.get_node_list()
|
||||
local fallback_list = {}
|
||||
local is_balancer = nil
|
||||
@@ -273,8 +274,10 @@ end -- [[ 负载均衡 End ]]
|
||||
|
||||
if load_iface_options then -- [[ 自定义接口 Start ]]
|
||||
o = s:option(Value, _n("iface"), translate("Interface"))
|
||||
o.default = "eth1"
|
||||
o:depends({ [_n("protocol")] = "_iface" })
|
||||
for _, d in ipairs(netdev_list) do
|
||||
o:value(d.name, d.label)
|
||||
end
|
||||
end -- [[ 自定义接口 End ]]
|
||||
|
||||
|
||||
@@ -818,8 +821,7 @@ if not load_shunt_options then
|
||||
o3 = s:option(Value, _n("outbound_iface"), translate("Outbound Interface"))
|
||||
o3:depends({ [_n("chain_proxy")] = "3" })
|
||||
o3:value("", translate("All"))
|
||||
local iface = api.get_network_devices()
|
||||
for _, d in ipairs(iface) do
|
||||
for _, d in ipairs(netdev_list) do
|
||||
o3:value(d.name, d.label)
|
||||
end
|
||||
|
||||
|
||||
@@ -91,6 +91,7 @@ if not arg_select_proto:find("_") then
|
||||
load_normal_options = true
|
||||
end
|
||||
|
||||
local netdev_list = api.get_network_devices()
|
||||
local node_list = api.get_node_list()
|
||||
|
||||
if load_urltest_options then -- [[ URLTest Start ]]
|
||||
@@ -196,8 +197,10 @@ end -- [[ URLTest End ]]
|
||||
|
||||
if load_iface_options then -- [[ 自定义接口 Start ]]
|
||||
o = s:option(Value, _n("iface"), translate("Interface"))
|
||||
o.default = "eth1"
|
||||
o:depends({ [_n("protocol")] = "_iface" })
|
||||
for _, d in ipairs(netdev_list) do
|
||||
o:value(d.name, d.label)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -836,8 +839,7 @@ if not load_shunt_options then
|
||||
o3 = s:option(Value, _n("outbound_iface"), translate("Outbound Interface"))
|
||||
o3:depends({ [_n("chain_proxy")] = "3" })
|
||||
o3:value("", translate("All"))
|
||||
local iface = api.get_network_devices()
|
||||
for _, d in ipairs(iface) do
|
||||
for _, d in ipairs(netdev_list) do
|
||||
o3:value(d.name, d.label)
|
||||
end
|
||||
|
||||
|
||||
@@ -483,8 +483,11 @@ o:depends({ [_n("outbound_node")] = "_socks"})
|
||||
o:depends({ [_n("outbound_node")] = "_http"})
|
||||
|
||||
o = s:option(Value, _n("outbound_node_iface"), translate("Interface"))
|
||||
o.default = "eth1"
|
||||
o:depends({ [_n("outbound_node")] = "_iface"})
|
||||
local netdev_list = api.get_network_devices()
|
||||
for _, d in ipairs(netdev_list) do
|
||||
o:value(d.name, d.label)
|
||||
end
|
||||
|
||||
o = s:option(TextValue, _n("custom_config"), translate("Custom Config"))
|
||||
o.rows = 10
|
||||
|
||||
@@ -461,8 +461,11 @@ o:depends({ [_n("outbound_node")] = "_socks" })
|
||||
o:depends({ [_n("outbound_node")] = "_http" })
|
||||
|
||||
o = s:option(Value, _n("outbound_node_iface"), translate("Interface"))
|
||||
o.default = "eth1"
|
||||
o:depends({ [_n("outbound_node")] = "_iface" })
|
||||
local netdev_list = api.get_network_devices()
|
||||
for _, d in ipairs(netdev_list) do
|
||||
o:value(d.name, d.label)
|
||||
end
|
||||
|
||||
o = s:option(TextValue, _n("custom_config"), translate("Custom Config"))
|
||||
o.rows = 10
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=teleproxy
|
||||
PKG_VERSION:=4.12.2
|
||||
PKG_RELEASE:=9
|
||||
PKG_RELEASE:=10
|
||||
|
||||
PKG_MAINTAINER:=Kosntantine Shevlakov <shevlakov@132lan.ru>
|
||||
PKG_LICENSE:=GPLv2
|
||||
@@ -10,7 +10,7 @@ PKG_LICENSE_FILES:=LICENSE
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://github.com/teleproxy/teleproxy.git
|
||||
PKG_SOURCE_VERSION:=12a822ef794bab357772348d698dfef3a13487de
|
||||
PKG_SOURCE_VERSION:=2f26609daf78765e09fcea8b0d906d9e2532faf9
|
||||
|
||||
PKG_SOURCE_SUBDIR:=$(PKG_NAME)
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||
|
||||
Reference in new issue
Block a user