From 1dd96ac2bbf9745820dab6662c42dfe64dfc2c58 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 15 Sep 2026 02:13:06 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=8D=93=20Sync=202026-09-15=2002:13:06?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- agentflow/Makefile | 8 +- cloudflared-next/Makefile | 89 + cloudflared-next/files/cloudflared.config | 17 + cloudflared-next/files/cloudflared.init | 64 + cloudflared-next/files/sample_config.yml | 17 + cloudflared-next/test.sh | 3 + cloudflared-next/update.sh | 78 + easytier-next/Makefile | 96 + frpc-next/Makefile | 63 + frpc-next/test.sh | 3 + frpc-next/update.sh | 45 + linkback/Makefile | 70 + linkback/files/linkback.config | 9 + linkback/files/linkback.init | 32 + linkback/src/Makefile | 18 + linkback/src/linkbackd.c | 849 ++ linkback/src/linkbackd.h | 67 + luci-app-ap-switch/Makefile | 15 + .../resources/view/ap-switch/ap-switch.js | 201 + luci-app-ap-switch/po/templates/ap-switch.pot | 116 + luci-app-ap-switch/po/zh-cn | 1 + luci-app-ap-switch/po/zh_Hans/ap-switch.po | 169 + luci-app-ap-switch/root/etc/config/ap-switch | 15 + .../share/luci-app-ap-switch/dhcp-probe.sh | 5 + .../share/luci/menu.d/luci-app-ap-switch.json | 13 + .../share/rpcd/acl.d/luci-app-ap-switch.json | 19 + .../root/usr/share/rpcd/ucode/luci.ap-switch | 226 + luci-app-cloudflared-next/Makefile | 20 + .../resources/view/cloudflared/config.js | 102 + .../resources/view/cloudflared/log.js | 125 + .../resources/view/cloudflared/tunnels.js | 101 + .../po/ar/cloudflared.po | 207 + .../po/be/cloudflared.po | 202 + .../po/bg/cloudflared.po | 206 + .../po/bn_BD/cloudflared.po | 206 + .../po/ca/cloudflared.po | 206 + .../po/cs/cloudflared.po | 212 + .../po/da/cloudflared.po | 203 + .../po/de/cloudflared.po | 214 + .../po/el/cloudflared.po | 206 + .../po/eo/cloudflared.po | 201 + .../po/es/cloudflared.po | 211 + .../po/et/cloudflared.po | 201 + .../po/fa/cloudflared.po | 207 + .../po/fi/cloudflared.po | 206 + .../po/fr/cloudflared.po | 208 + .../po/ga/cloudflared.po | 212 + .../po/he/cloudflared.po | 203 + .../po/hi/cloudflared.po | 206 + .../po/hu/cloudflared.po | 206 + .../po/it/cloudflared.po | 210 + .../po/ja/cloudflared.po | 207 + .../po/ko/cloudflared.po | 206 + .../po/lt/cloudflared.po | 218 + .../po/mr/cloudflared.po | 202 + .../po/ms/cloudflared.po | 202 + .../po/nb_NO/cloudflared.po | 206 + .../po/nl/cloudflared.po | 206 + .../po/pl/cloudflared.po | 214 + .../po/pt/cloudflared.po | 214 + .../po/pt_BR/cloudflared.po | 208 + .../po/ro/cloudflared.po | 209 + .../po/ru/cloudflared.po | 215 + .../po/sk/cloudflared.po | 203 + .../po/sv/cloudflared.po | 206 + .../po/ta/cloudflared.po | 212 + .../po/templates/cloudflared.pot | 195 + .../po/tr/cloudflared.po | 211 + .../po/uk/cloudflared.po | 215 + .../po/vi/cloudflared.po | 222 + .../po/yua/cloudflared.po | 209 + luci-app-cloudflared-next/po/zh-cn | 1 + .../po/zh_Hans/cloudflared.po | 206 + .../po/zh_Hant/cloudflared.po | 206 + .../luci/menu.d/luci-app-cloudflared.json | 37 + .../rpcd/acl.d/luci-app-cloudflared.json | 22 + luci-app-easytier-next/Makefile | 2 +- .../root/usr/libexec/rpcd/easytier | 471 - .../root/usr/share/rpcd/ucode/easytier.uc | 419 + luci-app-flowproxy/Makefile | 33 + .../resources/view/flowproxy/flowproxy.js | 560 ++ luci-app-flowproxy/po/templates/flowproxy.pot | 228 + luci-app-flowproxy/po/zh-cn | 1 + luci-app-flowproxy/po/zh_Hans/flowproxy.po | 252 + luci-app-flowproxy/root/etc/config/flowproxy | 104 + luci-app-flowproxy/root/etc/init.d/flowproxy | 299 + .../root/usr/share/flowproxy/chnroute.txt | 8788 +++++++++++++++++ .../root/usr/share/flowproxy/generate_nft.sh | 215 + .../share/luci/menu.d/luci-app-flowproxy.json | 11 + .../share/rpcd/acl.d/luci-app-flowproxy.json | 26 + .../root/usr/share/rpcd/ucode/luci.flowproxy | 175 + luci-app-frpc-next/Makefile | 32 + .../luci-static/resources/view/frpc/log.js | 44 + .../resources/view/frpc/overview.js | 294 + .../resources/view/frpc/settings.js | 276 + luci-app-frpc-next/po/zh-cn | 1 + luci-app-frpc-next/po/zh_Hans/frpc.po | 342 + luci-app-frpc-next/root/etc/config/frpc | 2 + .../root/etc/hotplug.d/iface/99-frpc | 25 + luci-app-frpc-next/root/etc/init.d/frpc | 50 + .../usr/share/luci/menu.d/luci-app-frpc.json | 37 + .../usr/share/rpcd/acl.d/luci-app-frpc.json | 37 + .../root/usr/share/rpcd/ucode/luci.frpc | 283 + luci-app-linkback/Makefile | 29 + .../resources/view/linkback/log.js | 44 + .../resources/view/linkback/overview.js | 261 + .../resources/view/linkback/settings.js | 429 + luci-app-linkback/po/zh-cn | 1 + luci-app-linkback/po/zh_Hans/linkback.po | 322 + .../share/luci/menu.d/luci-app-linkback.json | 37 + .../share/rpcd/acl.d/luci-app-linkback.json | 19 + .../root/usr/share/rpcd/ucode/luci.linkback | 64 + luci-app-oui/Makefile | 4 +- .../htdocs/luci-static/resources/oui/oui.js | 2 +- luci-app-oui/tools/test_oui.js | 6 +- luci-app-ssserver-next/Makefile | 24 + .../resources/view/ssserver/config.js | 106 + .../resources/view/ssserver/log.js | 47 + .../resources/view/ssserver/overview.js | 189 + luci-app-ssserver-next/po/zh-cn | 1 + luci-app-ssserver-next/po/zh_Hans/ssserver.po | 146 + .../root/etc/config/ssserver | 11 + .../root/etc/init.d/ssserver | 104 + .../share/luci/menu.d/luci-app-ssserver.json | 33 + .../share/rpcd/acl.d/luci-app-ssserver.json | 17 + .../root/usr/share/rpcd/ucode/luci.ssserver | 110 + luci-base/po/templates/base.pot | 3 + luci-base/po/zh_Hans/base.po | 3 + luci-base/po/zh_Hant/base.po | 3 + luci-mod-status/Makefile | 4 +- .../view/status/include/30_network.js | 4 +- .../resources/view/status/include/40_dhcp.js | 33 +- .../root/usr/libexec/luci-client-history | 22 +- .../usr/share/ucode/luci/client_history.uc | 40 + .../root/usr/share/ucode/luci/client_names.uc | 75 + luci-mod-status/tests/README.md | 14 + luci-mod-status/tests/client-names.uc | 35 + shadowsocks-rust-next/Makefile | 81 + shadowsocks-rust-next/test.sh | 3 + shadowsocks-rust-next/update.sh | 69 + tailscale-next/Makefile | 97 + tailscale-next/README.md | 23 + tailscale-next/files/tailscale.conf | 8 + tailscale-next/files/tailscale.init | 68 + torrserver/Makefile | 6 +- wwand/Makefile | 4 +- 146 files changed, 26541 insertions(+), 508 deletions(-) create mode 100644 cloudflared-next/Makefile create mode 100644 cloudflared-next/files/cloudflared.config create mode 100755 cloudflared-next/files/cloudflared.init create mode 100644 cloudflared-next/files/sample_config.yml create mode 100644 cloudflared-next/test.sh create mode 100755 cloudflared-next/update.sh create mode 100644 easytier-next/Makefile create mode 100644 frpc-next/Makefile create mode 100755 frpc-next/test.sh create mode 100755 frpc-next/update.sh create mode 100644 linkback/Makefile create mode 100644 linkback/files/linkback.config create mode 100644 linkback/files/linkback.init create mode 100644 linkback/src/Makefile create mode 100644 linkback/src/linkbackd.c create mode 100644 linkback/src/linkbackd.h create mode 100644 luci-app-ap-switch/Makefile create mode 100644 luci-app-ap-switch/htdocs/luci-static/resources/view/ap-switch/ap-switch.js create mode 100644 luci-app-ap-switch/po/templates/ap-switch.pot create mode 120000 luci-app-ap-switch/po/zh-cn create mode 100644 luci-app-ap-switch/po/zh_Hans/ap-switch.po create mode 100644 luci-app-ap-switch/root/etc/config/ap-switch create mode 100755 luci-app-ap-switch/root/usr/share/luci-app-ap-switch/dhcp-probe.sh create mode 100644 luci-app-ap-switch/root/usr/share/luci/menu.d/luci-app-ap-switch.json create mode 100644 luci-app-ap-switch/root/usr/share/rpcd/acl.d/luci-app-ap-switch.json create mode 100644 luci-app-ap-switch/root/usr/share/rpcd/ucode/luci.ap-switch create mode 100644 luci-app-cloudflared-next/Makefile create mode 100644 luci-app-cloudflared-next/htdocs/luci-static/resources/view/cloudflared/config.js create mode 100644 luci-app-cloudflared-next/htdocs/luci-static/resources/view/cloudflared/log.js create mode 100644 luci-app-cloudflared-next/htdocs/luci-static/resources/view/cloudflared/tunnels.js create mode 100644 luci-app-cloudflared-next/po/ar/cloudflared.po create mode 100644 luci-app-cloudflared-next/po/be/cloudflared.po create mode 100644 luci-app-cloudflared-next/po/bg/cloudflared.po create mode 100644 luci-app-cloudflared-next/po/bn_BD/cloudflared.po create mode 100644 luci-app-cloudflared-next/po/ca/cloudflared.po create mode 100644 luci-app-cloudflared-next/po/cs/cloudflared.po create mode 100644 luci-app-cloudflared-next/po/da/cloudflared.po create mode 100644 luci-app-cloudflared-next/po/de/cloudflared.po create mode 100644 luci-app-cloudflared-next/po/el/cloudflared.po create mode 100644 luci-app-cloudflared-next/po/eo/cloudflared.po create mode 100644 luci-app-cloudflared-next/po/es/cloudflared.po create mode 100644 luci-app-cloudflared-next/po/et/cloudflared.po create mode 100644 luci-app-cloudflared-next/po/fa/cloudflared.po create mode 100644 luci-app-cloudflared-next/po/fi/cloudflared.po create mode 100644 luci-app-cloudflared-next/po/fr/cloudflared.po create mode 100644 luci-app-cloudflared-next/po/ga/cloudflared.po create mode 100644 luci-app-cloudflared-next/po/he/cloudflared.po create mode 100644 luci-app-cloudflared-next/po/hi/cloudflared.po create mode 100644 luci-app-cloudflared-next/po/hu/cloudflared.po create mode 100644 luci-app-cloudflared-next/po/it/cloudflared.po create mode 100644 luci-app-cloudflared-next/po/ja/cloudflared.po create mode 100644 luci-app-cloudflared-next/po/ko/cloudflared.po create mode 100644 luci-app-cloudflared-next/po/lt/cloudflared.po create mode 100644 luci-app-cloudflared-next/po/mr/cloudflared.po create mode 100644 luci-app-cloudflared-next/po/ms/cloudflared.po create mode 100644 luci-app-cloudflared-next/po/nb_NO/cloudflared.po create mode 100644 luci-app-cloudflared-next/po/nl/cloudflared.po create mode 100644 luci-app-cloudflared-next/po/pl/cloudflared.po create mode 100644 luci-app-cloudflared-next/po/pt/cloudflared.po create mode 100644 luci-app-cloudflared-next/po/pt_BR/cloudflared.po create mode 100644 luci-app-cloudflared-next/po/ro/cloudflared.po create mode 100644 luci-app-cloudflared-next/po/ru/cloudflared.po create mode 100644 luci-app-cloudflared-next/po/sk/cloudflared.po create mode 100644 luci-app-cloudflared-next/po/sv/cloudflared.po create mode 100644 luci-app-cloudflared-next/po/ta/cloudflared.po create mode 100644 luci-app-cloudflared-next/po/templates/cloudflared.pot create mode 100644 luci-app-cloudflared-next/po/tr/cloudflared.po create mode 100644 luci-app-cloudflared-next/po/uk/cloudflared.po create mode 100644 luci-app-cloudflared-next/po/vi/cloudflared.po create mode 100644 luci-app-cloudflared-next/po/yua/cloudflared.po create mode 120000 luci-app-cloudflared-next/po/zh-cn create mode 100644 luci-app-cloudflared-next/po/zh_Hans/cloudflared.po create mode 100644 luci-app-cloudflared-next/po/zh_Hant/cloudflared.po create mode 100644 luci-app-cloudflared-next/root/usr/share/luci/menu.d/luci-app-cloudflared.json create mode 100644 luci-app-cloudflared-next/root/usr/share/rpcd/acl.d/luci-app-cloudflared.json delete mode 100755 luci-app-easytier-next/root/usr/libexec/rpcd/easytier create mode 100644 luci-app-easytier-next/root/usr/share/rpcd/ucode/easytier.uc create mode 100644 luci-app-flowproxy/Makefile create mode 100644 luci-app-flowproxy/htdocs/luci-static/resources/view/flowproxy/flowproxy.js create mode 100644 luci-app-flowproxy/po/templates/flowproxy.pot create mode 120000 luci-app-flowproxy/po/zh-cn create mode 100644 luci-app-flowproxy/po/zh_Hans/flowproxy.po create mode 100644 luci-app-flowproxy/root/etc/config/flowproxy create mode 100755 luci-app-flowproxy/root/etc/init.d/flowproxy create mode 100644 luci-app-flowproxy/root/usr/share/flowproxy/chnroute.txt create mode 100755 luci-app-flowproxy/root/usr/share/flowproxy/generate_nft.sh create mode 100644 luci-app-flowproxy/root/usr/share/luci/menu.d/luci-app-flowproxy.json create mode 100644 luci-app-flowproxy/root/usr/share/rpcd/acl.d/luci-app-flowproxy.json create mode 100755 luci-app-flowproxy/root/usr/share/rpcd/ucode/luci.flowproxy create mode 100644 luci-app-frpc-next/Makefile create mode 100644 luci-app-frpc-next/htdocs/luci-static/resources/view/frpc/log.js create mode 100644 luci-app-frpc-next/htdocs/luci-static/resources/view/frpc/overview.js create mode 100644 luci-app-frpc-next/htdocs/luci-static/resources/view/frpc/settings.js create mode 120000 luci-app-frpc-next/po/zh-cn create mode 100644 luci-app-frpc-next/po/zh_Hans/frpc.po create mode 100644 luci-app-frpc-next/root/etc/config/frpc create mode 100755 luci-app-frpc-next/root/etc/hotplug.d/iface/99-frpc create mode 100755 luci-app-frpc-next/root/etc/init.d/frpc create mode 100644 luci-app-frpc-next/root/usr/share/luci/menu.d/luci-app-frpc.json create mode 100644 luci-app-frpc-next/root/usr/share/rpcd/acl.d/luci-app-frpc.json create mode 100644 luci-app-frpc-next/root/usr/share/rpcd/ucode/luci.frpc create mode 100644 luci-app-linkback/Makefile create mode 100644 luci-app-linkback/htdocs/luci-static/resources/view/linkback/log.js create mode 100644 luci-app-linkback/htdocs/luci-static/resources/view/linkback/overview.js create mode 100644 luci-app-linkback/htdocs/luci-static/resources/view/linkback/settings.js create mode 120000 luci-app-linkback/po/zh-cn create mode 100644 luci-app-linkback/po/zh_Hans/linkback.po create mode 100644 luci-app-linkback/root/usr/share/luci/menu.d/luci-app-linkback.json create mode 100644 luci-app-linkback/root/usr/share/rpcd/acl.d/luci-app-linkback.json create mode 100644 luci-app-linkback/root/usr/share/rpcd/ucode/luci.linkback create mode 100644 luci-app-ssserver-next/Makefile create mode 100644 luci-app-ssserver-next/htdocs/luci-static/resources/view/ssserver/config.js create mode 100644 luci-app-ssserver-next/htdocs/luci-static/resources/view/ssserver/log.js create mode 100644 luci-app-ssserver-next/htdocs/luci-static/resources/view/ssserver/overview.js create mode 120000 luci-app-ssserver-next/po/zh-cn create mode 100644 luci-app-ssserver-next/po/zh_Hans/ssserver.po create mode 100644 luci-app-ssserver-next/root/etc/config/ssserver create mode 100755 luci-app-ssserver-next/root/etc/init.d/ssserver create mode 100644 luci-app-ssserver-next/root/usr/share/luci/menu.d/luci-app-ssserver.json create mode 100644 luci-app-ssserver-next/root/usr/share/rpcd/acl.d/luci-app-ssserver.json create mode 100644 luci-app-ssserver-next/root/usr/share/rpcd/ucode/luci.ssserver create mode 100644 luci-mod-status/root/usr/share/ucode/luci/client_names.uc create mode 100644 luci-mod-status/tests/client-names.uc create mode 100644 shadowsocks-rust-next/Makefile create mode 100755 shadowsocks-rust-next/test.sh create mode 100755 shadowsocks-rust-next/update.sh create mode 100644 tailscale-next/Makefile create mode 100644 tailscale-next/README.md create mode 100644 tailscale-next/files/tailscale.conf create mode 100755 tailscale-next/files/tailscale.init diff --git a/agentflow/Makefile b/agentflow/Makefile index 467c95252..9bee136eb 100644 --- a/agentflow/Makefile +++ b/agentflow/Makefile @@ -10,12 +10,12 @@ AGENTFLOW_ARCH_x86_64:=amd64 AGENTFLOW_ARCH_aarch64:=arm64 AGENTFLOW_ARCH:=$(AGENTFLOW_ARCH_$(ARCH)) -AGENTFLOW_HASH_x86_64:=ccf06c24eee59f9638bc0ba42d2ea420723317dccef980a42a51499844fbde2c -AGENTFLOW_HASH_aarch64:=369017b7e7ea359018875cde2ee9260f0eb92d6fda329e82a219b98516bb6350 +AGENTFLOW_HASH_x86_64:=95cb43ba4e2ce5f060e3609d050caf25170dc151ba882a3a626494b7750d5fbc +AGENTFLOW_HASH_aarch64:=93e92628b26087b87d8571400e83046197167e4795593e757d4dcf7dac5f8231 PKG_NAME:=agentflow -PKG_VERSION:=0.3.1 -PKG_RELEASE:=10 +PKG_VERSION:=0.3.3 +PKG_RELEASE:=11 AGENTFLOW_URL_FILE:=agentflow-linux-$(AGENTFLOW_ARCH) AGENTFLOW_DOWNLOAD:=$(AGENTFLOW_URL_FILE)-$(AGENTFLOW_HASH_$(ARCH)) diff --git a/cloudflared-next/Makefile b/cloudflared-next/Makefile new file mode 100644 index 000000000..aaa2eec45 --- /dev/null +++ b/cloudflared-next/Makefile @@ -0,0 +1,89 @@ +# SPDX-License-Identifier: GPL-3.0-only +# +# Copyright (C) 2021 ImmortalWrt.org + +include $(TOPDIR)/rules.mk + +PKG_NAME:=cloudflared-next +PKG_VERSION:=2026.9.1 +PKG_RELEASE:=1 + +# Architecture mapping for pre-built binaries +ifeq ($(ARCH),x86_64) + CF_ARCH:=amd64 +endif +ifeq ($(ARCH),aarch64) + CF_ARCH:=arm64 +endif +ifeq ($(ARCH),arm64) + CF_ARCH:=arm64 +endif +ifeq ($(ARCH),armv8) + CF_ARCH:=arm64 +endif +ifeq ($(ARCH),arm) + CF_ARCH:=arm +endif +ifeq ($(ARCH),armv7) + CF_ARCH:=arm +endif +ifeq ($(ARCH),i386) + CF_ARCH:=386 +endif + +PKG_SOURCE:=cloudflared-linux-$(CF_ARCH)-$(PKG_VERSION) +PKG_SOURCE_URL:=https://github.com/cloudflare/cloudflared/releases/download/$(PKG_VERSION)/cloudflared-linux-$(CF_ARCH)? +PKG_HASH:=skip + +PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION) + +PKG_LICENSE:=Apache-2.0 +PKG_LICENSE_FILES:=LICENSE +PKG_MAINTAINER:=Tianling Shen + +include $(INCLUDE_DIR)/package.mk + +define Package/cloudflared-next + SECTION:=net + CATEGORY:=Network + SUBMENU:=Web Servers/Proxies + TITLE:=Cloudflare Tunnel client Next - Pre-built Binary + URL:=https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/get-started/ + DEPENDS:=@(x86_64||aarch64||arm||i386) +ca-bundle + PROVIDES:=cloudflared + CONFLICTS:=cloudflared +endef + +define Package/cloudflared-next/description + Contains the command-line client for Cloudflare Tunnel, a tunneling + daemon that proxies traffic from the Cloudflare network to your origins. + This package contains official pre-built static binaries. +endef + +define Package/cloudflared-next/conffiles +/etc/config/cloudflared +/etc/cloudflared/ +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) + $(CP) $(DL_DIR)/$(PKG_SOURCE) $(PKG_BUILD_DIR)/cloudflared + chmod 0755 $(PKG_BUILD_DIR)/cloudflared +endef + +define Build/Compile +endef + +define Package/cloudflared-next/install + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/cloudflared $(1)/usr/bin/cloudflared + + $(INSTALL_DIR) $(1)/etc/cloudflared/ + $(INSTALL_CONF) $(CURDIR)/files/sample_config.yml $(1)/etc/cloudflared/config.yml + $(INSTALL_DIR) $(1)/etc/config/ + $(INSTALL_CONF) $(CURDIR)/files/cloudflared.config $(1)/etc/config/cloudflared + $(INSTALL_DIR) $(1)/etc/init.d/ + $(INSTALL_BIN) $(CURDIR)/files/cloudflared.init $(1)/etc/init.d/cloudflared +endef + +$(eval $(call BuildPackage,cloudflared-next)) diff --git a/cloudflared-next/files/cloudflared.config b/cloudflared-next/files/cloudflared.config new file mode 100644 index 000000000..36d1652ef --- /dev/null +++ b/cloudflared-next/files/cloudflared.config @@ -0,0 +1,17 @@ + +config cloudflared 'config' + option enabled '0' + option token '' +# option config '/etc/cloudflared/config.yml' +# option origincert '/etc/cloudflared/cert.pem' + option edge_bind_address '' + option edge_ip_version '' + option grace_period '' + option protocol 'auto' + option region '' + option retries '' + option tag '' + option metrics '' + option loglevel 'info' + option logfile '/var/log/cloudflared.log' + diff --git a/cloudflared-next/files/cloudflared.init b/cloudflared-next/files/cloudflared.init new file mode 100755 index 000000000..cfdd091aa --- /dev/null +++ b/cloudflared-next/files/cloudflared.init @@ -0,0 +1,64 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2021 Tianling Shen + +USE_PROCD=1 +START=99 + +CONF="cloudflared" +PROG="/usr/bin/cloudflared" + +append_param_arg() { + local value + + config_get value "config" "$1" $2 + [ -n "$value" ] && procd_append_param command "--${1//_/-}" "$value" +} + +start_service() { + config_load "$CONF" + + local enabled + local token + + config_get_bool enabled "config" "enabled" + [ "$enabled" -eq "1" ] || return 1 + + procd_open_instance "$CONF" + procd_set_param command "$PROG" "tunnel" + procd_append_param command "--no-autoupdate" + + append_param_arg "edge_bind_address" + append_param_arg "edge_ip_version" + append_param_arg "grace_period" + append_param_arg "protocol" + append_param_arg "region" + append_param_arg "retries" + append_param_arg "tag" + append_param_arg "metrics" + append_param_arg "loglevel" + append_param_arg "logfile" + + config_get token "config" "token" + if [ -z "$token" ]; then + # Locally-managed tunnels + append_param_arg "config" "/etc/cloudflared/config.yml" + append_param_arg "origincert" "/etc/cloudflared/cert.pem" + fi + + procd_append_param command "run" + + if [ -n "$token" ]; then + # Remotely-managed tunnel (recommended by Cloudflare) + procd_append_param command "--token" "$token" + fi + + procd_set_param respawn + procd_set_param stderr 1 + + procd_close_instance +} + +service_triggers() { + procd_add_reload_trigger "$CONF" + procd_add_interface_trigger "interface.*.up" "wan" /etc/init.d/cloudflared restart +} diff --git a/cloudflared-next/files/sample_config.yml b/cloudflared-next/files/sample_config.yml new file mode 100644 index 000000000..af98abbc7 --- /dev/null +++ b/cloudflared-next/files/sample_config.yml @@ -0,0 +1,17 @@ +# https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/do-more-with-tunnels/local-management/configuration-file/ + +# NOTICE +# Cloudflare recommends setting up a remotely-managed tunnel. +# Remotely-managed configurations are stored on Cloudflare, +# which allows you to manage the tunnel from any machine +# using the dashboard, API, or Terraform. + +#tunnel: +#credentials-file: /etc/cloudflared/.json +# +#ingress: +# - hostname: luci.example.com +# service: http://localhost:80 +# - hostname: ssh.example.com +# service: ssh://localhost:22 +# - service: http_status:404 diff --git a/cloudflared-next/test.sh b/cloudflared-next/test.sh new file mode 100644 index 000000000..31f10611e --- /dev/null +++ b/cloudflared-next/test.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +cloudflared --version | grep "$PKG_VERSION" diff --git a/cloudflared-next/update.sh b/cloudflared-next/update.sh new file mode 100755 index 000000000..d0367afb7 --- /dev/null +++ b/cloudflared-next/update.sh @@ -0,0 +1,78 @@ +#!/bin/bash + +# 自动更新 OpenWrt cloudflared-next 包的版本和 Hash +# 依赖: curl, grep, sed, sha256sum (或 shasum) + +set -e + +PKG_DIR=$(cd "$(dirname "$0")"; pwd) +MAKEFILE="$PKG_DIR/Makefile" + +if [ ! -f "$MAKEFILE" ]; then + echo "错误: 找不到 Makefile 文件 ($MAKEFILE)" + exit 1 +fi + +# 1. 获取当前本地版本 +CURRENT_VERSION=$(grep 'PKG_VERSION:=' "$MAKEFILE" | cut -d'=' -f2 | tr -d ' ') +echo "当前本地版本: $CURRENT_VERSION" + +# 2. 获取 GitHub 上的最新版本号 +# 注意: cloudflared 的 tag 通常是 2024.x.y 这种格式,无需特殊处理 +LATEST_VERSION=$(curl -s https://api.github.com/repos/cloudflare/cloudflared/releases/latest | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/' | sed 's/^v//') + +if [ -z "$LATEST_VERSION" ]; then + echo "错误: 无法从 GitHub 获取最新版本号。" + exit 1 +fi + +echo "GitHub 最新版本: $LATEST_VERSION" + +# 3. 比较版本 +if [ "$CURRENT_VERSION" == "$LATEST_VERSION" ]; then + echo "版本已经是最新,无需更新。" + exit 0 +fi + +echo "发现新版本! 正在准备更新..." + +# 4. 下载新版本的源码包并计算 Hash +SOURCE_URL="https://codeload.github.com/cloudflare/cloudflared/tar.gz/$LATEST_VERSION" +echo "正在从 $SOURCE_URL 下载并计算 Hash..." + +# 探测可用的哈希计算工具 +if command -v sha256sum >/dev/null 2>&1; then + NEW_HASH=$(curl -sL "$SOURCE_URL" | sha256sum | cut -d' ' -f1) +elif command -v shasum >/dev/null 2>&1; then + NEW_HASH=$(curl -sL "$SOURCE_URL" | shasum -a 256 | cut -d' ' -f1) +else + echo "错误: 系统中未找到 sha256sum 或 shasum 命令。" + exit 1 +fi + +if [ -z "$NEW_HASH" ] || [ ${#NEW_HASH} -ne 64 ]; then + echo "错误: 计算得到的 Hash 值无效: $NEW_HASH" + exit 1 +fi + +echo "新 Hash 值: $NEW_HASH" + +# 5. 更新 Makefile +# 使用特定的正则表达式确保精准替换 +if [[ "$OSTYPE" == "darwin"* ]]; then + sed -i '' "s/PKG_VERSION:=.*/PKG_VERSION:=$LATEST_VERSION/" "$MAKEFILE" + sed -i '' "s/PKG_HASH:=.*/PKG_HASH:=$NEW_HASH/" "$MAKEFILE" +else + sed -i "s/PKG_VERSION:=.*/PKG_VERSION:=$LATEST_VERSION/" "$MAKEFILE" + sed -i "s/PKG_HASH:=.*/PKG_HASH:=$NEW_HASH/" "$MAKEFILE" +fi + +echo "Makefile 更新成功: $CURRENT_VERSION -> $LATEST_VERSION" + +# 6. 可选: 提交更改 (如果是在 Git 仓库中且您希望自动提交) +# cd "$PKG_DIR/.." +# if [ -d ".git" ]; then +# git add cloudflared-next/Makefile +# git commit -m "cloudflared-next: update to version $LATEST_VERSION" +# echo "已在本地 Git 仓库中提交更新。" +# fi diff --git a/easytier-next/Makefile b/easytier-next/Makefile new file mode 100644 index 000000000..b25b5900c --- /dev/null +++ b/easytier-next/Makefile @@ -0,0 +1,96 @@ +include $(TOPDIR)/rules.mk +-include $(dir $(lastword $(MAKEFILE_LIST)))../version.mk + +PKG_NAME:=easytier-next +PKG_VERSION:=2.6.4 +PKG_RELEASE:=1 + +# Architecture mapping for pre-built binaries +ifeq ($(ARCH),mipsel) + APP_ARCH:=mipsel +endif +ifeq ($(ARCH),mips) + APP_ARCH:=mips +endif +ifeq ($(ARCH),arm) + APP_ARCH:=arm +endif +ifeq ($(BOARD),kirkwood) + APP_ARCH:=arm +endif +ifeq ($(ARCH),armv7) + APP_ARCH:=armv7 +endif +ifeq ($(ARCH),aarch64) + APP_ARCH:=aarch64 +endif +ifeq ($(ARCH),arm64) + APP_ARCH:=aarch64 +endif +ifeq ($(ARCH),armv8) + APP_ARCH:=aarch64 +endif +ifeq ($(ARCH),x86_64) + APP_ARCH:=x86_64 +endif + +PKG_SOURCE:=easytier-linux-$(APP_ARCH)-v$(PKG_VERSION).zip +PKG_SOURCE_URL:=https://github.com/EasyTier/EasyTier/releases/download/v$(PKG_VERSION)/ +PKG_HASH:=skip + +PKG_LICENSE:=Apache-2.0 +PKG_LICENSE_FILES:=LICENSE +PKG_MAINTAINER:=Dante + +PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION) + +include $(INCLUDE_DIR)/package.mk + +define Package/$(PKG_NAME) + SECTION:=net + CATEGORY:=Network + SUBMENU:=VPN + TITLE:=A simple, decentralized mesh VPN with WireGuard support (Next) + URL:=https://github.com/EasyTier/EasyTier + DEPENDS:=@(x86_64||arm||aarch64||mipsel||mips) +kmod-tun + PROVIDES:=easytier + CONFLICTS:=easytier +endef + +define Package/$(PKG_NAME)/description + A simple, decentralized mesh VPN with WireGuard support. +endef + +define Package/$(PKG_NAME)/config + config EASYTIER_INCLUDE_WEBCONSOLE + bool "Include Web Console (easytier-web)" + depends on PACKAGE_$(PKG_NAME) + depends on !(mips || mipsel) + default y + help + Install the easytier-web web console. +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) + unzip -q -o $(DL_DIR)/$(PKG_SOURCE) -d $(PKG_BUILD_DIR) + find $(PKG_BUILD_DIR) -mindepth 2 -type f -exec mv -f {} $(PKG_BUILD_DIR)/ \; +endef + +define Build/Compile +endef + +define Package/$(PKG_NAME)/install + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/easytier-core $(1)/usr/bin/ + $(INSTALL_BIN) $(PKG_BUILD_DIR)/easytier-cli $(1)/usr/bin/ +ifdef CONFIG_EASYTIER_INCLUDE_WEBCONSOLE + if [ -f $(PKG_BUILD_DIR)/easytier-web-embed ]; then \ + $(INSTALL_BIN) $(PKG_BUILD_DIR)/easytier-web-embed $(1)/usr/bin/easytier-web; \ + elif [ -f $(PKG_BUILD_DIR)/easytier-web ]; then \ + $(INSTALL_BIN) $(PKG_BUILD_DIR)/easytier-web $(1)/usr/bin/easytier-web; \ + fi +endif +endef + +$(eval $(call BuildPackage,$(PKG_NAME))) diff --git a/frpc-next/Makefile b/frpc-next/Makefile new file mode 100644 index 000000000..a32cd5071 --- /dev/null +++ b/frpc-next/Makefile @@ -0,0 +1,63 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=frpc-next +PKG_VERSION:=0.71.0 +PKG_RELEASE:=1 + +# Architecture mapping for pre-built binaries +ifeq ($(ARCH),mipsel) + FRP_ARCH:=mipsle +endif +ifeq ($(ARCH),mips) + FRP_ARCH:=mips +endif +ifeq ($(ARCH),i386) + FRP_ARCH:=386 +endif +ifeq ($(ARCH),x86_64) + FRP_ARCH:=amd64 +endif +ifeq ($(ARCH),arm) + FRP_ARCH:=arm +endif +ifeq ($(ARCH),aarch64) + FRP_ARCH:=arm64 +endif + +PKG_SOURCE:=frp_$(PKG_VERSION)_linux_$(FRP_ARCH).tar.gz +PKG_SOURCE_URL:=https://github.com/fatedier/frp/releases/download/v$(PKG_VERSION)/ +PKG_HASH:=skip + +PKG_LICENSE:=Apache-2.0 +PKG_LICENSE_FILES:=LICENSE +PKG_MAINTAINER:=Dante + +PKG_BUILD_DIR:=$(BUILD_DIR)/frp_$(PKG_VERSION)_linux_$(FRP_ARCH) + +include $(INCLUDE_DIR)/package.mk + +define Package/frpc-next + SECTION:=net + CATEGORY:=Network + SUBMENU:=Web Servers/Proxies + TITLE:=A fast reverse proxy (Client) - Binary + URL:=https://github.com/fatedier/frp + DEPENDS:=@(i386||x86_64||arm||aarch64||mipsel||mips) + PROVIDES:=frpc + CONFLICTS:=frpc +endef + +define Package/frpc-next/description + frp is a fast reverse proxy to help you expose a local server behind a + NAT or firewall to the internet. This package contains the pre-built frpc client. +endef + +define Build/Compile +endef + +define Package/frpc-next/install + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/frpc $(1)/usr/bin/ +endef + +$(eval $(call BuildPackage,frpc-next)) diff --git a/frpc-next/test.sh b/frpc-next/test.sh new file mode 100755 index 000000000..a25cbd7a8 --- /dev/null +++ b/frpc-next/test.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +frpc --version | grep "$PKG_VERSION" diff --git a/frpc-next/update.sh b/frpc-next/update.sh new file mode 100755 index 000000000..3df6ca094 --- /dev/null +++ b/frpc-next/update.sh @@ -0,0 +1,45 @@ +#!/bin/bash + +# 自动更新 OpenWrt frpc-next 包的版本和 Hash +# 依赖: curl, grep, sed, sha256sum (或 shasum) + +set -e + +PKG_DIR=$(cd "$(dirname "$0")"; pwd) +MAKEFILE="$PKG_DIR/Makefile" + +if [ ! -f "$MAKEFILE" ]; then + echo "错误: 找不到 Makefile 文件 ($MAKEFILE)" + exit 1 +fi + +# 1. 获取当前本地版本 +CURRENT_VERSION=$(grep 'PKG_VERSION:=' "$MAKEFILE" | cut -d'=' -f2 | tr -d ' ') +echo "当前本地版本: $CURRENT_VERSION" + +# 2. 获取 GitHub 上的最新版本号 +LATEST_VERSION=$(curl -s https://api.github.com/repos/fatedier/frp/releases/latest | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/' | sed 's/^v//') + +if [ -z "$LATEST_VERSION" ]; then + echo "错误: 无法从 GitHub 获取最新版本号。" + exit 1 +fi + +echo "GitHub 最新版本: $LATEST_VERSION" + +# 3. 比较版本 +if [ "$CURRENT_VERSION" == "$LATEST_VERSION" ]; then + echo "版本已经是最新,无需更新。" + exit 0 +fi + +echo "发现新版本! 正在准备更新..." + +# 4. 更新 Makefile +if [[ "$OSTYPE" == "darwin"* ]]; then + sed -i '' "s/PKG_VERSION:=.*/PKG_VERSION:=$LATEST_VERSION/" "$MAKEFILE" +else + sed -i "s/PKG_VERSION:=.*/PKG_VERSION:=$LATEST_VERSION/" "$MAKEFILE" +fi + +echo "Makefile 更新成功: $CURRENT_VERSION -> $LATEST_VERSION (Binary Mode)" diff --git a/linkback/Makefile b/linkback/Makefile new file mode 100644 index 000000000..bb4fc3635 --- /dev/null +++ b/linkback/Makefile @@ -0,0 +1,70 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright (C) 2026 Dante +# +# This is free software, licensed under the Apache License, Version 2.0 . +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=linkback +PKG_VERSION:=1.0.0 +PKG_RELEASE:=1 +PKG_MAINTAINER:=Dante + +PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME) + +include $(INCLUDE_DIR)/package.mk + +define Package/$(PKG_NAME) + SECTION:=net + CATEGORY:=Network + SUBMENU:=Routing and Redirection + TITLE:=LinkBack gateway switch daemon + DEPENDS:=+libuci +libubus +libubox +libblobmsg-json +ip-full + MAINTAINER:=Dante +endef + +define Package/$(PKG_NAME)/description + LinkBack: A highly efficient and lightweight C-based Multi-WAN link health monitoring + and dynamic route metric failover/failback daemon. Supports Ping, DNS, and TCP probes. +endef + +define Package/$(PKG_NAME)/conffiles +/etc/config/linkback +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) + $(CP) ./src/* $(PKG_BUILD_DIR)/ +endef + +define Build/Compile + $(MAKE) -C $(PKG_BUILD_DIR) \ + CC="$(TARGET_CC)" \ + CFLAGS="$(TARGET_CFLAGS)" \ + LDFLAGS="$(TARGET_LDFLAGS)" +endef + +define Package/$(PKG_NAME)/install + # Install C daemon binary + $(INSTALL_DIR) $(1)/usr/sbin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/linkbackd $(1)/usr/sbin/linkbackd + + # Install config and init files + $(INSTALL_DIR) $(1)/etc/config + $(INSTALL_CONF) ./files/linkback.config $(1)/etc/config/linkback + $(INSTALL_DIR) $(1)/etc/init.d + $(INSTALL_BIN) ./files/linkback.init $(1)/etc/init.d/linkback +endef + +define Package/$(PKG_NAME)/postinst +#!/sh +[ -n "$${IPKG_INSTROOT}" ] || { + /etc/init.d/linkback enable + /etc/init.d/linkback restart +} +exit 0 +endef + +$(eval $(call BuildPackage,$(PKG_NAME))) diff --git a/linkback/files/linkback.config b/linkback/files/linkback.config new file mode 100644 index 000000000..7e36a72c7 --- /dev/null +++ b/linkback/files/linkback.config @@ -0,0 +1,9 @@ + +config global + option enabled '0' + option check_interval '5' + option check_timeout '3' + option recovery_delay '3' + option failover_delay '2' + + diff --git a/linkback/files/linkback.init b/linkback/files/linkback.init new file mode 100644 index 000000000..0f785d641 --- /dev/null +++ b/linkback/files/linkback.init @@ -0,0 +1,32 @@ +#!/bin/sh /etc/rc.common + +START=99 +USE_PROCD=1 + +_get_global_enabled() { + config_get_bool _GLOBAL_ENABLED "$1" "enabled" 0 +} + +start_service() { + config_load "linkback" + + local _GLOBAL_ENABLED=0 + config_foreach _get_global_enabled "global" + [ "$_GLOBAL_ENABLED" -eq 1 ] || return 0 + + procd_open_instance "main" + procd_set_param command /usr/sbin/linkbackd + procd_set_param respawn + procd_set_param stdout 1 + procd_set_param stderr 1 + procd_close_instance +} + +reload_service() { + stop + start +} + +service_triggers() { + procd_add_reload_trigger "linkback" +} diff --git a/linkback/src/Makefile b/linkback/src/Makefile new file mode 100644 index 000000000..f44f84299 --- /dev/null +++ b/linkback/src/Makefile @@ -0,0 +1,18 @@ +TARGET := linkbackd +OBJS := linkbackd.o + +CFLAGS += -Wall -O2 +LIBS := -luci + +all: $(TARGET) + +$(TARGET): $(OBJS) + $(CC) $(CFLAGS) $(OBJS) -o $(TARGET) $(LDFLAGS) $(LIBS) + +%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ + +clean: + rm -f *.o $(TARGET) + +.PHONY: all clean diff --git a/linkback/src/linkbackd.c b/linkback/src/linkbackd.c new file mode 100644 index 000000000..c887f6efa --- /dev/null +++ b/linkback/src/linkbackd.c @@ -0,0 +1,849 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "linkbackd.h" + +// DNS Header struct for raw check +struct dns_header { + unsigned short id; + unsigned short flags; + unsigned short qdcount; + unsigned short ancount; + unsigned short nscount; + unsigned short arcount; +}; + +// Global daemon state +static global_config_t global_cfg; +static link_t links[MAX_LINKS]; +static int link_count = 0; +static volatile bool keep_running = true; + +// Prototypes +static void restore_all_metrics(void); +static bool validate_loaded_config(void); +static void handle_signal(int sig) { + syslog(LOG_INFO, "Received signal %d, exiting...", sig); + keep_running = false; +} + +// Ubus popen JSON parser +static bool get_interface_ubus_status(const char *ifname, char *device, int dev_len, char *gateway, int gw_len, bool *is_up) { + char cmd[256]; + snprintf(cmd, sizeof(cmd), "ubus call network.interface.%s status 2>/dev/null", ifname); + FILE *fp = popen(cmd, "r"); + if (!fp) return false; + + char buf[4096] = {0}; + int bytes_read = fread(buf, 1, sizeof(buf) - 1, fp); + pclose(fp); + + if (bytes_read <= 0) return false; + + // Check if interface is up + *is_up = false; + char *p_up = strstr(buf, "\"up\":"); + if (p_up) { + char *p_true = strstr(p_up, "true"); + // Ensure 'true' belongs to this property and isn't far away + if (p_true && p_true - p_up < 10) { + *is_up = true; + } + } + + // Extract physical device + device[0] = '\0'; + char *p_dev = strstr(buf, "\"l3_device\":"); + int dev_key_len = 12; + if (!p_dev) { + p_dev = strstr(buf, "\"device\":"); + dev_key_len = 9; + } + if (p_dev) { + char *p_start = strchr(p_dev + dev_key_len, '"'); + if (p_start) { + char *p_end = strchr(p_start + 1, '"'); + if (p_end) { + int len = p_end - p_start - 1; + if (len >= dev_len) len = dev_len - 1; + strncpy(device, p_start + 1, len); + device[len] = '\0'; + } + } + } + + // Extract gateway/nexthop from route list + gateway[0] = '\0'; + char *p_route = strstr(buf, "\"route\":"); + if (p_route) { + char *p_nexthop = strstr(p_route, "\"nexthop\":"); + if (p_nexthop) { + char *p_start = strchr(p_nexthop + 10, '"'); + if (p_start) { + char *p_end = strchr(p_start + 1, '"'); + if (p_end) { + int len = p_end - p_start - 1; + if (len >= gw_len) len = gw_len - 1; + strncpy(gateway, p_start + 1, len); + gateway[len] = '\0'; + } + } + } + } + + return true; +} + +// Ping check +static bool run_ping_check(const char *device, const char *target, int timeout, int *rtt_ms) { + if (device[0] == '\0' || target[0] == '\0') return false; + + char cmd[256]; + snprintf(cmd, sizeof(cmd), "ping -I %s -c 1 -W %d %s 2>/dev/null", device, timeout, target); + FILE *fp = popen(cmd, "r"); + if (!fp) return false; + + char line[128]; + bool ok = false; + *rtt_ms = -1; + while (fgets(line, sizeof(line), fp)) { + char *p = strstr(line, "time="); + if (p) { + ok = true; + double rtt = atof(p + 5); + *rtt_ms = (int)rtt; + } + } + int status = pclose(fp); + return ok && (WIFEXITED(status) && WEXITSTATUS(status) == 0); +} + +// DNS check +static bool run_dns_check(const char *device, const char *dns_server, const char *domain, int timeout, int *rtt_ms) { + if (device[0] == '\0' || dns_server[0] == '\0' || domain[0] == '\0') return false; + + struct timeval start, end; + gettimeofday(&start, NULL); + + int sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd < 0) return false; + + // Set non-blocking + int flags = fcntl(sockfd, F_GETFL, 0); + fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); + + // Bind to device + if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, device, strlen(device)) < 0) { + close(sockfd); + return false; + } + + struct sockaddr_in servaddr; + memset(&servaddr, 0, sizeof(servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_port = htons(53); + if (inet_pton(AF_INET, dns_server, &servaddr.sin_addr) <= 0) { + close(sockfd); + return false; + } + + // Format DNS packet + unsigned char packet[512]; + memset(packet, 0, sizeof(packet)); + + struct dns_header *dns = (struct dns_header *)packet; + dns->id = (unsigned short)htons(getpid()); + dns->flags = htons(0x0100); + dns->qdcount = htons(1); + + unsigned char *qname = packet + sizeof(struct dns_header); + const char *src = domain; + unsigned char *dst = qname; + while (*src) { + const char *next = strchr(src, '.'); + int len = next ? (next - src) : strlen(src); + *dst++ = len; + memcpy(dst, src, len); + dst += len; + src = next ? (next + 1) : (src + len); + } + *dst++ = 0; + + unsigned short *qtype = (unsigned short *)dst; + *qtype = htons(1); // A Record + dst += 2; + unsigned short *qclass = (unsigned short *)dst; + *qclass = htons(1); // IN + dst += 2; + + int packet_len = dst - packet; + + if (sendto(sockfd, packet, packet_len, 0, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) { + if (errno != EAGAIN && errno != EWOULDBLOCK) { + close(sockfd); + return false; + } + } + + fd_set readfds; + FD_ZERO(&readfds); + FD_SET(sockfd, &readfds); + struct timeval tv; + tv.tv_sec = timeout; + tv.tv_usec = 0; + + int sel = select(sockfd + 1, &readfds, NULL, NULL, &tv); + if (sel <= 0) { + close(sockfd); + return false; + } + + unsigned char response[512]; + struct sockaddr_in from; + socklen_t from_len = sizeof(from); + int resp_len = recvfrom(sockfd, response, sizeof(response), 0, (struct sockaddr *)&from, &from_len); + close(sockfd); + + if (resp_len < 12) return false; + + struct dns_header *resp_dns = (struct dns_header *)response; + if (ntohs(resp_dns->id) != getpid()) return false; + + gettimeofday(&end, NULL); + *rtt_ms = (int)((end.tv_sec - start.tv_sec) * 1000 + (end.tv_usec - start.tv_usec) / 1000); + return true; +} + +// TCP check +static bool run_tcp_check(const char *device, const char *tcp_target, int port, int timeout, int *rtt_ms) { + if (device[0] == '\0' || tcp_target[0] == '\0' || port <= 0) return false; + + struct timeval start, end; + gettimeofday(&start, NULL); + + int sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd < 0) return false; + + // Set non-blocking + int flags = fcntl(sockfd, F_GETFL, 0); + fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); + + // Bind to device + if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, device, strlen(device)) < 0) { + close(sockfd); + return false; + } + + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + if (inet_pton(AF_INET, tcp_target, &addr.sin_addr) <= 0) { + close(sockfd); + return false; + } + + int rc = connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)); + if (rc < 0) { + if (errno != EINPROGRESS) { + close(sockfd); + return false; + } + } else { + gettimeofday(&end, NULL); + *rtt_ms = (int)((end.tv_sec - start.tv_sec) * 1000 + (end.tv_usec - start.tv_usec) / 1000); + close(sockfd); + return true; + } + + fd_set writefds; + FD_ZERO(&writefds); + FD_SET(sockfd, &writefds); + struct timeval tv; + tv.tv_sec = timeout; + tv.tv_usec = 0; + + int sel = select(sockfd + 1, NULL, &writefds, NULL, &tv); + if (sel <= 0) { + close(sockfd); + return false; + } + + int optval; + socklen_t optlen = sizeof(optval); + if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0 || optval != 0) { + close(sockfd); + return false; + } + + gettimeofday(&end, NULL); + *rtt_ms = (int)((end.tv_sec - start.tv_sec) * 1000 + (end.tv_usec - start.tv_usec) / 1000); + close(sockfd); + return true; +} + +// UCI parser helper +static bool load_config(void) { + struct uci_context *ctx = uci_alloc_context(); + if (!ctx) return false; + + struct uci_package *pkg = NULL; + if (uci_load(ctx, "linkback", &pkg) != UCI_OK) { + uci_free_context(ctx); + return false; + } + + // Parse global config + global_cfg.enabled = false; + + struct uci_section *global_sec = uci_lookup_section(ctx, pkg, "global"); + if (!global_sec) { + struct uci_element *ge; + uci_foreach_element(&pkg->sections, ge) { + struct uci_section *s = uci_to_section(ge); + if (strcmp(s->type, "global") == 0) { + global_sec = s; + break; + } + } + } + + if (global_sec) { + const char *enabled = uci_lookup_option_string(ctx, global_sec, "enabled"); + global_cfg.enabled = (enabled && strcmp(enabled, "1") == 0); + } + + // Parse links + link_count = 0; + struct uci_element *e; + uci_foreach_element(&pkg->sections, e) { + struct uci_section *s = uci_to_section(e); + if (strcmp(s->type, "link") != 0) continue; + + const char *enabled = uci_lookup_option_string(ctx, s, "enabled"); + if (enabled && strcmp(enabled, "0") == 0) continue; + + link_t *link = &links[link_count]; + memset(link, 0, sizeof(link_t)); + + const char *name = uci_lookup_option_string(ctx, s, "name"); + if (!name) continue; + strncpy(link->name, name, MAX_NAME_LEN - 1); + + link->enabled = true; + + const char *priority = uci_lookup_option_string(ctx, s, "priority"); + int prio_val = priority ? atoi(priority) : 1; + link->priority = (prio_val > 0) ? prio_val : 1; + + link->metric = link->priority * 10; + link->current_metric = link->metric; + + // Parse ping targets (split by comma or space) + const char *pings = uci_lookup_option_string(ctx, s, "ping_targets"); + if (pings) { + char tmp[256]; + strncpy(tmp, pings, sizeof(tmp) - 1); + tmp[sizeof(tmp) - 1] = '\0'; + char *token = strtok(tmp, ", \t"); + while (token && link->ping_target_count < MAX_TARGETS) { + // Trim leading whitespace + while (*token == ' ' || *token == '\t' || *token == '\r' || *token == '\n') { + token++; + } + // Trim trailing whitespace + char *end = token + strlen(token) - 1; + while (end > token && (*end == ' ' || *end == '\t' || *end == '\r' || *end == '\n')) { + *end = '\0'; + end--; + } + if (*token != '\0') { + strncpy(link->ping_targets[link->ping_target_count], token, MAX_IP_LEN - 1); + link->ping_target_count++; + } + token = strtok(NULL, ","); + } + } + + // Parse DNS targets + const char *dns_srv = uci_lookup_option_string(ctx, s, "dns_server"); + if (dns_srv) strncpy(link->dns_server, dns_srv, MAX_IP_LEN - 1); + + const char *dns_dom = uci_lookup_option_string(ctx, s, "dns_domain"); + if (dns_dom) strncpy(link->dns_domain, dns_dom, MAX_DOMAIN_LEN - 1); + + // Parse TCP targets + const char *tcp_tgt = uci_lookup_option_string(ctx, s, "tcp_target"); + if (tcp_tgt) strncpy(link->tcp_target, tcp_tgt, MAX_IP_LEN - 1); + + const char *tcp_p = uci_lookup_option_string(ctx, s, "tcp_port"); + if (tcp_p) link->tcp_port = atoi(tcp_p); + + const char *interval = uci_lookup_option_string(ctx, s, "check_interval"); + link->check_interval = interval ? atoi(interval) : 5; + + const char *timeout = uci_lookup_option_string(ctx, s, "check_timeout"); + link->check_timeout = timeout ? atoi(timeout) : 3; + + const char *recovery = uci_lookup_option_string(ctx, s, "recovery_delay"); + link->recovery_delay = recovery ? atoi(recovery) : 3; + + const char *failover = uci_lookup_option_string(ctx, s, "failover_delay"); + link->failover_delay = failover ? atoi(failover) : 2; + + // Default runtime states + link->healthy = true; + link->is_up = false; + link->last_checked = 0; // Force immediate check on startup + + link_count++; + if (link_count >= MAX_LINKS) break; + } + + uci_unload(ctx, pkg); + uci_free_context(ctx); + + if (!validate_loaded_config()) { + return false; + } + + return true; +} + +// Startup-time defensive validation. LuCI-side checks can be bypassed by +// direct UCI edits, so daemon must refuse unsafe/incomplete configs. +static bool validate_loaded_config(void) { + if (!global_cfg.enabled) { + return true; + } + + if (link_count < 2) { + syslog(LOG_ERR, "Invalid config: at least 2 enabled monitored links are required, got %d.", link_count); + return false; + } + + for (int i = 0; i < link_count; i++) { + link_t *a = &links[i]; + + if (a->name[0] == '\0') { + syslog(LOG_ERR, "Invalid config: link[%d] has empty interface name.", i); + return false; + } + + if (a->priority <= 0) { + syslog(LOG_ERR, "Invalid config: link %s has invalid priority %d (must be > 0).", a->name, a->priority); + return false; + } + + if (a->metric <= 0) { + syslog(LOG_ERR, "Invalid config: link %s has invalid metric %d (must be > 0).", a->name, a->metric); + return false; + } + + // No duplicate priorities + for (int j = i + 1; j < link_count; j++) { + link_t *b = &links[j]; + if (a->priority == b->priority) { + syslog(LOG_ERR, "Invalid config: duplicate priority %d on links %s and %s.", a->priority, a->name, b->name); + return false; + } + } + + bool has_ping = (a->ping_target_count > 0); + bool has_dns = (a->dns_server[0] != '\0' && a->dns_domain[0] != '\0'); + bool has_tcp = (a->tcp_target[0] != '\0' && a->tcp_port > 0); + + int check_count = 0; + if (has_ping) check_count++; + if (has_dns) check_count++; + if (has_tcp) check_count++; + + if (check_count == 0) { + syslog(LOG_ERR, "Invalid config: link %s has no complete health-check probe configured.", a->name); + return false; + } + if (check_count > 1) { + syslog(LOG_ERR, "Invalid config: link %s has multiple health-check probes configured. Only one check type is allowed.", a->name); + return false; + } + + if ((a->dns_server[0] != '\0') != (a->dns_domain[0] != '\0')) { + syslog(LOG_ERR, "Invalid config: link %s DNS probe is incomplete (dns_server + dns_domain required).", a->name); + return false; + } + + if ((a->tcp_target[0] != '\0') != (a->tcp_port > 0)) { + syslog(LOG_ERR, "Invalid config: link %s TCP probe is incomplete (tcp_target + tcp_port required).", a->name); + return false; + } + + if (a->check_interval <= 0 || a->check_timeout <= 0 || + a->recovery_delay <= 0 || a->failover_delay <= 0) { + syslog(LOG_ERR, "Invalid config: link %s timing values must be > 0.", a->name); + return false; + } + } + + return true; +} + +// Retrieve the real default route metric for a device from /proc/net/route +static int get_system_route_metric(const char *device, int expected_metric) { + if (device[0] == '\0') return -1; + FILE *fp = fopen("/proc/net/route", "r"); + if (!fp) return -1; + + char line[256]; + char iface[32]; + unsigned long dest; + int metric = -1; + int first_found_metric = -1; + bool found_expected = false; + + // Skip header line + if (fgets(line, sizeof(line), fp)) { + while (fgets(line, sizeof(line), fp)) { + // Destination is 2nd column, Metric is 7th column, dest is in hex. + // Use %*s for Gateway and Flags to safely skip non-numeric characters. + if (sscanf(line, "%31s %lx %*s %*s %*d %*d %d", iface, &dest, &metric) == 3) { + if (strcmp(iface, device) == 0 && dest == 0) { + if (first_found_metric == -1) { + first_found_metric = metric; + } + if (metric == expected_metric) { + found_expected = true; + break; + } + } + } + } + } + fclose(fp); + + if (found_expected) { + return expected_metric; + } + return first_found_metric; +} + +// Compare priority for sorting (lowest priority number is highest precedence) +static int compare_links(const void *a, const void *b) { + link_t *la = (link_t *)a; + link_t *lb = (link_t *)b; + return la->priority - lb->priority; +} + +// Dynamic route update using ip route command +static void update_route_metric(link_t *link, int new_metric, int old_metric_to_delete) { + if (link->device[0] == '\0') return; + + char cmd[512]; + + // 1. Delete the specified old metric to prevent duplicate routes + if (old_metric_to_delete != -1 && old_metric_to_delete != new_metric) { + if (link->gateway[0] != '\0') { + snprintf(cmd, sizeof(cmd), "ip route del default via %s dev %s metric %d 2>/dev/null", + link->gateway, link->device, old_metric_to_delete); + } else { + snprintf(cmd, sizeof(cmd), "ip route del default dev %s metric %d 2>/dev/null", + link->device, old_metric_to_delete); + } + system(cmd); + } + + // 2. Delete the current_metric if it is different from new_metric and old_metric_to_delete + if (link->current_metric != new_metric && link->current_metric != old_metric_to_delete) { + if (link->gateway[0] != '\0') { + snprintf(cmd, sizeof(cmd), "ip route del default via %s dev %s metric %d 2>/dev/null", + link->gateway, link->device, link->current_metric); + } else { + snprintf(cmd, sizeof(cmd), "ip route del default dev %s metric %d 2>/dev/null", + link->device, link->current_metric); + } + system(cmd); + } + + // 3. Add/replace with new_metric + if (link->gateway[0] != '\0') { + snprintf(cmd, sizeof(cmd), "ip route replace default via %s dev %s metric %d 2>/dev/null", + link->gateway, link->device, new_metric); + } else { + snprintf(cmd, sizeof(cmd), "ip route replace default dev %s metric %d 2>/dev/null", + link->device, new_metric); + } + + syslog(LOG_INFO, "Applying route metric update on link %s (%s, priority %d): %d -> %d", + link->name, link->device, link->priority, link->current_metric, new_metric); + + int rc = system(cmd); + if (rc == 0) { + link->current_metric = new_metric; + } else { + syslog(LOG_ERR, "Failed to apply route update for %s (priority %d) using cmd: %s", link->name, link->priority, cmd); + } +} + +// Restore default metrics on exit +static void restore_all_metrics(void) { + syslog(LOG_INFO, "Restoring all interface metrics on exit..."); + for (int i = 0; i < link_count; i++) { + link_t *link = &links[i]; + if (link->enabled && link->is_up && link->device[0] != '\0') { + char cmd[512]; + // Delete floated metric if it was in fault state + if (link->current_metric != link->metric) { + if (link->gateway[0] != '\0') { + snprintf(cmd, sizeof(cmd), "ip route del default via %s dev %s metric %d 2>/dev/null", + link->gateway, link->device, link->current_metric); + } else { + snprintf(cmd, sizeof(cmd), "ip route del default dev %s metric %d 2>/dev/null", + link->device, link->current_metric); + } + system(cmd); + } + if (link->gateway[0] != '\0') { + snprintf(cmd, sizeof(cmd), "ip route replace default via %s dev %s metric %d 2>/dev/null", + link->gateway, link->device, link->metric); + } else { + snprintf(cmd, sizeof(cmd), "ip route replace default dev %s metric %d 2>/dev/null", + link->device, link->metric); + } + int rc = system(cmd); + if (rc == 0) { + syslog(LOG_INFO, "Successfully restored default metric %d for interface %s (priority %d)", link->metric, link->name, link->priority); + } + } + } +} + +// Write status file to /var/run/linkback.json +static void write_status_json(void) { + FILE *fp = fopen(STATUS_FILE, "w"); + if (!fp) return; + + fprintf(fp, "{\n"); + fprintf(fp, " \"enabled\": %s,\n", global_cfg.enabled ? "true" : "false"); + fprintf(fp, " \"check_interval\": 5,\n"); + + // Find current active gateway link (first healthy link ordered by priority) + char active_link[MAX_NAME_LEN] = "none"; + for (int i = 0; i < link_count; i++) { + if (links[i].is_up && links[i].healthy) { + strncpy(active_link, links[i].name, MAX_NAME_LEN - 1); + break; + } + } + fprintf(fp, " \"active_link\": \"%s\",\n", active_link); + fprintf(fp, " \"links\": [\n"); + + for (int i = 0; i < link_count; i++) { + link_t *link = &links[i]; + fprintf(fp, " {\n"); + fprintf(fp, " \"name\": \"%s\",\n", link->name); + fprintf(fp, " \"priority\": %d,\n", link->priority); + fprintf(fp, " \"metric\": %d,\n", link->metric); + fprintf(fp, " \"current_metric\": %d,\n", link->current_metric); + fprintf(fp, " \"healthy\": %s,\n", link->healthy ? "true" : "false"); + fprintf(fp, " \"is_up\": %s,\n", link->is_up ? "true" : "false"); + fprintf(fp, " \"device\": \"%s\",\n", link->device); + fprintf(fp, " \"gateway\": \"%s\",\n", link->gateway); + fprintf(fp, " \"score\": %d,\n", link->current_score); + fprintf(fp, " \"threshold\": %d,\n", link->weight_threshold); + fprintf(fp, " \"check_interval\": %d,\n", link->check_interval); + fprintf(fp, " \"check_timeout\": %d,\n", link->check_timeout); + fprintf(fp, " \"recovery_delay\": %d,\n", link->recovery_delay); + fprintf(fp, " \"failover_delay\": %d,\n", link->failover_delay); + const char *type = "none"; + if (link->ping_target_count > 0) type = "ping"; + else if (link->dns_server[0] != '\0') type = "dns"; + else if (link->tcp_target[0] != '\0') type = "tcp"; + + fprintf(fp, " \"check_type\": \"%s\",\n", type); + fprintf(fp, " \"ping\": {\"ok\": %s, \"rtt\": %d},\n", link->ping_ok ? "true" : "false", link->ping_rtt_ms); + fprintf(fp, " \"dns\": {\"ok\": %s, \"rtt\": %d},\n", link->dns_ok ? "true" : "false", link->dns_rtt_ms); + fprintf(fp, " \"tcp\": {\"ok\": %s, \"rtt\": %d}\n", link->tcp_ok ? "true" : "false", link->tcp_rtt_ms); + fprintf(fp, " }%s\n", (i == link_count - 1) ? "" : ","); + } + fprintf(fp, " ]\n"); + fprintf(fp, "}\n"); + fclose(fp); +} + +int main(int argc, char **argv) { + // Setup syslog + openlog("linkbackd", LOG_PID | LOG_NDELAY, LOG_DAEMON); + syslog(LOG_INFO, "Starting LinkBack daemon..."); + + // Register signal handlers for clean exits and metric restoration + signal(SIGTERM, handle_signal); + signal(SIGINT, handle_signal); + + // Load configuration + if (!load_config()) { + syslog(LOG_ERR, "Failed to load linkback config. Exiting."); + closelog(); + return 1; + } + + if (!global_cfg.enabled) { + syslog(LOG_WARNING, "LinkBack is disabled globally in configuration. Exiting."); + closelog(); + return 0; + } + + // Sort links by priority (lowest priority number first) + qsort(links, link_count, sizeof(link_t), compare_links); + + syslog(LOG_INFO, "Loaded %d monitored interfaces. Starting health check scheduler.", link_count); + + // Core check loop + while (keep_running) { + time_t now = time(NULL); + bool any_checked = false; + + for (int i = 0; i < link_count; i++) { + link_t *link = &links[i]; + + // Check if this interface is due for checking + if (now - link->last_checked < link->check_interval) { + continue; + } + link->last_checked = now; + any_checked = true; + + // 1. Fetch real-time netifd status + char dev[MAX_NAME_LEN] = {0}; + char gw[MAX_IP_LEN] = {0}; + bool is_up = false; + + get_interface_ubus_status(link->name, dev, sizeof(dev), gw, sizeof(gw), &is_up); + link->is_up = is_up; + strncpy(link->device, dev, MAX_NAME_LEN - 1); + strncpy(link->gateway, gw, MAX_IP_LEN - 1); + + if (!is_up || dev[0] == '\0') { + // Interface is down in netifd, mark unhealthy immediately + link->healthy = false; + link->current_score = 0; + link->ping_ok = false; + link->dns_ok = false; + link->tcp_ok = false; + link->consecutive_success = 0; + link->consecutive_failure = 0; + + // If it still has low metric, float it + if (link->current_metric == link->metric) { + update_route_metric(link, 1000 + link->metric, -1); + } + continue; + } + + // 2. Perform health checks + bool check_success = false; + + if (link->ping_target_count > 0) { + link->ping_ok = false; + link->ping_rtt_ms = -1; + for (int p = 0; p < link->ping_target_count; p++) { + int rtt = -1; + if (run_ping_check(link->device, link->ping_targets[p], link->check_timeout, &rtt)) { + link->ping_ok = true; + link->ping_rtt_ms = rtt; + break; + } + } + check_success = link->ping_ok; + } + else if (link->dns_server[0] != '\0' && link->dns_domain[0] != '\0') { + link->dns_ok = false; + link->dns_rtt_ms = -1; + int rtt = -1; + if (run_dns_check(link->device, link->dns_server, link->dns_domain, link->check_timeout, &rtt)) { + link->dns_ok = true; + link->dns_rtt_ms = rtt; + } + check_success = link->dns_ok; + } + else if (link->tcp_target[0] != '\0' && link->tcp_port > 0) { + link->tcp_ok = false; + link->tcp_rtt_ms = -1; + int rtt = -1; + if (run_tcp_check(link->device, link->tcp_target, link->tcp_port, link->check_timeout, &rtt)) { + link->tcp_ok = true; + link->tcp_rtt_ms = rtt; + } + check_success = link->tcp_ok; + } + + link->current_score = check_success ? 1 : 0; + + // 3. Evaluate health state changes (filtering and delay) + + if (check_success) { + link->consecutive_success++; + link->consecutive_failure = 0; + + if (!link->healthy && link->consecutive_success >= link->recovery_delay) { + // Recovered! Failback! + link->healthy = true; + syslog(LOG_NOTICE, "Link %s (%s, priority %d) recovered to healthy after %d successes.", + link->name, link->device, link->priority, link->consecutive_success); + + // Restore original metric + update_route_metric(link, link->metric, -1); + } + } else { + link->consecutive_failure++; + link->consecutive_success = 0; + + if (link->healthy && link->consecutive_failure >= link->failover_delay) { + // Failed! Failover! + link->healthy = false; + syslog(LOG_WARNING, "Link %s (%s, priority %d) went down after %d failures.", + link->name, link->device, link->priority, link->consecutive_failure); + + // Push metric out of choice range + update_route_metric(link, 1000 + link->metric, -1); + } + } + + // 4. Active routing metric self-healing to prevent external/netifd interference + if (link->device[0] != '\0') { + int expected_metric = (link->is_up && link->healthy) ? link->metric : (1000 + link->metric); + int real_metric = get_system_route_metric(link->device, expected_metric); + if (real_metric != -1 && real_metric != expected_metric) { + syslog(LOG_WARNING, "Route metric mismatch detected on %s (%s, priority %d): expected %d, got %d. Correcting...", + link->name, link->device, link->priority, expected_metric, real_metric); + update_route_metric(link, expected_metric, real_metric); + } + } + } + + if (any_checked) { + // Write states to shared JSON file + write_status_json(); + } + + // High-responsiveness scheduler ticks every second + sleep(1); + } + + // Terminating: clean up routes before exit + restore_all_metrics(); + unlink(STATUS_FILE); + syslog(LOG_INFO, "LinkBack daemon terminated successfully."); + closelog(); + return 0; +} diff --git a/linkback/src/linkbackd.h b/linkback/src/linkbackd.h new file mode 100644 index 000000000..490d03043 --- /dev/null +++ b/linkback/src/linkbackd.h @@ -0,0 +1,67 @@ +#ifndef LINKBACKD_H +#define LINKBACKD_H + +#include +#include + +#define MAX_LINKS 16 +#define MAX_NAME_LEN 32 +#define MAX_TARGETS 8 +#define MAX_IP_LEN 64 +#define MAX_DOMAIN_LEN 128 +#define STATUS_FILE "/var/run/linkback.json" + +typedef struct { + char name[MAX_NAME_LEN]; + bool enabled; + int priority; + int metric; + + // Ping config + char ping_targets[MAX_TARGETS][MAX_IP_LEN]; + int ping_target_count; + int ping_weight; + + // DNS config + char dns_server[MAX_IP_LEN]; + char dns_domain[MAX_DOMAIN_LEN]; + int dns_weight; + + // TCP config + char tcp_target[MAX_IP_LEN]; + int tcp_port; + int tcp_weight; + + // Thresholds + int weight_threshold; + int check_interval; + int check_timeout; + int recovery_delay; + int failover_delay; + + // Runtime state + char device[MAX_NAME_LEN]; // physical interface name e.g., pppoe-wan, eth1 + char gateway[MAX_IP_LEN]; // gateway IP address + bool is_up; // whether interface is reported up by netifd + bool healthy; // daemon link health state + int consecutive_success; + int consecutive_failure; + time_t last_checked; // Last health check timestamp + + // Detailed health checks status + bool ping_ok; + int ping_rtt_ms; + bool dns_ok; + int dns_rtt_ms; + bool tcp_ok; + int tcp_rtt_ms; + + int current_score; + int current_metric; // actual system metric applied +} link_t; + +typedef struct { + bool enabled; +} global_config_t; + +#endif // LINKBACKD_H diff --git a/luci-app-ap-switch/Makefile b/luci-app-ap-switch/Makefile new file mode 100644 index 000000000..d2be43771 --- /dev/null +++ b/luci-app-ap-switch/Makefile @@ -0,0 +1,15 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=luci-app-ap-switch +PKG_VERSION:=1.0.0 +PKG_RELEASE:=1 +PKG_LICENSE:=Apache-2.0 +PKG_MAINTAINER:=Dante + +LUCI_TITLE:=LuCI support for one-click AP mode switching +LUCI_DEPENDS:=+luci-base +ucode +ucode-mod-fs +ucode-mod-uci +ucode-mod-ubus +LUCI_PKGARCH:=all + +include $(TOPDIR)/feeds/luci/luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-app-ap-switch/htdocs/luci-static/resources/view/ap-switch/ap-switch.js b/luci-app-ap-switch/htdocs/luci-static/resources/view/ap-switch/ap-switch.js new file mode 100644 index 000000000..788fab6d8 --- /dev/null +++ b/luci-app-ap-switch/htdocs/luci-static/resources/view/ap-switch/ap-switch.js @@ -0,0 +1,201 @@ +'use strict'; +'require view'; +'require rpc'; +'require ui'; +'require uci'; + +var callGetStatus = rpc.declare({ + object: 'luci.ap-switch', + method: 'get_status' +}); + +var callSetMode = rpc.declare({ + object: 'luci.ap-switch', + method: 'set_mode', + params: ['mode'] +}); + +var callProbeIP = rpc.declare({ + object: 'luci.ap-switch', + method: 'probe_ip' +}); + +return L.view.extend({ + i18n: 'ap-switch', + handleSaveApply: null, + handleSave: null, + handleReset: null, + + load: function() { + return Promise.all([ + callGetStatus(), + uci.load('ap-switch') + ]); + }, + + render: function(data) { + var self = this; + var status = data[0]; + var mode = status.mode || 'router'; + var lan_ip = status.lan_ip || 'N/A'; + var lan_proto = status.lan_proto || 'static'; + var lan_mac = status.lan_mac || 'N/A'; + + var changeModeRows = [ + E('tr', { 'class': 'tr' }, [ + E('td', { 'class': 'td left', 'width': '33%' }, _('Switch to %s').format(mode === 'ap' ? _('Router Mode') : _('AP Mode'))), + E('td', { 'class': 'td left' }, [ + E('button', { + 'class': 'cbi-button cbi-button-apply', + 'click': ui.createHandlerFn(self, function() { + return self.handleSwitch(mode === 'ap' ? 'router' : 'ap', status); + }) + }, [ (mode === 'ap' ? _('Switch to Router Mode') : _('Switch to AP Mode')) ]) + ]) + ]) + ]; + + var body = E('div', { 'class': 'cbi-map' }, [ + E('h2', {}, _('AP Switch Title') + ' - ' + _('Switch Mode')), + E('div', { 'class': 'cbi-map-descr' }, _('Switch your system runtime configuration smoothly between standard Router and Access Point (AP) modes. Network interfaces and bridge rules will be adjusted automatically.')), + E('fieldset', { 'class': 'cbi-section' }, [ + E('legend', {}, _('Current Status')), + E('div', { 'class': 'cbi-section-node' }, [ + E('table', { 'class': 'table cbi-section-table' }, [ + E('tr', { 'class': 'tr' }, [ + E('td', { 'class': 'td left', 'width': '33%' }, _('Operation Mode')), + E('td', { 'class': 'td left' }, E('strong', {}, (mode === 'ap' ? _('Access Point (AP)') : _('Router')))) + ]), + E('tr', { 'class': 'tr' }, [ + E('td', { 'class': 'td left' }, _('Login URL')), + E('td', { 'class': 'td left' }, lan_ip ? E('a', { + 'href': 'http://' + lan_ip, + 'target': '_blank', + 'style': 'text-decoration: underline; font-weight: bold; color: blue;' + }, 'http://' + lan_ip) : _('N/A')) + ]), + E('tr', { 'class': 'tr' }, [ + E('td', { 'class': 'td left' }, _('LAN IP Address')), + E('td', { 'class': 'td left' }, [ + E('strong', { 'style': 'color: #2196F3;' }, lan_ip || _('Pending...')), + E('span', { 'style': 'margin-left: 10px; color: #666;' }, '(' + lan_proto + ')') + ]) + ]), + E('tr', { 'class': 'tr' }, [ + E('td', { 'class': 'td left' }, _('LAN MAC Address')), + E('td', { 'class': 'td left', 'id': 'lan-mac' }, lan_mac) + ]) + ]) + ]) + ]), + E('fieldset', { 'class': 'cbi-section' }, [ + E('legend', {}, _('Change Mode')), + E('div', { 'class': 'cbi-section-node' }, [ + E('table', { 'class': 'table cbi-section-table' }, changeModeRows) + ]) + ]) + ]); + + return body; + }, + + handleSwitch: function(target_mode, status) { + var self = this; + + var executeSwitch = function() { + ui.showModal(null, [ + E('p', { 'class': 'spinning' }, _('Applying changes and restarting network...')), + E('p', {}, _('The page will redirect or you may need to manually reconnect to the new IP address in a few moments.')) + ]); + + return callSetMode(target_mode).then(function(res) { + if (res && res.result === 'success') { + setTimeout(function() { + ui.hideModal(); + ui.addNotification(null, E('p', _('Mode switched successfully. Please check your network connection.')), 'info'); + }, 5000); + } else { + ui.hideModal(); + ui.addNotification(null, E('p', _('Failed to switch mode: %s').format(res.error || 'Unknown error')), 'error'); + } + }).catch(function(err) { + ui.hideModal(); + ui.addNotification(null, E('p', _('Error calling RPC: %s').format(err.message)), 'error'); + }); + }; + + var showConfirmModal = function(title, messages, onConfirm) { + var content = []; + messages.forEach(function(msg) { + content.push(E('p', { 'style': 'margin-bottom: 10px; line-height: 1.5;' }, msg)); + }); + content.push(E('div', { 'class': 'right', 'style': 'margin-top: 20px;' }, [ + E('button', { + 'class': 'cbi-button cbi-button-reset', + 'click': ui.hideModal + }, _('Cancel')), + E('button', { + 'class': 'cbi-button cbi-button-action cbi-button-apply', + 'style': 'margin-left: 10px;', + 'click': function() { + ui.hideModal(); + onConfirm(); + } + }, _('Confirm')) + ])); + + ui.showModal(title, content); + }; + + if (target_mode === 'ap') { + ui.showModal(null, [ + E('p', { 'class': 'spinning' }, _('Auto-probing for future AP IP via DHCP on br-lan...')), + E('p', {}, _('This ensures you can find your way back to the management panel after the switch.')) + ]); + + return callProbeIP().then(function(res) { + ui.hideModal(); + + var title = _('Confirm AP Mode Switch'); + var messages = []; + + if (res && res.ip) { + messages.push(E('span', {}, [ + _('Successfully pre-fetched future management IP: '), + E('a', { + 'href': 'http://' + res.ip, + 'target': '_blank', + 'style': 'color: #2196F3; font-weight: bold; text-decoration: underline; word-break: break-all;' + }, 'http://' + res.ip) + ])); + messages.push(_('You can use this URL to access this dashboard after the switch.')); + messages.push(_('Are you sure you want to switch to AP mode and restart network?')); + } else { + messages.push(_('WARNING: Failed to pre-fetch IP address via DHCP probe!')); + messages.push(_('This may be because your LAN port is not connected to the main router.')); + messages.push(_('If you proceed, you must find the new IP from your main router client list using MAC: %s').format(status.lan_mac || 'N/A')); + messages.push(_('Do you still want to force the switch anyway?')); + } + + showConfirmModal(title, messages, executeSwitch); + }).catch(function(err) { + ui.hideModal(); + + var title = _('Confirm AP Mode Switch'); + var messages = [ + _('WARNING: DHCP probe RPC error: %s').format(err.message), + _('If you proceed, you must find the new IP from your main router client list using MAC: %s').format(status.lan_mac || 'N/A'), + _('Do you still want to force the switch anyway?') + ]; + + showConfirmModal(title, messages, executeSwitch); + }); + } else { + var title = _('Confirm Router Mode Switch'); + var messages = [ + _('Switching to Router mode will restore the WAN port and local DHCP server. Your device will use the previous static IP address. Are you sure?') + ]; + showConfirmModal(title, messages, executeSwitch); + } + } +}); diff --git a/luci-app-ap-switch/po/templates/ap-switch.pot b/luci-app-ap-switch/po/templates/ap-switch.pot new file mode 100644 index 000000000..343dc49de --- /dev/null +++ b/luci-app-ap-switch/po/templates/ap-switch.pot @@ -0,0 +1,116 @@ +msgid "" +msgstr "Content-Type: text/plain; charset=UTF-8" + +msgid "AP Switch" +msgstr "" + +msgid "Switch between Router and Access Point (AP) mode." +msgstr "" + +msgid "Current Status" +msgstr "" + +msgid "Operation Mode" +msgstr "" + +msgid "Access Point (AP)" +msgstr "" + +msgid "Router" +msgstr "" + +msgid "LAN IP Address" +msgstr "" + +msgid "Change Mode" +msgstr "" + +msgid "Switch to %s" +msgstr "" + +msgid "Router Mode" +msgstr "" + +msgid "AP Mode" +msgstr "" + +msgid "Switch to Router Mode" +msgstr "" + +msgid "Switch to AP Mode" +msgstr "" + +msgid "LAN MAC Address" +msgstr "" + +msgid "Switching to AP mode will bridge the WAN port into \"br-lan\". The \"br-lan\" interface will become a DHCP client to your main router." +msgstr "" + +msgid "Pre-fetch AP IP" +msgstr "" + +msgid "Probing for DHCP IP on br-lan..." +msgstr "" + +msgid "Successfully fetched IP: %s" +msgstr "" + +msgid "Failed to fetch IP. Ensure a LAN port is connected to your main router." +msgstr "" + +msgid "Probe IP" +msgstr "" + +msgid "Not probed" +msgstr "" + +msgid "A valid IP was pre-fetched: %s. You can use this address to log in after the switch." +msgstr "" + +msgid "Are you sure you want to proceed?" +msgstr "" + +msgid "WARNING: No IP address was pre-fetched via DHCP probe!" +msgstr "" + +msgid "We strongly recommend connecting your LAN port to the main router and using \"Probe IP\" first." +msgstr "" + +msgid "If you proceed now, you must find the new IP from your main router using MAC: %s" +msgstr "" + +msgid "Do you want to proceed anyway or cancel to plug in the cable and try again?" +msgstr "" + +msgid "Pending..." +msgstr "" + +msgid "Login URL" +msgstr "" + +msgid "N/A" +msgstr "" + +msgid "None" +msgstr "" + +msgid "Are you sure?" +msgstr "" + +msgid "Switching to Router mode will restore the WAN port and local DHCP server. Your device will use the previous static IP address. Are you sure?" +msgstr "" + +msgid "Applying changes and restarting network..." +msgstr "" + +msgid "The page will redirect or you may need to manually reconnect to the new IP address in a few moments." +msgstr "" + +msgid "Mode switched successfully. Please check your network connection." +msgstr "" + +msgid "Failed to switch mode: %s" +msgstr "" + +msgid "Error calling RPC: %s" +msgstr "" diff --git a/luci-app-ap-switch/po/zh-cn b/luci-app-ap-switch/po/zh-cn new file mode 120000 index 000000000..8d69574dd --- /dev/null +++ b/luci-app-ap-switch/po/zh-cn @@ -0,0 +1 @@ +zh_Hans \ No newline at end of file diff --git a/luci-app-ap-switch/po/zh_Hans/ap-switch.po b/luci-app-ap-switch/po/zh_Hans/ap-switch.po new file mode 100644 index 000000000..8ed2ffa1a --- /dev/null +++ b/luci-app-ap-switch/po/zh_Hans/ap-switch.po @@ -0,0 +1,169 @@ +msgid "" +msgstr "Content-Type: text/plain; charset=UTF-8" + +msgid "AP Switch" +msgstr "AP模式切换" + +msgid "Switch between Router and Access Point (AP) mode." +msgstr "在路由器模式和访问点 (AP) 模式之间切换。" + +msgid "Current Status" +msgstr "当前状态" + +msgid "Operation Mode" +msgstr "运行模式" + +msgid "Access Point (AP)" +msgstr "访问点 (AP)" + +msgid "Router" +msgstr "路由器" + +msgid "LAN IP Address" +msgstr "LAN IP 地址" + +msgid "Change Mode" +msgstr "更改模式" + +msgid "Switch to %s" +msgstr "切换到 %s" + +msgid "Router Mode" +msgstr "路由器模式" + +msgid "AP Mode" +msgstr "AP 模式" + +msgid "Switch to Router Mode" +msgstr "切换到路由器模式" + +msgid "Switch to AP Mode" +msgstr "切换到 AP 模式" + +msgid "LAN MAC Address" +msgstr "LAN MAC 地址" + +msgid "Switching to AP mode will bridge the WAN port into \"br-lan\". The \"br-lan\" interface will become a DHCP client to your main router." +msgstr "切换到 AP 模式会将 WAN 口桥接到 \"br-lan\"。\"br-lan\" 接口将成为主路由器的 DHCP 客户端。" + +msgid "Pre-fetch AP IP" +msgstr "预获取 AP IP" + +msgid "Probing for DHCP IP on br-lan..." +msgstr "正在 br-lan 接口探测 DHCP IP..." + +msgid "Successfully fetched IP: %s" +msgstr "成功获取到 IP:%s" + +msgid "Failed to fetch IP. Ensure a LAN port is connected to your main router." +msgstr "获取 IP 失败。请确保 LAN 口已连接到主路由器。" + +msgid "Probe IP" +msgstr "开始探测" + +msgid "Not probed" +msgstr "未探测" + +msgid "A valid IP was pre-fetched: %s. You can use this address to log in after the switch." +msgstr "已预获取到有效的 IP:%s。切换后,您可以使用此地址登录。" + +msgid "Are you sure you want to proceed?" +msgstr "确定要继续吗?" + +msgid "WARNING: No IP address was pre-fetched via DHCP probe!" +msgstr "警告:未通过 DHCP 探测预获取到 IP 地址!" + +msgid "We strongly recommend connecting your LAN port to the main router and using \"Probe IP\" first." +msgstr "强烈建议先将 LAN 口连接到主路由器,并使用“预获取 AP IP”功能。" + +msgid "If you proceed now, you must find the new IP from your main router using MAC: %s" +msgstr "如果您现在继续,切换后必须通过 MAC 地址在主路由中查找新 IP:%s" + +msgid "Do you want to proceed anyway or cancel to plug in the cable and try again?" +msgstr "您是坚持继续,还是取消操作并在插上网线后重新尝试?" + +msgid "Pending..." +msgstr "等待中..." + +msgid "Login URL" +msgstr "登录地址" + +msgid "N/A" +msgstr "不适用" + +msgid "None" +msgstr "无" + +msgid "Are you sure?" +msgstr "确定要继续吗?" + +msgid "Switching to Router mode will restore the WAN port and local DHCP server. Your device will use the previous static IP address. Are you sure?" +msgstr "切换到路由器模式将恢复 WAN 口和本地 DHCP 服务。您的设备将使用之前的静态 IP 地址。确定要继续吗?" + +msgid "Applying changes and restarting network..." +msgstr "正在应用更改并重启网络..." + +msgid "The page will redirect or you may need to manually reconnect to the new IP address in a few moments." +msgstr "页面将会重定向,或者您可能需要在片刻后手动连接到新的 IP 地址。" + +msgid "Mode switched successfully. Please check your network connection." +msgstr "模式切换成功。请检查您的网络连接。" + +msgid "Failed to switch mode: %s" +msgstr "切换模式失败:%s" + +msgid "Error calling RPC: %s" +msgstr "调用 RPC 错误:%s" + +msgid "Switch Mode" +msgstr "模式切换" + +msgid "Switch your system runtime configuration smoothly between standard Router and Access Point (AP) modes. Network interfaces and bridge rules will be adjusted automatically." +msgstr "在标准路由器模式与 AP 桥接访问点模式之间平滑切换系统运行配置。切换后,网口物理桥接规则以及接口 DHCP 客户端行为将自动智能调整。" + +msgid "AP Switch Title" +msgstr "AP 模式切换" + +msgid "Auto-probing for future AP IP via DHCP on br-lan..." +msgstr "正在通过 br-lan 接口的 DHCP 自动探测未来的 AP 管理 IP 地址..." + +msgid "This ensures you can find your way back to the management panel after the switch." +msgstr "这可以确保您在切换模式后,能够顺利找到并登录新的设备管理后台。" + +msgid "Successfully pre-fetched future management IP: " +msgstr "成功预先获取到未来的管理 IP:" + +msgid "You can use this URL to access this dashboard after the switch." +msgstr "您可以使用此 URL 地址在切换后访问本控制台。" + +msgid "Are you sure you want to switch to AP mode and restart network?" +msgstr "您确定要切换到 AP 模式并重启网络吗?" + +msgid "WARNING: Failed to pre-fetch IP address via DHCP probe!" +msgstr "警告:通过 DHCP 探测预获取 IP 地址失败!" + +msgid "This may be because your LAN port is not connected to the main router." +msgstr "这可能是由于您设备的 LAN 物理端口尚未连接到上层主路由器。" + +msgid "If you proceed, you must find the new IP from your main router client list using MAC: %s" +msgstr "如果您继续,切换后必须通过 MAC 地址在上级主路由的客户端列表中查找新 IP:%s" + +msgid "Do you still want to force the switch anyway?" +msgstr "您是否仍要强制执行切换?" + +msgid "WARNING: DHCP probe RPC error: %s" +msgstr "警告:DHCP 探测 RPC 请求发生错误:%s" + +msgid "Confirm AP Mode Switch" +msgstr "确认切换至 AP 模式" + +msgid "Confirm Router Mode Switch" +msgstr "确认切换至路由器模式" + +msgid "Cancel" +msgstr "取消" + +msgid "Confirm" +msgstr "确认" + + diff --git a/luci-app-ap-switch/root/etc/config/ap-switch b/luci-app-ap-switch/root/etc/config/ap-switch new file mode 100644 index 000000000..2bcbb3569 --- /dev/null +++ b/luci-app-ap-switch/root/etc/config/ap-switch @@ -0,0 +1,15 @@ + +config global 'settings' + option mode 'router' + +config backup 'router_state' + option lan_proto 'static' + option lan_ipaddr '192.168.1.1' + option lan_netmask '255.255.255.0' + option lan_gateway '' + list lan_dns '' + option dhcp_ignore '0' + option wan_device '' + option wan_disabled '0' + option wan6_disabled '0' + diff --git a/luci-app-ap-switch/root/usr/share/luci-app-ap-switch/dhcp-probe.sh b/luci-app-ap-switch/root/usr/share/luci-app-ap-switch/dhcp-probe.sh new file mode 100755 index 000000000..c83f25d08 --- /dev/null +++ b/luci-app-ap-switch/root/usr/share/luci-app-ap-switch/dhcp-probe.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +[ "$1" = "bound" ] || exit 0 + +echo "$ip" > /tmp/ap_switch_probed_ip diff --git a/luci-app-ap-switch/root/usr/share/luci/menu.d/luci-app-ap-switch.json b/luci-app-ap-switch/root/usr/share/luci/menu.d/luci-app-ap-switch.json new file mode 100644 index 000000000..c6971dd9a --- /dev/null +++ b/luci-app-ap-switch/root/usr/share/luci/menu.d/luci-app-ap-switch.json @@ -0,0 +1,13 @@ +{ + "admin/services/ap_switch": { + "title": "AP Switch", + "action": { + "type": "view", + "path": "ap-switch/ap-switch" + }, + "order": 90, + "depends": { + "acl": [ "luci-app-ap-switch" ] + } + } +} diff --git a/luci-app-ap-switch/root/usr/share/rpcd/acl.d/luci-app-ap-switch.json b/luci-app-ap-switch/root/usr/share/rpcd/acl.d/luci-app-ap-switch.json new file mode 100644 index 000000000..1f0b286f5 --- /dev/null +++ b/luci-app-ap-switch/root/usr/share/rpcd/acl.d/luci-app-ap-switch.json @@ -0,0 +1,19 @@ +{ + "luci-app-ap-switch": { + "description": "ACL for AP Switch", + "read": { + "uci": [ "ap-switch", "network", "dhcp" ], + "ubus": { + "luci.ap-switch": [ "get_status", "probe_ip" ], + "network.interface": [ "dump" ], + "network.device": [ "status" ] + } + }, + "write": { + "uci": [ "ap-switch", "network", "dhcp" ], + "ubus": { + "luci.ap-switch": [ "set_mode" ] + } + } + } +} diff --git a/luci-app-ap-switch/root/usr/share/rpcd/ucode/luci.ap-switch b/luci-app-ap-switch/root/usr/share/rpcd/ucode/luci.ap-switch new file mode 100644 index 000000000..975e0993f --- /dev/null +++ b/luci-app-ap-switch/root/usr/share/rpcd/ucode/luci.ap-switch @@ -0,0 +1,226 @@ +'use strict'; + +import { cursor } from 'uci'; +import { connect } from 'ubus'; +import { readfile, unlink } from 'fs'; + +const UCI_CONFIG = 'ap-switch'; +const PROBE_FILE = '/tmp/ap_switch_probed_ip'; + +const methods = { + get_status: { + call: function() { + let uci_cursor = cursor(); + let mode = uci_cursor.get(UCI_CONFIG, 'settings', 'mode') || 'router'; + + let lan_proto = uci_cursor.get('network', 'lan', 'proto') || 'static'; + let lan_ip = ''; // We will get the real-time IP + + let ubus_conn = connect(); + let lan_mac = ''; + let wan_mac = ''; + let wan_ip = ''; + + if (ubus_conn) { + // 1. Get real-time LAN IP and MAC + let lan_status = ubus_conn.call('network.interface.lan', 'status'); + if (lan_status && type(lan_status['ipv4-address']) === 'array' && length(lan_status['ipv4-address']) > 0) { + lan_ip = lan_status['ipv4-address'][0].address; + } + + let lan_dev = ubus_conn.call('network.device', 'status', { name: 'br-lan' }); + lan_mac = lan_dev?.macaddr || ''; + + // 2. Get current WAN interface status and its physical device MAC + let wan_status = ubus_conn.call('network.interface.wan', 'status'); + let wan_device_name = wan_status?.device || ''; + if (wan_device_name) { + let wan_dev = ubus_conn.call('network.device', 'status', { name: wan_device_name }); + wan_mac = wan_dev?.macaddr || ''; + } + + // 3. Get current WAN IP + if (wan_status && type(wan_status['ipv4-address']) === 'array' && length(wan_status['ipv4-address']) > 0) { + wan_ip = wan_status['ipv4-address'][0].address; + } + ubus_conn.disconnect(); + } + + let probed_ip = rtrim(readfile(PROBE_FILE) || ''); + + return { + mode: mode, + lan_proto: lan_proto, + lan_ip: lan_ip, + lan_mac: lan_mac, + wan_mac: wan_mac, + wan_ip: wan_ip, + probed_ip: probed_ip + }; + } + }, + + probe_ip: { + call: function() { + unlink(PROBE_FILE); + // Run udhcpc on br-lan with a short timeout and our probe script + // -n: exit if no lease + // -q: quit after obtaining lease + // -t 3: send 3 discover packets + // -T 2: pause 2 seconds between packets + let rc = system('udhcpc -i br-lan -n -q -t 3 -T 2 -s /usr/share/luci-app-ap-switch/dhcp-probe.sh >/dev/null 2>&1'); + + let ip = rtrim(readfile(PROBE_FILE) || ''); + return { success: (rc === 0), ip: ip }; + } + }, + + set_mode: { + args: { mode: 'string' }, + call: function(request) { + let target_mode = request.args?.mode; + if (target_mode !== 'router' && target_mode !== 'ap') { + return { error: 'Invalid mode' }; + } + + let uci_cursor = cursor(); + let current_mode = uci_cursor.get(UCI_CONFIG, 'settings', 'mode') || 'router'; + + if (target_mode === current_mode) { + return { result: 'Already in target mode' }; + } + + if (target_mode === 'ap') { + // --- Switch to AP Mode (Full Lossless Snapshot) --- + + // 1. Identify WAN device + let wan_device = uci_cursor.get('network', 'wan', 'device'); + if (!wan_device) { + wan_device = uci_cursor.get('network', 'wan', 'ifname'); + } + + // 2. Full Snapshot Backup of Router Mode state + let lan_proto = uci_cursor.get('network', 'lan', 'proto') || 'static'; + let lan_ipaddr = uci_cursor.get('network', 'lan', 'ipaddr') || ''; + let lan_netmask = uci_cursor.get('network', 'lan', 'netmask') || ''; + let lan_gateway = uci_cursor.get('network', 'lan', 'gateway') || ''; + let lan_dns = uci_cursor.get('network', 'lan', 'dns') || []; + let dhcp_ignore = uci_cursor.get('dhcp', 'lan', 'ignore') || '0'; + let wan_disabled = uci_cursor.get('network', 'wan', 'disabled') || '0'; + let wan6_disabled = uci_cursor.get('network', 'wan6', 'disabled') || '0'; + + uci_cursor.set(UCI_CONFIG, 'router_state', 'lan_proto', lan_proto); + uci_cursor.set(UCI_CONFIG, 'router_state', 'lan_ipaddr', lan_ipaddr); + uci_cursor.set(UCI_CONFIG, 'router_state', 'lan_netmask', lan_netmask); + uci_cursor.set(UCI_CONFIG, 'router_state', 'lan_gateway', lan_gateway); + uci_cursor.set(UCI_CONFIG, 'router_state', 'lan_dns', lan_dns); + uci_cursor.set(UCI_CONFIG, 'router_state', 'dhcp_ignore', dhcp_ignore); + uci_cursor.set(UCI_CONFIG, 'router_state', 'wan_device', wan_device || ''); + uci_cursor.set(UCI_CONFIG, 'router_state', 'wan_disabled', wan_disabled); + uci_cursor.set(UCI_CONFIG, 'router_state', 'wan6_disabled', wan6_disabled); + uci_cursor.set(UCI_CONFIG, 'settings', 'mode', 'ap'); + + // 3. Bridge WAN device to LAN bridge + if (wan_device) { + uci_cursor.foreach('network', 'device', (s) => { + if (s.name === 'br-lan') { + let ports = s.ports || []; + if (type(ports) === 'string') ports = [ports]; + let exists = false; + for (let p in ports) if (p === wan_device) exists = true; + if (!exists) { + push(ports, wan_device); + uci_cursor.set('network', s['.name'], 'ports', ports); + } + } + }); + } + + // 4. Set LAN to DHCP client + uci_cursor.set('network', 'lan', 'proto', 'dhcp'); + uci_cursor.delete('network', 'lan', 'ipaddr'); + uci_cursor.delete('network', 'lan', 'netmask'); + uci_cursor.delete('network', 'lan', 'gateway'); + uci_cursor.delete('network', 'lan', 'dns'); + + // 5. Disable WAN interface + uci_cursor.set('network', 'wan', 'disabled', '1'); + uci_cursor.set('network', 'wan6', 'disabled', '1'); + + // 6. Disable DHCP Server + uci_cursor.set('dhcp', 'lan', 'ignore', '1'); + + } else { + // --- Switch to Router Mode (Lossless State Restoration) --- + + // 1. Read Snapshot + let wan_device = uci_cursor.get(UCI_CONFIG, 'router_state', 'wan_device'); + let lan_proto = uci_cursor.get(UCI_CONFIG, 'router_state', 'lan_proto') || 'static'; + let lan_ipaddr = uci_cursor.get(UCI_CONFIG, 'router_state', 'lan_ipaddr') || '192.168.1.1'; + let lan_netmask = uci_cursor.get(UCI_CONFIG, 'router_state', 'lan_netmask') || ''; + let lan_gateway = uci_cursor.get(UCI_CONFIG, 'router_state', 'lan_gateway') || ''; + let lan_dns = uci_cursor.get(UCI_CONFIG, 'router_state', 'lan_dns') || []; + let dhcp_ignore = uci_cursor.get(UCI_CONFIG, 'router_state', 'dhcp_ignore') || '0'; + let wan_disabled = uci_cursor.get(UCI_CONFIG, 'router_state', 'wan_disabled') || '0'; + let wan6_disabled = uci_cursor.get(UCI_CONFIG, 'router_state', 'wan6_disabled') || '0'; + + uci_cursor.set(UCI_CONFIG, 'settings', 'mode', 'router'); + + // 2. Remove WAN device from LAN bridge + if (wan_device) { + uci_cursor.foreach('network', 'device', (s) => { + if (s.name === 'br-lan') { + let ports = s.ports || []; + if (type(ports) === 'string') ports = [ports]; + let new_ports = []; + for (let p in ports) if (p !== wan_device) push(new_ports, p); + uci_cursor.set('network', s['.name'], 'ports', new_ports); + } + }); + } + + // 3. Restore LAN settings accurately without hardcoding + uci_cursor.set('network', 'lan', 'proto', lan_proto); + if (lan_ipaddr) uci_cursor.set('network', 'lan', 'ipaddr', lan_ipaddr); + if (lan_netmask) uci_cursor.set('network', 'lan', 'netmask', lan_netmask); + if (lan_gateway) uci_cursor.set('network', 'lan', 'gateway', lan_gateway); + if (type(lan_dns) === 'array' && length(lan_dns) > 0) { + uci_cursor.set('network', 'lan', 'dns', lan_dns); + } else if (type(lan_dns) === 'string' && lan_dns !== '') { + uci_cursor.set('network', 'lan', 'dns', lan_dns); + } + + // 4. Restore WAN / WAN6 states + if (wan_disabled === '1') { + uci_cursor.set('network', 'wan', 'disabled', '1'); + } else { + uci_cursor.delete('network', 'wan', 'disabled'); + } + if (wan6_disabled === '1') { + uci_cursor.set('network', 'wan6', 'disabled', '1'); + } else { + uci_cursor.delete('network', 'wan6', 'disabled'); + } + + // 5. Restore DHCP Server state + if (dhcp_ignore === '1') { + uci_cursor.set('dhcp', 'lan', 'ignore', '1'); + } else { + uci_cursor.delete('dhcp', 'lan', 'ignore'); + } + } + + uci_cursor.commit('ap-switch'); + uci_cursor.commit('network'); + uci_cursor.commit('dhcp'); + + // Apply changes in background + system('/etc/init.d/network restart &'); + system('/etc/init.d/dnsmasq restart &'); + + return { success: true, result: 'success' }; + } + } +}; + +return { 'luci.ap-switch': methods }; diff --git a/luci-app-cloudflared-next/Makefile b/luci-app-cloudflared-next/Makefile new file mode 100644 index 000000000..73a1412a5 --- /dev/null +++ b/luci-app-cloudflared-next/Makefile @@ -0,0 +1,20 @@ +# This is free software, licensed under the Apache License, Version 2.0 +# +# Copyright (C) 2024 Hilman Maulana + +include $(TOPDIR)/rules.mk + +PKG_NAME:=luci-app-cloudflared-next + +LUCI_TITLE:=LuCI for Cloudflared +LUCI_DEPENDS:=+cloudflared-next +LUCI_DESCRIPTION:=LuCI support for Cloudflare Zero Trust Tunnels + +PKG_MAINTAINER:=Hilman Maulana , Sergey Ponomarev +PKG_VERSION:=1.2 +PKG_RELEASE:=1 +PKG_LICENSE:=Apache-2.0 + +include $(TOPDIR)/feeds/luci/luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-app-cloudflared-next/htdocs/luci-static/resources/view/cloudflared/config.js b/luci-app-cloudflared-next/htdocs/luci-static/resources/view/cloudflared/config.js new file mode 100644 index 000000000..16e7d0160 --- /dev/null +++ b/luci-app-cloudflared-next/htdocs/luci-static/resources/view/cloudflared/config.js @@ -0,0 +1,102 @@ +/* This is free software, licensed under the Apache License, Version 2.0 + * + * Copyright (C) 2024 Hilman Maulana + */ + +'use strict'; +'require form'; +'require rpc'; +'require view'; + +const callServiceList = rpc.declare({ + object: 'service', + method: 'list', + params: ['name'], + expect: { '': {} } +}); + +function getServiceStatus() { + return L.resolveDefault(callServiceList('cloudflared'), {}).then(function (res) { + var isRunning = false; + try { + isRunning = res['cloudflared']['instances']['cloudflared']['running']; + } catch (ignored) {} + return isRunning; + }); +} + +return view.extend({ + load: function () { + return Promise.all([ + getServiceStatus() + ]); + }, + + render: function (data) { + let isRunning = data[0]; + let m, s, o; + + m = new form.Map('cloudflared', _('Cloudflare Zero Trust Tunnel'), + _('Cloudflare Zero Trust Security services help you get maximum security both from outside and within the network.') + '
' + + _('Create and manage your network on the Cloudflare Zero Trust dashboard.') + .format('href="https://one.dash.cloudflare.com" target="_blank"') + '
' + + _('See documentation.') + .format('href="https://openwrt.org/docs/guide-user/services/vpn/cloudfare_tunnel" target="_blank"') + ); + + s = m.section(form.NamedSection, 'config', 'cloudflared'); + + o = s.option(form.DummyValue, '_status', _('Status')); + o.rawhtml = true; + o.cfgvalue = function(section_id) { + var span = '%s'; + var renderHTML = isRunning ? + String.format(span, 'green', _('Running')) : + String.format(span, 'red', _('Not Running')); + return renderHTML; + }; + + o = s.option(form.Flag, 'enabled', _('Enable')); + o.rmempty = false; + + o = s.option(form.TextValue, 'token', _('Token'), + _('The tunnel token is shown in the dashboard once you create a tunnel.') + ); + o.optional = true; + o.rmempty = false; + o.monospace = true; + + o = s.option(form.FileUpload, 'config', _('Config file path'), + _('See documentation.') + .format('href="https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/configure-tunnels/local-management/configuration-file/" target="_blank"') + ); + o.default = '/etc/cloudflared/config.yml'; + o.root_directory = '/etc/cloudflared/'; + o.optional = true; + + o = s.option(form.FileUpload, 'origincert', _('Certificate of Origin'), + _('The account certificate for your zones authorizing the client to serve as an Origin for that zone') + '
' + + _('Obtain a certificate here.') + .format('href="https://dash.cloudflare.com/argotunnel" target="_blank"') + ); + o.default = '/etc/cloudflared/cert.pem'; + o.root_directory = '/etc/cloudflared/'; + o.optional = true; + + o = s.option(form.ListValue, 'region', _('Region'), + _('The region to which connections are established.') + ); + o.value('us', _('United States')); + o.optional = true; + + o = s.option(form.ListValue, 'loglevel', _('Logging level')); + o.value('fatal', _('Fatal')); + o.value('error', _('Error')); + o.value('warn', _('Warning')); + o.value('info', _('Info')); + o.value('debug', _('Debug')); + o.default = 'info'; + + return m.render(); + } +}); \ No newline at end of file diff --git a/luci-app-cloudflared-next/htdocs/luci-static/resources/view/cloudflared/log.js b/luci-app-cloudflared-next/htdocs/luci-static/resources/view/cloudflared/log.js new file mode 100644 index 000000000..bc2c9e96f --- /dev/null +++ b/luci-app-cloudflared-next/htdocs/luci-static/resources/view/cloudflared/log.js @@ -0,0 +1,125 @@ +/* This is free software, licensed under the Apache License, Version 2.0 + * + * Copyright (C) 2024 Hilman Maulana + */ + +'use strict'; +'require fs'; +'require ui'; +'require view'; +'require poll'; + +function formatLogEntry(logObj) { + var formattedTime = new Date(logObj.time).toISOString().replace('T', ' ').split('.')[0]; + var tunnelIDMessage = logObj.tunnelID ? ', ID: ' + logObj.tunnelID : ''; + var errorMessage = logObj.error ? ', Error: ' + logObj.error : ''; + var ipMessage = logObj.ip ? ', IP: ' + logObj.ip : ''; + var configMessage = logObj.config ? ', Config: ' + JSON.stringify(logObj.config) : ''; + var connectionMessage = logObj.connection ? ', Connection: ' + JSON.stringify(logObj.connection) : ''; + var locationMessage = logObj.location ? ', Location: ' + logObj.location : ''; + var protocolMessage = logObj.protocol ? ', Protocol: ' + logObj.protocol : ''; + + return '[' + formattedTime + '] [' + logObj.level + '] : ' + logObj.message + ipMessage + tunnelIDMessage + errorMessage + configMessage + connectionMessage + locationMessage + protocolMessage; +} + +return view.extend({ + handleSaveApply: null, + handleSave: null, + handleReset: null, + load: function() { + poll.add(function () { + return fs.read('/var/log/cloudflared.log').then(function(res) { + if (!res || res.trim() === '') { + ui.addNotification(null, E('p', {}, _('Unable to read the interface info from /var/log/cloudflared.log.'))); + return ''; + } + + var logs = res.trim().split('\n').map(function(entry) { + try { + var logObj = JSON.parse(entry); + return logObj.time && logObj.message && logObj.level + ? formatLogEntry(logObj) + : ''; + } catch (error) { + console.error('Error parsing log entry:', error); + return ''; + } + }); + + logs = logs.filter(function(entry) { + return entry.trim() !== ''; + }); + + var info = logs.join('\n'); + var view = document.getElementById('syslog'); + var filterLevel = document.getElementById('filter-level').value; + var logDirection = document.getElementById('log-direction').value; + + if (view) { + var filteredLogs; + if (filterLevel !== 'all') { + filteredLogs = logs.filter(function(entry) { + var logLevel = entry.match(/\[.*\] \[(.*)\]/)[1].toLowerCase(); + return logLevel.includes(filterLevel.toLowerCase()); + }); + } else { + filteredLogs = logs; + } + + if (logDirection === 'up') { + filteredLogs = filteredLogs.reverse(); + } + + info = filteredLogs.join('\n'); + view.innerHTML = info; + } + + return info; + }); + }); + + return Promise.resolve(''); + }, + render: function(info) { + return E([], [ + E('h2', { 'class': 'section-title' }, _('Log')), + E('div', { 'id': 'logs' }, [ + E('label', { 'for': 'filter-level', 'style': 'margin-right: 8px;' }, _('Filter Level:')), + E('select', { 'id': 'filter-level', 'style': 'margin-right: 8px;' }, [ + E('option', { 'value': 'all', 'selected': 'selected' }, _('All')), + E('option', { 'value': 'info' }, _('Info')), + E('option', { 'value': 'warn' }, _('Warn')), + E('option', { 'value': 'error' }, _('Error')), + ]), + E('label', { 'for': 'log-direction', 'style': 'margin-right: 8px;' }, _('Log Direction:')), + E('select', { 'id': 'log-direction', 'style': 'margin-right: 8px;' }, [ + E('option', { 'value': 'down', 'selected': 'selected' }, _('Down')), + E('option', { 'value': 'up' }, _('Up')), + ]), + E('button', { + 'id': 'download-log', + 'class': 'cbi-button cbi-button-save', + 'click': L.bind(this.handleDownloadLog, this), + 'style': 'margin-bottom: 8px;' + }, _('Download Log')), + E('textarea', { + 'id': 'syslog', + 'class': 'cbi-input-textarea', + 'style': 'height: 500px; overflow-y: scroll;', + 'readonly': 'readonly', + 'wrap': 'off', + 'rows': 1 + }, [ info ]) + ]) + ]); + }, + + handleDownloadLog: function() { + var logs = document.getElementById('syslog').value; + var blob = new Blob([logs], { type: 'text/plain' }); + var link = document.createElement('a'); + link.href = window.URL.createObjectURL(blob); + link.download = 'cloudflared.log'; + link.click(); + } +}); diff --git a/luci-app-cloudflared-next/htdocs/luci-static/resources/view/cloudflared/tunnels.js b/luci-app-cloudflared-next/htdocs/luci-static/resources/view/cloudflared/tunnels.js new file mode 100644 index 000000000..23fb4c47a --- /dev/null +++ b/luci-app-cloudflared-next/htdocs/luci-static/resources/view/cloudflared/tunnels.js @@ -0,0 +1,101 @@ +/* This is free software, licensed under the Apache License, Version 2.0 + * + * Copyright (C) 2024 Sergey Ponomarev + */ + +'use strict'; +'require view'; +'require fs'; + +function listTunnels() { + let command = '/usr/bin/cloudflared'; + let commandArgs = ['tunnel', 'list', '-o', 'json']; + return fs.exec(command, commandArgs).then(function (res) { + if (res.code === 0) { + return JSON.parse(res.stdout); + } else { + throw new Error(res.stdout + ' ' + res.stderr); + } + }); +} + +return view.extend({ + handleSaveApply: null, + handleSave: null, + handleReset: null, + + load: function () { + return Promise.all([ + listTunnels() + ]); + }, + + render: function (data) { + var tunnels = data[0]; + + var tunnelRows = tunnels.map(function (tunnel, index) { + var rowClass = index % 2 === 0 ? 'cbi-rowstyle-1' : 'cbi-rowstyle-2'; + var tunneldate = new Date(tunnel.created_at).toLocaleString(); + return E('tr', { 'class': 'tr ' + rowClass }, [ + E('td', {'class': 'td'}, tunnel.name), + E('td', {'class': 'td'}, tunnel.id), + E('td', {'class': 'td'}, tunneldate), + E('td', {'class': 'td'}, tunnel.connections.length) + ]); + }); + + var tunnelTable = [ + E('h3', _('Tunnels Information')), + E('table', { 'class': 'table cbi-section-table' }, [ + E('tr', { 'class': 'tr table-titles' }, [ + E('th', {'class': 'th'}, _('Name')), + E('th', {'class': 'th'}, _('ID')), + E('th', {'class': 'th'}, _('Created At')), + E('th', {'class': 'th'}, _('Connections')) + ]), + E(tunnelRows) + ]) + ]; + + var connectionsTables = tunnels.map(function (tunnel) { + var connectionsTable; + if (tunnel.connections.length > 0) { + var connectionRows = tunnel.connections.map(function (connection, index) { + var rowClass = index % 2 === 0 ? 'cbi-rowstyle-1' : 'cbi-rowstyle-2'; + var connectiondate = new Date(connection.opened_at).toLocaleString(); + return E('tr', { 'class': 'tr ' + rowClass }, [ + E('td', {'class': 'td'}, connection.id), + E('td', {'class': 'td'}, connection.origin_ip), + E('td', {'class': 'td'}, connectiondate), + E('td', {'class': 'td'}, connection.colo_name) + ]); + }); + + connectionsTable = E('table', { 'class': 'table cbi-section-table' }, [ + E('tr', { 'class': 'tr table-titles' }, [ + E('th', {'class': 'th'}, _('Connection ID')), + E('th', {'class': 'th'}, _('Origin IP')), + E('th', {'class': 'th'}, _('Opened At')), + E('th', {'class': 'th'}, _('Data Center')) + ]), + E(connectionRows) + ]); + } else { + connectionsTable = E('div', {'class':'cbi-value center'}, [ + E('em', _('No connections')) + ]); + } + + return E('div', {'class': 'cbi-section'}, [ + E('h3', _('Connections') + ' ' + tunnel.name), + E(connectionsTable) + ]); + }); + + return E([], [ + E('h2', { 'class': 'section-title' }, _('Tunnels')), + E('div', {'class': 'cbi-section'}, tunnelTable), + E(connectionsTables) + ]); + } +}); diff --git a/luci-app-cloudflared-next/po/ar/cloudflared.po b/luci-app-cloudflared-next/po/ar/cloudflared.po new file mode 100644 index 000000000..f565110a9 --- /dev/null +++ b/luci-app-cloudflared-next/po/ar/cloudflared.po @@ -0,0 +1,207 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2024-07-16 16:41+0000\n" +"Last-Translator: Rex_sa \n" +"Language-Team: Arabic \n" +"Language: ar\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 " +"&& n%100<=10 ? 3 : n%100>=11 ? 4 : 5;\n" +"X-Generator: Weblate 5.7-dev\n" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:89 +msgid "All" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:77 +msgid "Certificate of Origin" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:40 +msgid "" +"Cloudflare Zero Trust Security services help you get maximum security both " +"from outside and within the network." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:39 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:3 +msgid "Cloudflare Zero Trust Tunnel" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:69 +msgid "Config file path" +msgstr "" + +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:14 +msgid "Configuration" +msgstr "التكوين" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:76 +msgid "Connection ID" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:54 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:90 +msgid "Connections" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:41 +msgid "" +"Create and manage your network on the Cloudflare Zero Trust " +"dashboard." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:53 +msgid "Created At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:79 +msgid "Data Center" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:97 +msgid "Debug" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:96 +msgid "Down" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:104 +msgid "Download Log" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:59 +msgid "Enable" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:94 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:92 +msgid "Error" +msgstr "خطأ" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:93 +msgid "Fatal" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:87 +msgid "Filter Level:" +msgstr "" + +#: applications/luci-app-cloudflared/root/usr/share/rpcd/acl.d/luci-app-cloudflared.json:3 +msgid "Grant access to Cloudflared configuration" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:52 +msgid "ID" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:96 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:90 +msgid "Info" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:85 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:30 +msgid "Log" +msgstr "السجل" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:94 +msgid "Log Direction:" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:92 +msgid "Logging level" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:51 +msgid "Name" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:85 +msgid "No connections" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:55 +msgid "Not Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:79 +msgid "Obtain a certificate here." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:78 +msgid "Opened At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:77 +msgid "Origin IP" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:86 +msgid "Region" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:54 +msgid "Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:43 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:70 +msgid "See documentation." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:49 +msgid "Status" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:78 +msgid "" +"The account certificate for your zones authorizing the client to serve as an " +"Origin for that zone" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:87 +msgid "The region to which connections are established." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:63 +msgid "The tunnel token is shown in the dashboard once you create a tunnel." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:62 +msgid "Token" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:96 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:22 +msgid "Tunnels" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:48 +msgid "Tunnels Information" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:33 +msgid "Unable to read the interface info from /var/log/cloudflared.log." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:89 +msgid "United States" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:97 +msgid "Up" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:91 +msgid "Warn" +msgstr "حذر" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:95 +msgid "Warning" +msgstr "تحذير" diff --git a/luci-app-cloudflared-next/po/be/cloudflared.po b/luci-app-cloudflared-next/po/be/cloudflared.po new file mode 100644 index 000000000..00316e771 --- /dev/null +++ b/luci-app-cloudflared-next/po/be/cloudflared.po @@ -0,0 +1,202 @@ +msgid "" +msgstr "" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: be\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && " +"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:89 +msgid "All" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:77 +msgid "Certificate of Origin" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:40 +msgid "" +"Cloudflare Zero Trust Security services help you get maximum security both " +"from outside and within the network." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:39 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:3 +msgid "Cloudflare Zero Trust Tunnel" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:69 +msgid "Config file path" +msgstr "" + +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:14 +msgid "Configuration" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:76 +msgid "Connection ID" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:54 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:90 +msgid "Connections" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:41 +msgid "" +"Create and manage your network on the Cloudflare Zero Trust " +"dashboard." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:53 +msgid "Created At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:79 +msgid "Data Center" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:97 +msgid "Debug" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:96 +msgid "Down" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:104 +msgid "Download Log" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:59 +msgid "Enable" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:94 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:92 +msgid "Error" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:93 +msgid "Fatal" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:87 +msgid "Filter Level:" +msgstr "" + +#: applications/luci-app-cloudflared/root/usr/share/rpcd/acl.d/luci-app-cloudflared.json:3 +msgid "Grant access to Cloudflared configuration" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:52 +msgid "ID" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:96 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:90 +msgid "Info" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:85 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:30 +msgid "Log" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:94 +msgid "Log Direction:" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:92 +msgid "Logging level" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:51 +msgid "Name" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:85 +msgid "No connections" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:55 +msgid "Not Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:79 +msgid "Obtain a certificate here." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:78 +msgid "Opened At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:77 +msgid "Origin IP" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:86 +msgid "Region" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:54 +msgid "Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:43 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:70 +msgid "See documentation." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:49 +msgid "Status" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:78 +msgid "" +"The account certificate for your zones authorizing the client to serve as an " +"Origin for that zone" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:87 +msgid "The region to which connections are established." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:63 +msgid "The tunnel token is shown in the dashboard once you create a tunnel." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:62 +msgid "Token" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:96 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:22 +msgid "Tunnels" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:48 +msgid "Tunnels Information" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:33 +msgid "Unable to read the interface info from /var/log/cloudflared.log." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:89 +msgid "United States" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:97 +msgid "Up" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:91 +msgid "Warn" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:95 +msgid "Warning" +msgstr "" diff --git a/luci-app-cloudflared-next/po/bg/cloudflared.po b/luci-app-cloudflared-next/po/bg/cloudflared.po new file mode 100644 index 000000000..ec4140211 --- /dev/null +++ b/luci-app-cloudflared-next/po/bg/cloudflared.po @@ -0,0 +1,206 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2026-03-15 08:27+0000\n" +"Last-Translator: Daniel Konstantinov \n" +"Language-Team: Bulgarian \n" +"Language: bg\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.17-dev\n" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:89 +msgid "All" +msgstr "Всички" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:77 +msgid "Certificate of Origin" +msgstr "Сертификат за произход" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:40 +msgid "" +"Cloudflare Zero Trust Security services help you get maximum security both " +"from outside and within the network." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:39 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:3 +msgid "Cloudflare Zero Trust Tunnel" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:69 +msgid "Config file path" +msgstr "" + +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:14 +msgid "Configuration" +msgstr "Настройки" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:76 +msgid "Connection ID" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:54 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:90 +msgid "Connections" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:41 +msgid "" +"Create and manage your network on the Cloudflare Zero Trust " +"dashboard." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:53 +msgid "Created At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:79 +msgid "Data Center" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:97 +msgid "Debug" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:96 +msgid "Down" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:104 +msgid "Download Log" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:59 +msgid "Enable" +msgstr "Активиране" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:94 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:92 +msgid "Error" +msgstr "Грешка" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:93 +msgid "Fatal" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:87 +msgid "Filter Level:" +msgstr "" + +#: applications/luci-app-cloudflared/root/usr/share/rpcd/acl.d/luci-app-cloudflared.json:3 +msgid "Grant access to Cloudflared configuration" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:52 +msgid "ID" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:96 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:90 +msgid "Info" +msgstr "Инфо" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:85 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:30 +msgid "Log" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:94 +msgid "Log Direction:" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:92 +msgid "Logging level" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:51 +msgid "Name" +msgstr "Име" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:85 +msgid "No connections" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:55 +msgid "Not Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:79 +msgid "Obtain a certificate here." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:78 +msgid "Opened At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:77 +msgid "Origin IP" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:86 +msgid "Region" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:54 +msgid "Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:43 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:70 +msgid "See documentation." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:49 +msgid "Status" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:78 +msgid "" +"The account certificate for your zones authorizing the client to serve as an " +"Origin for that zone" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:87 +msgid "The region to which connections are established." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:63 +msgid "The tunnel token is shown in the dashboard once you create a tunnel." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:62 +msgid "Token" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:96 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:22 +msgid "Tunnels" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:48 +msgid "Tunnels Information" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:33 +msgid "Unable to read the interface info from /var/log/cloudflared.log." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:89 +msgid "United States" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:97 +msgid "Up" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:91 +msgid "Warn" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:95 +msgid "Warning" +msgstr "" diff --git a/luci-app-cloudflared-next/po/bn_BD/cloudflared.po b/luci-app-cloudflared-next/po/bn_BD/cloudflared.po new file mode 100644 index 000000000..4e473bbfb --- /dev/null +++ b/luci-app-cloudflared-next/po/bn_BD/cloudflared.po @@ -0,0 +1,206 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2025-04-15 20:45+0000\n" +"Last-Translator: Random Github User \n" +"Language-Team: Bengali (Bangladesh) \n" +"Language: bn_BD\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 5.11-dev\n" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:89 +msgid "All" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:77 +msgid "Certificate of Origin" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:40 +msgid "" +"Cloudflare Zero Trust Security services help you get maximum security both " +"from outside and within the network." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:39 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:3 +msgid "Cloudflare Zero Trust Tunnel" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:69 +msgid "Config file path" +msgstr "" + +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:14 +msgid "Configuration" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:76 +msgid "Connection ID" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:54 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:90 +msgid "Connections" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:41 +msgid "" +"Create and manage your network on the Cloudflare Zero Trust " +"dashboard." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:53 +msgid "Created At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:79 +msgid "Data Center" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:97 +msgid "Debug" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:96 +msgid "Down" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:104 +msgid "Download Log" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:59 +msgid "Enable" +msgstr "সক্রিয় করুন" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:94 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:92 +msgid "Error" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:93 +msgid "Fatal" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:87 +msgid "Filter Level:" +msgstr "" + +#: applications/luci-app-cloudflared/root/usr/share/rpcd/acl.d/luci-app-cloudflared.json:3 +msgid "Grant access to Cloudflared configuration" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:52 +msgid "ID" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:96 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:90 +msgid "Info" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:85 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:30 +msgid "Log" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:94 +msgid "Log Direction:" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:92 +msgid "Logging level" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:51 +msgid "Name" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:85 +msgid "No connections" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:55 +msgid "Not Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:79 +msgid "Obtain a certificate here." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:78 +msgid "Opened At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:77 +msgid "Origin IP" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:86 +msgid "Region" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:54 +msgid "Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:43 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:70 +msgid "See documentation." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:49 +msgid "Status" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:78 +msgid "" +"The account certificate for your zones authorizing the client to serve as an " +"Origin for that zone" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:87 +msgid "The region to which connections are established." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:63 +msgid "The tunnel token is shown in the dashboard once you create a tunnel." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:62 +msgid "Token" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:96 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:22 +msgid "Tunnels" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:48 +msgid "Tunnels Information" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:33 +msgid "Unable to read the interface info from /var/log/cloudflared.log." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:89 +msgid "United States" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:97 +msgid "Up" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:91 +msgid "Warn" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:95 +msgid "Warning" +msgstr "" diff --git a/luci-app-cloudflared-next/po/ca/cloudflared.po b/luci-app-cloudflared-next/po/ca/cloudflared.po new file mode 100644 index 000000000..605744a9d --- /dev/null +++ b/luci-app-cloudflared-next/po/ca/cloudflared.po @@ -0,0 +1,206 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2025-12-02 19:00+0000\n" +"Last-Translator: Alfonso Montero López \n" +"Language-Team: Catalan \n" +"Language: ca\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.15-dev\n" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:89 +msgid "All" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:77 +msgid "Certificate of Origin" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:40 +msgid "" +"Cloudflare Zero Trust Security services help you get maximum security both " +"from outside and within the network." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:39 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:3 +msgid "Cloudflare Zero Trust Tunnel" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:69 +msgid "Config file path" +msgstr "" + +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:14 +msgid "Configuration" +msgstr "Configuració" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:76 +msgid "Connection ID" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:54 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:90 +msgid "Connections" +msgstr "Connexions" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:41 +msgid "" +"Create and manage your network on the Cloudflare Zero Trust " +"dashboard." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:53 +msgid "Created At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:79 +msgid "Data Center" +msgstr "Centre de dades" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:97 +msgid "Debug" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:96 +msgid "Down" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:104 +msgid "Download Log" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:59 +msgid "Enable" +msgstr "Activa" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:94 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:92 +msgid "Error" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:93 +msgid "Fatal" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:87 +msgid "Filter Level:" +msgstr "" + +#: applications/luci-app-cloudflared/root/usr/share/rpcd/acl.d/luci-app-cloudflared.json:3 +msgid "Grant access to Cloudflared configuration" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:52 +msgid "ID" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:96 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:90 +msgid "Info" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:85 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:30 +msgid "Log" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:94 +msgid "Log Direction:" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:92 +msgid "Logging level" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:51 +msgid "Name" +msgstr "Nom" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:85 +msgid "No connections" +msgstr "Cap connexió" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:55 +msgid "Not Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:79 +msgid "Obtain a certificate here." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:78 +msgid "Opened At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:77 +msgid "Origin IP" +msgstr "IP origen" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:86 +msgid "Region" +msgstr "Regió" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:54 +msgid "Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:43 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:70 +msgid "See documentation." +msgstr "Vegeu la documentació." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:49 +msgid "Status" +msgstr "Estat" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:78 +msgid "" +"The account certificate for your zones authorizing the client to serve as an " +"Origin for that zone" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:87 +msgid "The region to which connections are established." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:63 +msgid "The tunnel token is shown in the dashboard once you create a tunnel." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:62 +msgid "Token" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:96 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:22 +msgid "Tunnels" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:48 +msgid "Tunnels Information" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:33 +msgid "Unable to read the interface info from /var/log/cloudflared.log." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:89 +msgid "United States" +msgstr "Estats Units" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:97 +msgid "Up" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:91 +msgid "Warn" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:95 +msgid "Warning" +msgstr "" diff --git a/luci-app-cloudflared-next/po/cs/cloudflared.po b/luci-app-cloudflared-next/po/cs/cloudflared.po new file mode 100644 index 000000000..afeeb3bcf --- /dev/null +++ b/luci-app-cloudflared-next/po/cs/cloudflared.po @@ -0,0 +1,212 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2026-03-08 17:33+0000\n" +"Last-Translator: Pavel Borecki \n" +"Language-Team: Czech \n" +"Language: cs\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=((n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2);\n" +"X-Generator: Weblate 5.17-dev\n" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:89 +msgid "All" +msgstr "Vše" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:77 +msgid "Certificate of Origin" +msgstr "Certifikát původu" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:40 +msgid "" +"Cloudflare Zero Trust Security services help you get maximum security both " +"from outside and within the network." +msgstr "" +"Cloudflare Zero Trust bezpečnostní služby pomáhají získat maximální " +"bezpečnost zvenčí a zevnitř sítě." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:39 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:3 +msgid "Cloudflare Zero Trust Tunnel" +msgstr "Tunel Cloudflare Zero Trust" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:69 +msgid "Config file path" +msgstr "Popis umístění souboru s nastaveními" + +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:14 +msgid "Configuration" +msgstr "Nastavení" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:76 +msgid "Connection ID" +msgstr "Identif. spojení" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:54 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:90 +msgid "Connections" +msgstr "Spojení" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:41 +msgid "" +"Create and manage your network on the Cloudflare Zero Trust " +"dashboard." +msgstr "" +"Svou síť vytvoříte a spravujete na přehledu u Cloudflare Zero Trust." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:53 +msgid "Created At" +msgstr "Vytvořeno v" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:79 +msgid "Data Center" +msgstr "Datacentrum" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:97 +msgid "Debug" +msgstr "Ladění" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:96 +msgid "Down" +msgstr "Dole" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:104 +msgid "Download Log" +msgstr "Stáhnout si záznam událostí" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:59 +msgid "Enable" +msgstr "Povolit" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:94 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:92 +msgid "Error" +msgstr "Chyba" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:93 +msgid "Fatal" +msgstr "Zásadní" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:87 +msgid "Filter Level:" +msgstr "Úroveň filtru:" + +#: applications/luci-app-cloudflared/root/usr/share/rpcd/acl.d/luci-app-cloudflared.json:3 +msgid "Grant access to Cloudflared configuration" +msgstr "Udělit přístup do nastavování Cloudflared" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:52 +msgid "ID" +msgstr "Identifikátor" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:96 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:90 +msgid "Info" +msgstr "Info" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:85 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:30 +msgid "Log" +msgstr "Záznam událostí" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:94 +msgid "Log Direction:" +msgstr "Směr záznamu událostí:" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:92 +msgid "Logging level" +msgstr "Stupeň podrobnosti zaznamenávání událostí" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:51 +msgid "Name" +msgstr "Název" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:85 +msgid "No connections" +msgstr "Žádná spojení" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:55 +msgid "Not Running" +msgstr "Nespuštěné" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:79 +msgid "Obtain a certificate here." +msgstr "Certifikát získejte zde." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:78 +msgid "Opened At" +msgstr "Otevřít v" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:77 +msgid "Origin IP" +msgstr "IP adresa původu" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:86 +msgid "Region" +msgstr "Oblast" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:54 +msgid "Running" +msgstr "Spuštěné" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:43 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:70 +msgid "See documentation." +msgstr "Viz dokumentace." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:49 +msgid "Status" +msgstr "Stav" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:78 +msgid "" +"The account certificate for your zones authorizing the client to serve as an " +"Origin for that zone" +msgstr "" +"Certifikát účtu pro vaše pověřování zón ke které klient slouží jako původ " +"pro takovou zónu" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:87 +msgid "The region to which connections are established." +msgstr "Oblast do které jsou spojení navázány." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:63 +msgid "The tunnel token is shown in the dashboard once you create a tunnel." +msgstr "Token tunelu je zobrazen v přehledu poté co vytvoříte tunel." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:62 +msgid "Token" +msgstr "Token" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:96 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:22 +msgid "Tunnels" +msgstr "Tunely" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:48 +msgid "Tunnels Information" +msgstr "Informace o tunelech" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:33 +msgid "Unable to read the interface info from /var/log/cloudflared.log." +msgstr "Nepodařilo se načíst informace o rozhraní z /var/log/cloudflared.log." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:89 +msgid "United States" +msgstr "Spojené státy" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:97 +msgid "Up" +msgstr "Nahoře" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:91 +msgid "Warn" +msgstr "Varov." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:95 +msgid "Warning" +msgstr "Varování" diff --git a/luci-app-cloudflared-next/po/da/cloudflared.po b/luci-app-cloudflared-next/po/da/cloudflared.po new file mode 100644 index 000000000..e486cd34f --- /dev/null +++ b/luci-app-cloudflared-next/po/da/cloudflared.po @@ -0,0 +1,203 @@ +msgid "" +msgstr "" +"Content-Type: text/plain; charset=UTF-8\n" +"Project-Id-Version: PACKAGE VERSION\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: da\n" +"MIME-Version: 1.0\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:89 +msgid "All" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:77 +msgid "Certificate of Origin" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:40 +msgid "" +"Cloudflare Zero Trust Security services help you get maximum security both " +"from outside and within the network." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:39 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:3 +msgid "Cloudflare Zero Trust Tunnel" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:69 +msgid "Config file path" +msgstr "" + +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:14 +msgid "Configuration" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:76 +msgid "Connection ID" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:54 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:90 +msgid "Connections" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:41 +msgid "" +"Create and manage your network on the Cloudflare Zero Trust " +"dashboard." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:53 +msgid "Created At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:79 +msgid "Data Center" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:97 +msgid "Debug" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:96 +msgid "Down" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:104 +msgid "Download Log" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:59 +msgid "Enable" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:94 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:92 +msgid "Error" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:93 +msgid "Fatal" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:87 +msgid "Filter Level:" +msgstr "" + +#: applications/luci-app-cloudflared/root/usr/share/rpcd/acl.d/luci-app-cloudflared.json:3 +msgid "Grant access to Cloudflared configuration" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:52 +msgid "ID" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:96 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:90 +msgid "Info" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:85 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:30 +msgid "Log" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:94 +msgid "Log Direction:" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:92 +msgid "Logging level" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:51 +msgid "Name" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:85 +msgid "No connections" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:55 +msgid "Not Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:79 +msgid "Obtain a certificate here." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:78 +msgid "Opened At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:77 +msgid "Origin IP" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:86 +msgid "Region" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:54 +msgid "Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:43 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:70 +msgid "See documentation." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:49 +msgid "Status" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:78 +msgid "" +"The account certificate for your zones authorizing the client to serve as an " +"Origin for that zone" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:87 +msgid "The region to which connections are established." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:63 +msgid "The tunnel token is shown in the dashboard once you create a tunnel." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:62 +msgid "Token" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:96 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:22 +msgid "Tunnels" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:48 +msgid "Tunnels Information" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:33 +msgid "Unable to read the interface info from /var/log/cloudflared.log." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:89 +msgid "United States" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:97 +msgid "Up" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:91 +msgid "Warn" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:95 +msgid "Warning" +msgstr "" diff --git a/luci-app-cloudflared-next/po/de/cloudflared.po b/luci-app-cloudflared-next/po/de/cloudflared.po new file mode 100644 index 000000000..016e2779c --- /dev/null +++ b/luci-app-cloudflared-next/po/de/cloudflared.po @@ -0,0 +1,214 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2026-03-02 15:14+0000\n" +"Last-Translator: Werner Schleifer \n" +"Language-Team: German \n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.16.1-dev\n" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:89 +msgid "All" +msgstr "Alle" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:77 +msgid "Certificate of Origin" +msgstr "Ursprungsbescheinigung" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:40 +msgid "" +"Cloudflare Zero Trust Security services help you get maximum security both " +"from outside and within the network." +msgstr "" +"Cloudflare Zero Trust Security Services helfen Ihnen, maximale Sicherheit " +"sowohl von außerhalb als auch innerhalb des Netzwerks zu erhalten." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:39 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:3 +msgid "Cloudflare Zero Trust Tunnel" +msgstr "Cloudflare Zero Trust- Tunnel" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:69 +msgid "Config file path" +msgstr "Konfig-Dateipfad" + +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:14 +msgid "Configuration" +msgstr "Konfiguration" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:76 +msgid "Connection ID" +msgstr "Verbindungs-ID" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:54 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:90 +msgid "Connections" +msgstr "Verbindungen" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:41 +msgid "" +"Create and manage your network on the Cloudflare Zero Trust " +"dashboard." +msgstr "" +"Erstellen und verwalten Sie Ihr Netzwerk auf dem Cloudflare Zero " +"Trust-Dashboard." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:53 +msgid "Created At" +msgstr "Erstellt am" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:79 +msgid "Data Center" +msgstr "Rechenzentrum" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:97 +msgid "Debug" +msgstr "Debug" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:96 +msgid "Down" +msgstr "Runter" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:104 +msgid "Download Log" +msgstr "Log herunterladen" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:59 +msgid "Enable" +msgstr "Aktivieren" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:94 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:92 +msgid "Error" +msgstr "Fehler" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:93 +msgid "Fatal" +msgstr "Schwerwiegend" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:87 +msgid "Filter Level:" +msgstr "Filterebene:" + +#: applications/luci-app-cloudflared/root/usr/share/rpcd/acl.d/luci-app-cloudflared.json:3 +msgid "Grant access to Cloudflared configuration" +msgstr "Zugriff auf Cloudflared-Konfiguration gewähren" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:52 +msgid "ID" +msgstr "ID" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:96 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:90 +msgid "Info" +msgstr "Info" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:85 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:30 +msgid "Log" +msgstr "Log" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:94 +msgid "Log Direction:" +msgstr "Log-Richtung:" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:92 +msgid "Logging level" +msgstr "Protokollierungsebene" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:51 +msgid "Name" +msgstr "Name" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:85 +msgid "No connections" +msgstr "Keine Verbindungen" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:55 +msgid "Not Running" +msgstr "Angehalten" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:79 +msgid "Obtain a certificate here." +msgstr "Ein Zertifikat hier erhalten." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:78 +msgid "Opened At" +msgstr "Geöffnet Am" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:77 +msgid "Origin IP" +msgstr "Ursprungs-IP" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:86 +msgid "Region" +msgstr "Region" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:54 +msgid "Running" +msgstr "Läuft" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:43 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:70 +msgid "See documentation." +msgstr "Siehe Dokumentation." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:49 +msgid "Status" +msgstr "Status" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:78 +msgid "" +"The account certificate for your zones authorizing the client to serve as an " +"Origin for that zone" +msgstr "" +"Das Konto-Zertifikat für Ihre Zonen, das den Client berechtigt, als Origin " +"für diese Zone zu dienen" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:87 +msgid "The region to which connections are established." +msgstr "Der Bereich, zu dem Verbindungen aufgebaut werden." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:63 +msgid "The tunnel token is shown in the dashboard once you create a tunnel." +msgstr "" +"Der Tunnel-Token wird im Dashboard angezeigt, sobald Sie einen Tunnel " +"erstellen." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:62 +msgid "Token" +msgstr "Token" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:96 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:22 +msgid "Tunnels" +msgstr "Tunnels" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:48 +msgid "Tunnels Information" +msgstr "Tunnel-Informationen" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:33 +msgid "Unable to read the interface info from /var/log/cloudflared.log." +msgstr "Kann die Interface-Info nicht von /var/log/cloudflared.log lesen." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:89 +msgid "United States" +msgstr "Vereinigte Staaten" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:97 +msgid "Up" +msgstr "Oben" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:91 +msgid "Warn" +msgstr "Warn" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:95 +msgid "Warning" +msgstr "Warnung" diff --git a/luci-app-cloudflared-next/po/el/cloudflared.po b/luci-app-cloudflared-next/po/el/cloudflared.po new file mode 100644 index 000000000..3958d8dca --- /dev/null +++ b/luci-app-cloudflared-next/po/el/cloudflared.po @@ -0,0 +1,206 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2025-05-03 17:07+0000\n" +"Last-Translator: george kitsoukakis \n" +"Language-Team: Greek \n" +"Language: el\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.12-dev\n" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:89 +msgid "All" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:77 +msgid "Certificate of Origin" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:40 +msgid "" +"Cloudflare Zero Trust Security services help you get maximum security both " +"from outside and within the network." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:39 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:3 +msgid "Cloudflare Zero Trust Tunnel" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:69 +msgid "Config file path" +msgstr "" + +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:14 +msgid "Configuration" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:76 +msgid "Connection ID" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:54 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:90 +msgid "Connections" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:41 +msgid "" +"Create and manage your network on the Cloudflare Zero Trust " +"dashboard." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:53 +msgid "Created At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:79 +msgid "Data Center" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:97 +msgid "Debug" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:96 +msgid "Down" +msgstr "Κάτω" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:104 +msgid "Download Log" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:59 +msgid "Enable" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:94 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:92 +msgid "Error" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:93 +msgid "Fatal" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:87 +msgid "Filter Level:" +msgstr "" + +#: applications/luci-app-cloudflared/root/usr/share/rpcd/acl.d/luci-app-cloudflared.json:3 +msgid "Grant access to Cloudflared configuration" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:52 +msgid "ID" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:96 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:90 +msgid "Info" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:85 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:30 +msgid "Log" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:94 +msgid "Log Direction:" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:92 +msgid "Logging level" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:51 +msgid "Name" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:85 +msgid "No connections" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:55 +msgid "Not Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:79 +msgid "Obtain a certificate here." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:78 +msgid "Opened At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:77 +msgid "Origin IP" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:86 +msgid "Region" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:54 +msgid "Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:43 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:70 +msgid "See documentation." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:49 +msgid "Status" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:78 +msgid "" +"The account certificate for your zones authorizing the client to serve as an " +"Origin for that zone" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:87 +msgid "The region to which connections are established." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:63 +msgid "The tunnel token is shown in the dashboard once you create a tunnel." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:62 +msgid "Token" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:96 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:22 +msgid "Tunnels" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:48 +msgid "Tunnels Information" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:33 +msgid "Unable to read the interface info from /var/log/cloudflared.log." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:89 +msgid "United States" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:97 +msgid "Up" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:91 +msgid "Warn" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:95 +msgid "Warning" +msgstr "" diff --git a/luci-app-cloudflared-next/po/eo/cloudflared.po b/luci-app-cloudflared-next/po/eo/cloudflared.po new file mode 100644 index 000000000..a22a576e5 --- /dev/null +++ b/luci-app-cloudflared-next/po/eo/cloudflared.po @@ -0,0 +1,201 @@ +msgid "" +msgstr "" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: eo\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:89 +msgid "All" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:77 +msgid "Certificate of Origin" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:40 +msgid "" +"Cloudflare Zero Trust Security services help you get maximum security both " +"from outside and within the network." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:39 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:3 +msgid "Cloudflare Zero Trust Tunnel" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:69 +msgid "Config file path" +msgstr "" + +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:14 +msgid "Configuration" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:76 +msgid "Connection ID" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:54 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:90 +msgid "Connections" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:41 +msgid "" +"Create and manage your network on the Cloudflare Zero Trust " +"dashboard." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:53 +msgid "Created At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:79 +msgid "Data Center" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:97 +msgid "Debug" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:96 +msgid "Down" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:104 +msgid "Download Log" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:59 +msgid "Enable" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:94 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:92 +msgid "Error" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:93 +msgid "Fatal" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:87 +msgid "Filter Level:" +msgstr "" + +#: applications/luci-app-cloudflared/root/usr/share/rpcd/acl.d/luci-app-cloudflared.json:3 +msgid "Grant access to Cloudflared configuration" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:52 +msgid "ID" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:96 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:90 +msgid "Info" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:85 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:30 +msgid "Log" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:94 +msgid "Log Direction:" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:92 +msgid "Logging level" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:51 +msgid "Name" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:85 +msgid "No connections" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:55 +msgid "Not Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:79 +msgid "Obtain a certificate here." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:78 +msgid "Opened At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:77 +msgid "Origin IP" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:86 +msgid "Region" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:54 +msgid "Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:43 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:70 +msgid "See documentation." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:49 +msgid "Status" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:78 +msgid "" +"The account certificate for your zones authorizing the client to serve as an " +"Origin for that zone" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:87 +msgid "The region to which connections are established." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:63 +msgid "The tunnel token is shown in the dashboard once you create a tunnel." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:62 +msgid "Token" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:96 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:22 +msgid "Tunnels" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:48 +msgid "Tunnels Information" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:33 +msgid "Unable to read the interface info from /var/log/cloudflared.log." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:89 +msgid "United States" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:97 +msgid "Up" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:91 +msgid "Warn" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:95 +msgid "Warning" +msgstr "" diff --git a/luci-app-cloudflared-next/po/es/cloudflared.po b/luci-app-cloudflared-next/po/es/cloudflared.po new file mode 100644 index 000000000..a4f500c3e --- /dev/null +++ b/luci-app-cloudflared-next/po/es/cloudflared.po @@ -0,0 +1,211 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2026-03-05 21:05+0000\n" +"Last-Translator: Francisco Serrador \n" +"Language-Team: Spanish \n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.17-dev\n" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:89 +msgid "All" +msgstr "Todo" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:77 +msgid "Certificate of Origin" +msgstr "Certificado de origen" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:40 +msgid "" +"Cloudflare Zero Trust Security services help you get maximum security both " +"from outside and within the network." +msgstr "" +"Los servicios de seguridad Cloudflare Zero Trust le ayudan a obtener la " +"máxima seguridad tanto desde el exterior como dentro de la red." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:39 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:3 +msgid "Cloudflare Zero Trust Tunnel" +msgstr "Tunel Cloudflare Zero Trust" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:69 +msgid "Config file path" +msgstr "Ruta del archivo de configuración" + +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:14 +msgid "Configuration" +msgstr "Configuración" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:76 +msgid "Connection ID" +msgstr "ID de conexión" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:54 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:90 +msgid "Connections" +msgstr "Conexiones" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:41 +msgid "" +"Create and manage your network on the Cloudflare Zero Trust " +"dashboard." +msgstr "Cree y gestione su red en el panel Cloudflare Zero Trust." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:53 +msgid "Created At" +msgstr "Creado en" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:79 +msgid "Data Center" +msgstr "Centro de datos" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:97 +msgid "Debug" +msgstr "Depuración" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:96 +msgid "Down" +msgstr "Bajar" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:104 +msgid "Download Log" +msgstr "Descargar registro" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:59 +msgid "Enable" +msgstr "Activar" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:94 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:92 +msgid "Error" +msgstr "Error" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:93 +msgid "Fatal" +msgstr "Fatal" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:87 +msgid "Filter Level:" +msgstr "Nivel de filtro:" + +#: applications/luci-app-cloudflared/root/usr/share/rpcd/acl.d/luci-app-cloudflared.json:3 +msgid "Grant access to Cloudflared configuration" +msgstr "Permitir acceso a la configuración de Cloudflared" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:52 +msgid "ID" +msgstr "ID" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:96 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:90 +msgid "Info" +msgstr "Informe" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:85 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:30 +msgid "Log" +msgstr "Registro" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:94 +msgid "Log Direction:" +msgstr "Dirección de registro:" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:92 +msgid "Logging level" +msgstr "Nivel de depuración" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:51 +msgid "Name" +msgstr "Nombre" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:85 +msgid "No connections" +msgstr "Sin conexiones" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:55 +msgid "Not Running" +msgstr "No se está ejecutando" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:79 +msgid "Obtain a certificate here." +msgstr "Obtenga un certificado aquí." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:78 +msgid "Opened At" +msgstr "Abierto el" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:77 +msgid "Origin IP" +msgstr "IP de origen" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:86 +msgid "Region" +msgstr "Región" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:54 +msgid "Running" +msgstr "Ejecutando" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:43 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:70 +msgid "See documentation." +msgstr "Ver documentación." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:49 +msgid "Status" +msgstr "Estado" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:78 +msgid "" +"The account certificate for your zones authorizing the client to serve as an " +"Origin for that zone" +msgstr "" +"El certificado de cuenta para sus zonas que autoriza al cliente a actuar " +"como Origen para esa zona" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:87 +msgid "The region to which connections are established." +msgstr "La región con la que se establecen las conexiones." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:63 +msgid "The tunnel token is shown in the dashboard once you create a tunnel." +msgstr "El token del túnel se muestra en el panel una vez que crea un túnel." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:62 +msgid "Token" +msgstr "Token" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:96 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:22 +msgid "Tunnels" +msgstr "Túneles" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:48 +msgid "Tunnels Information" +msgstr "Información de túneles" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:33 +msgid "Unable to read the interface info from /var/log/cloudflared.log." +msgstr "" +"No se puede leer la información de la interfaz de /var/log/cloudflared.log." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:89 +msgid "United States" +msgstr "Estados Unidos" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:97 +msgid "Up" +msgstr "Subir" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:91 +msgid "Warn" +msgstr "Advertir" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:95 +msgid "Warning" +msgstr "Aviso" diff --git a/luci-app-cloudflared-next/po/et/cloudflared.po b/luci-app-cloudflared-next/po/et/cloudflared.po new file mode 100644 index 000000000..8e7f574b6 --- /dev/null +++ b/luci-app-cloudflared-next/po/et/cloudflared.po @@ -0,0 +1,201 @@ +msgid "" +msgstr "" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: et\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:89 +msgid "All" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:77 +msgid "Certificate of Origin" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:40 +msgid "" +"Cloudflare Zero Trust Security services help you get maximum security both " +"from outside and within the network." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:39 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:3 +msgid "Cloudflare Zero Trust Tunnel" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:69 +msgid "Config file path" +msgstr "" + +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:14 +msgid "Configuration" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:76 +msgid "Connection ID" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:54 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:90 +msgid "Connections" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:41 +msgid "" +"Create and manage your network on the Cloudflare Zero Trust " +"dashboard." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:53 +msgid "Created At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:79 +msgid "Data Center" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:97 +msgid "Debug" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:96 +msgid "Down" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:104 +msgid "Download Log" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:59 +msgid "Enable" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:94 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:92 +msgid "Error" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:93 +msgid "Fatal" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:87 +msgid "Filter Level:" +msgstr "" + +#: applications/luci-app-cloudflared/root/usr/share/rpcd/acl.d/luci-app-cloudflared.json:3 +msgid "Grant access to Cloudflared configuration" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:52 +msgid "ID" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:96 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:90 +msgid "Info" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:85 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:30 +msgid "Log" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:94 +msgid "Log Direction:" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:92 +msgid "Logging level" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:51 +msgid "Name" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:85 +msgid "No connections" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:55 +msgid "Not Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:79 +msgid "Obtain a certificate here." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:78 +msgid "Opened At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:77 +msgid "Origin IP" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:86 +msgid "Region" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:54 +msgid "Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:43 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:70 +msgid "See documentation." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:49 +msgid "Status" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:78 +msgid "" +"The account certificate for your zones authorizing the client to serve as an " +"Origin for that zone" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:87 +msgid "The region to which connections are established." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:63 +msgid "The tunnel token is shown in the dashboard once you create a tunnel." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:62 +msgid "Token" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:96 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:22 +msgid "Tunnels" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:48 +msgid "Tunnels Information" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:33 +msgid "Unable to read the interface info from /var/log/cloudflared.log." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:89 +msgid "United States" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:97 +msgid "Up" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:91 +msgid "Warn" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:95 +msgid "Warning" +msgstr "" diff --git a/luci-app-cloudflared-next/po/fa/cloudflared.po b/luci-app-cloudflared-next/po/fa/cloudflared.po new file mode 100644 index 000000000..b00d33da1 --- /dev/null +++ b/luci-app-cloudflared-next/po/fa/cloudflared.po @@ -0,0 +1,207 @@ +msgid "" +msgstr "" +"PO-Revision-Date: 2025-07-13 14:02+0000\n" +"Last-Translator: reza \n" +"Language-Team: Persian \n" +"Language: fa\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 5.13-dev\n" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:89 +msgid "All" +msgstr "همه" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:77 +msgid "Certificate of Origin" +msgstr "گواهی مبدا" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:40 +msgid "" +"Cloudflare Zero Trust Security services help you get maximum security both " +"from outside and within the network." +msgstr "" +"سرویس‌های امنیتی اعتماد صفر کلودفلر به شما کمک می‌کنند تا حداکثر امنیت را هم " +"از بیرون و هم از داخل شبکه داشته باشید." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:39 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:3 +msgid "Cloudflare Zero Trust Tunnel" +msgstr "تونل اعتماد صفر کلودفلر" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:69 +msgid "Config file path" +msgstr "مسیر فایل پیکربندی" + +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:14 +msgid "Configuration" +msgstr "پیکربندی" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:76 +msgid "Connection ID" +msgstr "شناسه اتصال" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:54 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:90 +msgid "Connections" +msgstr "اتصالات" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:41 +msgid "" +"Create and manage your network on the Cloudflare Zero Trust " +"dashboard." +msgstr "" +"شبکه خود را در داشبورد اعتماد صفر کلودفلر ایجاد و مدیریت کنید." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:53 +msgid "Created At" +msgstr "ایجاد شده در" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:79 +msgid "Data Center" +msgstr "مرکز داده" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:97 +msgid "Debug" +msgstr "اشکال‌زدایی" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:96 +msgid "Down" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:104 +msgid "Download Log" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:59 +msgid "Enable" +msgstr "فعال‌" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:94 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:92 +msgid "Error" +msgstr "خطا" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:93 +msgid "Fatal" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:87 +msgid "Filter Level:" +msgstr "" + +#: applications/luci-app-cloudflared/root/usr/share/rpcd/acl.d/luci-app-cloudflared.json:3 +msgid "Grant access to Cloudflared configuration" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:52 +msgid "ID" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:96 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:90 +msgid "Info" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:85 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:30 +msgid "Log" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:94 +msgid "Log Direction:" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:92 +msgid "Logging level" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:51 +msgid "Name" +msgstr "اسم" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:85 +msgid "No connections" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:55 +msgid "Not Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:79 +msgid "Obtain a certificate here." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:78 +msgid "Opened At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:77 +msgid "Origin IP" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:86 +msgid "Region" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:54 +msgid "Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:43 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:70 +msgid "See documentation." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:49 +msgid "Status" +msgstr "وضعیت" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:78 +msgid "" +"The account certificate for your zones authorizing the client to serve as an " +"Origin for that zone" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:87 +msgid "The region to which connections are established." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:63 +msgid "The tunnel token is shown in the dashboard once you create a tunnel." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:62 +msgid "Token" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:96 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:22 +msgid "Tunnels" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:48 +msgid "Tunnels Information" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:33 +msgid "Unable to read the interface info from /var/log/cloudflared.log." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:89 +msgid "United States" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:97 +msgid "Up" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:91 +msgid "Warn" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:95 +msgid "Warning" +msgstr "" diff --git a/luci-app-cloudflared-next/po/fi/cloudflared.po b/luci-app-cloudflared-next/po/fi/cloudflared.po new file mode 100644 index 000000000..e008ad173 --- /dev/null +++ b/luci-app-cloudflared-next/po/fi/cloudflared.po @@ -0,0 +1,206 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2025-07-22 08:17+0000\n" +"Last-Translator: Ricky Tigg \n" +"Language-Team: Finnish \n" +"Language: fi\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.13-dev\n" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:89 +msgid "All" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:77 +msgid "Certificate of Origin" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:40 +msgid "" +"Cloudflare Zero Trust Security services help you get maximum security both " +"from outside and within the network." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:39 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:3 +msgid "Cloudflare Zero Trust Tunnel" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:69 +msgid "Config file path" +msgstr "" + +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:14 +msgid "Configuration" +msgstr "Kokoonpano" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:76 +msgid "Connection ID" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:54 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:90 +msgid "Connections" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:41 +msgid "" +"Create and manage your network on the Cloudflare Zero Trust " +"dashboard." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:53 +msgid "Created At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:79 +msgid "Data Center" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:97 +msgid "Debug" +msgstr "Viankorjaus" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:96 +msgid "Down" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:104 +msgid "Download Log" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:59 +msgid "Enable" +msgstr "Ota käyttöön" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:94 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:92 +msgid "Error" +msgstr "Virhe" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:93 +msgid "Fatal" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:87 +msgid "Filter Level:" +msgstr "" + +#: applications/luci-app-cloudflared/root/usr/share/rpcd/acl.d/luci-app-cloudflared.json:3 +msgid "Grant access to Cloudflared configuration" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:52 +msgid "ID" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:96 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:90 +msgid "Info" +msgstr "Tiedot" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:85 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:30 +msgid "Log" +msgstr "Loki" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:94 +msgid "Log Direction:" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:92 +msgid "Logging level" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:51 +msgid "Name" +msgstr "Nimi" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:85 +msgid "No connections" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:55 +msgid "Not Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:79 +msgid "Obtain a certificate here." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:78 +msgid "Opened At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:77 +msgid "Origin IP" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:86 +msgid "Region" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:54 +msgid "Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:43 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:70 +msgid "See documentation." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:49 +msgid "Status" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:78 +msgid "" +"The account certificate for your zones authorizing the client to serve as an " +"Origin for that zone" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:87 +msgid "The region to which connections are established." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:63 +msgid "The tunnel token is shown in the dashboard once you create a tunnel." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:62 +msgid "Token" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:96 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:22 +msgid "Tunnels" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:48 +msgid "Tunnels Information" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:33 +msgid "Unable to read the interface info from /var/log/cloudflared.log." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:89 +msgid "United States" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:97 +msgid "Up" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:91 +msgid "Warn" +msgstr "Varoita" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:95 +msgid "Warning" +msgstr "" diff --git a/luci-app-cloudflared-next/po/fr/cloudflared.po b/luci-app-cloudflared-next/po/fr/cloudflared.po new file mode 100644 index 000000000..2f509013d --- /dev/null +++ b/luci-app-cloudflared-next/po/fr/cloudflared.po @@ -0,0 +1,208 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2025-11-28 05:06+0000\n" +"Last-Translator: Martin Devolder \n" +"Language-Team: French \n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 5.15-dev\n" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:89 +msgid "All" +msgstr "Tous" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:77 +msgid "Certificate of Origin" +msgstr "Certificat d'origine" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:40 +msgid "" +"Cloudflare Zero Trust Security services help you get maximum security both " +"from outside and within the network." +msgstr "" +"Les service de Zéro Trust de Cloudflare vous aident à avoir une sécurité " +"maximale à partir de l'intérieur et de l'extérieur de votre réseau." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:39 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:3 +msgid "Cloudflare Zero Trust Tunnel" +msgstr "Tunnel Zéro Trust de Cloudflare" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:69 +msgid "Config file path" +msgstr "" + +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:14 +msgid "Configuration" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:76 +msgid "Connection ID" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:54 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:90 +msgid "Connections" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:41 +msgid "" +"Create and manage your network on the Cloudflare Zero Trust " +"dashboard." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:53 +msgid "Created At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:79 +msgid "Data Center" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:97 +msgid "Debug" +msgstr "Débug" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:96 +msgid "Down" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:104 +msgid "Download Log" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:59 +msgid "Enable" +msgstr "Activer" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:94 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:92 +msgid "Error" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:93 +msgid "Fatal" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:87 +msgid "Filter Level:" +msgstr "" + +#: applications/luci-app-cloudflared/root/usr/share/rpcd/acl.d/luci-app-cloudflared.json:3 +msgid "Grant access to Cloudflared configuration" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:52 +msgid "ID" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:96 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:90 +msgid "Info" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:85 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:30 +msgid "Log" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:94 +msgid "Log Direction:" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:92 +msgid "Logging level" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:51 +msgid "Name" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:85 +msgid "No connections" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:55 +msgid "Not Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:79 +msgid "Obtain a certificate here." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:78 +msgid "Opened At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:77 +msgid "Origin IP" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:86 +msgid "Region" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:54 +msgid "Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:43 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:70 +msgid "See documentation." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:49 +msgid "Status" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:78 +msgid "" +"The account certificate for your zones authorizing the client to serve as an " +"Origin for that zone" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:87 +msgid "The region to which connections are established." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:63 +msgid "The tunnel token is shown in the dashboard once you create a tunnel." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:62 +msgid "Token" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:96 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:22 +msgid "Tunnels" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:48 +msgid "Tunnels Information" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:33 +msgid "Unable to read the interface info from /var/log/cloudflared.log." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:89 +msgid "United States" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:97 +msgid "Up" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:91 +msgid "Warn" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:95 +msgid "Warning" +msgstr "" diff --git a/luci-app-cloudflared-next/po/ga/cloudflared.po b/luci-app-cloudflared-next/po/ga/cloudflared.po new file mode 100644 index 000000000..2aca86c0f --- /dev/null +++ b/luci-app-cloudflared-next/po/ga/cloudflared.po @@ -0,0 +1,212 @@ +msgid "" +msgstr "" +"PO-Revision-Date: 2026-03-09 19:10+0000\n" +"Last-Translator: Aindriú Mac Giolla Eoin \n" +"Language-Team: Irish \n" +"Language: ga\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=5; plural=n==1 ? 0 : n==2 ? 1 : (n>2 && n<7) ? 2 :(n>" +"6 && n<11) ? 3 : 4;\n" +"X-Generator: Weblate 5.17-dev\n" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:89 +msgid "All" +msgstr "Gach" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:77 +msgid "Certificate of Origin" +msgstr "Deimhniú Tionscnaimh" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:40 +msgid "" +"Cloudflare Zero Trust Security services help you get maximum security both " +"from outside and within the network." +msgstr "" +"Cabhraíonn seirbhísí slándála Cloudflare Zero Trust leat an t-uasmhéid " +"slándála a fháil ón taobh amuigh agus laistigh den líonra." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:39 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:3 +msgid "Cloudflare Zero Trust Tunnel" +msgstr "Tollán Iontaobhas Zero Cloudflare" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:69 +msgid "Config file path" +msgstr "Cosán comhaid cumraíochta" + +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:14 +msgid "Configuration" +msgstr "Cumraíocht" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:76 +msgid "Connection ID" +msgstr "ID ceangail" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:54 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:90 +msgid "Connections" +msgstr "Naisc" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:41 +msgid "" +"Create and manage your network on the Cloudflare Zero Trust " +"dashboard." +msgstr "" +"Cruthaigh agus bainistigh do líonra ar an deais Cloudflare Zero Trust." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:53 +msgid "Created At" +msgstr "Cruthaithe Ag" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:79 +msgid "Data Center" +msgstr "Lárionad Sonraí" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:97 +msgid "Debug" +msgstr "Dífhabhtú" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:96 +msgid "Down" +msgstr "an Dúin" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:104 +msgid "Download Log" +msgstr "Íoslódáil an logáil isteach" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:59 +msgid "Enable" +msgstr "Cumasaigh" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:94 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:92 +msgid "Error" +msgstr "Earráid" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:93 +msgid "Fatal" +msgstr "Marfach" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:87 +msgid "Filter Level:" +msgstr "Leibhéal Scagaire:" + +#: applications/luci-app-cloudflared/root/usr/share/rpcd/acl.d/luci-app-cloudflared.json:3 +msgid "Grant access to Cloudflared configuration" +msgstr "Deonaigh rochtain ar chumraíocht Cloudflared" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:52 +msgid "ID" +msgstr "ID" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:96 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:90 +msgid "Info" +msgstr "Eolas" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:85 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:30 +msgid "Log" +msgstr "Loga" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:94 +msgid "Log Direction:" +msgstr "Treo Loga:" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:92 +msgid "Logging level" +msgstr "Leibhéal logáil" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:51 +msgid "Name" +msgstr "Ainm" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:85 +msgid "No connections" +msgstr "Gan naisc" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:55 +msgid "Not Running" +msgstr "Gan Rith" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:79 +msgid "Obtain a certificate here." +msgstr "Faigh teastas anseo." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:78 +msgid "Opened At" +msgstr "Osclaíodh Ag" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:77 +msgid "Origin IP" +msgstr "IP tionscnaimh" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:86 +msgid "Region" +msgstr "Réigiún" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:54 +msgid "Running" +msgstr "Ag rith" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:43 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:70 +msgid "See documentation." +msgstr "Féach ar doiciméadúchán." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:49 +msgid "Status" +msgstr "Stádas" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:78 +msgid "" +"The account certificate for your zones authorizing the client to serve as an " +"Origin for that zone" +msgstr "" +"An teastas cuntais le do chriosanna a údaraíonn don chliant feidhmiú mar " +"Bhunús don chrios sin" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:87 +msgid "The region to which connections are established." +msgstr "An réigiún lena mbunaítear naisc." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:63 +msgid "The tunnel token is shown in the dashboard once you create a tunnel." +msgstr "" +"Taispeántar comhartha an tolláin ar an deais nuair a chruthaíonn tú tollán." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:62 +msgid "Token" +msgstr "Comhartha" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:96 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:22 +msgid "Tunnels" +msgstr "Tolláin" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:48 +msgid "Tunnels Information" +msgstr "Eolas Tolláin" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:33 +msgid "Unable to read the interface info from /var/log/cloudflared.log." +msgstr "Ní féidir faisnéis an chomhéadain ó /var/log/cloudflared.log a léamh." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:89 +msgid "United States" +msgstr "Stáit Aontaithe Mheiriceá" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:97 +msgid "Up" +msgstr "Suas" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:91 +msgid "Warn" +msgstr "Rabhadh" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:95 +msgid "Warning" +msgstr "Aire" diff --git a/luci-app-cloudflared-next/po/he/cloudflared.po b/luci-app-cloudflared-next/po/he/cloudflared.po new file mode 100644 index 000000000..745c12c5b --- /dev/null +++ b/luci-app-cloudflared-next/po/he/cloudflared.po @@ -0,0 +1,203 @@ +msgid "" +msgstr "" +"Content-Type: text/plain; charset=UTF-8\n" +"Project-Id-Version: PACKAGE VERSION\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: he\n" +"MIME-Version: 1.0\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:89 +msgid "All" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:77 +msgid "Certificate of Origin" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:40 +msgid "" +"Cloudflare Zero Trust Security services help you get maximum security both " +"from outside and within the network." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:39 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:3 +msgid "Cloudflare Zero Trust Tunnel" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:69 +msgid "Config file path" +msgstr "" + +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:14 +msgid "Configuration" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:76 +msgid "Connection ID" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:54 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:90 +msgid "Connections" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:41 +msgid "" +"Create and manage your network on the Cloudflare Zero Trust " +"dashboard." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:53 +msgid "Created At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:79 +msgid "Data Center" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:97 +msgid "Debug" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:96 +msgid "Down" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:104 +msgid "Download Log" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:59 +msgid "Enable" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:94 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:92 +msgid "Error" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:93 +msgid "Fatal" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:87 +msgid "Filter Level:" +msgstr "" + +#: applications/luci-app-cloudflared/root/usr/share/rpcd/acl.d/luci-app-cloudflared.json:3 +msgid "Grant access to Cloudflared configuration" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:52 +msgid "ID" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:96 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:90 +msgid "Info" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:85 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:30 +msgid "Log" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:94 +msgid "Log Direction:" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:92 +msgid "Logging level" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:51 +msgid "Name" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:85 +msgid "No connections" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:55 +msgid "Not Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:79 +msgid "Obtain a certificate here." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:78 +msgid "Opened At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:77 +msgid "Origin IP" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:86 +msgid "Region" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:54 +msgid "Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:43 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:70 +msgid "See documentation." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:49 +msgid "Status" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:78 +msgid "" +"The account certificate for your zones authorizing the client to serve as an " +"Origin for that zone" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:87 +msgid "The region to which connections are established." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:63 +msgid "The tunnel token is shown in the dashboard once you create a tunnel." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:62 +msgid "Token" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:96 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:22 +msgid "Tunnels" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:48 +msgid "Tunnels Information" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:33 +msgid "Unable to read the interface info from /var/log/cloudflared.log." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:89 +msgid "United States" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:97 +msgid "Up" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:91 +msgid "Warn" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:95 +msgid "Warning" +msgstr "" diff --git a/luci-app-cloudflared-next/po/hi/cloudflared.po b/luci-app-cloudflared-next/po/hi/cloudflared.po new file mode 100644 index 000000000..39a5f9b47 --- /dev/null +++ b/luci-app-cloudflared-next/po/hi/cloudflared.po @@ -0,0 +1,206 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2024-07-06 11:32+0000\n" +"Last-Translator: Sathvic \n" +"Language-Team: Hindi \n" +"Language: hi\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 5.7-dev\n" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:89 +msgid "All" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:77 +msgid "Certificate of Origin" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:40 +msgid "" +"Cloudflare Zero Trust Security services help you get maximum security both " +"from outside and within the network." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:39 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:3 +msgid "Cloudflare Zero Trust Tunnel" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:69 +msgid "Config file path" +msgstr "" + +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:14 +msgid "Configuration" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:76 +msgid "Connection ID" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:54 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:90 +msgid "Connections" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:41 +msgid "" +"Create and manage your network on the Cloudflare Zero Trust " +"dashboard." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:53 +msgid "Created At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:79 +msgid "Data Center" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:97 +msgid "Debug" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:96 +msgid "Down" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:104 +msgid "Download Log" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:59 +msgid "Enable" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:94 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:92 +msgid "Error" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:93 +msgid "Fatal" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:87 +msgid "Filter Level:" +msgstr "" + +#: applications/luci-app-cloudflared/root/usr/share/rpcd/acl.d/luci-app-cloudflared.json:3 +msgid "Grant access to Cloudflared configuration" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:52 +msgid "ID" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:96 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:90 +msgid "Info" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:85 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:30 +msgid "Log" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:94 +msgid "Log Direction:" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:92 +msgid "Logging level" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:51 +msgid "Name" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:85 +msgid "No connections" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:55 +msgid "Not Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:79 +msgid "Obtain a certificate here." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:78 +msgid "Opened At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:77 +msgid "Origin IP" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:86 +msgid "Region" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:54 +msgid "Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:43 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:70 +msgid "See documentation." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:49 +msgid "Status" +msgstr "स्थिति" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:78 +msgid "" +"The account certificate for your zones authorizing the client to serve as an " +"Origin for that zone" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:87 +msgid "The region to which connections are established." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:63 +msgid "The tunnel token is shown in the dashboard once you create a tunnel." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:62 +msgid "Token" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:96 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:22 +msgid "Tunnels" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:48 +msgid "Tunnels Information" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:33 +msgid "Unable to read the interface info from /var/log/cloudflared.log." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:89 +msgid "United States" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:97 +msgid "Up" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:91 +msgid "Warn" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:95 +msgid "Warning" +msgstr "" diff --git a/luci-app-cloudflared-next/po/hu/cloudflared.po b/luci-app-cloudflared-next/po/hu/cloudflared.po new file mode 100644 index 000000000..3cd86b291 --- /dev/null +++ b/luci-app-cloudflared-next/po/hu/cloudflared.po @@ -0,0 +1,206 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2026-03-08 17:32+0000\n" +"Last-Translator: hmzs \n" +"Language-Team: Hungarian \n" +"Language: hu\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.17-dev\n" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:89 +msgid "All" +msgstr "Minden" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:77 +msgid "Certificate of Origin" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:40 +msgid "" +"Cloudflare Zero Trust Security services help you get maximum security both " +"from outside and within the network." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:39 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:3 +msgid "Cloudflare Zero Trust Tunnel" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:69 +msgid "Config file path" +msgstr "" + +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:14 +msgid "Configuration" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:76 +msgid "Connection ID" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:54 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:90 +msgid "Connections" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:41 +msgid "" +"Create and manage your network on the Cloudflare Zero Trust " +"dashboard." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:53 +msgid "Created At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:79 +msgid "Data Center" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:97 +msgid "Debug" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:96 +msgid "Down" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:104 +msgid "Download Log" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:59 +msgid "Enable" +msgstr "Engedélyezés" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:94 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:92 +msgid "Error" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:93 +msgid "Fatal" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:87 +msgid "Filter Level:" +msgstr "" + +#: applications/luci-app-cloudflared/root/usr/share/rpcd/acl.d/luci-app-cloudflared.json:3 +msgid "Grant access to Cloudflared configuration" +msgstr "Hozzáférés engedélyezése az Cloudflared beállításaihoz" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:52 +msgid "ID" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:96 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:90 +msgid "Info" +msgstr "Infó" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:85 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:30 +msgid "Log" +msgstr "Napló" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:94 +msgid "Log Direction:" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:92 +msgid "Logging level" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:51 +msgid "Name" +msgstr "Név" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:85 +msgid "No connections" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:55 +msgid "Not Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:79 +msgid "Obtain a certificate here." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:78 +msgid "Opened At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:77 +msgid "Origin IP" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:86 +msgid "Region" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:54 +msgid "Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:43 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:70 +msgid "See documentation." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:49 +msgid "Status" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:78 +msgid "" +"The account certificate for your zones authorizing the client to serve as an " +"Origin for that zone" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:87 +msgid "The region to which connections are established." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:63 +msgid "The tunnel token is shown in the dashboard once you create a tunnel." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:62 +msgid "Token" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:96 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:22 +msgid "Tunnels" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:48 +msgid "Tunnels Information" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:33 +msgid "Unable to read the interface info from /var/log/cloudflared.log." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:89 +msgid "United States" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:97 +msgid "Up" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:91 +msgid "Warn" +msgstr "Figyelmeztetés" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:95 +msgid "Warning" +msgstr "" diff --git a/luci-app-cloudflared-next/po/it/cloudflared.po b/luci-app-cloudflared-next/po/it/cloudflared.po new file mode 100644 index 000000000..64e36e4f6 --- /dev/null +++ b/luci-app-cloudflared-next/po/it/cloudflared.po @@ -0,0 +1,210 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2025-11-25 16:35+0000\n" +"Last-Translator: Alex Caserini \n" +"Language-Team: Italian \n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.15-dev\n" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:89 +msgid "All" +msgstr "Tutti" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:77 +msgid "Certificate of Origin" +msgstr "Certificato d'origine" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:40 +msgid "" +"Cloudflare Zero Trust Security services help you get maximum security both " +"from outside and within the network." +msgstr "" +"I servizi di sicurezza Cloudflare Zero Trust ti aiutano a ottenere la " +"massima sicurezza sia dall'esterno che all'interno della rete." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:39 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:3 +msgid "Cloudflare Zero Trust Tunnel" +msgstr "Tunnel Cloudflare Zero Trust" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:69 +msgid "Config file path" +msgstr "Path file di configurazione" + +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:14 +msgid "Configuration" +msgstr "Configurazione" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:76 +msgid "Connection ID" +msgstr "ID di connessione" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:54 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:90 +msgid "Connections" +msgstr "Connessioni" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:41 +msgid "" +"Create and manage your network on the Cloudflare Zero Trust " +"dashboard." +msgstr "" +"Crea e gestisci la tua rete nella dashboard di Cloudflare Zero Trust." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:53 +msgid "Created At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:79 +msgid "Data Center" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:97 +msgid "Debug" +msgstr "Debug" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:96 +msgid "Down" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:104 +msgid "Download Log" +msgstr "Registro Download" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:59 +msgid "Enable" +msgstr "Abilitare" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:94 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:92 +msgid "Error" +msgstr "Errore" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:93 +msgid "Fatal" +msgstr "Fatale" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:87 +msgid "Filter Level:" +msgstr "Livello Filtro:" + +#: applications/luci-app-cloudflared/root/usr/share/rpcd/acl.d/luci-app-cloudflared.json:3 +msgid "Grant access to Cloudflared configuration" +msgstr "Concedere l'accesso alla configurazione Cloudflarizzata" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:52 +msgid "ID" +msgstr "ID" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:96 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:90 +msgid "Info" +msgstr "Info" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:85 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:30 +msgid "Log" +msgstr "Registro" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:94 +msgid "Log Direction:" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:92 +msgid "Logging level" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:51 +msgid "Name" +msgstr "Nome" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:85 +msgid "No connections" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:55 +msgid "Not Running" +msgstr "Non in esecuzione" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:79 +msgid "Obtain a certificate here." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:78 +msgid "Opened At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:77 +msgid "Origin IP" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:86 +msgid "Region" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:54 +msgid "Running" +msgstr "In esecuzione" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:43 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:70 +msgid "See documentation." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:49 +msgid "Status" +msgstr "Stato" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:78 +msgid "" +"The account certificate for your zones authorizing the client to serve as an " +"Origin for that zone" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:87 +msgid "The region to which connections are established." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:63 +msgid "The tunnel token is shown in the dashboard once you create a tunnel." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:62 +msgid "Token" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:96 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:22 +msgid "Tunnels" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:48 +msgid "Tunnels Information" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:33 +msgid "Unable to read the interface info from /var/log/cloudflared.log." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:89 +msgid "United States" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:97 +msgid "Up" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:91 +msgid "Warn" +msgstr "Avvisa" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:95 +msgid "Warning" +msgstr "Avviso" diff --git a/luci-app-cloudflared-next/po/ja/cloudflared.po b/luci-app-cloudflared-next/po/ja/cloudflared.po new file mode 100644 index 000000000..0efc0caa3 --- /dev/null +++ b/luci-app-cloudflared-next/po/ja/cloudflared.po @@ -0,0 +1,207 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2025-12-07 21:54+0000\n" +"Last-Translator: Monarch " +"\n" +"Language-Team: Japanese \n" +"Language: ja\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Weblate 5.15-dev\n" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:89 +msgid "All" +msgstr "すべて" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:77 +msgid "Certificate of Origin" +msgstr "オリジン証明書" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:40 +msgid "" +"Cloudflare Zero Trust Security services help you get maximum security both " +"from outside and within the network." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:39 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:3 +msgid "Cloudflare Zero Trust Tunnel" +msgstr "Cloudflare Zero Trust Tunnel" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:69 +msgid "Config file path" +msgstr "構成ファイルのパス" + +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:14 +msgid "Configuration" +msgstr "設定" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:76 +msgid "Connection ID" +msgstr "接続 ID" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:54 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:90 +msgid "Connections" +msgstr "接続" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:41 +msgid "" +"Create and manage your network on the Cloudflare Zero Trust " +"dashboard." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:53 +msgid "Created At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:79 +msgid "Data Center" +msgstr "データ センター" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:97 +msgid "Debug" +msgstr "デバッグ" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:96 +msgid "Down" +msgstr "停止中" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:104 +msgid "Download Log" +msgstr "ログをダウンロード" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:59 +msgid "Enable" +msgstr "有効化" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:94 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:92 +msgid "Error" +msgstr "エラー" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:93 +msgid "Fatal" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:87 +msgid "Filter Level:" +msgstr "" + +#: applications/luci-app-cloudflared/root/usr/share/rpcd/acl.d/luci-app-cloudflared.json:3 +msgid "Grant access to Cloudflared configuration" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:52 +msgid "ID" +msgstr "ID" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:96 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:90 +msgid "Info" +msgstr "情報" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:85 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:30 +msgid "Log" +msgstr "ログ" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:94 +msgid "Log Direction:" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:92 +msgid "Logging level" +msgstr "ログ レベル" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:51 +msgid "Name" +msgstr "名前" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:85 +msgid "No connections" +msgstr "接続がありません" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:55 +msgid "Not Running" +msgstr "停止中" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:79 +msgid "Obtain a certificate here." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:78 +msgid "Opened At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:77 +msgid "Origin IP" +msgstr "オリジン IP" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:86 +msgid "Region" +msgstr "地域" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:54 +msgid "Running" +msgstr "実行中" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:43 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:70 +msgid "See documentation." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:49 +msgid "Status" +msgstr "状態" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:78 +msgid "" +"The account certificate for your zones authorizing the client to serve as an " +"Origin for that zone" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:87 +msgid "The region to which connections are established." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:63 +msgid "The tunnel token is shown in the dashboard once you create a tunnel." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:62 +msgid "Token" +msgstr "トークン" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:96 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:22 +msgid "Tunnels" +msgstr "トンネル" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:48 +msgid "Tunnels Information" +msgstr "トンネル情報" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:33 +msgid "Unable to read the interface info from /var/log/cloudflared.log." +msgstr "/var/log/cloudflared.log からインターフェース情報を読み込めません。" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:89 +msgid "United States" +msgstr "アメリカ合衆国" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:97 +msgid "Up" +msgstr "起動中" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:91 +msgid "Warn" +msgstr "警告" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:95 +msgid "Warning" +msgstr "警告" diff --git a/luci-app-cloudflared-next/po/ko/cloudflared.po b/luci-app-cloudflared-next/po/ko/cloudflared.po new file mode 100644 index 000000000..3bf989d69 --- /dev/null +++ b/luci-app-cloudflared-next/po/ko/cloudflared.po @@ -0,0 +1,206 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2026-02-07 16:33+0000\n" +"Last-Translator: Hyeonjeong Lee \n" +"Language-Team: Korean \n" +"Language: ko\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Weblate 5.16-dev\n" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:89 +msgid "All" +msgstr "전체" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:77 +msgid "Certificate of Origin" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:40 +msgid "" +"Cloudflare Zero Trust Security services help you get maximum security both " +"from outside and within the network." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:39 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:3 +msgid "Cloudflare Zero Trust Tunnel" +msgstr "Cloudflare Zero Trust 터널" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:69 +msgid "Config file path" +msgstr "설정 파일 경로" + +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:14 +msgid "Configuration" +msgstr "설정" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:76 +msgid "Connection ID" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:54 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:90 +msgid "Connections" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:41 +msgid "" +"Create and manage your network on the Cloudflare Zero Trust " +"dashboard." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:53 +msgid "Created At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:79 +msgid "Data Center" +msgstr "데이터 센터" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:97 +msgid "Debug" +msgstr "디버그" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:96 +msgid "Down" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:104 +msgid "Download Log" +msgstr "로그 다운로드" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:59 +msgid "Enable" +msgstr "활성화" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:94 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:92 +msgid "Error" +msgstr "오류(Error)" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:93 +msgid "Fatal" +msgstr "심각(Fatal)" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:87 +msgid "Filter Level:" +msgstr "필터 수준:" + +#: applications/luci-app-cloudflared/root/usr/share/rpcd/acl.d/luci-app-cloudflared.json:3 +msgid "Grant access to Cloudflared configuration" +msgstr "Cloudflared 설정에 접근 권한 부여" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:52 +msgid "ID" +msgstr "ID" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:96 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:90 +msgid "Info" +msgstr "정보(Info)" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:85 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:30 +msgid "Log" +msgstr "로그" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:94 +msgid "Log Direction:" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:92 +msgid "Logging level" +msgstr "로그 기록 수준" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:51 +msgid "Name" +msgstr "이름" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:85 +msgid "No connections" +msgstr "연결된 내역이 없습니다" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:55 +msgid "Not Running" +msgstr "중지됨" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:79 +msgid "Obtain a certificate here." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:78 +msgid "Opened At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:77 +msgid "Origin IP" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:86 +msgid "Region" +msgstr "지역" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:54 +msgid "Running" +msgstr "실행 중" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:43 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:70 +msgid "See documentation." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:49 +msgid "Status" +msgstr "상태" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:78 +msgid "" +"The account certificate for your zones authorizing the client to serve as an " +"Origin for that zone" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:87 +msgid "The region to which connections are established." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:63 +msgid "The tunnel token is shown in the dashboard once you create a tunnel." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:62 +msgid "Token" +msgstr "토큰" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:96 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:22 +msgid "Tunnels" +msgstr "터널" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:48 +msgid "Tunnels Information" +msgstr "터널 정보" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:33 +msgid "Unable to read the interface info from /var/log/cloudflared.log." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:89 +msgid "United States" +msgstr "미국" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:97 +msgid "Up" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:91 +msgid "Warn" +msgstr "경고(Warn)" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:95 +msgid "Warning" +msgstr "경고(Warning)" diff --git a/luci-app-cloudflared-next/po/lt/cloudflared.po b/luci-app-cloudflared-next/po/lt/cloudflared.po new file mode 100644 index 000000000..0dd9f3bf1 --- /dev/null +++ b/luci-app-cloudflared-next/po/lt/cloudflared.po @@ -0,0 +1,218 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2026-03-10 17:04+0000\n" +"Last-Translator: Džiugas Januševičius \n" +"Language-Team: Lithuanian \n" +"Language: lt\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " +"(n%100<10 || n%100>=20) ? 1 : 2);\n" +"X-Generator: Weblate 5.17-dev\n" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:89 +msgid "All" +msgstr "Visi" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:77 +msgid "Certificate of Origin" +msgstr "Kilmės sertifikatas" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:40 +msgid "" +"Cloudflare Zero Trust Security services help you get maximum security both " +"from outside and within the network." +msgstr "" +"„Cloudflare; Nulinio pasitikėjimo“ apsaugos tarnybos padeda Jums gauti " +"maksimalią apsaugą nuo išorės ir vidaus tinklo." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:39 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:3 +msgid "Cloudflare Zero Trust Tunnel" +msgstr "„Cloudflare; Nulinio pasitikėjimo tunelis“" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:69 +msgid "Config file path" +msgstr "Konfigūracijos failo kelias" + +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:14 +msgid "Configuration" +msgstr "Konfigūracija" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:76 +msgid "Connection ID" +msgstr "Prisijungimo ID" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:54 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:90 +msgid "Connections" +msgstr "Prisijungimai" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:41 +msgid "" +"Create and manage your network on the Cloudflare Zero Trust " +"dashboard." +msgstr "" +"Sukurti ir valdyti savo tinklą per „Cloudflare; Nulinis " +"pasitikėjimas“ ataskaitų skydelį." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:53 +msgid "Created At" +msgstr "Sukurta –" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:79 +msgid "Data Center" +msgstr "Duomenų centras" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:97 +msgid "Debug" +msgstr "Derinimas/Trukdžių šalinimas" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:96 +msgid "Down" +msgstr "Žemyn" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:104 +msgid "Download Log" +msgstr "Atsisiuntimo žurnalas" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:59 +msgid "Enable" +msgstr "Įjungti/Įgalinti" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:94 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:92 +msgid "Error" +msgstr "Klaida" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:93 +msgid "Fatal" +msgstr "Kritinė" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:87 +msgid "Filter Level:" +msgstr "Filtro lygis:" + +#: applications/luci-app-cloudflared/root/usr/share/rpcd/acl.d/luci-app-cloudflared.json:3 +msgid "Grant access to Cloudflared configuration" +msgstr "Duoti prieigą prie „Cloudflared“ konfigūracijos" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:52 +msgid "ID" +msgstr "ID – Identifikatorius" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:96 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:90 +msgid "Info" +msgstr "Informacija" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:85 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:30 +msgid "Log" +msgstr "Žurnalas" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:94 +msgid "Log Direction:" +msgstr "Žurnalo kryptis:" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:92 +msgid "Logging level" +msgstr "Žurnalinimo lygis" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:51 +msgid "Name" +msgstr "Pavadinimas" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:85 +msgid "No connections" +msgstr "Nėra prisijungimų" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:55 +msgid "Not Running" +msgstr "Neveikia" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:79 +msgid "Obtain a certificate here." +msgstr "Gauti sertifikatą čia." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:78 +msgid "Opened At" +msgstr "Atidaryta –" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:77 +msgid "Origin IP" +msgstr "Kilmės IP" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:86 +msgid "Region" +msgstr "Regionas" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:54 +msgid "Running" +msgstr "Veikia" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:43 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:70 +msgid "See documentation." +msgstr "Peržiūrėti dokumentaciją." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:49 +msgid "Status" +msgstr "Būklė/Būsena" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:78 +msgid "" +"The account certificate for your zones authorizing the client to serve as an " +"Origin for that zone" +msgstr "" +"Paskyros sertifikatas Jūsų zonoms, autorizuojant klientą, kad tarnautu kaip " +"kilmė(?) („Origin“) tai zonai" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:87 +msgid "The region to which connections are established." +msgstr "Regionas, kuriame prisijungimai yra įtvirtinti." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:63 +msgid "The tunnel token is shown in the dashboard once you create a tunnel." +msgstr "" +"„Tunelio“ – Tinklo protokolo, skirto šifruoti/pereiti į kitą tinklą žetonas " +"yra rodomas ataskaitų skydelyje, kai Jūs sukuriate „tunelį“ – tinklo " +"protokolą, skirta šifruoti/pereiti į kitą tinklą." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:62 +msgid "Token" +msgstr "Žetonas" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:96 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:22 +msgid "Tunnels" +msgstr "„Tuneliai“ – Tinklo protokolai" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:48 +msgid "Tunnels Information" +msgstr "" +"„Tunelių“ – Tinklo protokolas, skirtas šifruoti/pereiti į kitus tinklus " +"informacija" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:33 +msgid "Unable to read the interface info from /var/log/cloudflared.log." +msgstr "Nepavyko skaityti sąsajos informacijos iš „/var/log/cloudflared.log“." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:89 +msgid "United States" +msgstr "Jungtinės Amerikos Valstijos" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:97 +msgid "Up" +msgstr "Viršun/Aukštyn" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:91 +msgid "Warn" +msgstr "Įspėti" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:95 +msgid "Warning" +msgstr "Įspėjimas" diff --git a/luci-app-cloudflared-next/po/mr/cloudflared.po b/luci-app-cloudflared-next/po/mr/cloudflared.po new file mode 100644 index 000000000..585b4048c --- /dev/null +++ b/luci-app-cloudflared-next/po/mr/cloudflared.po @@ -0,0 +1,202 @@ +msgid "" +msgstr "" +"Content-Type: text/plain; charset=UTF-8\n" +"Project-Id-Version: PACKAGE VERSION\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: mr\n" +"MIME-Version: 1.0\n" +"Content-Transfer-Encoding: 8bit\n" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:89 +msgid "All" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:77 +msgid "Certificate of Origin" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:40 +msgid "" +"Cloudflare Zero Trust Security services help you get maximum security both " +"from outside and within the network." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:39 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:3 +msgid "Cloudflare Zero Trust Tunnel" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:69 +msgid "Config file path" +msgstr "" + +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:14 +msgid "Configuration" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:76 +msgid "Connection ID" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:54 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:90 +msgid "Connections" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:41 +msgid "" +"Create and manage your network on the Cloudflare Zero Trust " +"dashboard." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:53 +msgid "Created At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:79 +msgid "Data Center" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:97 +msgid "Debug" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:96 +msgid "Down" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:104 +msgid "Download Log" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:59 +msgid "Enable" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:94 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:92 +msgid "Error" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:93 +msgid "Fatal" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:87 +msgid "Filter Level:" +msgstr "" + +#: applications/luci-app-cloudflared/root/usr/share/rpcd/acl.d/luci-app-cloudflared.json:3 +msgid "Grant access to Cloudflared configuration" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:52 +msgid "ID" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:96 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:90 +msgid "Info" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:85 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:30 +msgid "Log" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:94 +msgid "Log Direction:" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:92 +msgid "Logging level" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:51 +msgid "Name" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:85 +msgid "No connections" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:55 +msgid "Not Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:79 +msgid "Obtain a certificate here." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:78 +msgid "Opened At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:77 +msgid "Origin IP" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:86 +msgid "Region" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:54 +msgid "Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:43 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:70 +msgid "See documentation." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:49 +msgid "Status" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:78 +msgid "" +"The account certificate for your zones authorizing the client to serve as an " +"Origin for that zone" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:87 +msgid "The region to which connections are established." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:63 +msgid "The tunnel token is shown in the dashboard once you create a tunnel." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:62 +msgid "Token" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:96 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:22 +msgid "Tunnels" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:48 +msgid "Tunnels Information" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:33 +msgid "Unable to read the interface info from /var/log/cloudflared.log." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:89 +msgid "United States" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:97 +msgid "Up" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:91 +msgid "Warn" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:95 +msgid "Warning" +msgstr "" diff --git a/luci-app-cloudflared-next/po/ms/cloudflared.po b/luci-app-cloudflared-next/po/ms/cloudflared.po new file mode 100644 index 000000000..367ffa321 --- /dev/null +++ b/luci-app-cloudflared-next/po/ms/cloudflared.po @@ -0,0 +1,202 @@ +msgid "" +msgstr "" +"Content-Type: text/plain; charset=UTF-8\n" +"Project-Id-Version: PACKAGE VERSION\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: ms\n" +"MIME-Version: 1.0\n" +"Content-Transfer-Encoding: 8bit\n" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:89 +msgid "All" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:77 +msgid "Certificate of Origin" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:40 +msgid "" +"Cloudflare Zero Trust Security services help you get maximum security both " +"from outside and within the network." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:39 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:3 +msgid "Cloudflare Zero Trust Tunnel" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:69 +msgid "Config file path" +msgstr "" + +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:14 +msgid "Configuration" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:76 +msgid "Connection ID" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:54 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:90 +msgid "Connections" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:41 +msgid "" +"Create and manage your network on the Cloudflare Zero Trust " +"dashboard." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:53 +msgid "Created At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:79 +msgid "Data Center" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:97 +msgid "Debug" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:96 +msgid "Down" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:104 +msgid "Download Log" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:59 +msgid "Enable" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:94 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:92 +msgid "Error" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:93 +msgid "Fatal" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:87 +msgid "Filter Level:" +msgstr "" + +#: applications/luci-app-cloudflared/root/usr/share/rpcd/acl.d/luci-app-cloudflared.json:3 +msgid "Grant access to Cloudflared configuration" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:52 +msgid "ID" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:96 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:90 +msgid "Info" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:85 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:30 +msgid "Log" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:94 +msgid "Log Direction:" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:92 +msgid "Logging level" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:51 +msgid "Name" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:85 +msgid "No connections" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:55 +msgid "Not Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:79 +msgid "Obtain a certificate here." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:78 +msgid "Opened At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:77 +msgid "Origin IP" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:86 +msgid "Region" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:54 +msgid "Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:43 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:70 +msgid "See documentation." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:49 +msgid "Status" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:78 +msgid "" +"The account certificate for your zones authorizing the client to serve as an " +"Origin for that zone" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:87 +msgid "The region to which connections are established." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:63 +msgid "The tunnel token is shown in the dashboard once you create a tunnel." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:62 +msgid "Token" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:96 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:22 +msgid "Tunnels" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:48 +msgid "Tunnels Information" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:33 +msgid "Unable to read the interface info from /var/log/cloudflared.log." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:89 +msgid "United States" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:97 +msgid "Up" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:91 +msgid "Warn" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:95 +msgid "Warning" +msgstr "" diff --git a/luci-app-cloudflared-next/po/nb_NO/cloudflared.po b/luci-app-cloudflared-next/po/nb_NO/cloudflared.po new file mode 100644 index 000000000..11544580d --- /dev/null +++ b/luci-app-cloudflared-next/po/nb_NO/cloudflared.po @@ -0,0 +1,206 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2025-03-14 09:11+0000\n" +"Last-Translator: Lasse Skogland \n" +"Language-Team: Norwegian Bokmål \n" +"Language: nb_NO\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.11-dev\n" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:89 +msgid "All" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:77 +msgid "Certificate of Origin" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:40 +msgid "" +"Cloudflare Zero Trust Security services help you get maximum security both " +"from outside and within the network." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:39 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:3 +msgid "Cloudflare Zero Trust Tunnel" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:69 +msgid "Config file path" +msgstr "" + +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:14 +msgid "Configuration" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:76 +msgid "Connection ID" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:54 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:90 +msgid "Connections" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:41 +msgid "" +"Create and manage your network on the Cloudflare Zero Trust " +"dashboard." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:53 +msgid "Created At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:79 +msgid "Data Center" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:97 +msgid "Debug" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:96 +msgid "Down" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:104 +msgid "Download Log" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:59 +msgid "Enable" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:94 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:92 +msgid "Error" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:93 +msgid "Fatal" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:87 +msgid "Filter Level:" +msgstr "" + +#: applications/luci-app-cloudflared/root/usr/share/rpcd/acl.d/luci-app-cloudflared.json:3 +msgid "Grant access to Cloudflared configuration" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:52 +msgid "ID" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:96 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:90 +msgid "Info" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:85 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:30 +msgid "Log" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:94 +msgid "Log Direction:" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:92 +msgid "Logging level" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:51 +msgid "Name" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:85 +msgid "No connections" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:55 +msgid "Not Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:79 +msgid "Obtain a certificate here." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:78 +msgid "Opened At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:77 +msgid "Origin IP" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:86 +msgid "Region" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:54 +msgid "Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:43 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:70 +msgid "See documentation." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:49 +msgid "Status" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:78 +msgid "" +"The account certificate for your zones authorizing the client to serve as an " +"Origin for that zone" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:87 +msgid "The region to which connections are established." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:63 +msgid "The tunnel token is shown in the dashboard once you create a tunnel." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:62 +msgid "Token" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:96 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:22 +msgid "Tunnels" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:48 +msgid "Tunnels Information" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:33 +msgid "Unable to read the interface info from /var/log/cloudflared.log." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:89 +msgid "United States" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:97 +msgid "Up" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:91 +msgid "Warn" +msgstr "Advar" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:95 +msgid "Warning" +msgstr "" diff --git a/luci-app-cloudflared-next/po/nl/cloudflared.po b/luci-app-cloudflared-next/po/nl/cloudflared.po new file mode 100644 index 000000000..734e22e24 --- /dev/null +++ b/luci-app-cloudflared-next/po/nl/cloudflared.po @@ -0,0 +1,206 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2026-01-10 04:39+0000\n" +"Last-Translator: Marco Otto \n" +"Language-Team: Dutch \n" +"Language: nl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.15.1\n" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:89 +msgid "All" +msgstr "Alle" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:77 +msgid "Certificate of Origin" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:40 +msgid "" +"Cloudflare Zero Trust Security services help you get maximum security both " +"from outside and within the network." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:39 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:3 +msgid "Cloudflare Zero Trust Tunnel" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:69 +msgid "Config file path" +msgstr "" + +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:14 +msgid "Configuration" +msgstr "Configuratie" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:76 +msgid "Connection ID" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:54 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:90 +msgid "Connections" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:41 +msgid "" +"Create and manage your network on the Cloudflare Zero Trust " +"dashboard." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:53 +msgid "Created At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:79 +msgid "Data Center" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:97 +msgid "Debug" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:96 +msgid "Down" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:104 +msgid "Download Log" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:59 +msgid "Enable" +msgstr "Inschakelen" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:94 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:92 +msgid "Error" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:93 +msgid "Fatal" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:87 +msgid "Filter Level:" +msgstr "" + +#: applications/luci-app-cloudflared/root/usr/share/rpcd/acl.d/luci-app-cloudflared.json:3 +msgid "Grant access to Cloudflared configuration" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:52 +msgid "ID" +msgstr "ID" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:96 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:90 +msgid "Info" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:85 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:30 +msgid "Log" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:94 +msgid "Log Direction:" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:92 +msgid "Logging level" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:51 +msgid "Name" +msgstr "Naam" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:85 +msgid "No connections" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:55 +msgid "Not Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:79 +msgid "Obtain a certificate here." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:78 +msgid "Opened At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:77 +msgid "Origin IP" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:86 +msgid "Region" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:54 +msgid "Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:43 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:70 +msgid "See documentation." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:49 +msgid "Status" +msgstr "Status" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:78 +msgid "" +"The account certificate for your zones authorizing the client to serve as an " +"Origin for that zone" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:87 +msgid "The region to which connections are established." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:63 +msgid "The tunnel token is shown in the dashboard once you create a tunnel." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:62 +msgid "Token" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:96 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:22 +msgid "Tunnels" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:48 +msgid "Tunnels Information" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:33 +msgid "Unable to read the interface info from /var/log/cloudflared.log." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:89 +msgid "United States" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:97 +msgid "Up" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:91 +msgid "Warn" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:95 +msgid "Warning" +msgstr "" diff --git a/luci-app-cloudflared-next/po/pl/cloudflared.po b/luci-app-cloudflared-next/po/pl/cloudflared.po new file mode 100644 index 000000000..ce41c6a4d --- /dev/null +++ b/luci-app-cloudflared-next/po/pl/cloudflared.po @@ -0,0 +1,214 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2026-01-18 00:24+0000\n" +"Last-Translator: Matthaiks \n" +"Language-Team: Polish \n" +"Language: pl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " +"|| n%100>=20) ? 1 : 2);\n" +"X-Generator: Weblate 5.15.2\n" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:89 +msgid "All" +msgstr "Wszystko" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:77 +msgid "Certificate of Origin" +msgstr "Certyfikat pochodzenia" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:40 +msgid "" +"Cloudflare Zero Trust Security services help you get maximum security both " +"from outside and within the network." +msgstr "" +"Usługi Cloudflare Zero Trust Security pomagają uzyskać maksymalne " +"bezpieczeństwo zarówno z zewnątrz, jak i wewnątrz sieci." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:39 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:3 +msgid "Cloudflare Zero Trust Tunnel" +msgstr "Tunel Cloudflare Zero Trust" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:69 +msgid "Config file path" +msgstr "Ścieżka pliku konfiguracyjnego" + +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:14 +msgid "Configuration" +msgstr "Konfiguracja" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:76 +msgid "Connection ID" +msgstr "Identyfikator połączenia" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:54 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:90 +msgid "Connections" +msgstr "Połączenia" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:41 +msgid "" +"Create and manage your network on the Cloudflare Zero Trust " +"dashboard." +msgstr "" +"Twórz swoją sieć i zarządzaj nią na pulpicie nawigacyjnym Cloudflare " +"Zero Trust." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:53 +msgid "Created At" +msgstr "Utworzono" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:79 +msgid "Data Center" +msgstr "Centrum danych" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:97 +msgid "Debug" +msgstr "Debugowanie" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:96 +msgid "Down" +msgstr "W dół" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:104 +msgid "Download Log" +msgstr "Pobierz dziennik" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:59 +msgid "Enable" +msgstr "Włącz" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:94 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:92 +msgid "Error" +msgstr "Błąd" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:93 +msgid "Fatal" +msgstr "Krytyczne" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:87 +msgid "Filter Level:" +msgstr "Poziom filtra:" + +#: applications/luci-app-cloudflared/root/usr/share/rpcd/acl.d/luci-app-cloudflared.json:3 +msgid "Grant access to Cloudflared configuration" +msgstr "Udziel dostępu do konfiguracji Cloudflared" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:52 +msgid "ID" +msgstr "Identyfikator" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:96 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:90 +msgid "Info" +msgstr "Info" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:85 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:30 +msgid "Log" +msgstr "Dziennik" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:94 +msgid "Log Direction:" +msgstr "Kierunek dziennika:" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:92 +msgid "Logging level" +msgstr "Poziom rejestrowania" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:51 +msgid "Name" +msgstr "Nazwa" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:85 +msgid "No connections" +msgstr "Brak połączeń" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:55 +msgid "Not Running" +msgstr "Nieuruchomione" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:79 +msgid "Obtain a certificate here." +msgstr "Uzyskaj certyfikat tutaj." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:78 +msgid "Opened At" +msgstr "Otworzono" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:77 +msgid "Origin IP" +msgstr "Pochodzenie IP" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:86 +msgid "Region" +msgstr "Region" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:54 +msgid "Running" +msgstr "Uruchomione" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:43 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:70 +msgid "See documentation." +msgstr "Zobacz dokumentację." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:49 +msgid "Status" +msgstr "Status" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:78 +msgid "" +"The account certificate for your zones authorizing the client to serve as an " +"Origin for that zone" +msgstr "" +"Certyfikat konta dla Twoich stref, upoważniający klienta do pełnienia " +"funkcji Origin dla tej strefy" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:87 +msgid "The region to which connections are established." +msgstr "Region, z którym nawiązywane są połączenia." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:63 +msgid "The tunnel token is shown in the dashboard once you create a tunnel." +msgstr "Po utworzeniu tunelu token tunelu pojawi się na pulpicie nawigacyjnym." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:62 +msgid "Token" +msgstr "Token" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:96 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:22 +msgid "Tunnels" +msgstr "Tunele" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:48 +msgid "Tunnels Information" +msgstr "Informacje o tunelach" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:33 +msgid "Unable to read the interface info from /var/log/cloudflared.log." +msgstr "" +"Nie można odczytać informacji o interfejsie z pliku /var/log/cloudflared.log." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:89 +msgid "United States" +msgstr "Stany Zjednoczone" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:97 +msgid "Up" +msgstr "W górę" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:91 +msgid "Warn" +msgstr "Uwaga" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:95 +msgid "Warning" +msgstr "Ostrzeżenie" diff --git a/luci-app-cloudflared-next/po/pt/cloudflared.po b/luci-app-cloudflared-next/po/pt/cloudflared.po new file mode 100644 index 000000000..d0ba83685 --- /dev/null +++ b/luci-app-cloudflared-next/po/pt/cloudflared.po @@ -0,0 +1,214 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2025-06-06 21:59+0000\n" +"Last-Translator: \"Filipe Mota (BlackSpirits)\" \n" +"Language-Team: Portuguese \n" +"Language: pt\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.12-dev\n" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:89 +msgid "All" +msgstr "Todos" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:77 +msgid "Certificate of Origin" +msgstr "Certificado de origem" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:40 +msgid "" +"Cloudflare Zero Trust Security services help you get maximum security both " +"from outside and within the network." +msgstr "" +"Os serviços de segurança Cloudflare Zero Trust proporcionam uma proteção " +"máxima, tanto contra ameaças externas como internas à rede." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:39 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:3 +msgid "Cloudflare Zero Trust Tunnel" +msgstr "Túnel Cloudflare Zero Trust" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:69 +msgid "Config file path" +msgstr "Caminho do ficheiro de configuração" + +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:14 +msgid "Configuration" +msgstr "Configuração" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:76 +msgid "Connection ID" +msgstr "ID de ligação" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:54 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:90 +msgid "Connections" +msgstr "Ligações" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:41 +msgid "" +"Create and manage your network on the Cloudflare Zero Trust " +"dashboard." +msgstr "" +"Crie e administre a sua rede no painel de controlo Cloudflare Zero " +"Trust." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:53 +msgid "Created At" +msgstr "Criado em" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:79 +msgid "Data Center" +msgstr "Centro de dados" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:97 +msgid "Debug" +msgstr "Depuração" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:96 +msgid "Down" +msgstr "Em baixo" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:104 +msgid "Download Log" +msgstr "Descarregar registo" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:59 +msgid "Enable" +msgstr "Ativar" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:94 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:92 +msgid "Error" +msgstr "Erro" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:93 +msgid "Fatal" +msgstr "Fatal" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:87 +msgid "Filter Level:" +msgstr "Nível de filtro:" + +#: applications/luci-app-cloudflared/root/usr/share/rpcd/acl.d/luci-app-cloudflared.json:3 +msgid "Grant access to Cloudflared configuration" +msgstr "Conceder acesso à configuração do Cloudflared" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:52 +msgid "ID" +msgstr "ID" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:96 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:90 +msgid "Info" +msgstr "Informações" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:85 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:30 +msgid "Log" +msgstr "Registo" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:94 +msgid "Log Direction:" +msgstr "Direção do registo:" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:92 +msgid "Logging level" +msgstr "Nível de registo" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:51 +msgid "Name" +msgstr "Nome" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:85 +msgid "No connections" +msgstr "Sem ligações" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:55 +msgid "Not Running" +msgstr "Não em execução" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:79 +msgid "Obtain a certificate here." +msgstr "Obter um certificado aqui." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:78 +msgid "Opened At" +msgstr "Aberto em" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:77 +msgid "Origin IP" +msgstr "IP de origem" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:86 +msgid "Region" +msgstr "Região" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:54 +msgid "Running" +msgstr "A executar" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:43 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:70 +msgid "See documentation." +msgstr "Ver a documentação." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:49 +msgid "Status" +msgstr "Estado" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:78 +msgid "" +"The account certificate for your zones authorizing the client to serve as an " +"Origin for that zone" +msgstr "" +"O certificado de conta associado às suas zonas que autoriza o cliente a " +"atuar como Origem para essas zonas" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:87 +msgid "The region to which connections are established." +msgstr "A região à qual as ligações são estabelecidas." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:63 +msgid "The tunnel token is shown in the dashboard once you create a tunnel." +msgstr "" +"O token do túnel é apresentado no painel de controlo assim que criar um " +"túnel." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:62 +msgid "Token" +msgstr "Token" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:96 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:22 +msgid "Tunnels" +msgstr "Túneis" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:48 +msgid "Tunnels Information" +msgstr "Informação de túneis" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:33 +msgid "Unable to read the interface info from /var/log/cloudflared.log." +msgstr "Incapaz de ler as informações da interface de /var/log/cloudflared.log." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:89 +msgid "United States" +msgstr "Estados Unidos" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:97 +msgid "Up" +msgstr "Para cima" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:91 +msgid "Warn" +msgstr "Aviso" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:95 +msgid "Warning" +msgstr "Alerta" diff --git a/luci-app-cloudflared-next/po/pt_BR/cloudflared.po b/luci-app-cloudflared-next/po/pt_BR/cloudflared.po new file mode 100644 index 000000000..332f6526b --- /dev/null +++ b/luci-app-cloudflared-next/po/pt_BR/cloudflared.po @@ -0,0 +1,208 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2026-03-09 19:10+0000\n" +"Last-Translator: Volenski \n" +"Language-Team: Portuguese (Brazil) \n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 5.17-dev\n" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:89 +msgid "All" +msgstr "Todos" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:77 +msgid "Certificate of Origin" +msgstr "Certificado de Origem" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:40 +msgid "" +"Cloudflare Zero Trust Security services help you get maximum security both " +"from outside and within the network." +msgstr "" +"Os serviços de segurança Zero Trust da Cloudflare ajudam você a obter " +"segurança máxima tanto de fora quanto de dentro da rede." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:39 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:3 +msgid "Cloudflare Zero Trust Tunnel" +msgstr "Tunel do Cloudflare Zero Trust" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:69 +msgid "Config file path" +msgstr "Desativar saída de cores do log" + +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:14 +msgid "Configuration" +msgstr "Configuração" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:76 +msgid "Connection ID" +msgstr "ID da conexão (Connection ID)" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:54 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:90 +msgid "Connections" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:41 +msgid "" +"Create and manage your network on the Cloudflare Zero Trust " +"dashboard." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:53 +msgid "Created At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:79 +msgid "Data Center" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:97 +msgid "Debug" +msgstr "Depuração (Debug)" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:96 +msgid "Down" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:104 +msgid "Download Log" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:59 +msgid "Enable" +msgstr "Habilitar" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:94 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:92 +msgid "Error" +msgstr "Erro" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:93 +msgid "Fatal" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:87 +msgid "Filter Level:" +msgstr "" + +#: applications/luci-app-cloudflared/root/usr/share/rpcd/acl.d/luci-app-cloudflared.json:3 +msgid "Grant access to Cloudflared configuration" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:52 +msgid "ID" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:96 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:90 +msgid "Info" +msgstr "Informação (Info)" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:85 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:30 +msgid "Log" +msgstr "Registro" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:94 +msgid "Log Direction:" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:92 +msgid "Logging level" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:51 +msgid "Name" +msgstr "Nome" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:85 +msgid "No connections" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:55 +msgid "Not Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:79 +msgid "Obtain a certificate here." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:78 +msgid "Opened At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:77 +msgid "Origin IP" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:86 +msgid "Region" +msgstr "Região" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:54 +msgid "Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:43 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:70 +msgid "See documentation." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:49 +msgid "Status" +msgstr "Status" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:78 +msgid "" +"The account certificate for your zones authorizing the client to serve as an " +"Origin for that zone" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:87 +msgid "The region to which connections are established." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:63 +msgid "The tunnel token is shown in the dashboard once you create a tunnel." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:62 +msgid "Token" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:96 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:22 +msgid "Tunnels" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:48 +msgid "Tunnels Information" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:33 +msgid "Unable to read the interface info from /var/log/cloudflared.log." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:89 +msgid "United States" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:97 +msgid "Up" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:91 +msgid "Warn" +msgstr "Aviso" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:95 +msgid "Warning" +msgstr "" diff --git a/luci-app-cloudflared-next/po/ro/cloudflared.po b/luci-app-cloudflared-next/po/ro/cloudflared.po new file mode 100644 index 000000000..239ff4eac --- /dev/null +++ b/luci-app-cloudflared-next/po/ro/cloudflared.po @@ -0,0 +1,209 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2025-11-24 10:29+0000\n" +"Last-Translator: CRISTIAN ANDREI \n" +"Language-Team: Romanian \n" +"Language: ro\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=n==1 ? 0 : " +"(n==0 || (n%100 > 0 && n%100 < 20)) ? 1 : 2;\n" +"X-Generator: Weblate 5.15-dev\n" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:89 +msgid "All" +msgstr "Toate" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:77 +msgid "Certificate of Origin" +msgstr "Certificat de Origine" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:40 +msgid "" +"Cloudflare Zero Trust Security services help you get maximum security both " +"from outside and within the network." +msgstr "" +"Serviciile Cloudflare Zero Trust Security te ajută să obții securitate " +"maximă atât din exterior, cât și din interiorul rețelei." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:39 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:3 +msgid "Cloudflare Zero Trust Tunnel" +msgstr "Tunelul Cloudflare Zero Trust" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:69 +msgid "Config file path" +msgstr "Calea fișierului de configurare" + +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:14 +msgid "Configuration" +msgstr "Configurație" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:76 +msgid "Connection ID" +msgstr "ID-ul conexiunii" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:54 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:90 +msgid "Connections" +msgstr "Conexiuni" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:41 +msgid "" +"Create and manage your network on the Cloudflare Zero Trust " +"dashboard." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:53 +msgid "Created At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:79 +msgid "Data Center" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:97 +msgid "Debug" +msgstr "Depanare" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:96 +msgid "Down" +msgstr "Nefuncțional" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:104 +msgid "Download Log" +msgstr "Descărcare Jurnal" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:59 +msgid "Enable" +msgstr "Activați" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:94 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:92 +msgid "Error" +msgstr "Eroare" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:93 +msgid "Fatal" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:87 +msgid "Filter Level:" +msgstr "" + +#: applications/luci-app-cloudflared/root/usr/share/rpcd/acl.d/luci-app-cloudflared.json:3 +msgid "Grant access to Cloudflared configuration" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:52 +msgid "ID" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:96 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:90 +msgid "Info" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:85 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:30 +msgid "Log" +msgstr "Jurnal" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:94 +msgid "Log Direction:" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:92 +msgid "Logging level" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:51 +msgid "Name" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:85 +msgid "No connections" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:55 +msgid "Not Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:79 +msgid "Obtain a certificate here." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:78 +msgid "Opened At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:77 +msgid "Origin IP" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:86 +msgid "Region" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:54 +msgid "Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:43 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:70 +msgid "See documentation." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:49 +msgid "Status" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:78 +msgid "" +"The account certificate for your zones authorizing the client to serve as an " +"Origin for that zone" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:87 +msgid "The region to which connections are established." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:63 +msgid "The tunnel token is shown in the dashboard once you create a tunnel." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:62 +msgid "Token" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:96 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:22 +msgid "Tunnels" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:48 +msgid "Tunnels Information" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:33 +msgid "Unable to read the interface info from /var/log/cloudflared.log." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:89 +msgid "United States" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:97 +msgid "Up" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:91 +msgid "Warn" +msgstr "Atenție" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:95 +msgid "Warning" +msgstr "Atenționare" diff --git a/luci-app-cloudflared-next/po/ru/cloudflared.po b/luci-app-cloudflared-next/po/ru/cloudflared.po new file mode 100644 index 000000000..81a4ddb01 --- /dev/null +++ b/luci-app-cloudflared-next/po/ru/cloudflared.po @@ -0,0 +1,215 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2026-02-20 11:50+0000\n" +"Last-Translator: SnIPeRSnIPeR " +"\n" +"Language-Team: Russian \n" +"Language: ru\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " +"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +"X-Generator: Weblate 5.16.1-dev\n" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:89 +msgid "All" +msgstr "Все" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:77 +msgid "Certificate of Origin" +msgstr "Сертификат Origin" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:40 +msgid "" +"Cloudflare Zero Trust Security services help you get maximum security both " +"from outside and within the network." +msgstr "" +"Сервисы Cloudflare Безопасность Нулевого Доверия (Zero Trust Security) " +"помогают вам получить максимальную безопасность как извне, так и внутри сети." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:39 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:3 +msgid "Cloudflare Zero Trust Tunnel" +msgstr "Cloudflare Безопасность Нулевого Доверия" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:69 +msgid "Config file path" +msgstr "Путь к файлу конфигурации" + +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:14 +msgid "Configuration" +msgstr "Конфигурация" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:76 +msgid "Connection ID" +msgstr "Идентификатор соединения" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:54 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:90 +msgid "Connections" +msgstr "Соединения" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:41 +msgid "" +"Create and manage your network on the Cloudflare Zero Trust " +"dashboard." +msgstr "" +"Создайте и управляйте своей сетью на панели Cloudflare Zero Trust." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:53 +msgid "Created At" +msgstr "Создано в" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:79 +msgid "Data Center" +msgstr "Дата-центр" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:97 +msgid "Debug" +msgstr "Отладка" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:96 +msgid "Down" +msgstr "Вниз" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:104 +msgid "Download Log" +msgstr "Скачать журнал" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:59 +msgid "Enable" +msgstr "Включить" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:94 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:92 +msgid "Error" +msgstr "Ошибка" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:93 +msgid "Fatal" +msgstr "Фатальный" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:87 +msgid "Filter Level:" +msgstr "Фильтровать по уровню:" + +#: applications/luci-app-cloudflared/root/usr/share/rpcd/acl.d/luci-app-cloudflared.json:3 +msgid "Grant access to Cloudflared configuration" +msgstr "Доступ к конфигурации Cloudflared" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:52 +msgid "ID" +msgstr "Идентификатор" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:96 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:90 +msgid "Info" +msgstr "Информация" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:85 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:30 +msgid "Log" +msgstr "Журнал" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:94 +msgid "Log Direction:" +msgstr "Направление в журнале:" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:92 +msgid "Logging level" +msgstr "Уровень журналирования" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:51 +msgid "Name" +msgstr "Название" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:85 +msgid "No connections" +msgstr "Нет соединений" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:55 +msgid "Not Running" +msgstr "Не запущенно" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:79 +msgid "Obtain a certificate here." +msgstr "Получить сертификат здесь." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:78 +msgid "Opened At" +msgstr "Открыто в" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:77 +msgid "Origin IP" +msgstr "Исходный IP-адрес" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:86 +msgid "Region" +msgstr "Регион" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:54 +msgid "Running" +msgstr "Запущено" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:43 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:70 +msgid "See documentation." +msgstr "Смотрите документацию." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:49 +msgid "Status" +msgstr "Статус" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:78 +msgid "" +"The account certificate for your zones authorizing the client to serve as an " +"Origin for that zone" +msgstr "" +"Сертификат учётной записи для ваших зон, уполномочивающих клиента служить " +"Происхождением (Origin) для этой зоны" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:87 +msgid "The region to which connections are established." +msgstr "Регион к которому устанавливать соединение." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:63 +msgid "The tunnel token is shown in the dashboard once you create a tunnel." +msgstr "" +"Токен туннеля будет показан в панели управления после создания туннеля." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:62 +msgid "Token" +msgstr "Токен" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:96 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:22 +msgid "Tunnels" +msgstr "Туннели" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:48 +msgid "Tunnels Information" +msgstr "Информация о туннелях" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:33 +msgid "Unable to read the interface info from /var/log/cloudflared.log." +msgstr "" +"Невозможно прочитать информацию об интерфейсе из /var/log/cloudflared.log." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:89 +msgid "United States" +msgstr "Соединенные Штаты" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:97 +msgid "Up" +msgstr "Вверх" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:91 +msgid "Warn" +msgstr "Предупреждение" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:95 +msgid "Warning" +msgstr "Предупреждение" diff --git a/luci-app-cloudflared-next/po/sk/cloudflared.po b/luci-app-cloudflared-next/po/sk/cloudflared.po new file mode 100644 index 000000000..9d490d55d --- /dev/null +++ b/luci-app-cloudflared-next/po/sk/cloudflared.po @@ -0,0 +1,203 @@ +msgid "" +msgstr "" +"Content-Type: text/plain; charset=UTF-8\n" +"Project-Id-Version: PACKAGE VERSION\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: sk\n" +"MIME-Version: 1.0\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:89 +msgid "All" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:77 +msgid "Certificate of Origin" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:40 +msgid "" +"Cloudflare Zero Trust Security services help you get maximum security both " +"from outside and within the network." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:39 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:3 +msgid "Cloudflare Zero Trust Tunnel" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:69 +msgid "Config file path" +msgstr "" + +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:14 +msgid "Configuration" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:76 +msgid "Connection ID" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:54 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:90 +msgid "Connections" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:41 +msgid "" +"Create and manage your network on the Cloudflare Zero Trust " +"dashboard." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:53 +msgid "Created At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:79 +msgid "Data Center" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:97 +msgid "Debug" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:96 +msgid "Down" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:104 +msgid "Download Log" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:59 +msgid "Enable" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:94 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:92 +msgid "Error" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:93 +msgid "Fatal" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:87 +msgid "Filter Level:" +msgstr "" + +#: applications/luci-app-cloudflared/root/usr/share/rpcd/acl.d/luci-app-cloudflared.json:3 +msgid "Grant access to Cloudflared configuration" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:52 +msgid "ID" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:96 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:90 +msgid "Info" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:85 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:30 +msgid "Log" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:94 +msgid "Log Direction:" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:92 +msgid "Logging level" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:51 +msgid "Name" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:85 +msgid "No connections" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:55 +msgid "Not Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:79 +msgid "Obtain a certificate here." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:78 +msgid "Opened At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:77 +msgid "Origin IP" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:86 +msgid "Region" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:54 +msgid "Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:43 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:70 +msgid "See documentation." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:49 +msgid "Status" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:78 +msgid "" +"The account certificate for your zones authorizing the client to serve as an " +"Origin for that zone" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:87 +msgid "The region to which connections are established." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:63 +msgid "The tunnel token is shown in the dashboard once you create a tunnel." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:62 +msgid "Token" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:96 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:22 +msgid "Tunnels" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:48 +msgid "Tunnels Information" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:33 +msgid "Unable to read the interface info from /var/log/cloudflared.log." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:89 +msgid "United States" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:97 +msgid "Up" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:91 +msgid "Warn" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:95 +msgid "Warning" +msgstr "" diff --git a/luci-app-cloudflared-next/po/sv/cloudflared.po b/luci-app-cloudflared-next/po/sv/cloudflared.po new file mode 100644 index 000000000..5ce3f90e2 --- /dev/null +++ b/luci-app-cloudflared-next/po/sv/cloudflared.po @@ -0,0 +1,206 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2026-01-25 20:29+0000\n" +"Last-Translator: Kristoffer Grundström \n" +"Language-Team: Swedish \n" +"Language: sv\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.16-dev\n" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:89 +msgid "All" +msgstr "Alla" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:77 +msgid "Certificate of Origin" +msgstr "Originalcertifikat" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:40 +msgid "" +"Cloudflare Zero Trust Security services help you get maximum security both " +"from outside and within the network." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:39 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:3 +msgid "Cloudflare Zero Trust Tunnel" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:69 +msgid "Config file path" +msgstr "Genväg för konfig-fil" + +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:14 +msgid "Configuration" +msgstr "Konfiguration" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:76 +msgid "Connection ID" +msgstr "ID för anslutningen" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:54 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:90 +msgid "Connections" +msgstr "Anslutningar" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:41 +msgid "" +"Create and manage your network on the Cloudflare Zero Trust " +"dashboard." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:53 +msgid "Created At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:79 +msgid "Data Center" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:97 +msgid "Debug" +msgstr "Felsök" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:96 +msgid "Down" +msgstr "Ner" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:104 +msgid "Download Log" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:59 +msgid "Enable" +msgstr "Aktivera" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:94 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:92 +msgid "Error" +msgstr "Fel" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:93 +msgid "Fatal" +msgstr "Dödligt" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:87 +msgid "Filter Level:" +msgstr "" + +#: applications/luci-app-cloudflared/root/usr/share/rpcd/acl.d/luci-app-cloudflared.json:3 +msgid "Grant access to Cloudflared configuration" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:52 +msgid "ID" +msgstr "ID" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:96 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:90 +msgid "Info" +msgstr "Info" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:85 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:30 +msgid "Log" +msgstr "Logg" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:94 +msgid "Log Direction:" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:92 +msgid "Logging level" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:51 +msgid "Name" +msgstr "Namn" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:85 +msgid "No connections" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:55 +msgid "Not Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:79 +msgid "Obtain a certificate here." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:78 +msgid "Opened At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:77 +msgid "Origin IP" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:86 +msgid "Region" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:54 +msgid "Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:43 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:70 +msgid "See documentation." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:49 +msgid "Status" +msgstr "Status" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:78 +msgid "" +"The account certificate for your zones authorizing the client to serve as an " +"Origin for that zone" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:87 +msgid "The region to which connections are established." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:63 +msgid "The tunnel token is shown in the dashboard once you create a tunnel." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:62 +msgid "Token" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:96 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:22 +msgid "Tunnels" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:48 +msgid "Tunnels Information" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:33 +msgid "Unable to read the interface info from /var/log/cloudflared.log." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:89 +msgid "United States" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:97 +msgid "Up" +msgstr "Upp" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:91 +msgid "Warn" +msgstr "Varna" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:95 +msgid "Warning" +msgstr "Varning" diff --git a/luci-app-cloudflared-next/po/ta/cloudflared.po b/luci-app-cloudflared-next/po/ta/cloudflared.po new file mode 100644 index 000000000..de3d9381e --- /dev/null +++ b/luci-app-cloudflared-next/po/ta/cloudflared.po @@ -0,0 +1,212 @@ +msgid "" +msgstr "" +"PO-Revision-Date: 2025-01-25 02:34+0000\n" +"Last-Translator: தமிழ்நேரம் \n" +"Language-Team: Tamil \n" +"Language: ta\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.10-dev\n" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:89 +msgid "All" +msgstr "அனைத்தும்" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:77 +msgid "Certificate of Origin" +msgstr "தோற்றம் சான்றிதழ்" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:40 +msgid "" +"Cloudflare Zero Trust Security services help you get maximum security both " +"from outside and within the network." +msgstr "" +"கிளவுட்ஃப்ளேர் சீரோ அறக்கட்டளை பாதுகாப்பு சேவைகள் வெளியில் இருந்து மற்றும் பிணையத்திற்குள் " +"அதிகபட்ச பாதுகாப்பைப் பெற உதவுகின்றன." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:39 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:3 +msgid "Cloudflare Zero Trust Tunnel" +msgstr "கிளவுட்ஃப்ளேர் சீரோ டிரச்ட் சுரங்கப்பாதை" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:69 +msgid "Config file path" +msgstr "கோப்பு பாதை" + +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:14 +msgid "Configuration" +msgstr "உள்ளமைவு" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:76 +msgid "Connection ID" +msgstr "இணைப்பு ஐடி" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:54 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:90 +msgid "Connections" +msgstr "இணைப்புகள்" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:41 +msgid "" +"Create and manage your network on the Cloudflare Zero Trust " +"dashboard." +msgstr "" +" கிளவுட்ஃப்ளேர் சீரோ டிரச்ட் டாச்போர்டில் உங்கள் பிணையத்தை உருவாக்கி " +"நிர்வகிக்கவும்." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:53 +msgid "Created At" +msgstr "உருவாக்கப்பட்டது" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:79 +msgid "Data Center" +msgstr "தரவு நடுவண்" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:97 +msgid "Debug" +msgstr "பிழைத்திருத்தம்" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:96 +msgid "Down" +msgstr "கீழே" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:104 +msgid "Download Log" +msgstr "பதிவைப் பதிவிறக்கவும்" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:59 +msgid "Enable" +msgstr "இயக்கு" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:94 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:92 +msgid "Error" +msgstr "பிழை" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:93 +msgid "Fatal" +msgstr "அபாயகரமான" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:87 +msgid "Filter Level:" +msgstr "வடிகட்டி நிலை:" + +#: applications/luci-app-cloudflared/root/usr/share/rpcd/acl.d/luci-app-cloudflared.json:3 +msgid "Grant access to Cloudflared configuration" +msgstr "கிளவுட்ஃப்ளைர் உள்ளமைவுக்கு அணுகலை வழங்கவும்" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:52 +msgid "ID" +msgstr "ஐடி" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:96 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:90 +msgid "Info" +msgstr "தகவல்" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:85 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:30 +msgid "Log" +msgstr "பதிவு" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:94 +msgid "Log Direction:" +msgstr "பதிவு திசை:" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:92 +msgid "Logging level" +msgstr "பதிவு நிலை" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:51 +msgid "Name" +msgstr "பெயர்" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:85 +msgid "No connections" +msgstr "இணைப்புகள் இல்லை" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:55 +msgid "Not Running" +msgstr "ஓடவில்லை" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:79 +msgid "Obtain a certificate here." +msgstr "ஒரு சான்றிதழைப் பெறுங்கள் இங்கே ." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:78 +msgid "Opened At" +msgstr "இல் திறக்கப்பட்டது" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:77 +msgid "Origin IP" +msgstr "ஆரிசின் ஐபி" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:86 +msgid "Region" +msgstr "பகுதி" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:54 +msgid "Running" +msgstr "இயங்கும்" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:43 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:70 +msgid "See documentation." +msgstr " ஆவணங்கள் ஐப் பார்க்கவும்." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:49 +msgid "Status" +msgstr "நிலை" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:78 +msgid "" +"The account certificate for your zones authorizing the client to serve as an " +"Origin for that zone" +msgstr "" +"உங்கள் மண்டலங்களுக்கான கணக்கு சான்றிதழ் வாடிக்கையாளருக்கு அந்த மண்டலத்திற்கான தோற்றமாக " +"செயல்பட ஏற்பு அளிக்கிறது" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:87 +msgid "The region to which connections are established." +msgstr "இணைப்புகள் நிறுவப்பட்ட பகுதி." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:63 +msgid "The tunnel token is shown in the dashboard once you create a tunnel." +msgstr "" +"நீங்கள் ஒரு சுரங்கப்பாதையை உருவாக்கியவுடன் டாச்போர்டில் சுரங்கப்பாதை கிள்ளாக்கு " +"காட்டப்பட்டுள்ளது." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:62 +msgid "Token" +msgstr "கிள்ளாக்கு" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:96 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:22 +msgid "Tunnels" +msgstr "சுரங்கங்கள்" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:48 +msgid "Tunnels Information" +msgstr "சுரங்கங்கள் செய்தி" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:33 +msgid "Unable to read the interface info from /var/log/cloudflared.log." +msgstr "/Var/log/cloudflared.log இலிருந்து இடைமுக தகவலை படிக்க முடியவில்லை." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:89 +msgid "United States" +msgstr "ஐக்கிய அமெரிக்கா" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:97 +msgid "Up" +msgstr "மேலே" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:91 +msgid "Warn" +msgstr "எச்சரிக்கை" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:95 +msgid "Warning" +msgstr "எச்சரிக்கை" diff --git a/luci-app-cloudflared-next/po/templates/cloudflared.pot b/luci-app-cloudflared-next/po/templates/cloudflared.pot new file mode 100644 index 000000000..78710e073 --- /dev/null +++ b/luci-app-cloudflared-next/po/templates/cloudflared.pot @@ -0,0 +1,195 @@ +msgid "" +msgstr "Content-Type: text/plain; charset=UTF-8" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:89 +msgid "All" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:77 +msgid "Certificate of Origin" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:40 +msgid "" +"Cloudflare Zero Trust Security services help you get maximum security both " +"from outside and within the network." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:39 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:3 +msgid "Cloudflare Zero Trust Tunnel" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:69 +msgid "Config file path" +msgstr "" + +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:14 +msgid "Configuration" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:76 +msgid "Connection ID" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:54 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:90 +msgid "Connections" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:41 +msgid "" +"Create and manage your network on the Cloudflare Zero Trust " +"dashboard." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:53 +msgid "Created At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:79 +msgid "Data Center" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:97 +msgid "Debug" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:96 +msgid "Down" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:104 +msgid "Download Log" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:59 +msgid "Enable" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:94 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:92 +msgid "Error" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:93 +msgid "Fatal" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:87 +msgid "Filter Level:" +msgstr "" + +#: applications/luci-app-cloudflared/root/usr/share/rpcd/acl.d/luci-app-cloudflared.json:3 +msgid "Grant access to Cloudflared configuration" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:52 +msgid "ID" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:96 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:90 +msgid "Info" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:85 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:30 +msgid "Log" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:94 +msgid "Log Direction:" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:92 +msgid "Logging level" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:51 +msgid "Name" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:85 +msgid "No connections" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:55 +msgid "Not Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:79 +msgid "Obtain a certificate here." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:78 +msgid "Opened At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:77 +msgid "Origin IP" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:86 +msgid "Region" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:54 +msgid "Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:43 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:70 +msgid "See documentation." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:49 +msgid "Status" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:78 +msgid "" +"The account certificate for your zones authorizing the client to serve as an " +"Origin for that zone" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:87 +msgid "The region to which connections are established." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:63 +msgid "The tunnel token is shown in the dashboard once you create a tunnel." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:62 +msgid "Token" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:96 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:22 +msgid "Tunnels" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:48 +msgid "Tunnels Information" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:33 +msgid "Unable to read the interface info from /var/log/cloudflared.log." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:89 +msgid "United States" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:97 +msgid "Up" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:91 +msgid "Warn" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:95 +msgid "Warning" +msgstr "" diff --git a/luci-app-cloudflared-next/po/tr/cloudflared.po b/luci-app-cloudflared-next/po/tr/cloudflared.po new file mode 100644 index 000000000..0d607142e --- /dev/null +++ b/luci-app-cloudflared-next/po/tr/cloudflared.po @@ -0,0 +1,211 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2025-09-08 17:09+0000\n" +"Last-Translator: Derman \n" +"Language-Team: Turkish \n" +"Language: tr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.14-dev\n" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:89 +msgid "All" +msgstr "Hepsi" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:77 +msgid "Certificate of Origin" +msgstr "Menşei Belgesi" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:40 +msgid "" +"Cloudflare Zero Trust Security services help you get maximum security both " +"from outside and within the network." +msgstr "" +"Cloudflare Zero Trust Security hizmetleri, hem dışarıdan hem de ağ içinden " +"maksimum güvenlik elde etmenize yardımcı olur." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:39 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:3 +msgid "Cloudflare Zero Trust Tunnel" +msgstr "Cloudflare Zero Trust Tüneli" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:69 +msgid "Config file path" +msgstr "Yapılandırma dosyası yolu" + +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:14 +msgid "Configuration" +msgstr "Yapılandırma" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:76 +msgid "Connection ID" +msgstr "Bağlantı Kimliği" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:54 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:90 +msgid "Connections" +msgstr "Bağlantılar" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:41 +msgid "" +"Create and manage your network on the Cloudflare Zero Trust " +"dashboard." +msgstr "Ağınızı Cloudflare Zero Trust panosunda oluşturun ve yönetin." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:53 +msgid "Created At" +msgstr "Oluşturulduğu Yer" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:79 +msgid "Data Center" +msgstr "Veri Merkezi" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:97 +msgid "Debug" +msgstr "Hata Ayıklama" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:96 +msgid "Down" +msgstr "Aşağı" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:104 +msgid "Download Log" +msgstr "Günlüğü indir" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:59 +msgid "Enable" +msgstr "Etkinleştir" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:94 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:92 +msgid "Error" +msgstr "Hata" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:93 +msgid "Fatal" +msgstr "Ölümcül" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:87 +msgid "Filter Level:" +msgstr "Filtre Seviyesi:" + +#: applications/luci-app-cloudflared/root/usr/share/rpcd/acl.d/luci-app-cloudflared.json:3 +msgid "Grant access to Cloudflared configuration" +msgstr "Cloudflared yapılandırmasına erişim izni ver" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:52 +msgid "ID" +msgstr "ID" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:96 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:90 +msgid "Info" +msgstr "Bilgi" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:85 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:30 +msgid "Log" +msgstr "Günlük" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:94 +msgid "Log Direction:" +msgstr "Günlük Yolu:" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:92 +msgid "Logging level" +msgstr "Günlük seviyesi" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:51 +msgid "Name" +msgstr "İsim" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:85 +msgid "No connections" +msgstr "Bağlantı yok" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:55 +msgid "Not Running" +msgstr "Çalışmıyor" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:79 +msgid "Obtain a certificate here." +msgstr "buradan bir sertifika edinin." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:78 +msgid "Opened At" +msgstr "Açıldığı Yer" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:77 +msgid "Origin IP" +msgstr "Kaynak IP" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:86 +msgid "Region" +msgstr "Bölge" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:54 +msgid "Running" +msgstr "Çalışıyor" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:43 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:70 +msgid "See documentation." +msgstr "dokümantasyon bölümüne bakın." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:49 +msgid "Status" +msgstr "Durum" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:78 +msgid "" +"The account certificate for your zones authorizing the client to serve as an " +"Origin for that zone" +msgstr "" +"Bölgeleriniz için, istemciyi o bölge için bir Origin olarak hizmet vermek " +"üzere yetkilendiren hesap sertifikası" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:87 +msgid "The region to which connections are established." +msgstr "Bağlantıların kurulduğu bölge." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:63 +msgid "The tunnel token is shown in the dashboard once you create a tunnel." +msgstr "" +"Tünel belirteci, bir tünel oluşturduğunuzda kontrol panelinde gösterilir." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:62 +msgid "Token" +msgstr "Token" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:96 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:22 +msgid "Tunnels" +msgstr "Tüneller" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:48 +msgid "Tunnels Information" +msgstr "Tünel Bilgileri" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:33 +msgid "Unable to read the interface info from /var/log/cloudflared.log." +msgstr "Arayüz bilgisi /var/log/cloudflared.log dosyasından okunamıyor." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:89 +msgid "United States" +msgstr "Amerika Birleşik Devletleri" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:97 +msgid "Up" +msgstr "Yukarı" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:91 +msgid "Warn" +msgstr "Uyarı" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:95 +msgid "Warning" +msgstr "Dikkat" diff --git a/luci-app-cloudflared-next/po/uk/cloudflared.po b/luci-app-cloudflared-next/po/uk/cloudflared.po new file mode 100644 index 000000000..caa628eab --- /dev/null +++ b/luci-app-cloudflared-next/po/uk/cloudflared.po @@ -0,0 +1,215 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2026-01-22 09:00+0000\n" +"Last-Translator: Максим Горпиніч \n" +"Language-Team: Ukrainian \n" +"Language: uk\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " +"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +"X-Generator: Weblate 5.16-dev\n" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:89 +msgid "All" +msgstr "Усі" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:77 +msgid "Certificate of Origin" +msgstr "Сертифікат походження" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:40 +msgid "" +"Cloudflare Zero Trust Security services help you get maximum security both " +"from outside and within the network." +msgstr "" +"Служби безпеки Cloudflare Zero Trust допомагають забезпечити максимальний " +"рівень захисту як іззовні, так і всередині мережі." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:39 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:3 +msgid "Cloudflare Zero Trust Tunnel" +msgstr "Тунель нульової довіри Cloudflare" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:69 +msgid "Config file path" +msgstr "Шлях до конфігураційного файлу" + +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:14 +msgid "Configuration" +msgstr "Конфігурація" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:76 +msgid "Connection ID" +msgstr "ID підключення" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:54 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:90 +msgid "Connections" +msgstr "Зв'язки" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:41 +msgid "" +"Create and manage your network on the Cloudflare Zero Trust " +"dashboard." +msgstr "" +"Створюйте свою мережу та керуйте нею на інформаційній панелі Cloudflare Zero Trust." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:53 +msgid "Created At" +msgstr "Створено Ат" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:79 +msgid "Data Center" +msgstr "Центр обробки даних" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:97 +msgid "Debug" +msgstr "Налагодження" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:96 +msgid "Down" +msgstr "Вниз" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:104 +msgid "Download Log" +msgstr "Журнал завантажень" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:59 +msgid "Enable" +msgstr "Увімкнути" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:94 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:92 +msgid "Error" +msgstr "Помилка" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:93 +msgid "Fatal" +msgstr "Фатальний" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:87 +msgid "Filter Level:" +msgstr "Рівень фільтра:" + +#: applications/luci-app-cloudflared/root/usr/share/rpcd/acl.d/luci-app-cloudflared.json:3 +msgid "Grant access to Cloudflared configuration" +msgstr "Надайте доступ до конфігурації Cloudflare" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:52 +msgid "ID" +msgstr "ID" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:96 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:90 +msgid "Info" +msgstr "Інфо" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:85 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:30 +msgid "Log" +msgstr "Журнал" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:94 +msgid "Log Direction:" +msgstr "Напрямок журналу:" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:92 +msgid "Logging level" +msgstr "Рівень реєстрації" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:51 +msgid "Name" +msgstr "Ім'я" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:85 +msgid "No connections" +msgstr "Жодних зв'язків" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:55 +msgid "Not Running" +msgstr "Не працює" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:79 +msgid "Obtain a certificate here." +msgstr "Отримайте сертифікат тут." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:78 +msgid "Opened At" +msgstr "Відкрито при" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:77 +msgid "Origin IP" +msgstr "Походження IP" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:86 +msgid "Region" +msgstr "Регіон" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:54 +msgid "Running" +msgstr "Запуск" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:43 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:70 +msgid "See documentation." +msgstr "Перегляньте документацію." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:49 +msgid "Status" +msgstr "Статус" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:78 +msgid "" +"The account certificate for your zones authorizing the client to serve as an " +"Origin for that zone" +msgstr "" +"Сертифікат облікового запису для ваших зон, що дозволяє клієнту служити " +"джерелом для цієї зони" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:87 +msgid "The region to which connections are established." +msgstr "Регіон, з яким встановлені зв'язки." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:63 +msgid "The tunnel token is shown in the dashboard once you create a tunnel." +msgstr "" +"Маркер тунелю відображається на інформаційній панелі після створення тунелю." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:62 +msgid "Token" +msgstr "Токен" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:96 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:22 +msgid "Tunnels" +msgstr "Тунелі" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:48 +msgid "Tunnels Information" +msgstr "Інформація про тунелі" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:33 +msgid "Unable to read the interface info from /var/log/cloudflared.log." +msgstr "" +"Не вдалося прочитати інформацію про інтерфейс із /var/log/cloudflared.log." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:89 +msgid "United States" +msgstr "США" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:97 +msgid "Up" +msgstr "Вгору" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:91 +msgid "Warn" +msgstr "Попередити" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:95 +msgid "Warning" +msgstr "Попередження" diff --git a/luci-app-cloudflared-next/po/vi/cloudflared.po b/luci-app-cloudflared-next/po/vi/cloudflared.po new file mode 100644 index 000000000..feff10336 --- /dev/null +++ b/luci-app-cloudflared-next/po/vi/cloudflared.po @@ -0,0 +1,222 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2025-08-01 11:02+0000\n" +"Last-Translator: Vũ Minh Ngọc \n" +"Language-Team: Vietnamese \n" +"Language: vi\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Weblate 5.13-dev\n" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:89 +msgid "All" +msgstr "Tất cả" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:77 +#, fuzzy +msgid "Certificate of Origin" +msgstr "Giấy chứng nhận xuất xứ" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:40 +#, fuzzy +msgid "" +"Cloudflare Zero Trust Security services help you get maximum security both " +"from outside and within the network." +msgstr "" +"Dịch vụ Cloudflare Zero Trust Security giúp bạn có được mức bảo mật tối đa " +"từ cả bên ngoài và bên trong mạng." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:39 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:3 +#, fuzzy +msgid "Cloudflare Zero Trust Tunnel" +msgstr "Đường hầm Cloudflare Zero Trust" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:69 +#, fuzzy +msgid "Config file path" +msgstr "Đường dẫn tệp cấu hình" + +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:14 +#, fuzzy +msgid "Configuration" +msgstr "Cấu hình" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:76 +#, fuzzy +msgid "Connection ID" +msgstr "ID kết nối" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:54 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:90 +#, fuzzy +msgid "Connections" +msgstr "Kết nối" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:41 +#, fuzzy +msgid "" +"Create and manage your network on the Cloudflare Zero Trust " +"dashboard." +msgstr "" +"Tạo và quản lý mạng của bạn trên bảng điều khiển Cloudflare Zero " +"Trust." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:53 +msgid "Created At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:79 +msgid "Data Center" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:97 +msgid "Debug" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:96 +msgid "Down" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:104 +msgid "Download Log" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:59 +msgid "Enable" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:94 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:92 +msgid "Error" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:93 +msgid "Fatal" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:87 +msgid "Filter Level:" +msgstr "" + +#: applications/luci-app-cloudflared/root/usr/share/rpcd/acl.d/luci-app-cloudflared.json:3 +msgid "Grant access to Cloudflared configuration" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:52 +msgid "ID" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:96 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:90 +msgid "Info" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:85 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:30 +msgid "Log" +msgstr "Nhật ký" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:94 +#, fuzzy +msgid "Log Direction:" +msgstr "Hướng nhật ký:" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:92 +msgid "Logging level" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:51 +msgid "Name" +msgstr "Tên" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:85 +msgid "No connections" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:55 +msgid "Not Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:79 +msgid "Obtain a certificate here." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:78 +msgid "Opened At" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:77 +msgid "Origin IP" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:86 +msgid "Region" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:54 +msgid "Running" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:43 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:70 +msgid "See documentation." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:49 +msgid "Status" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:78 +msgid "" +"The account certificate for your zones authorizing the client to serve as an " +"Origin for that zone" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:87 +msgid "The region to which connections are established." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:63 +#, fuzzy +msgid "The tunnel token is shown in the dashboard once you create a tunnel." +msgstr "" +"Mã thông báo đường hầm sẽ được hiển thị trên bảng điều khiển sau khi bạn tạo " +"đường hầm." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:62 +msgid "Token" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:96 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:22 +msgid "Tunnels" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:48 +msgid "Tunnels Information" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:33 +msgid "Unable to read the interface info from /var/log/cloudflared.log." +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:89 +msgid "United States" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:97 +msgid "Up" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:91 +msgid "Warn" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:95 +msgid "Warning" +msgstr "" diff --git a/luci-app-cloudflared-next/po/yua/cloudflared.po b/luci-app-cloudflared-next/po/yua/cloudflared.po new file mode 100644 index 000000000..642cf150d --- /dev/null +++ b/luci-app-cloudflared-next/po/yua/cloudflared.po @@ -0,0 +1,209 @@ +msgid "" +msgstr "" +"PO-Revision-Date: 2024-09-07 19:01+0000\n" +"Last-Translator: brodrigueznu \n" +"Language-Team: Yucateco \n" +"Language: yua\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.8-dev\n" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:89 +msgid "All" +msgstr "Toda" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:77 +msgid "Certificate of Origin" +msgstr "Certificado de origen" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:40 +msgid "" +"Cloudflare Zero Trust Security services help you get maximum security both " +"from outside and within the network." +msgstr "" +"Los servicios de seguridad Cloudflare Zero Trust le ayudan a obtener la " +"máxima seguridad tanto desde el exterior como dentro de la red." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:39 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:3 +msgid "Cloudflare Zero Trust Tunnel" +msgstr "Tunel Cloudflare Zero Trust" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:69 +msgid "Config file path" +msgstr "Ruta del archivo de configuración" + +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:14 +msgid "Configuration" +msgstr "Configuración" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:76 +msgid "Connection ID" +msgstr "ID de conexión" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:54 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:90 +msgid "Connections" +msgstr "Conexiones" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:41 +msgid "" +"Create and manage your network on the Cloudflare Zero Trust " +"dashboard." +msgstr "Cree y gestione su red en el panel Cloudflare Zero Trust." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:53 +msgid "Created At" +msgstr "Creado en" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:79 +msgid "Data Center" +msgstr "Centro de datos" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:97 +msgid "Debug" +msgstr "Depurar" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:96 +msgid "Down" +msgstr "Abajo" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:104 +msgid "Download Log" +msgstr "Descargar registro" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:59 +msgid "Enable" +msgstr "Activar" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:94 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:92 +msgid "Error" +msgstr "Error" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:93 +msgid "Fatal" +msgstr "Fatal" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:87 +msgid "Filter Level:" +msgstr "Nivel de filtro:" + +#: applications/luci-app-cloudflared/root/usr/share/rpcd/acl.d/luci-app-cloudflared.json:3 +msgid "Grant access to Cloudflared configuration" +msgstr "Permitir acceso a la configuración de Cloudflared" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:52 +msgid "ID" +msgstr "ID" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:96 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:90 +msgid "Info" +msgstr "Info" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:85 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:30 +msgid "Log" +msgstr "Registro" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:94 +msgid "Log Direction:" +msgstr "Dirección de registro:" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:92 +msgid "Logging level" +msgstr "Nivel de depuración" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:51 +msgid "Name" +msgstr "Nombre" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:85 +msgid "No connections" +msgstr "Sin conexiones" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:55 +msgid "Not Running" +msgstr "No se está ejecutando" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:79 +msgid "Obtain a certificate here." +msgstr "Obtenga un certificado aquí." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:78 +msgid "Opened At" +msgstr "Abierto el" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:77 +msgid "Origin IP" +msgstr "IP de origen" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:86 +msgid "Region" +msgstr "Región" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:54 +msgid "Running" +msgstr "Ejecutando" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:43 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:70 +msgid "See documentation." +msgstr "Ver documentación." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:49 +msgid "Status" +msgstr "Estado" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:78 +msgid "" +"The account certificate for your zones authorizing the client to serve as an " +"Origin for that zone" +msgstr "" +"El certificado de cuenta para sus zonas que autoriza al cliente a actuar " +"como Origen para esa zona" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:87 +msgid "The region to which connections are established." +msgstr "La región con la que se establecen las conexiones." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:63 +msgid "The tunnel token is shown in the dashboard once you create a tunnel." +msgstr "El token del túnel se muestra en el panel una vez que crea un túnel." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:62 +msgid "Token" +msgstr "Token" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:96 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:22 +msgid "Tunnels" +msgstr "Túneles" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:48 +msgid "Tunnels Information" +msgstr "Información de túneles" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:33 +msgid "Unable to read the interface info from /var/log/cloudflared.log." +msgstr "" +"No se puede leer la información de la interfaz de /var/log/cloudflared.log." + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:89 +msgid "United States" +msgstr "Estados Unidos" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:97 +msgid "Up" +msgstr "Arriba" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:91 +msgid "Warn" +msgstr "Advertir" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:95 +msgid "Warning" +msgstr "Advertencia" diff --git a/luci-app-cloudflared-next/po/zh-cn b/luci-app-cloudflared-next/po/zh-cn new file mode 120000 index 000000000..8d69574dd --- /dev/null +++ b/luci-app-cloudflared-next/po/zh-cn @@ -0,0 +1 @@ +zh_Hans \ No newline at end of file diff --git a/luci-app-cloudflared-next/po/zh_Hans/cloudflared.po b/luci-app-cloudflared-next/po/zh_Hans/cloudflared.po new file mode 100644 index 000000000..63968838b --- /dev/null +++ b/luci-app-cloudflared-next/po/zh_Hans/cloudflared.po @@ -0,0 +1,206 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2026-03-06 16:33+0000\n" +"Last-Translator: nKsyn \n" +"Language-Team: Chinese (Simplified Han script) \n" +"Language: zh_Hans\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Weblate 5.17-dev\n" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:89 +msgid "All" +msgstr "全部" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:77 +msgid "Certificate of Origin" +msgstr "源站证书" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:40 +msgid "" +"Cloudflare Zero Trust Security services help you get maximum security both " +"from outside and within the network." +msgstr "Cloudflare 零信任安全服务帮助你从网络内外部获取最大程度的安全性。" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:39 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:3 +msgid "Cloudflare Zero Trust Tunnel" +msgstr "Cloudflare 零信任隧道" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:69 +msgid "Config file path" +msgstr "配置文件路径" + +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:14 +msgid "Configuration" +msgstr "配置" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:76 +msgid "Connection ID" +msgstr "连接 ID" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:54 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:90 +msgid "Connections" +msgstr "连接" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:41 +msgid "" +"Create and manage your network on the Cloudflare Zero Trust " +"dashboard." +msgstr "在 Cloudflare 零信任仪表板上创建并管理你的网络。" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:53 +msgid "Created At" +msgstr "创建于" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:79 +msgid "Data Center" +msgstr "数据中心" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:97 +msgid "Debug" +msgstr "调试 (Debug)" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:96 +msgid "Down" +msgstr "↓" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:104 +msgid "Download Log" +msgstr "下载日志" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:59 +msgid "Enable" +msgstr "启用" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:94 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:92 +msgid "Error" +msgstr "错误 (Error)" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:93 +msgid "Fatal" +msgstr "致命" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:87 +msgid "Filter Level:" +msgstr "过滤等级:" + +#: applications/luci-app-cloudflared/root/usr/share/rpcd/acl.d/luci-app-cloudflared.json:3 +msgid "Grant access to Cloudflared configuration" +msgstr "授予访问 Cloudflared 配置的权限" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:52 +msgid "ID" +msgstr "ID" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:96 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:90 +msgid "Info" +msgstr "信息 (Info)" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:85 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:30 +msgid "Log" +msgstr "日志" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:94 +msgid "Log Direction:" +msgstr "日志呈现时序:" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:92 +msgid "Logging level" +msgstr "调试等级" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:51 +msgid "Name" +msgstr "名称" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:85 +msgid "No connections" +msgstr "无连接" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:55 +msgid "Not Running" +msgstr "未在运行" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:79 +msgid "Obtain a certificate here." +msgstr "在此处获取证书。" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:78 +msgid "Opened At" +msgstr "连接时间" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:77 +msgid "Origin IP" +msgstr "源 IP" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:86 +msgid "Region" +msgstr "地区" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:54 +msgid "Running" +msgstr "运行中" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:43 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:70 +msgid "See documentation." +msgstr "见 文档。" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:49 +msgid "Status" +msgstr "状态" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:78 +msgid "" +"The account certificate for your zones authorizing the client to serve as an " +"Origin for that zone" +msgstr "您区域的账户证书,用于授权客户端充当该区域的源站" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:87 +msgid "The region to which connections are established." +msgstr "建立连接的目标地区。" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:63 +msgid "The tunnel token is shown in the dashboard once you create a tunnel." +msgstr "一旦你创建了隧道,隧道令牌就会显示在仪表板中。" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:62 +msgid "Token" +msgstr "令牌" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:96 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:22 +msgid "Tunnels" +msgstr "隧道" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:48 +msgid "Tunnels Information" +msgstr "隧道信息" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:33 +msgid "Unable to read the interface info from /var/log/cloudflared.log." +msgstr "无法从 /var/log/cloudflared.log 中读取接口信息。" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:89 +msgid "United States" +msgstr "美国" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:97 +msgid "Up" +msgstr "↑" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:91 +msgid "Warn" +msgstr "警告" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:95 +msgid "Warning" +msgstr "警告 (Warning)" diff --git a/luci-app-cloudflared-next/po/zh_Hant/cloudflared.po b/luci-app-cloudflared-next/po/zh_Hant/cloudflared.po new file mode 100644 index 000000000..8398a8433 --- /dev/null +++ b/luci-app-cloudflared-next/po/zh_Hant/cloudflared.po @@ -0,0 +1,206 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2026-03-09 19:11+0000\n" +"Last-Translator: EESF-2 \n" +"Language-Team: Chinese (Traditional Han script) \n" +"Language: zh_Hant\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Weblate 5.17-dev\n" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:89 +msgid "All" +msgstr "全部" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:77 +msgid "Certificate of Origin" +msgstr "原點憑證" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:40 +msgid "" +"Cloudflare Zero Trust Security services help you get maximum security both " +"from outside and within the network." +msgstr "Cloudflare Zero Trust 安全服務幫助您在網路內外都得到最大程度的安全性。" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:39 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:3 +msgid "Cloudflare Zero Trust Tunnel" +msgstr "Cloudflare Zero Trust 隧道" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:69 +msgid "Config file path" +msgstr "配置檔案路徑" + +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:14 +msgid "Configuration" +msgstr "配置" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:76 +msgid "Connection ID" +msgstr "連線 ID" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:54 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:90 +msgid "Connections" +msgstr "連線數" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:41 +msgid "" +"Create and manage your network on the Cloudflare Zero Trust " +"dashboard." +msgstr "在 Cloudflare Zero Trust 儀表板上建立並管理你的網路。" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:53 +msgid "Created At" +msgstr "建立於" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:79 +msgid "Data Center" +msgstr "資料中心" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:97 +msgid "Debug" +msgstr "偵錯" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:96 +msgid "Down" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:104 +msgid "Download Log" +msgstr "下載紀錄" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:59 +msgid "Enable" +msgstr "啟用" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:94 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:92 +msgid "Error" +msgstr "錯誤" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:93 +msgid "Fatal" +msgstr "致命" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:87 +msgid "Filter Level:" +msgstr "篩選等級:" + +#: applications/luci-app-cloudflared/root/usr/share/rpcd/acl.d/luci-app-cloudflared.json:3 +msgid "Grant access to Cloudflared configuration" +msgstr "授予存取 Cloudflared 配置的權限" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:52 +msgid "ID" +msgstr "ID" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:96 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:90 +msgid "Info" +msgstr "資訊" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:85 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:30 +msgid "Log" +msgstr "紀錄" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:94 +msgid "Log Direction:" +msgstr "紀錄方向:" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:92 +msgid "Logging level" +msgstr "記錄等級" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:51 +msgid "Name" +msgstr "名稱" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:85 +msgid "No connections" +msgstr "無連線" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:55 +msgid "Not Running" +msgstr "未執行" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:79 +msgid "Obtain a certificate here." +msgstr "從這裡取得憑證。" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:78 +msgid "Opened At" +msgstr "已開啟於" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:77 +msgid "Origin IP" +msgstr "原點 IP" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:86 +msgid "Region" +msgstr "地區" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:54 +msgid "Running" +msgstr "執行中" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:43 +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:70 +msgid "See documentation." +msgstr "請看文件。" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:49 +msgid "Status" +msgstr "狀態" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:78 +msgid "" +"The account certificate for your zones authorizing the client to serve as an " +"Origin for that zone" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:87 +msgid "The region to which connections are established." +msgstr "建立連線的區域。" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:63 +msgid "The tunnel token is shown in the dashboard once you create a tunnel." +msgstr "當您建立隧道時,權杖會顯示在儀表板上。" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:62 +msgid "Token" +msgstr "權杖" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:96 +#: applications/luci-app-cloudflared/root/usr/share/luci/menu.d/luci-app-cloudflared.json:22 +msgid "Tunnels" +msgstr "隧道" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/tunnels.js:48 +msgid "Tunnels Information" +msgstr "隧道資訊" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:33 +msgid "Unable to read the interface info from /var/log/cloudflared.log." +msgstr "無法從 /var/log/cloudflared.log 讀取介面資訊。" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:89 +msgid "United States" +msgstr "美國" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:97 +msgid "Up" +msgstr "" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/log.js:91 +msgid "Warn" +msgstr "警告" + +#: applications/luci-app-cloudflared/htdocs/luci-static/resources/view/cloudflared/config.js:95 +msgid "Warning" +msgstr "警告" diff --git a/luci-app-cloudflared-next/root/usr/share/luci/menu.d/luci-app-cloudflared.json b/luci-app-cloudflared-next/root/usr/share/luci/menu.d/luci-app-cloudflared.json new file mode 100644 index 000000000..a5dfe9d26 --- /dev/null +++ b/luci-app-cloudflared-next/root/usr/share/luci/menu.d/luci-app-cloudflared.json @@ -0,0 +1,37 @@ +{ + "admin/vpn/cloudflared": { + "title": "Cloudflare Zero Trust Tunnel", + "order": 80, + "action": { + "type": "firstchild" + }, + "depends": { + "acl": [ "luci-app-cloudflared" ], + "uci": { "cloudflared": true } + } + }, + "admin/vpn/cloudflared/config": { + "title": "Configuration", + "order": 10, + "action": { + "type": "view", + "path": "cloudflared/config" + } + }, + "admin/vpn/cloudflared/tunnels": { + "title": "Tunnels", + "order": 20, + "action": { + "type": "view", + "path": "cloudflared/tunnels" + } + }, + "admin/vpn/cloudflared/log": { + "title": "Log", + "order": 30, + "action": { + "type": "view", + "path": "cloudflared/log" + } + } +} \ No newline at end of file diff --git a/luci-app-cloudflared-next/root/usr/share/rpcd/acl.d/luci-app-cloudflared.json b/luci-app-cloudflared-next/root/usr/share/rpcd/acl.d/luci-app-cloudflared.json new file mode 100644 index 000000000..287110f4d --- /dev/null +++ b/luci-app-cloudflared-next/root/usr/share/rpcd/acl.d/luci-app-cloudflared.json @@ -0,0 +1,22 @@ +{ + "luci-app-cloudflared": { + "description": "Grant access to Cloudflared configuration", + "read": { + "uci": [ "cloudflared" ], + "ubus": { + "service": [ "list" ] + }, + "file": { + "/etc/cloudflared/*": [ "read" ], + "/var/log/cloudflared.log": [ "read" ] + } + }, + "write": { + "uci": [ "cloudflared" ], + "file": { + "/etc/cloudflared/*": [ "write" ], + "/usr/bin/cloudflared *": [ "exec" ] + } + } + } +} \ No newline at end of file diff --git a/luci-app-easytier-next/Makefile b/luci-app-easytier-next/Makefile index 3b4b9e6d4..e146206ec 100644 --- a/luci-app-easytier-next/Makefile +++ b/luci-app-easytier-next/Makefile @@ -4,7 +4,7 @@ LUCI_TITLE:=LuCI support for EasyTier Next LUCI_URL:=https://github.com/EasyTier/EasyTier PKG_DESCRIPTION:=Provides a modern LuCI Web management interface for EasyTier decentralized mesh VPN. PKG_MAINTAINER:=Dante -LUCI_DEPENDS:=+easytier-next +luci-base +LUCI_DEPENDS:=+easytier-next +luci-base +ucode +ucode-mod-fs +ucode-mod-uci +ucode-mod-ubus LUCI_PKGARCH:=all define Package/luci-app-easytier-next/conffiles diff --git a/luci-app-easytier-next/root/usr/libexec/rpcd/easytier b/luci-app-easytier-next/root/usr/libexec/rpcd/easytier deleted file mode 100755 index 0db781866..000000000 --- a/luci-app-easytier-next/root/usr/libexec/rpcd/easytier +++ /dev/null @@ -1,471 +0,0 @@ -#!/usr/bin/env lua - -local json = require "luci.jsonc" -local nixio = require "nixio" -local fs = require "nixio.fs" - -local function trim(s) - if type(s) ~= 'string' then return '' end - return s:gsub("^%s+", ""):gsub("%s+$", "") -end - -local function exec_cmd(cmd) - local f = io.popen(cmd) - if not f then - return { code = -1, stdout = {}, raw = "" } - end - local content = f:read("*a") or "" - local success, msg, code = f:close() - content = trim(content) - local lines = {} - for line in string.gmatch(content .. "\n", "(.-)\r?\n") do - if line ~= "" then - table.insert(lines, line) - end - end - return { - code = (type(success) == "number" and success) or (code or 0), - stdout = lines, - raw = content - } -end - -local function get_procd_status(instance_name) - local ubus_res = exec_cmd("ubus call service list '{\"name\":\"easytier\"}' 2>/dev/null") - if ubus_res.raw and #ubus_res.raw > 0 then - local parsed = json.parse(ubus_res.raw) - if parsed and parsed.easytier and parsed.easytier.instances then - local inst = parsed.easytier.instances[instance_name or 'core'] - if inst and inst.running then - return { running = true, pid = inst.pid } - end - end - end - return { running = false } -end - -local function get_rogue_pid(bin_name, managed_pid) - local res = exec_cmd("pidof " .. bin_name .. " 2>/dev/null") - if res.raw and #res.raw > 0 then - for pid in string.gmatch(res.raw, "%d+") do - local num_pid = tonumber(pid) - if num_pid and (managed_pid == nil or num_pid ~= managed_pid) then - return num_pid - end - end - end - return nil -end - -local function get_service_state(bin_name, instance_name) - local procd_st = get_procd_status(instance_name) - local rogue_pid = get_rogue_pid(bin_name, procd_st.pid) - - local state = "stopped" - if procd_st.running then - state = "managed" - elseif rogue_pid then - state = "unmanaged" - end - - return { - state = state, - running = (state ~= "stopped"), - pid = procd_st.pid or rogue_pid - } -end - -local function get_cached_version() - local cache_file = '/tmp/easytier_version.cache' - local bin_path = '/usr/bin/easytier-core' - if not fs.access(bin_path) then return 'Unknown' end - - local bin_st = fs.stat(bin_path) - local cache_st = fs.stat(cache_file) - - if cache_st and (cache_st.size or 0) > 0 and bin_st and (cache_st.mtime or 0) >= (bin_st.mtime or 0) then - local cached = trim(fs.readfile(cache_file) or '') - if cached ~= '' then return cached end - end - - local ver_res = exec_cmd(bin_path .. ' --version 2>/dev/null') - if ver_res.stdout and #ver_res.stdout > 0 then - local ver_line = trim(ver_res.stdout[1]) - if ver_line ~= '' then - fs.writefile(cache_file, ver_line .. '\n') - return ver_line - end - end - return 'Unknown' -end - -local function get_route_info_map() - local route_map = {} - if not fs.access('/usr/bin/easytier-cli') then return route_map end - local r_res = exec_cmd('/usr/bin/easytier-cli -o json route 2>/dev/null') - if r_res.code == 0 and r_res.raw and #r_res.raw > 0 then - local r_data = json.parse(r_res.raw) - if r_data and type(r_data) == 'table' and #r_data > 0 then - for _, item in ipairs(r_data) do - local cidrs = trim(item.proxy_cidrs or '') - local ip = trim(item.ipv4 or '') - local host = trim(item.hostname or '') - local next_hop_host = trim(item.next_hop_hostname_lat_first or item.next_hop_hostname or '') - local next_hop_ip = trim(item.next_hop_ipv4_lat_first or item.next_hop_ipv4 or '') - local path_len = item.path_len_lat_first ~= nil and item.path_len_lat_first or item.path_len - local path_lat = item.path_latency_lat_first ~= nil and item.path_latency_lat_first or item.path_latency - - local entry = { - proxy_cidrs = cidrs, - next_hop_hostname = next_hop_host, - next_hop_ipv4 = next_hop_ip, - path_len = path_len, - path_latency = path_lat - } - - if ip ~= '' then - route_map[ip] = entry - local ip_clean = ip:match("^([^/]+)") or ip - route_map[ip_clean] = entry - end - if host ~= '' then - route_map[host] = entry - end - end - end - end - return route_map -end - -local methods = { - get_status = { - args = {}, - call = function(args) - local core_st = get_service_state('/usr/bin/easytier-core', 'core') - local web_st = get_service_state('/usr/bin/easytier-web', 'web') - - local data = { - installed = fs.access('/usr/bin/easytier-core') and true or false, - web_installed = fs.access('/usr/bin/easytier-web') and true or false, - version = get_cached_version(), - core = core_st, - web = web_st, - node_info = nil - } - - if core_st.running and fs.access('/usr/bin/easytier-cli') then - local node_res = exec_cmd('/usr/bin/easytier-cli node 2>/dev/null') - if node_res.raw and #node_res.raw > 0 then - data.node_info = node_res.raw - end - end - - return data - end - }, - - get_peers = { - args = {}, - call = function(args) - if not fs.access('/usr/bin/easytier-cli') then - return { peers = {}, raw = '' } - end - - local route_map = get_route_info_map() - - local json_res = exec_cmd('/usr/bin/easytier-cli -o json peer 2>/dev/null') - if json_res.code == 0 and json_res.raw and #json_res.raw > 0 then - local j_data = json.parse(json_res.raw) - if j_data and type(j_data) == 'table' and #j_data > 0 then - local peers = {} - for _, item in ipairs(j_data) do - local p_ip = trim(item.cidr or item.ipv4 or '') - local p_host = trim(item.hostname or '') - local p_ip_clean = p_ip:match("^([^/]+)") or p_ip - local r_entry = route_map[p_ip] or route_map[p_ip_clean] or route_map[p_host] or {} - local proxy_cidrs = r_entry.proxy_cidrs or '' - local next_hop_hostname = r_entry.next_hop_hostname or '' - local next_hop_ipv4 = r_entry.next_hop_ipv4 or '' - local path_latency = r_entry.path_latency ~= nil and r_entry.path_latency or '' - - table.insert(peers, { - ipv4 = p_ip, - hostname = p_host, - proxy_cidrs = proxy_cidrs, - next_hop_hostname = next_hop_hostname, - next_hop_ipv4 = next_hop_ipv4, - path_latency = path_latency, - cost = trim(item.cost or ''), - latency = (item.lat_ms ~= nil and item.lat_ms ~= '-') and tostring(item.lat_ms) or '-', - loss_rate = trim(item.loss_rate or '-'), - rx = trim(item.rx_bytes or '-'), - tx = trim(item.tx_bytes or '-'), - tunnel = trim(item.tunnel_proto or '-'), - nat = trim(item.nat_type or '-'), - version = trim(item.version or '-') - }) - end - return { peers = peers, raw = '' } - end - end - - local peer_res = exec_cmd('/usr/bin/easytier-cli peer 2>/dev/null') - local raw_output = peer_res.raw or '' - local peers = {} - - if peer_res.stdout and #peer_res.stdout > 0 then - for _, line in ipairs(peer_res.stdout) do - local trimmed = trim(line) - if trimmed ~= '' and not (trimmed:match("[Ii]pv4") and trimmed:match("|")) and not trimmed:match("^[%-%+─━%=| ]+$") then - local cols = {} - for part in string.gmatch(trimmed, "[^|]+") do - table.insert(cols, trim(part)) - end - if #cols >= 2 then - local peer_ip = trim(cols[1] or '') - local peer_host = trim(cols[2] or '') - local peer_ip_clean = peer_ip:match("^([^/]+)") or peer_ip - local r_entry = route_map[peer_ip] or route_map[peer_ip_clean] or route_map[peer_host] or {} - local proxy_cidrs = r_entry.proxy_cidrs or '' - local next_hop_hostname = r_entry.next_hop_hostname or '' - local next_hop_ipv4 = r_entry.next_hop_ipv4 or '' - local path_latency = r_entry.path_latency ~= nil and r_entry.path_latency or '' - - table.insert(peers, { - ipv4 = peer_ip, - hostname = peer_host, - proxy_cidrs = proxy_cidrs, - next_hop_hostname = next_hop_hostname, - next_hop_ipv4 = next_hop_ipv4, - path_latency = path_latency, - cost = cols[3] or '-', - latency = cols[4] or '-', - loss_rate = cols[5] or '-', - rx = cols[6] or '-', - tx = cols[7] or '-', - tunnel = cols[8] or '-', - nat = cols[9] or '-', - version = cols[10] or '-' - }) - end - end - end - end - - return { peers = peers, raw = raw_output } - end - }, - - get_topology = { - args = {}, - call = function(args) - if not fs.access('/usr/bin/easytier-cli') then - return { nodes = {} } - end - - local route_map = get_route_info_map() - local res = exec_cmd('/usr/bin/easytier-cli -o json peer-center 2>/dev/null') - if res.code == 0 and res.raw and #res.raw > 0 then - local data = json.parse(res.raw) - if data and type(data) == 'table' and #data > 0 then - local valid_nodes = {} - for _, n in ipairs(data) do - local n_ip = trim(n.ipv4 or '') - local n_host = trim(n.hostname or '') - if n_host ~= '' and not n_host:lower():match("^unknown$") and n_ip ~= '' and n_ip ~= '-' then - local n_ip_clean = n_ip:match("^([^/]+)") or n_ip - local r_entry = route_map[n_ip] or route_map[n_ip_clean] or route_map[n_host] or {} - n.proxy_cidrs = r_entry.proxy_cidrs or '' - table.insert(valid_nodes, n) - end - end - return { nodes = valid_nodes } - end - end - return { nodes = {} } - end - }, - - get_subroutes = { - args = {}, - call = function(args) - local subnets = {} - local seen = {} - - local res = exec_cmd("ip -j route 2>/dev/null") - if res.code == 0 and res.raw and #res.raw > 0 then - local routes_json = json.parse(res.raw) - if routes_json and type(routes_json) == 'table' then - for _, r in ipairs(routes_json) do - if r.dst and r.dst ~= 'default' and r.scope == 'link' and r.dst:find("%.") and r.dev ~= 'easytier0' and r.dev ~= 'lo' then - if not seen[r.dst] then - seen[r.dst] = true - table.insert(subnets, r.dst) - end - end - end - end - end - - if #subnets == 0 then - local txt_res = exec_cmd("ip route 2>/dev/null") - if txt_res.stdout and #txt_res.stdout > 0 then - for _, line in ipairs(txt_res.stdout) do - line = trim(line) - if line ~= '' and not line:lower():match("^default") and not line:find("easytier0") and not line:find("lo") then - local subnet, dev = line:match("^(%d+%.%d+%.%d+%.%d+/%d+)%s+dev%s+([^%s]+)") - if subnet and dev and dev ~= 'easytier0' and dev ~= 'lo' and not seen[subnet] then - seen[subnet] = true - table.insert(subnets, subnet) - end - end - end - end - end - - if #subnets == 0 then - local net_res = exec_cmd("ubus call network.interface dump 2>/dev/null") - if net_res.raw and #net_res.raw > 0 then - local net_data = json.parse(net_res.raw) - if net_data and net_data.interface then - for _, iface in ipairs(net_data.interface) do - if iface.interface ~= 'loopback' and iface.interface ~= 'easytier' and iface['ipv4-address'] then - for _, addr in ipairs(iface['ipv4-address']) do - local ip_str = addr.address - local mask = addr.mask - if ip_str and mask then - local p1, p2, p3, p4 = ip_str:match("^(%d+)%.(%d+)%.(%d+)%.(%d+)$") - if p1 and p2 and p3 and p4 then - local subnet = '' - if mask == 24 then - subnet = string.format("%s.%s.%s.0/24", p1, p2, p3) - elseif mask == 16 then - subnet = string.format("%s.%s.0.0/16", p1, p2) - elseif mask == 8 then - subnet = string.format("%s.0.0.0/8", p1) - else - subnet = string.format("%s/%s", ip_str, mask) - end - if subnet ~= '' and not seen[subnet] then - seen[subnet] = true - table.insert(subnets, subnet) - end - end - end - end - end - end - end - end - end - - return { routes = subnets } - end - }, - - get_logs = { - args = {}, - call = function(args) - local logs = {} - local res = exec_cmd("logread -e easytier 2>/dev/null | tail -n 80") - if res.stdout and #res.stdout > 0 then - logs = res.stdout - elseif fs.access('/tmp/easytier.log') then - local f_res = exec_cmd("tail -n 80 /tmp/easytier.log 2>/dev/null") - if f_res.stdout then logs = f_res.stdout end - end - return { logs = logs } - end - }, - - clear_logs = { - args = {}, - call = function(args) - fs.writefile('/tmp/easytier.log', '') - fs.writefile('/tmp/easytier-web.log', '') - return { success = true } - end - }, - - service_action = { - args = { action = "action" }, - call = function(args) - local action = args and args.action - if not action then return { success = false, error = "Missing action" } end - - if action == "restart" or action == "stop" then - os.execute("killall -9 easytier-core easytier-web 2>/dev/null") - end - - if action == "start" or action == "restart" then - os.execute("/etc/init.d/easytier restart >/dev/null 2>&1") - elseif action == "stop" then - os.execute("/etc/init.d/easytier stop >/dev/null 2>&1") - end - - return { success = true } - end - } -} - -local function parseInput() - local parse = json.new() - local done, err - - while true do - local chunk = io.read(4096) - if not chunk or #chunk == 0 then - break - end - done, err = parse:parse(chunk) - if done then - break - end - end - - if not done then - print(json.stringify({ error = err or "Incomplete input" })) - os.exit(1) - end - - return parse:get() -end - -local function validateArgs(func, uargs) - local method = methods[func] - if not method then - print(json.stringify({ error = "Method not found" })) - os.exit(1) - end - - if type(uargs) ~= "table" then - print(json.stringify({ error = "Invalid arguments" })) - os.exit(1) - end - - uargs.ubus_rpc_session = nil - - local margs = method.args or {} - for k, _ in pairs(uargs) do - if margs[k] == nil then - print(json.stringify({ error = "Invalid argument: " .. tostring(k) })) - os.exit(1) - end - end - - return method -end - -if arg[1] == "list" then - local rv = {} - for name, method in pairs(methods) do - rv[name] = method.args or {} - end - print((json.stringify(rv):gsub(":%[%]", ":{}"))) -elseif arg[1] == "call" then - local args = parseInput() - local method = validateArgs(arg[2], args) - local result, code = method.call(args) - print((json.stringify(result):gsub("^%[%]$", "{}"))) - os.exit(code or 0) -end diff --git a/luci-app-easytier-next/root/usr/share/rpcd/ucode/easytier.uc b/luci-app-easytier-next/root/usr/share/rpcd/ucode/easytier.uc new file mode 100644 index 000000000..0b0000da7 --- /dev/null +++ b/luci-app-easytier-next/root/usr/share/rpcd/ucode/easytier.uc @@ -0,0 +1,419 @@ +'use strict'; + +import { connect } from 'ubus'; +import { access, readfile, writefile, stat, popen } from 'fs'; + +function exec(cmd) { + let p = popen(cmd, 'r'); + if (!p) return { code: -1, stdout: [] }; + let out = []; + while (true) { + let line = p.read('line'); + if (line == null) break; + push(out, rtrim(line, '\r\n')); + } + let code = p.close(); + return { code: code, stdout: out }; +} + +function trim(s) { + if (s == null) return ''; + return replace('' + s, /^[\s\r\n]+|[\s\r\n]+$/g, ''); +} + +function get_procd_status(instance_name) { + let u = connect(); + if (!u) return { running: false }; + + let res = u.call('service', 'list', { name: 'easytier' }); + if (res && res['easytier'] && res['easytier'].instances) { + let instances = res['easytier'].instances; + let inst = instances[instance_name || 'core']; + if (inst && inst.running) + return { running: true, pid: inst.pid }; + } + return { running: false }; +} + +function get_rogue_pid(bin_name, managed_pid) { + let res = exec('pidof ' + bin_name + ' 2>/dev/null'); + if (res.code == 0 && length(res.stdout) > 0) { + let pid_str = trim(join(' ', res.stdout)); + if (pid_str != '') { + let pids = split(pid_str, /\s+/); + for (let i = 0; i < length(pids); i++) { + let pid = pids[i]; + if (pid != '' && (managed_pid == null || pid != ('' + managed_pid))) + return +pid; + } + } + } + return null; +} + +function get_service_state(bin_name, instance_name) { + let procd_st = get_procd_status(instance_name); + let rogue_pid = get_rogue_pid(bin_name, procd_st.pid); + + let state = 'stopped'; + if (procd_st.running) + state = 'managed'; + else if (rogue_pid) + state = 'unmanaged'; + + return { + state: state, + running: (state != 'stopped'), + pid: procd_st.pid || rogue_pid || null + }; +} + +function get_cached_version() { + const cache_file = '/tmp/easytier_version.cache'; + const bin_path = '/usr/bin/easytier-core'; + if (!access(bin_path)) return 'Unknown'; + + let bin_st = stat(bin_path); + let cache_st = access(cache_file) ? stat(cache_file) : null; + + if (cache_st && cache_st.size > 0 && bin_st && cache_st.mtime >= bin_st.mtime) { + let cached = trim(readfile(cache_file) || ''); + if (cached != '') return cached; + } + + let ver_res = exec(bin_path + ' --version 2>/dev/null'); + if (ver_res.code == 0 && length(ver_res.stdout) > 0) { + let ver_line = trim(ver_res.stdout[0]); + if (ver_line != '') { + writefile(cache_file, ver_line + '\n'); + return ver_line; + } + } + return 'Unknown'; +} + +const methods = {}; + +methods.get_status = { + call: function() { + let core_st = get_service_state('/usr/bin/easytier-core', 'core'); + let web_st = get_service_state('/usr/bin/easytier-web', 'web'); + + let data = { + installed: access('/usr/bin/easytier-core') ? true : false, + web_installed: access('/usr/bin/easytier-web') ? true : false, + version: get_cached_version(), + core: core_st, + web: web_st, + node_info: null + }; + + if (core_st.running && access('/usr/bin/easytier-cli')) { + let node_res = exec('/usr/bin/easytier-cli node 2>/dev/null'); + if (node_res.code == 0 && length(node_res.stdout) > 0) { + data.node_info = join('\n', node_res.stdout); + } + } + + return data; + } +}; + +function get_route_info_map() { + let route_map = {}; + if (!access('/usr/bin/easytier-cli')) return route_map; + let r_res = exec('/usr/bin/easytier-cli -o json route 2>/dev/null'); + if (r_res.code == 0 && length(r_res.stdout) > 0) { + let r_data = json(join('\n', r_res.stdout)); + if (r_data && length(r_data) > 0) { + for (let i = 0; i < length(r_data); i++) { + let item = r_data[i]; + let cidrs = trim(item.proxy_cidrs || ''); + let ip = trim(item.ipv4 || ''); + let host = trim(item.hostname || ''); + let next_hop_host = trim(item.next_hop_hostname_lat_first || item.next_hop_hostname || ''); + let next_hop_ip = trim(item.next_hop_ipv4_lat_first || item.next_hop_ipv4 || ''); + let path_len = item.path_len_lat_first != null ? item.path_len_lat_first : item.path_len; + let path_lat = item.path_latency_lat_first != null ? item.path_latency_lat_first : item.path_latency; + + let entry = { + proxy_cidrs: cidrs, + next_hop_hostname: next_hop_host, + next_hop_ipv4: next_hop_ip, + path_len: path_len, + path_latency: path_lat + }; + + if (ip != '') { + route_map[ip] = entry; + let ip_clean = split(ip, '/')[0]; + route_map[ip_clean] = entry; + } + if (host != '') { + route_map[host] = entry; + } + } + } + } + return route_map; +} + +methods.get_peers = { + call: function() { + if (!access('/usr/bin/easytier-cli')) { + return { peers: [], raw: '' }; + } + + let route_map = get_route_info_map(); + let json_res = exec('/usr/bin/easytier-cli -o json peer 2>/dev/null'); + if (json_res.code == 0 && length(json_res.stdout) > 0) { + let j_data = json(join('\n', json_res.stdout)); + if (j_data && length(j_data) > 0) { + let peers = []; + for (let i = 0; i < length(j_data); i++) { + let item = j_data[i]; + let p_ip = trim(item.cidr || item.ipv4 || ''); + let p_host = trim(item.hostname || ''); + let p_ip_clean = split(p_ip, '/')[0]; + let r_entry = route_map[p_ip] || route_map[p_ip_clean] || route_map[p_host] || {}; + let proxy_cidrs = r_entry.proxy_cidrs || ''; + let next_hop_hostname = r_entry.next_hop_hostname || ''; + let next_hop_ipv4 = r_entry.next_hop_ipv4 || ''; + let path_latency = r_entry.path_latency != null ? r_entry.path_latency : ''; + + push(peers, { + ipv4: p_ip, + hostname: p_host, + proxy_cidrs: proxy_cidrs, + next_hop_hostname: next_hop_hostname, + next_hop_ipv4: next_hop_ipv4, + path_latency: path_latency, + cost: trim(item.cost || ''), + latency: (item.lat_ms != null && item.lat_ms != '-') ? ('' + item.lat_ms) : '-', + loss_rate: trim(item.loss_rate || '-'), + rx: trim(item.rx_bytes || '-'), + tx: trim(item.tx_bytes || '-'), + tunnel: trim(item.tunnel_proto || '-'), + nat: trim(item.nat_type || '-'), + version: trim(item.version || '-') + }); + } + return { peers: peers, raw: '' }; + } + } + + let peer_res = exec('/usr/bin/easytier-cli peer 2>/dev/null'); + let raw_output = (peer_res.code == 0) ? join('\n', peer_res.stdout) : ''; + let peers = []; + if (peer_res.code == 0 && length(peer_res.stdout) > 0) { + for (let i = 0; i < length(peer_res.stdout); i++) { + let line = trim(peer_res.stdout[i]); + if (line == '' || match(line, /ipv4|hostname|--/i) && match(line, /\|/)) continue; + if (match(line, /^[-+─━=| ]+$/)) continue; + + let parts = split(line, '|'); + let cols = []; + for (let idx = 0; idx < length(parts); idx++) { + push(cols, trim(parts[idx])); + } + if (length(cols) > 0 && cols[0] == '') shift(cols); + if (length(cols) > 0 && cols[length(cols) - 1] == '') pop(cols); + + if (length(cols) >= 2) { + let peer_ip = trim(cols[0] || ''); + let peer_host = trim(cols[1] || ''); + let peer_ip_clean = split(peer_ip, '/')[0]; + let r_entry = route_map[peer_ip] || route_map[peer_ip_clean] || route_map[peer_host] || {}; + let proxy_cidrs = r_entry.proxy_cidrs || ''; + let next_hop_hostname = r_entry.next_hop_hostname || ''; + let next_hop_ipv4 = r_entry.next_hop_ipv4 || ''; + let path_latency = r_entry.path_latency != null ? r_entry.path_latency : ''; + + push(peers, { + ipv4: peer_ip, + hostname: peer_host, + proxy_cidrs: proxy_cidrs, + next_hop_hostname: next_hop_hostname, + next_hop_ipv4: next_hop_ipv4, + path_latency: path_latency, + cost: trim(cols[2] || ''), + latency: trim(cols[3] || ''), + loss_rate: trim(cols[4] || ''), + rx: trim(cols[5] || ''), + tx: trim(cols[6] || ''), + tunnel: trim(cols[7] || ''), + nat: trim(cols[8] || ''), + version: trim(cols[9] || '') + }); + } + } + } + + return { peers: peers, raw: raw_output }; + } +}; + +methods.get_logs = { + call: function() { + let logs = []; + let res = exec('logread -e easytier 2>/dev/null | tail -n 80'); + if (res.code == 0 && length(res.stdout) > 0) { + logs = res.stdout; + } else if (access('/tmp/easytier.log')) { + let f_res = exec('tail -n 80 /tmp/easytier.log 2>/dev/null'); + if (f_res.code == 0) logs = f_res.stdout; + } + return { logs: logs }; + } +}; + +methods.get_topology = { + call: function() { + if (!access('/usr/bin/easytier-cli')) { + return { nodes: [] }; + } + let route_map = get_route_info_map(); + let res = exec('/usr/bin/easytier-cli -o json peer-center 2>/dev/null'); + if (res.code == 0 && length(res.stdout) > 0) { + let full_str = join('\n', res.stdout); + let data = json(full_str); + if (data && length(data) > 0) { + let valid_nodes = []; + for (let i = 0; i < length(data); i++) { + let n_ip = trim(data[i].ipv4 || ''); + let n_host = trim(data[i].hostname || ''); + if (n_host == '' || match(n_host, /^unknown$/i)) continue; + if (n_ip == '' || n_ip == '-') continue; + + let n_ip_clean = split(n_ip, '/')[0]; + let r_entry = route_map[n_ip] || route_map[n_ip_clean] || route_map[n_host] || {}; + data[i].proxy_cidrs = r_entry.proxy_cidrs || ''; + push(valid_nodes, data[i]); + } + return { nodes: valid_nodes }; + } + } + return { nodes: [] }; + } +}; + +methods.get_subroutes = { + call: function() { + try { + let subnets = []; + let seen = {}; + + // 1. 尝试 ip -j route (支持 JSON 的 iproute2) + let res = exec('ip -j route 2>/dev/null'); + if (res && res.code == 0 && length(res.stdout) > 0) { + let routes_json = json(join('', res.stdout)); + if (routes_json && length(routes_json) > 0) { + for (let i = 0; i < length(routes_json); i++) { + let r = routes_json[i]; + if (r.dst && r.dst != 'default' && r.scope == 'link' && index(r.dst, '.') != -1 && r.dev != 'easytier0' && r.dev != 'lo') { + if (!seen[r.dst]) { + seen[r.dst] = true; + push(subnets, r.dst); + } + } + } + } + } + + // 2. 降级:标准文本格式 ip route (兼容 OpenWrt 21.02/BusyBox) + if (length(subnets) == 0) { + let txt_res = exec('ip route 2>/dev/null'); + if (txt_res && txt_res.code == 0 && length(txt_res.stdout) > 0) { + for (let i = 0; i < length(txt_res.stdout); i++) { + let line = trim(txt_res.stdout[i]); + if (line == '' || match(line, /^default/i)) continue; + if (index(line, 'easytier0') != -1 || index(line, 'lo') != -1) continue; + let m = match(line, /^([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\/[0-9]+)\s+dev\s+([^\s]+)/); + if (m && m[1]) { + let subnet = m[1]; + let dev = m[2]; + if (dev != 'easytier0' && dev != 'lo' && !seen[subnet]) { + seen[subnet] = true; + push(subnets, subnet); + } + } + } + } + } + + // 3. 终极兜底:通过 ubus 调用 network.interface dump 提取各接口 IPv4 直连子网 + if (length(subnets) == 0) { + let net_res = exec('ubus call network.interface dump 2>/dev/null'); + if (net_res && net_res.code == 0 && length(net_res.stdout) > 0) { + let net_data = json(join('', net_res.stdout)); + if (net_data && net_data.interface && length(net_data.interface) > 0) { + for (let i = 0; i < length(net_data.interface); i++) { + let iface = net_data.interface[i]; + if (iface.interface == 'loopback' || iface.interface == 'easytier') continue; + if (iface['ipv4-address'] && length(iface['ipv4-address']) > 0) { + for (let j = 0; j < length(iface['ipv4-address']); j++) { + let addr = iface['ipv4-address'][j]; + let ip_str = addr.address; + let mask = addr.mask; + if (ip_str && mask) { + let parts = split(ip_str, '.'); + if (length(parts) == 4) { + let subnet = ''; + if (mask == 24) { + subnet = parts[0] + '.' + parts[1] + '.' + parts[2] + '.0/24'; + } else if (mask == 16) { + subnet = parts[0] + '.' + parts[1] + '.0.0/16'; + } else if (mask == 8) { + subnet = parts[0] + '.0.0.0/8'; + } else { + subnet = ip_str + '/' + mask; + } + if (subnet != '' && !seen[subnet]) { + seen[subnet] = true; + push(subnets, subnet); + } + } + } + } + } + } + } + } + } + + return { routes: subnets }; + } catch(e) { + return { routes: [] }; + } + } +}; + +methods.clear_logs = { + call: function() { + writefile('/tmp/easytier.log', ''); + writefile('/tmp/easytier-web.log', ''); + return { success: true }; + } +}; + +methods.service_action = { + args: { action: 'action' }, + call: function(req) { + let action = req.args?.action; + if (!action) return { success: false, error: 'Missing action' }; + + if (action == 'restart' || action == 'stop') { + exec('killall -9 easytier-core easytier-web 2>/dev/null'); + } + + if (action == 'start' || action == 'restart') { + exec('/etc/init.d/easytier restart >/dev/null 2>&1'); + } else if (action == 'stop') { + exec('/etc/init.d/easytier stop >/dev/null 2>&1'); + } + + return { success: true }; + } +}; + +return { 'easytier': methods }; diff --git a/luci-app-flowproxy/Makefile b/luci-app-flowproxy/Makefile new file mode 100644 index 000000000..e3b546140 --- /dev/null +++ b/luci-app-flowproxy/Makefile @@ -0,0 +1,33 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=luci-app-flowproxy +PKG_VERSION:=1.0.3 +PKG_RELEASE:=1 + +LUCI_TITLE:=LuCI Support for FlowProxy Traffic Diversion +LUCI_DEPENDS:=+luci-base +LUCI_PKGARCH:=all + +define Package/$(PKG_NAME)/prerm +#!/bin/sh +if [ -z "$${IPKG_INSTROOT}" ]; then + /etc/init.d/flowproxy stop + /etc/init.d/flowproxy disable +fi +exit 0 +endef + +define Package/$(PKG_NAME)/postrm +#!/bin/sh +if [ -z "$${IPKG_INSTROOT}" ]; then + rm -rf /tmp/flowproxy + rm -rf /usr/share/flowproxy + rm -f /var/log/flowproxy.log* + rm -f /var/run/flowproxy.* +fi +exit 0 +endef + +include $(TOPDIR)/feeds/luci/luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-app-flowproxy/htdocs/luci-static/resources/view/flowproxy/flowproxy.js b/luci-app-flowproxy/htdocs/luci-static/resources/view/flowproxy/flowproxy.js new file mode 100644 index 000000000..eb1449868 --- /dev/null +++ b/luci-app-flowproxy/htdocs/luci-static/resources/view/flowproxy/flowproxy.js @@ -0,0 +1,560 @@ +'use strict'; +'require form'; +'require uci'; +'require rpc'; +'require poll'; +'require view'; +'require dom'; +'require fs'; +'require ui'; +'require network'; + +var callGetStatus = rpc.declare({ + object: 'luci.flowproxy', + method: 'get_status' +}); + +var callGetLogs = rpc.declare({ + object: 'luci.flowproxy', + method: 'get_logs', + params: ['lines'] +}); + +var callClearLogs = rpc.declare({ + object: 'luci.flowproxy', + method: 'clear_logs' +}); + +var callGenerateNftConfig = rpc.declare({ + object: 'luci.flowproxy', + method: 'generate_nft_config' +}); + +var callGetRuntimeConfig = rpc.declare({ + object: 'luci.flowproxy', + method: 'get_runtime_config' +}); + +var callRestartService = rpc.declare({ + object: 'luci.flowproxy', + method: 'restart_service' +}); + +return L.view.extend({ + load: function() { + return Promise.all([ + uci.load('flowproxy').catch(function() { return {}; }), + network.getDevices(), + callGetStatus().catch(function() { return {}; }), + network.getNetworks().catch(function() { return []; }) + ]); + }, + + highlightNft: function(text) { + if (!text || text.trim() === '') return '' + _('(no content / table not loaded)') + ''; + var rules = [ + { rex: /#(.*)/g, cls: 'comment' }, + { rex: /\b(table|chain|set|elements|type)\b/g, cls: 'keyword' }, + { rex: /\b(ip|ip6|tcp|udp|ether|meta|meta nfproto)\b/g, cls: 'proto' }, + { rex: /\b(saddr|daddr|sport|dport|mark)\b/g, cls: 'match' }, + { rex: /\b(return|accept|drop|reject|counter|set)\b/g, cls: 'action' }, + { rex: /@[\w_]+/g, cls: 'variable' }, + { rex: /\{|\}/g, cls: 'bracket' } + ]; + var html = text.replace(/[&<>"']/g, function(m) { + return { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[m]; + }); + rules.forEach(function(r) { + html = html.replace(r.rex, function(match) { + return '' + match + ''; + }); + }); + return html; + }, + refreshStatus: function(map, node) { + return callGetStatus().then(L.bind(function(status) { + if (!status) return; + var isRunning = (status.running == 1); + var container = node || document; + + var statusEl = container.querySelector('#service-status'); + if (statusEl) { + var content = []; + if (isRunning) { + var chains = []; + if (status.nft && status.nft.tcp) chains.push('TCP'); + if (status.nft && status.nft.udp) chains.push('UDP'); + var ip = status.proxy_server_ip_addr || '-'; + content.push(E('span', { 'style': 'color: green; font-weight: bold;' }, [ _('running') ])); + content.push(' (' + ip + ':'); + content.push(E('span', { 'style': 'color: #FF9800; font-weight: bold;' }, [ chains.join('+') || '-' ])); + content.push(') '); + content.push(E('button', { + 'class': 'btn cbi-button cbi-button-apply', + 'style': 'margin-left: 10px;', + 'click': ui.createHandlerFn(this, 'handleRestart') + }, [ _('Restart') ])); + } else { + content.push(E('span', { 'style': 'color: red; font-weight: bold;' }, [ _('stopped') ])); + } + L.dom.content(statusEl, content); + } + + var dnsEl = container.querySelector('#dns-status'); + if (dnsEl) { + var dcontent = []; + if (status.dns_running == 1) { + var ip = status.proxy_server_ip_addr || '-'; + var port = status.proxy_server_dns_port || '5353'; + dcontent.push(E('span', { 'style': 'color: green; font-weight: bold;' }, [ _('running') ])); + dcontent.push(' (' + ip + ':'); + dcontent.push(E('span', { 'style': 'color: #FF9800; font-weight: bold;' }, [ port ])); + dcontent.push(')'); + } else { + dcontent.push(E('span', { 'style': 'color: red; font-weight: bold;' }, [ _('stopped') ])); + } + L.dom.content(dnsEl, dcontent); + } + }, this)); + }, + + refreshLogs: function() { + return callGetLogs(500).then(L.bind(function(data) { + var logEl = document.getElementById('log-content'); + if (logEl) { + var logs = (data && Array.isArray(data.logs)) ? data.logs : []; + logEl.value = logs.length > 0 ? logs.join('\n') : _('no logs available'); + if (logs.length > 0) logEl.scrollTop = logEl.scrollHeight; + } + }, this)); + }, + + handleRestart: function() { + ui.showModal(null, [ + E('p', { 'class': 'spinning' }, _('Restarting FlowProxy service...')) + ]); + + return callRestartService().then(L.bind(function(res) { + ui.hideModal(); + if (res && res.result) { + ui.addNotification(null, E('p', _('FlowProxy service restarted successfully.')), 'info'); + window.setTimeout(function() { + location.reload(); + }, 1500); + } else { + ui.addNotification(null, E('p', _('Failed to restart FlowProxy service.')), 'error'); + } + }, this)).catch(function(err) { + ui.hideModal(); + ui.addNotification(null, E('p', _('RPC error: %s').format((err && (err.message || String(err))) || 'Unknown error')), 'error'); + }); + }, + render: function(data) { + var self = this; + var devices = data[1]; + var status = data[2]; + var ifaces = data[3] || []; + var m, s, o; + + m = new form.Map('flowproxy', _('FlowProxy'), + _('Traffic diversion based on nftables rules. The service will automatically start/stop when you click "Save & Apply".')); + + if (!document.getElementById('flowproxy-style')) { + document.head.appendChild(E('style', { id: 'flowproxy-style' }, ` + #log-content { width: 100% !important; height: 60vh; min-height: 400px; font-family: monospace; font-size: 12px; background: #f5f5f5 !important; color: #333 !important; border: 1px solid #ccc !important; padding: 10px; resize: vertical; border-radius: 4px; box-sizing: border-box; } + .nft-code-view { background: #f5f5f5 !important; color: #333333 !important; padding: 15px !important; font-family: monospace !important; font-size: 12px !important; overflow-x: auto !important; white-space: pre-wrap !important; width: 100% !important; border: 1px solid #cccccc !important; border-radius: 4px; box-sizing: border-box; max-height: 70vh; } + .nft-comment { color: #777777; font-style: italic; } .nft-keyword { color: #a626a1; font-weight: bold; } .nft-proto { color: #4078f2; } .nft-match { color: #986801; } .nft-action { color: #e45649; font-weight: bold; } .nft-variable { color: #50a14f; font-weight: bold; } + .cbi-section-table-titles th[data-sortable-row]::after, .cbi-section-table-titles th[data-sortable-row]::before { display: none !important; } + .cbi-section-table-titles th[data-sortable-row] { pointer-events: none !important; cursor: default !important; } + `)); + } + + s = m.section(form.NamedSection, 'global', 'flowproxy'); + s.tab('settings', _('Settings')); + s.tab('rules', _('Rules')); + s.tab('lists', _('Lists')); + s.tab('preview', _('Preview')); + s.tab('logs', _('Logs')); + + // --- Settings --- + o = s.taboption('settings', form.DummyValue, '_service_status', _('Current Status')); + o.rawhtml = true; + o.cfgvalue = function() { return '
' + _('checking...') + '
'; }; + + o = s.taboption('settings', form.DummyValue, '_dns_status', _('DNS Redirection')); + o.rawhtml = true; + o.cfgvalue = function() { return '
-
'; }; + + s.taboption('settings', form.Flag, 'enabled', _('Enable FlowProxy')).rmempty = false; + s.taboption('settings', form.Flag, 'dns_proxy_enabled', _('Force upstream DNS to proxy server')).rmempty = false; + + o = s.taboption('settings', form.Value, 'proxy_server_ip_addr', _('Proxy server IP address')); + o.datatype = 'ip4addr'; o.rmempty = false; + o.placeholder = '192.168.1.254'; + o.validate = function(section_id, value) { + var ipInCidr = function(ipStr, cidrStr) { + if (!cidrStr || cidrStr.indexOf(':') !== -1 || !ipStr || ipStr.indexOf(':') !== -1) return false; + var parts = cidrStr.split('/'); + var cidrIp = parts[0]; + var maskBits = parseInt(parts[1] || '32', 10); + + var ipToNum = function(s) { + var p = s.split('.'); + if (p.length !== 4) return 0; + return (((parseInt(p[0], 10) << 24) | + (parseInt(p[1], 10) << 16) | + (parseInt(p[2], 10) << 8) | + parseInt(p[3], 10)) >>> 0); + }; + + var ipNum = ipToNum(ipStr); + var cidrNum = ipToNum(cidrIp); + + if (maskBits === 0) return true; + + var mask = (0xffffffff << (32 - maskBits)) >>> 0; + return (ipNum & mask) === (cidrNum & mask); + }; + + var selected_interface = s.formvalue(section_id, 'interface'); + if (!value || !selected_interface) return true; + + var target_iface = null; + for (var i = 0; i < ifaces.length; i++) { + var dev = ifaces[i].getL3Device() || ifaces[i].getDevice(); + if ((dev && dev.getName() === selected_interface) || ifaces[i].getName() === selected_interface) { + target_iface = ifaces[i]; + break; + } + } + + if (!target_iface) return true; + + var ips = target_iface.getIPAddrs(); + if (!ips || ips.length === 0) return true; + + var inSubnet = false; + for (var j = 0; j < ips.length; j++) { + if (ipInCidr(value, ips[j])) { + inSubnet = true; + break; + } + } + + if (!inSubnet) { + return _('The proxy server IP address must be within the subnet of the selected interface (%s).').format(ips.join(', ')); + } + + return true; + }; + + o = s.taboption('settings', form.Value, 'proxy_server_dns_port', _('Proxy server DNS port')); + o.datatype = 'port'; o.default = '5353'; o.rmempty = false; + + o = s.taboption('settings', form.ListValue, 'interface', _('Proxy server interface')); + devices.forEach(function(d) { o.value(d.getName(), d.getName()); }); + o.default = 'br-lan'; + + s.taboption('settings', form.Value, 'traffic_mark', _('Traffic Mark')).datatype = 'or(uinteger, hex)'; + s.taboption('settings', form.Value, 'routing_table', _('Routing Table ID')).datatype = 'and(uinteger,range(1, 4294967295))'; + s.taboption('settings', form.Value, 'rule_priority', _('Rule Priority')).datatype = 'and(uinteger,range(0, 4294967295))'; + + // --- Rules --- + var nftsets = uci.sections('flowproxy', 'nftset').map(function(ss) { return '@' + ss['.name']; }); + + var setupRuleTable = function(type, title, switch_opt) { + var st = s.taboption('rules', form.SectionValue, '_tab_' + type, form.TableSection, type, title); + var ss = st.subsection; + ss.addremove = true; ss.anonymous = true; ss.sortable = true; + + var refreshTable = function() { + return ss.render().then(function(newNode) { + var el = document.getElementById('flowproxy-table-' + type); + if (el && el.parentNode) { + el.parentNode.replaceChild(newNode, el); + } + }); + }; + + var createTemplateButtons = function() { + var presets = { + 'priv': { name: 'private (dst)', type: 'dst_ip', val: '@private_dst_ip_v4' }, + 'china': { name: 'china (dst)', type: 'dst_ip', val: '@chnroute_dst_ip_v4' }, + 'src_ip': { name: 'ip (src)', type: 'src_ip', val: '@no_proxy_src_ip_v4' }, + 'dst_ip': { name: 'ip (dst)', type: 'dst_ip', val: '@no_proxy_dst_ip_v4' }, + 'mac': { name: 'mac (src)', type: 'src_mac', val: '@no_proxy_src_mac' }, + 'ports': { name: 'ports (dst)', type: 'dst_port', val: (type === 'tcp_rule') ? '@no_proxy_dst_tcp_ports' : '@no_proxy_dst_udp_ports' } + }; + var btnGroup = E('div', { 'style': 'display: flex; flex-wrap: wrap; gap: 4px; margin-top: 8px; align-items: center;' }, [ E('small', { 'style': 'margin-right: 5px; color: #888;' }, _('Quick add:')) ]); + Object.keys(presets).forEach(function(k) { + var p = presets[k]; + + var bgColors = { + 'dst_ip': '#2196F3', + 'src_ip': '#2196F3', + 'custom': '#2196F3', + 'src_mac': '#9C27B0', + 'dst_port': '#FF9800' + }; + var btnStyle = 'padding: 0 6px; font-size: 0.75rem; height: 22px; line-height: 22px; opacity: 0.9; margin-bottom: 4px; border: none; color: #fff; border-radius: 3px; cursor: pointer;'; + var bgColor = bgColors[p.type] || '#607d8b'; + btnStyle += ' background-color: ' + bgColor + ';'; + + btnGroup.appendChild(E('button', { + 'style': btnStyle, + 'title': p.val, + 'click': ui.createHandlerFn(self, function() { + var sid = uci.add('flowproxy', type); + uci.set('flowproxy', sid, 'enabled', '1'); + uci.set('flowproxy', sid, 'match_type', p.type); + uci.set('flowproxy', sid, 'match_value', p.val); + uci.set('flowproxy', sid, 'action', 'return'); + uci.set('flowproxy', sid, 'counter', '0'); + return Promise.resolve().then(function() { + return m.load().then(function() { + return refreshTable(); + }); + }); + }) + }, [ E('em', { 'class': 'icon-plus' }), ' ', p.name ])); + }); + return btnGroup; + }; + + ss.render = function() { + return form.TableSection.prototype.render.apply(ss).then(function(node) { + node.id = 'flowproxy-table-' + type; + var titleEl = node.querySelector('h3'); + if (titleEl) { + titleEl.style.display = 'block'; + var headerRow = E('div', { 'style': 'display: flex; align-items: center; gap: 10px;' }, [ + E('span', {}, title), + E('div', { 'style': 'font-size: 0.8em; font-weight: normal; display: inline-flex; align-items: center; gap: 5px; color: #666;' }, [ + (function() { + var val = uci.get('flowproxy', 'global', switch_opt); + return E('input', { 'type': 'checkbox', 'style': 'width: 16px; height: 18px; cursor: pointer;', 'checked': (val !== '0') ? 'checked' : null, + 'change': function(ev) { uci.set('flowproxy', 'global', switch_opt, ev.target.checked ? '1' : '0'); ui.addNotification(null, E('p', _('Master switch updated.')), 'info'); } + }); + })(), + E('span', {}, _('enable protocol')) + ]) + ]); + L.dom.content(titleEl, [ headerRow, createTemplateButtons() ]); + } + return node; + }); + }; + + ss.renderSectionAdd = function(extra_class) { + var node = form.TableSection.prototype.renderSectionAdd.apply(this, [extra_class]); + var label = (type === 'tcp_rule') ? 'TCP' : 'UDP'; + var addBtn = node.querySelector('.cbi-button-add'); if (addBtn) addBtn.innerText = _('Add rule'); + var resetBtn = E('button', { 'class': 'cbi-button cbi-button-reset', 'style': 'margin-left: 10px; border: 1px solid #cc0000; color: #cc0000;', + 'click': ui.createHandlerFn(self, function() { + if (confirm(_('this will delete ALL current %s rules and generate default templates. are you sure?').format(label))) { + uci.sections('flowproxy', type).forEach(function(r) { uci.remove('flowproxy', r['.name']); }); + var defs = [ { t: 'src_mac', v: '@no_proxy_src_mac' }, { t: 'dst_ip', v: '@private_dst_ip_v4' }, { t: 'dst_ip', v: '@chnroute_dst_ip_v4' } ]; + if (type === 'tcp_rule') defs.push({ t: 'dst_port', v: '@no_proxy_dst_tcp_ports' }); else if (type === 'udp_rule') defs.push({ t: 'dst_port', v: '@no_proxy_dst_udp_ports' }); + defs.forEach(function(r) { var sid = uci.add('flowproxy', type); uci.set('flowproxy', sid, 'enabled', '1'); uci.set('flowproxy', sid, 'match_type', r.t); uci.set('flowproxy', sid, 'match_value', r.v); uci.set('flowproxy', sid, 'action', 'return'); uci.set('flowproxy', sid, 'counter', '0'); }); + return Promise.resolve().then(function() { + return m.load().then(function() { + return refreshTable(); + }); + }); + } + }) + }, [ E('em', { 'class': 'icon-reload' }), ' ', _('reset %s templates').format(label) ]); + node.appendChild(resetBtn); return node; + }; + + ss.option(form.Flag, 'enabled', _('Enabled')).width = '8%'; + var match_type = ss.option(form.ListValue, 'match_type', _('Match Type')); + match_type.value('dst_ip', 'dest ip'); match_type.value('src_ip', 'src ip'); match_type.value('src_mac', 'src mac'); + match_type.value('dst_port', 'dest port'); match_type.value('src_port', 'src port'); match_type.value('custom', 'custom (raw)'); + match_type.default = 'dst_ip'; match_type.rmempty = false; match_type.width = '15%'; + + var match_value = ss.option(form.Value, 'match_value', _('Match Value')); + match_value.rmempty = false; match_value.width = '45%'; + nftsets.forEach(function(set) { match_value.value(set); }); + match_value.validate = function(sid, val) { + if (!val || val === '') return _('Expecting: %s').format(_('Match Value')); + + var type = match_type.formvalue(sid); + if (!type) { + var typeEl = document.querySelector('[name="cbid.flowproxy.' + sid + '.match_type"]'); + if (typeEl && typeEl.value) type = typeEl.value; + } + if (!type) type = uci.get('flowproxy', sid, 'match_type'); + + if (val.match(/^@/)) { + var setName = val.substring(1); + // 仅当 section 确实存在时才尝试获取 type,否则不进行类型校验 + var section = uci.get('flowproxy', setName); + var setType = (section && section['.type'] === 'nftset') ? uci.get('flowproxy', setName, 'type') : null; + if (!setType) return true; + + var expectedType = ''; + if (type === 'dst_ip' || type === 'src_ip') expectedType = 'ipv4_addr'; + else if (type === 'src_mac') expectedType = 'ether_addr'; + else if (type === 'dst_port' || type === 'src_port') expectedType = 'inet_service'; + + if (expectedType && setType !== expectedType && type !== 'custom') { + return _('Set type mismatch: expected %s, got %s').format(expectedType, setType); + } + return true; + } + + switch (type) { + case 'dst_ip': + case 'src_ip': + if (!val.match(/^([0-9]{1,3}\.){3}[0-9]{1,3}(\/[0-9]{1,2})?$/)) return _('Invalid IPv4 address or CIDR'); + break; + case 'src_mac': + if (!val.match(/^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$/)) return _('Invalid MAC address'); + break; + case 'dst_port': + case 'src_port': + if (!val.match(/^[0-9]+(-[0-9]+)?$/)) return _('Invalid port or range'); + break; + } + return true; + }; + // 联动:当 match_type 改变时,强制触发 match_value 的校验 + match_type.onchange = function(ev, sid, val) { + var value_input = m.lookupOption('match_value', sid)[0]; + if (value_input) setTimeout(function() { + var el = document.getElementById(value_input.cbid(sid)); + if (el) { + var inputEl = el.tagName === 'INPUT' ? el : el.querySelector('input'); + if (inputEl) { + inputEl.dispatchEvent(new CustomEvent('change', { bubbles: true })); + inputEl.dispatchEvent(new CustomEvent('blur', { bubbles: true })); + inputEl.dispatchEvent(new CustomEvent('input', { bubbles: true })); + } + } + }, 0); + }; + ss.option(form.Flag, 'counter', _('Counter')).width = '8%'; + o = ss.option(form.ListValue, 'action', _('Action')); o.value('return', 'return'); o.value('accept', 'accept'); o.value('drop', 'drop'); o.default = 'return'; o.width = '12%'; + }; + setupRuleTable('tcp_rule', _('TCP Matching Rules'), 'tcp_enabled'); + setupRuleTable('udp_rule', _('UDP Matching Rules'), 'udp_enabled'); + + // --- Lists --- + var predefined = [ { id: 'no_proxy_src_mac', name: _('no_proxy_src_mac'), type: 'macaddr' }, { id: 'no_proxy_src_ip_v4', name: _('no_proxy_src_ip_v4'), type: 'or(ip4addr, cidr4)' }, { id: 'no_proxy_dst_ip_v4', name: _('no_proxy_dst_ip_v4'), type: 'or(ip4addr, cidr4)' }, { id: 'no_proxy_dst_tcp_ports', name: _('no_proxy_dst_tcp_ports'), type: 'or(port, portrange)' }, { id: 'no_proxy_dst_udp_ports', name: _('no_proxy_dst_udp_ports'), type: 'or(port, portrange)' } ]; + predefined.forEach(function(p) { + var sl = s.taboption('lists', form.SectionValue, '_list_' + p.id, form.NamedSection, p.id, 'nftset', p.name + ' (@' + p.id + ')'); + sl.subsection.option(form.Flag, 'enabled', _('Enabled')).default = '1'; + sl.subsection.option(form.DynamicList, 'elements', _('Elements')).datatype = p.type; + }); + var spriv = s.taboption('lists', form.SectionValue, '_list_priv', form.NamedSection, 'private_dst_ip_v4', 'nftset', _('private_dst_ip_v4') + ' (@private_dst_ip_v4)'); + spriv.subsection.option(form.Flag, 'enabled', _('Enabled')).default = '1'; + spriv.subsection.option(form.Flag, 'auto_generate', _('auto_generate')).default = '1'; + o = spriv.subsection.option(form.DynamicList, 'elements', _('elements')); o.datatype = 'cidr4'; o.depends('auto_generate', '0'); + + var sc = s.taboption('lists', form.SectionValue, '_list_chnroute', form.NamedSection, 'chnroute_dst_ip_v4', 'nftset', _('chnroute_dst_ip_v4') + ' (@chnroute_dst_ip_v4)'); + sc.subsection.option(form.Flag, 'enabled', _('Enabled')).default = '1'; + o = sc.subsection.option(form.Value, 'file_path', _('File Path')); o.default = '/usr/share/flowproxy/chnroute.txt'; + o.render = function(sid) { + return form.Value.prototype.render.apply(this, arguments).then(function(node) { + var path = uci.get('flowproxy', sid, 'file_path') || '/usr/share/flowproxy/chnroute.txt'; + var resNode = E('span', { 'style': 'margin-left: 10px; font-weight: bold; color: #444;', 'id': 'line-count-status' }, [ '...' ]); + var input = node.querySelector('input'); if (input) input.parentNode.appendChild(resNode); + fs.exec('/usr/bin/wc', ['-l', path]).then(function(res) { L.dom.content(resNode, (res.code === 0) ? [ _('(%d lines)').format(res.stdout.trim().split(' ')[0]) ] : [ _('(n/a)') ]); }); + return node; + }); + }; + sc.subsection.option(form.Value, 'download_url', _('Download URL')); + o = sc.subsection.option(form.Button, '_download', _('Update Chnroute')); o.inputstyle = 'apply'; + o.onclick = function(ev, sid) { + var urlOpt = m.lookupOption('download_url', sid)[0]; + var url = urlOpt ? urlOpt.formvalue(sid) : uci.get('flowproxy', sid, 'download_url'); + var pathOpt = m.lookupOption('file_path', sid)[0]; + var path = pathOpt ? pathOpt.formvalue(sid) : uci.get('flowproxy', sid, 'file_path'); + if (!path) path = '/usr/share/flowproxy/chnroute.txt'; + if (!url) { ui.addNotification(null, E('p', _('Please set download_url first')), 'error'); return; } + ui.showModal(null, [ E('p', { 'class': 'spinning', 'id': 'download-msg' }, [ _('Downloading chnroute data...') ]) ]); + return fs.exec('/usr/bin/wget', ['-q', '-O', path, url, '--timeout=10', '--no-check-certificate']).then(function(res) { + var msgEl = document.getElementById('download-msg'); + if (res.code === 0) { + if (msgEl) { msgEl.classList.remove('spinning'); L.dom.content(msgEl, [ _('Updated successfully.') ]); } + var cn = document.getElementById('line-count-status'); if (cn) fs.exec('/usr/bin/wc', ['-l', path]).then(function(r) { L.dom.content(cn, (r.code === 0) ? [ _('(%d lines)').format(r.stdout.trim().split(' ')[0]) ] : [ _('(n/a)') ]); }); + setTimeout(ui.hideModal, 1500); + } else { ui.hideModal(); ui.addNotification(null, E('p', _('Download failed')), 'error'); } + }).catch(function(e) { ui.hideModal(); ui.addNotification(null, E('p', _('Error: %s').format(e.message)), 'error'); }); + }; + + var sg = s.taboption('lists', form.SectionValue, '_list_custom', form.GridSection, 'nftset', _('Custom nftables sets')); + sg.subsection.addremove = true; sg.subsection.anonymous = false; sg.subsection.nodescription = true; + sg.subsection.filter = function(sid) { var pre = predefined.map(function(p){return p.id}); pre.push('private_dst_ip_v4','chnroute_dst_ip_v4'); return pre.indexOf(sid) === -1; }; + sg.subsection.option(form.Flag, 'enabled', _('Enabled')).default = '1'; + o = sg.subsection.option(form.ListValue, 'type', _('Element Type')); o.value('ipv4_addr', 'IPv4 Address/CIDR'); o.value('ether_addr', 'MAC Address'); o.value('inet_service', 'Port/Service'); o.default = 'ipv4_addr'; + sg.subsection.option(form.DynamicList, 'elements', _('Elements')); + + // --- Preview & Logs --- + var sp = s.taboption('preview', form.SectionValue, '_preview_section', form.NamedSection, 'global', 'flowproxy'); + sp.subsection.tab('generated', _('Generated Config')); sp.subsection.tab('runtime', _('Live Runtime State')); + + o = sp.subsection.taboption('generated', form.DummyValue, '_preview_gen'); + o.render = function() { + var node = E('div', { 'style': 'width:100%; box-sizing:border-box; margin-top: 10px;' }, [ + E('div', { 'style': 'margin-bottom: 10px' }, [ + E('button', { 'class': 'cbi-button cbi-button-apply', 'click': function() { + var el = document.getElementById('gen-code'); + if (el) { navigator.clipboard.writeText(el.innerText); ui.addNotification(null, E('p', _('Copied')), 'info'); } + } }, [ _('Copy Config') ]) + ]), + E('pre', { 'class': 'nft-code-view', 'id': 'gen-code' }, [ _('loading...') ]) + ]); + callGenerateNftConfig().then(function(res) { + var el = node.querySelector('#gen-code'); + if (el) el.innerHTML = self.highlightNft(res.config || ''); + }); + return node; + }; + + o = sp.subsection.taboption('runtime', form.DummyValue, '_preview_run'); + o.render = function() { + var node = E('div', { 'style': 'width:100%; box-sizing:border-box; margin-top: 10px;' }, [ + E('div', { 'style': 'margin-bottom: 10px' }, [ + E('button', { 'class': 'cbi-button cbi-button-refresh', 'click': function() { location.reload(); } }, [ _('Refresh Status') ]) + ]), + E('pre', { 'class': 'nft-code-view', 'id': 'run-code' }, [ _('loading...') ]) + ]); + callGetRuntimeConfig().then(function(res) { + var el = node.querySelector('#run-code'); + if (el) el.innerHTML = self.highlightNft(res.runtime || ''); + }); + return node; + }; + + o = s.taboption('logs', form.ListValue, 'log_level', _('Log Level')); + o.value('debug'); o.value('info'); o.value('warn'); o.value('error'); o.default = 'info'; + s.taboption('logs', form.Value, 'log_size', _('Log Size (KB)')).datatype = 'uinteger'; + o = s.taboption('logs', form.DummyValue, '_log_view'); + o.render = function() { + var node = E('div', { 'style': 'width:100%; box-sizing:border-box; margin-top: 15px;' }, [ + E('div', { 'style': 'margin-bottom: 5px; text-align: left;' }, [ + E('button', { 'class': 'cbi-button cbi-button-refresh', 'click': L.bind(self.refreshLogs, self) }, [ _('Refresh Logs') ]), + E('button', { 'class': 'cbi-button cbi-button-reset', 'style': 'margin-left: 10px;', 'click': L.bind(function() { if(confirm(_('Clear logs?'))) callClearLogs().then(L.bind(self.refreshLogs, self)); }, self) }, [ _('Clear Logs') ]) + ]), + E('textarea', { 'id': 'log-content', 'readonly': true }, [ _('loading logs...') ]) + ]); + callGetLogs(500).then(function(data) { + var logEl = node.querySelector('#log-content'); + if (logEl) { + var logs = (data && Array.isArray(data.logs)) ? data.logs : []; + logEl.value = logs.length > 0 ? logs.join('\n') : _('no logs available'); + if (logs.length > 0) logEl.scrollTop = logEl.scrollHeight; + } + }); + return node; + }; + + return m.render().then(L.bind(function(node) { + this.refreshStatus(m, node); + poll.add(L.bind(function() { if (!document.body.contains(node)) return false; return this.refreshStatus(m, node); }, this), 5); + return node; + }, this)); + } +}); diff --git a/luci-app-flowproxy/po/templates/flowproxy.pot b/luci-app-flowproxy/po/templates/flowproxy.pot new file mode 100644 index 000000000..0734ed227 --- /dev/null +++ b/luci-app-flowproxy/po/templates/flowproxy.pot @@ -0,0 +1,228 @@ +msgid "" +msgstr "" +"Content-Type: text/plain; charset=UTF-8\n" +"Project-Id-Version: luci-app-flowproxy\n" +"" + +msgid "(%d lines)" +msgstr "" + +msgid "(n/a)" +msgstr "" + +msgid "(no content / table not loaded)" +msgstr "" + +msgid "Action" +msgstr "" + +msgid "Add rule" +msgstr "" + +msgid "Clear Logs" +msgstr "" + +msgid "Clear logs?" +msgstr "" + +msgid "Copied" +msgstr "" + +msgid "Copy Config" +msgstr "" + +msgid "Counter" +msgstr "" + +msgid "Current Status" +msgstr "" + +msgid "Custom nftables sets" +msgstr "" + +msgid "DNS Redirection" +msgstr "" + +msgid "Download URL" +msgstr "" + +msgid "Download failed" +msgstr "" + +msgid "Downloading chnroute data..." +msgstr "" + +msgid "Element Type" +msgstr "" + +msgid "Elements" +msgstr "" + +msgid "Enable FlowProxy" +msgstr "" + +msgid "Enabled" +msgstr "" + +msgid "Error: %s" +msgstr "" + +msgid "Expecting: %s" +msgstr "" + +msgid "File Path" +msgstr "" + +msgid "FlowProxy" +msgstr "" + +msgid "Force upstream DNS to proxy server" +msgstr "" + +msgid "Generated Config" +msgstr "" + +msgid "Invalid IPv4 address or CIDR" +msgstr "" + +msgid "Invalid MAC address" +msgstr "" + +msgid "Invalid port or range" +msgstr "" + +msgid "Lists" +msgstr "" + +msgid "Live Runtime State" +msgstr "" + +msgid "Log Level" +msgstr "" + +msgid "Log Size (KB)" +msgstr "" + +msgid "Logs" +msgstr "" + +msgid "LuCI Support for FlowProxy Traffic Diversion" +msgstr "" + +msgid "Master switch updated." +msgstr "" + +msgid "Match Type" +msgstr "" + +msgid "Match Value" +msgstr "" + +msgid "Network interface" +msgstr "" + +msgid "Please set download_url first" +msgstr "" + +msgid "Preview" +msgstr "" + +msgid "Proxy server DNS port" +msgstr "" + +msgid "Proxy server IP address" +msgstr "" + +msgid "Quick add:" +msgstr "" + +msgid "Refresh Logs" +msgstr "" + +msgid "Refresh Status" +msgstr "" + +msgid "Routing Table ID" +msgstr "" + +msgid "Rules" +msgstr "" + +msgid "Set type mismatch: expected %s, got %s" +msgstr "" + +msgid "Settings" +msgstr "" + +msgid "TCP Matching Rules" +msgstr "" + +msgid "Traffic Mark" +msgstr "" + +msgid "Traffic diversion based on nftables rules. The service will automatically start/stop when you click \"Save & Apply\"." +msgstr "" + +msgid "UDP Matching Rules" +msgstr "" + +msgid "Update Chnroute" +msgstr "" + +msgid "Updated successfully." +msgstr "" + +msgid "auto_generate" +msgstr "" + +msgid "checking..." +msgstr "" + +msgid "chnroute_dst_ip_v4" +msgstr "" + +msgid "elements" +msgstr "" + +msgid "enable protocol" +msgstr "" + +msgid "loading logs..." +msgstr "" + +msgid "loading..." +msgstr "" + +msgid "no logs available" +msgstr "" + +msgid "no_proxy_dst_ip_v4" +msgstr "" + +msgid "no_proxy_dst_tcp_ports" +msgstr "" + +msgid "no_proxy_dst_udp_ports" +msgstr "" + +msgid "no_proxy_src_ip_v4" +msgstr "" + +msgid "no_proxy_src_mac" +msgstr "" + +msgid "private_dst_ip_v4" +msgstr "" + +msgid "reset %s templates" +msgstr "" + +msgid "running" +msgstr "" + +msgid "stopped" +msgstr "" + +msgid "this will delete ALL current %s rules and generate default templates. are you sure?" +msgstr "" + diff --git a/luci-app-flowproxy/po/zh-cn b/luci-app-flowproxy/po/zh-cn new file mode 120000 index 000000000..8d69574dd --- /dev/null +++ b/luci-app-flowproxy/po/zh-cn @@ -0,0 +1 @@ +zh_Hans \ No newline at end of file diff --git a/luci-app-flowproxy/po/zh_Hans/flowproxy.po b/luci-app-flowproxy/po/zh_Hans/flowproxy.po new file mode 100644 index 000000000..1faa8dfff --- /dev/null +++ b/luci-app-flowproxy/po/zh_Hans/flowproxy.po @@ -0,0 +1,252 @@ +msgid "" +msgstr "" +"Content-Type: text/plain; charset=UTF-8\n" +"Project-Id-Version: luci-app-flowproxy\n" +"Language: zh_Hans\n" + +msgid "(%d lines)" +msgstr "(%d 行)" + +msgid "(n/a)" +msgstr "(未知)" + +msgid "(no content / table not loaded)" +msgstr "(无内容 / 列表未加载)" + +msgid "Action" +msgstr "动作" + +msgid "Add rule" +msgstr "添加规则" + +msgid "Clear Logs" +msgstr "清空日志" + +msgid "Clear logs?" +msgstr "确定要清空日志吗?" + +msgid "Copied" +msgstr "已复制" + +msgid "Copy Config" +msgstr "复制配置" + +msgid "Counter" +msgstr "计数器" + +msgid "Current Status" +msgstr "当前状态" + +msgid "Custom nftables sets" +msgstr "自定义 nftables 集合" + +msgid "DNS Redirection" +msgstr "DNS 转发" + +msgid "Download URL" +msgstr "下载地址" + +msgid "Download failed" +msgstr "下载失败" + +msgid "Downloading chnroute data..." +msgstr "正在下载数据集..." + +msgid "Element Type" +msgstr "元素类型" + +msgid "Elements" +msgstr "元素列表" + +msgid "Enable FlowProxy" +msgstr "启用代理分流" + +msgid "Enabled" +msgstr "已启用" + +msgid "Error: %s" +msgstr "错误: %s" + +msgid "Expecting: %s" +msgstr "期望值: %s" + +msgid "File Path" +msgstr "文件路径" + +msgid "FlowProxy" +msgstr "代理分流" + +msgid "Force upstream DNS to proxy server" +msgstr "强制上游 DNS 为代理服务器" + +msgid "Generated Config" +msgstr "生成的配置" + +msgid "Invalid IPv4 address or CIDR" +msgstr "无效的 IPv4 地址或 CIDR" + +msgid "Invalid MAC address" +msgstr "无效的 MAC 地址" + +msgid "Invalid port or range" +msgstr "无效的端口或端口范围" + +msgid "Lists" +msgstr "名单" + +msgid "Live Runtime State" +msgstr "实时运行状态" + +msgid "Log Level" +msgstr "日志级别" + +msgid "Log Size (KB)" +msgstr "日志文件大小 (KB)" + +msgid "Logs" +msgstr "日志" + +msgid "LuCI Support for FlowProxy Traffic Diversion" +msgstr "LuCI 支持 FlowProxy 流量分流" + +msgid "Master switch updated." +msgstr "总开关状态已更新。" + +msgid "Match Type" +msgstr "匹配类型" + +msgid "Match Value" +msgstr "匹配值" + +msgid "Network interface" +msgstr "网络接口" + +msgid "Please set download_url first" +msgstr "请先设置下载 URL" + +msgid "Preview" +msgstr "预览" + +msgid "Proxy server DNS port" +msgstr "代理服务器 DNS 端口" + +msgid "Proxy server IP address" +msgstr "代理服务器 IP 地址" + +msgid "Proxy server interface" +msgstr "代理服务器所在接口" + +msgid "Quick add:" +msgstr "快速添加预设:" + +msgid "Refresh Logs" +msgstr "刷新日志" + +msgid "Refresh Status" +msgstr "刷新实时状态" + +msgid "Routing Table ID" +msgstr "路由表 ID" + +msgid "Rule Priority" +msgstr "策略路由优先级" + +msgid "Rules" +msgstr "规则" + +msgid "Set type mismatch: expected %s, got %s" +msgstr "集合类型不匹配: 期望 %s, 实际为 %s" + +msgid "Settings" +msgstr "设置" + +msgid "TCP Matching Rules" +msgstr "TCP 匹配规则列表" + +msgid "Traffic Mark" +msgstr "流量标记" + +msgid "Traffic diversion based on nftables rules. The service will automatically start/stop when you click \"Save & Apply\"." +msgstr "基于 nftables 规则的流量分流。当你点击 “保存并应用” 后,服务将自动启动或停止。" + +msgid "UDP Matching Rules" +msgstr "UDP 匹配规则列表" + +msgid "Update Chnroute" +msgstr "立即更新数据集" + +msgid "Updated successfully." +msgstr "数据集更新成功。" + +msgid "auto_generate" +msgstr "自动生成" + +msgid "checking..." +msgstr "检测中..." + +msgid "chnroute_dst_ip_v4" +msgstr "中国大陆 IP" + +msgid "elements" +msgstr "元素列表" + +msgid "enable protocol" +msgstr "启用协议" + +msgid "loading logs..." +msgstr "日志加载中..." + +msgid "loading..." +msgstr "加载中..." + +msgid "no logs available" +msgstr "暂无日志内容" + +msgid "no_proxy_dst_ip_v4" +msgstr "不代理的目标 IP" + +msgid "no_proxy_dst_tcp_ports" +msgstr "不代理的目标 TCP 端口" + +msgid "no_proxy_dst_udp_ports" +msgstr "不代理的目标 UDP 端口" + +msgid "no_proxy_src_ip_v4" +msgstr "不代理的源 IP" + +msgid "no_proxy_src_mac" +msgstr "不代理的源 MAC" + +msgid "private_dst_ip_v4" +msgstr "私有 IP" + +msgid "reset %s templates" +msgstr "重置 %s 模版" + +msgid "running" +msgstr "运行中" + +msgid "stopped" +msgstr "已停止" + +msgid "this will delete ALL current %s rules and generate default templates. are you sure?" +msgstr "这将删除当前所有 %s 规则并加载推荐的默认模版。确定吗?" + +msgid "Restart" +msgstr "重启" + +msgid "Restarting FlowProxy service..." +msgstr "正在重启 FlowProxy 服务..." + +msgid "FlowProxy service restarted successfully." +msgstr "FlowProxy 服务重启成功。" + +msgid "Failed to restart FlowProxy service." +msgstr "重启 FlowProxy 服务失败。" + +msgid "RPC error: %s" +msgstr "RPC 错误: %s" + +msgid "The proxy server IP address must be within the subnet of the selected interface (%s)." +msgstr "代理服务器 IP 地址必须在所选网络接口的子网网段之内 (%s)。" + diff --git a/luci-app-flowproxy/root/etc/config/flowproxy b/luci-app-flowproxy/root/etc/config/flowproxy new file mode 100644 index 000000000..a49b7b1b3 --- /dev/null +++ b/luci-app-flowproxy/root/etc/config/flowproxy @@ -0,0 +1,104 @@ +config flowproxy 'global' + option enabled '0' + option tcp_enabled '1' + option udp_enabled '1' + option proxy_server_ip_addr '' + option interface 'br-lan' + option traffic_mark '0x666' + option routing_table '888' + option rule_priority '1000' + option dns_proxy_enabled '0' + option proxy_server_dns_port '5353' + option log_level 'info' + option log_size '1024' + option log_count '3' + +# --- TCP 默认规则 --- +config tcp_rule + option enabled '1' + option match_type 'src_mac' + option match_value '@no_proxy_src_mac' + option action 'return' + option counter '0' + +config tcp_rule + option enabled '1' + option match_type 'dst_ip' + option match_value '@private_dst_ip_v4' + option action 'return' + option counter '0' + +config tcp_rule + option enabled '1' + option match_type 'dst_ip' + option match_value '@chnroute_dst_ip_v4' + option action 'return' + option counter '0' + +config tcp_rule + option enabled '1' + option match_type 'dst_port' + option match_value '@no_proxy_dst_tcp_ports' + option action 'return' + option counter '0' + +# --- UDP 默认规则 --- +config udp_rule + option enabled '1' + option match_type 'src_mac' + option match_value '@no_proxy_src_mac' + option action 'return' + option counter '0' + +config udp_rule + option enabled '1' + option match_type 'dst_ip' + option match_value '@private_dst_ip_v4' + option action 'return' + option counter '0' + +config udp_rule + option enabled '1' + option match_type 'dst_ip' + option match_value '@chnroute_dst_ip_v4' + option action 'return' + option counter '0' + +config udp_rule + option enabled '1' + option match_type 'dst_port' + option match_value '@no_proxy_dst_udp_ports' + option action 'return' + option counter '0' + +# nftables set 配置 +config nftset 'no_proxy_src_mac' + option enabled '1' + option type 'ether_addr' + +config nftset 'no_proxy_src_ip_v4' + option enabled '1' + option type 'ipv4_addr' + +config nftset 'no_proxy_dst_ip_v4' + option enabled '1' + option type 'ipv4_addr' + +config nftset 'private_dst_ip_v4' + option enabled '1' + option type 'ipv4_addr' + option auto_generate '1' + +config nftset 'chnroute_dst_ip_v4' + option enabled '1' + option type 'ipv4_addr' + option file_path '/usr/share/flowproxy/chnroute.txt' + option download_url 'https://proxy.seckv.com/https://raw.githubusercontent.com/mayaxcn/china-ip-list/master/chnroute.txt' + +config nftset 'no_proxy_dst_tcp_ports' + option enabled '1' + option type 'inet_service' + +config nftset 'no_proxy_dst_udp_ports' + option enabled '1' + option type 'inet_service' diff --git a/luci-app-flowproxy/root/etc/init.d/flowproxy b/luci-app-flowproxy/root/etc/init.d/flowproxy new file mode 100755 index 000000000..53cd40964 --- /dev/null +++ b/luci-app-flowproxy/root/etc/init.d/flowproxy @@ -0,0 +1,299 @@ +#!/bin/sh /etc/rc.common +# FlowProxy - Traffic Diversion Service + +START=99 +STOP=10 +USE_PROCD=1 + +NAME="flowproxy" +UCI_CONFIG="flowproxy" +LOG_FILE="/var/log/flowproxy.log" +NFT_CONF="/tmp/flowproxy/nft.conf" +GENERATE_SCRIPT="/usr/share/flowproxy/generate_nft.sh" +STATE_FILE="/var/run/flowproxy.running" + +get_level_weight() { + case "$1" in + debug) echo 0 ;; + info) echo 1 ;; + warn) echo 2 ;; + error) echo 3 ;; + *) echo 1 ;; + esac +} + +log_msg() { + local level="$1"; shift + local msg="$*" + local timestamp=$(date '+%Y-%m-%d %H:%M:%S') + + # 等级过滤 + local conf_level=$(uci -q get "$UCI_CONFIG.global.log_level" || echo "info") + local conf_weight=$(get_level_weight "$conf_level") + local msg_weight=$(get_level_weight "$level") + [ "$msg_weight" -lt "$conf_weight" ] && return + + # 简单的日志截断逻辑,防止日志无限增长 + # 读取配置的大小限制,默认 1024KB + local max_size=$(uci -q get "$UCI_CONFIG.global.log_size" || echo 1024) + local current_size=$(du -k "$LOG_FILE" 2>/dev/null | cut -f1) + if [ "${current_size:-0}" -gt "$max_size" ]; then + mv "$LOG_FILE" "$LOG_FILE.old" + touch "$LOG_FILE" + fi + + echo "[$timestamp] [$level] $msg" >> "$LOG_FILE" +} + +check_env() { + # 检测核心二进制工具是否存在 + if ! command -v nft >/dev/null 2>&1; then + log_msg error "nftables binary not found" + return 1 + fi + return 0 +} + +check_config() { + local proxy_server_ip_addr=$(uci -q get "$UCI_CONFIG.global.proxy_server_ip_addr") + [ -z "$proxy_server_ip_addr" ] && { log_msg error "proxy_server_ip_addr not configured"; return 1; } + return 0 +} + +apply_nft_rules() { + log_msg info "Generating nftables configuration..." + local conf_level=$(uci -q get "$UCI_CONFIG.global.log_level" || echo "info") + + mkdir -p "$(dirname "$NFT_CONF")" + if [ -x "$GENERATE_SCRIPT" ]; then + # 传递日志等级并捕获 stderr 到临时文件 + local err_file="/tmp/flowproxy/gen_err.tmp" + FLOWPROXY_LOG_LEVEL="$conf_level" "$GENERATE_SCRIPT" >/dev/null 2> "$err_file" + local ret=$? + + # 将脚本的输出记录到日志 + if [ -s "$err_file" ]; then + while read -r line; do + log_msg debug "Script: $line" + done < "$err_file" + rm -f "$err_file" + fi + + if [ $ret -eq 0 ]; then + log_msg info "Applying nftables rules from $NFT_CONF" + # 确保内核支持 inet 表 + nft delete table inet flowproxy 2>/dev/null + if nft -f "$NFT_CONF"; then + return 0 + else + log_msg error "nftables rules application failed (syntax error)" + return 1 + fi + else + log_msg error "Failed to generate nftables config" + return 1 + fi + else + log_msg error "Generator script $GENERATE_SCRIPT not found or not executable" + return 1 + fi +} + +add_route() { + local proxy_server_ip_addr=$(uci -q get "$UCI_CONFIG.global.proxy_server_ip_addr") + local interface=$(uci -q get "$UCI_CONFIG.global.interface" || echo "br-lan") + local traffic_mark=$(uci -q get "$UCI_CONFIG.global.traffic_mark" || echo "0x666") + local routing_table=$(uci -q get "$UCI_CONFIG.global.routing_table" || echo "888") + local rule_priority=$(uci -q get "$UCI_CONFIG.global.rule_priority" || echo "1000") + + # 1. 先尝试用旧记录清理一次,防止由于配置变更导致的残留 + delete_route "quiet" + + log_msg info "Setting up routing table $routing_table and rule for mark $traffic_mark with priority $rule_priority..." + + # 2. 记录当前使用的标记值、路由表 ID 和优先级 + echo "$traffic_mark:$routing_table:$rule_priority" > "/var/run/flowproxy.mark" + + # 3. 再次确保新标记和表的规则是干净的 + while ip rule del fwmark "$traffic_mark" lookup "$routing_table" 2>/dev/null; do :; done + ip route flush table "$routing_table" 2>/dev/null + + # 4. 添加路由和策略 + local err + ip route add default via "$proxy_server_ip_addr" dev "$interface" table "$routing_table" 2>/dev/null + err=$(ip rule add fwmark "$traffic_mark" lookup "$routing_table" priority "$rule_priority" 2>&1) + if [ $? -eq 0 ]; then + log_msg info "Route added: via $proxy_server_ip_addr dev $interface table $routing_table for mark $traffic_mark with priority $rule_priority" + else + log_msg error "Failed to add ip rule: $err" + fi +} + +delete_route() { + local traffic_mark routing_table rule_priority + local quiet="$1" + + # 1. 获取两组清理目标:旧值(记录文件) 和 新值(当前UCI) + local old_mark="" old_table="" old_prio="" + if [ -f "/var/run/flowproxy.mark" ]; then + local saved_val=$(cat "/var/run/flowproxy.mark") + old_mark=$(echo "$saved_val" | cut -d':' -f1) + old_table=$(echo "$saved_val" | cut -d':' -f2) + old_prio=$(echo "$saved_val" | cut -d':' -f3) + [ "$quiet" != "quiet" ] && rm -f "/var/run/flowproxy.mark" + fi + + local curr_mark=$(uci -q get "$UCI_CONFIG.global.traffic_mark" || echo "0x666") + local curr_table=$(uci -q get "$UCI_CONFIG.global.routing_table" || echo "888") + local curr_prio=$(uci -q get "$UCI_CONFIG.global.rule_priority" || echo "1000") + + [ "$quiet" != "quiet" ] && log_msg info "Cleaning up FlowProxy routes (Atomic Mode)..." + + # 2. 核心清理函数:只清理带 fwmark 且指向特定 table 的规则 + safe_del_rule() { + local m="$1" t="$2" p="$3" + [ -z "$m" ] || [ -z "$t" ] && return + log_msg debug "Attempting cleanup: mark=$m, table=$t, priority=${p:-any}" + # 精准清理 (带优先级) + [ -n "$p" ] && while ip rule del fwmark "$m" lookup "$t" priority "$p" 2>/dev/null; do + log_msg debug "Removed stale ip rule: mark $m lookup $t priority $p" + done + # 模糊清理 (不带优先级,防止配置中途被手动改动) + while ip rule del fwmark "$m" lookup "$t" 2>/dev/null; do + log_msg debug "Removed stale ip rule (fuzzy): mark $m lookup $t" + done + # 清空路由表 + ip route flush table "$t" 2>/dev/null + log_msg debug "Flushed routing table $t" + } + + # 执行清理:先清旧值,再清当前值 (防止残留) + safe_del_rule "$old_mark" "$old_table" "$old_prio" + [ "$old_mark" != "$curr_mark" ] || [ "$old_table" != "$curr_table" ] && \ + safe_del_rule "$curr_mark" "$curr_table" "$curr_prio" +} + +delete_nft() { + nft delete table inet flowproxy 2>/dev/null + log_msg info "Removed nftables table 'flowproxy'" +} + +setup_dns() { + local enabled=$(uci -q get "$UCI_CONFIG.global.enabled" || echo 0) + local dns_proxy_enabled=$(uci -q get "$UCI_CONFIG.global.dns_proxy_enabled" || echo 0) + local proxy_server_dns_port=$(uci -q get "$UCI_CONFIG.global.proxy_server_dns_port" || echo 5353) + local proxy_server_ip_addr=$(uci -q get "$UCI_CONFIG.global.proxy_server_ip_addr") + + # Only apply DNS proxy if BOTH main service and DNS proxy are enabled + if [ "$enabled" -eq 0 ] || [ "$dns_proxy_enabled" -eq 0 ]; then + cleanup_dns + return 0 + fi + + [ -z "$proxy_server_ip_addr" ] && { log_msg error "proxy_server_ip_addr not configured, cannot setup DNS"; return 1; } + + log_msg info "Setting up DNS redirection to $proxy_server_ip_addr#$proxy_server_dns_port..." + + # Persistent backup in UCI + if ! uci -q get "$UCI_CONFIG.dns_backup" >/dev/null; then + local old_noresolv=$(uci -q get dhcp.@dnsmasq[0].noresolv) + local old_dns_redirect=$(uci -q get dhcp.@dnsmasq[0].dns_redirect) + local old_servers=$(uci -q get dhcp.@dnsmasq[0].server | tr '\n' ',' | sed 's/,$//') + + log_msg debug "Backing up DNS: noresolv=${old_noresolv:-empty}, redirect=${old_dns_redirect:-empty}, servers=${old_servers:-empty}" + + uci set "$UCI_CONFIG.dns_backup=dns_backup" + [ -n "$old_noresolv" ] && uci set "$UCI_CONFIG.dns_backup.noresolv=$old_noresolv" + [ -n "$old_dns_redirect" ] && uci set "$UCI_CONFIG.dns_backup.dns_redirect=$old_dns_redirect" + [ -n "$old_servers" ] && uci set "$UCI_CONFIG.dns_backup.servers=$old_servers" + uci commit "$UCI_CONFIG" + fi + + log_msg debug "Applying new DNS: noresolv=1, redirect=0, server=$proxy_server_ip_addr#$proxy_server_dns_port" + uci set dhcp.@dnsmasq[0].noresolv='1' + uci set dhcp.@dnsmasq[0].dns_redirect='0' + + # Delete current servers and add our proxy + uci -q delete dhcp.@dnsmasq[0].server + uci add_list dhcp.@dnsmasq[0].server="$proxy_server_ip_addr#$proxy_server_dns_port" + + uci commit dhcp + /etc/init.d/dnsmasq restart +} + +cleanup_dns() { + if uci -q get "$UCI_CONFIG.dns_backup" >/dev/null; then + log_msg info "Restoring original DNS configuration..." + + local noresolv=$(uci -q get "$UCI_CONFIG.dns_backup.noresolv") + local dns_redirect=$(uci -q get "$UCI_CONFIG.dns_backup.dns_redirect") + local servers=$(uci -q get "$UCI_CONFIG.dns_backup.servers") + + log_msg debug "Restoring DNS values: noresolv=${noresolv:-0}, redirect=${dns_redirect:-1}, servers=${servers:-empty}" + + # Restore noresolv (default to 0 if not backed up) + [ -n "$noresolv" ] && uci set dhcp.@dnsmasq[0].noresolv="$noresolv" || uci set dhcp.@dnsmasq[0].noresolv="0" + + # Restore dns_redirect (default to 1 as requested for OpenWrt typical modded builds) + [ -n "$dns_redirect" ] && uci set dhcp.@dnsmasq[0].dns_redirect="$dns_redirect" || uci set dhcp.@dnsmasq[0].dns_redirect="1" + + # Restore servers + uci -q delete dhcp.@dnsmasq[0].server + if [ -n "$servers" ]; then + for s in $servers; do + [ -n "$s" ] && uci add_list dhcp.@dnsmasq[0].server="$s" + done + fi + + uci commit dhcp + uci delete "$UCI_CONFIG.dns_backup" + uci commit "$UCI_CONFIG" + /etc/init.d/dnsmasq restart + fi +} + +start_service() { + local enabled=$(uci -q get "$UCI_CONFIG.global.enabled" || echo 0) + + if [ "$enabled" -eq 0 ]; then + log_msg info "FlowProxy is disabled, ensuring service is stopped" + stop_service + return 0 + fi + + log_msg info "Starting FlowProxy..." + + check_env || return 1 + check_config || return 1 + apply_nft_rules || return 1 + add_route + setup_dns + + touch "$STATE_FILE" + log_msg info "FlowProxy service started successfully" +} +stop_service() { + log_msg info "Stopping FlowProxy..." + # 强制先移除标记,防止状态误报 + rm -f "$STATE_FILE" + delete_route + delete_nft + cleanup_dns + log_msg info "FlowProxy service stopped" +} + +restart_service() { + stop_service + start_service +} + +service_triggers() { + # 监听自身配置改动 + procd_add_reload_trigger "$UCI_CONFIG" + # 监听防火墙重载事件,防止规则被 fw4 清空后无法自动恢复 + procd_add_reload_trigger "firewall" +} + +reload_service() { + restart +} diff --git a/luci-app-flowproxy/root/usr/share/flowproxy/chnroute.txt b/luci-app-flowproxy/root/usr/share/flowproxy/chnroute.txt new file mode 100644 index 000000000..f231774bc --- /dev/null +++ b/luci-app-flowproxy/root/usr/share/flowproxy/chnroute.txt @@ -0,0 +1,8788 @@ +1.0.1.0/24 +1.0.2.0/23 +1.0.8.0/21 +1.0.32.0/19 +1.1.0.0/24 +1.1.2.0/23 +1.1.4.0/22 +1.1.8.0/24 +1.1.9.0/24 +1.1.10.0/23 +1.1.12.0/22 +1.1.16.0/20 +1.1.32.0/19 +1.2.0.0/23 +1.2.2.0/24 +1.2.4.0/24 +1.2.5.0/24 +1.2.6.0/23 +1.2.8.0/24 +1.2.9.0/24 +1.2.10.0/23 +1.2.12.0/22 +1.2.16.0/20 +1.2.32.0/19 +1.2.64.0/18 +1.3.0.0/16 +1.4.1.0/24 +1.4.2.0/23 +1.4.4.0/24 +1.4.5.0/24 +1.4.6.0/23 +1.4.8.0/21 +1.4.16.0/20 +1.4.32.0/19 +1.4.64.0/18 +1.8.0.0/16 +1.10.0.0/21 +1.10.8.0/23 +1.10.11.0/24 +1.10.12.0/22 +1.10.16.0/20 +1.10.32.0/19 +1.10.64.0/18 +1.12.0.0/14 +1.24.0.0/13 +1.45.0.0/16 +1.48.0.0/15 +1.50.0.0/16 +1.51.0.0/16 +1.56.0.0/13 +1.68.0.0/14 +1.80.0.0/13 +1.88.0.0/14 +1.92.0.0/15 +1.94.0.0/15 +1.116.0.0/15 +1.118.0.0/16 +1.119.0.0/17 +1.119.128.0/17 +1.180.0.0/14 +1.184.0.0/15 +1.188.0.0/14 +1.192.0.0/13 +1.202.0.0/15 +1.204.0.0/14 +14.0.0.0/21 +14.0.12.0/22 +14.1.0.0/22 +14.1.24.0/22 +14.1.96.0/22 +14.1.108.0/22 +14.16.0.0/12 +14.102.128.0/22 +14.102.156.0/22 +14.102.180.0/22 +14.103.0.0/16 +14.104.0.0/13 +14.112.0.0/12 +14.130.0.0/15 +14.134.0.0/15 +14.144.0.0/12 +14.192.60.0/22 +14.192.76.0/22 +14.196.0.0/15 +14.204.0.0/15 +14.208.0.0/12 +27.0.128.0/22 +27.0.132.0/22 +27.0.160.0/22 +27.0.164.0/22 +27.0.188.0/22 +27.0.204.0/22 +27.0.208.0/22 +27.0.212.0/22 +27.8.0.0/13 +27.16.0.0/12 +27.34.232.0/21 +27.36.0.0/14 +27.40.0.0/13 +27.50.40.0/21 +27.50.128.0/17 +27.54.72.0/21 +27.54.152.0/21 +27.54.192.0/18 +27.98.208.0/20 +27.98.224.0/19 +27.99.128.0/17 +27.103.0.0/16 +27.106.128.0/18 +27.106.204.0/22 +27.109.32.0/19 +27.109.124.0/22 +27.112.0.0/18 +27.112.80.0/20 +27.112.112.0/22 +27.112.116.0/22 +27.113.128.0/18 +27.115.0.0/17 +27.116.44.0/22 +27.121.72.0/21 +27.121.120.0/21 +27.128.0.0/15 +27.131.220.0/22 +27.144.0.0/16 +27.148.0.0/14 +27.152.0.0/13 +27.184.0.0/13 +27.192.0.0/11 +27.224.0.0/14 +36.0.0.0/22 +36.0.8.0/21 +36.0.16.0/20 +36.0.32.0/19 +36.0.64.0/18 +36.0.128.0/17 +36.1.0.0/16 +36.4.0.0/14 +36.16.0.0/12 +36.32.0.0/14 +36.36.0.0/16 +36.37.0.0/19 +36.37.36.0/23 +36.37.39.0/24 +36.37.40.0/21 +36.37.48.0/20 +36.40.0.0/13 +36.48.0.0/15 +36.50.226.0/23 +36.50.254.0/23 +36.51.0.0/16 +36.56.0.0/13 +36.96.0.0/11 +36.128.0.0/10 +36.192.0.0/11 +36.248.0.0/14 +36.254.0.0/16 +36.255.116.0/22 +36.255.128.0/22 +36.255.164.0/22 +36.255.172.0/22 +36.255.176.0/22 +39.0.0.0/24 +39.0.2.0/23 +39.0.4.0/22 +39.0.8.0/21 +39.0.16.0/20 +39.0.32.0/19 +39.0.64.0/18 +39.0.128.0/17 +39.64.0.0/11 +39.96.0.0/13 +39.104.0.0/14 +39.108.0.0/16 +39.128.0.0/10 +40.72.0.0/15 +40.125.128.0/17 +40.126.64.0/18 +40.162.0.0/16 +42.0.0.0/22 +42.0.8.0/21 +42.0.16.0/21 +42.0.24.0/22 +42.0.32.0/19 +42.0.128.0/17 +42.1.0.0/19 +42.1.32.0/20 +42.1.48.0/21 +42.1.56.0/22 +42.1.128.0/17 +42.4.0.0/14 +42.48.0.0/15 +42.50.0.0/16 +42.51.0.0/16 +42.52.0.0/14 +42.56.0.0/14 +42.62.0.0/17 +42.62.128.0/19 +42.62.160.0/20 +42.62.180.0/22 +42.62.184.0/21 +42.63.0.0/16 +42.80.0.0/15 +42.83.64.0/20 +42.83.80.0/22 +42.83.88.0/21 +42.83.96.0/19 +42.83.128.0/17 +42.84.0.0/14 +42.88.0.0/13 +42.96.64.0/19 +42.96.96.0/21 +42.96.108.0/22 +42.96.112.0/20 +42.96.128.0/17 +42.97.0.0/16 +42.99.0.0/18 +42.99.64.0/19 +42.99.96.0/20 +42.99.112.0/22 +42.99.120.0/21 +42.100.0.0/14 +42.120.0.0/15 +42.122.0.0/16 +42.123.0.0/19 +42.123.36.0/22 +42.123.40.0/21 +42.123.48.0/20 +42.123.64.0/18 +42.123.128.0/17 +42.128.0.0/12 +42.156.0.0/19 +42.156.36.0/22 +42.156.40.0/21 +42.156.48.0/20 +42.156.64.0/18 +42.156.128.0/17 +42.157.0.0/16 +42.158.0.0/16 +42.159.0.0/16 +42.160.0.0/12 +42.176.0.0/13 +42.184.0.0/15 +42.186.0.0/16 +42.187.0.0/18 +42.187.64.0/19 +42.187.96.0/20 +42.187.112.0/21 +42.187.120.0/22 +42.187.128.0/17 +42.192.0.0/15 +42.194.0.0/21 +42.194.8.0/22 +42.194.12.0/22 +42.194.16.0/20 +42.194.32.0/19 +42.194.64.0/18 +42.194.128.0/17 +42.195.0.0/16 +42.196.0.0/14 +42.201.0.0/21 +42.201.8.0/21 +42.201.16.0/20 +42.201.32.0/19 +42.201.64.0/18 +42.202.0.0/15 +42.204.0.0/14 +42.208.0.0/12 +42.224.0.0/12 +42.240.0.0/17 +42.240.128.0/17 +42.242.0.0/15 +42.244.0.0/14 +42.248.0.0/13 +43.136.0.0/13 +43.144.0.0/15 +43.148.0.0/14 +43.176.0.0/12 +43.192.0.0/15 +43.194.0.0/16 +43.195.0.0/16 +43.196.0.0/15 +43.224.12.0/22 +43.224.24.0/22 +43.224.44.0/22 +43.224.52.0/22 +43.224.56.0/22 +43.224.68.0/22 +43.224.72.0/22 +43.224.80.0/22 +43.224.100.0/22 +43.224.144.0/22 +43.224.160.0/22 +43.224.176.0/22 +43.224.184.0/22 +43.224.200.0/22 +43.224.204.0/22 +43.224.208.0/22 +43.224.212.0/22 +43.224.216.0/22 +43.224.240.0/22 +43.225.76.0/22 +43.225.84.0/22 +43.225.120.0/22 +43.225.172.0/22 +43.225.180.0/22 +43.225.208.0/22 +43.225.216.0/21 +43.225.224.0/21 +43.225.232.0/22 +43.225.236.0/22 +43.225.240.0/21 +43.225.252.0/22 +43.226.32.0/22 +43.226.36.0/22 +43.226.40.0/22 +43.226.44.0/22 +43.226.48.0/22 +43.226.52.0/22 +43.226.56.0/22 +43.226.60.0/22 +43.226.64.0/22 +43.226.68.0/22 +43.226.72.0/22 +43.226.76.0/22 +43.226.80.0/22 +43.226.84.0/22 +43.226.88.0/22 +43.226.92.0/22 +43.226.96.0/22 +43.226.100.0/22 +43.226.104.0/22 +43.226.108.0/22 +43.226.112.0/22 +43.226.116.0/22 +43.226.120.0/22 +43.226.128.0/22 +43.226.132.0/22 +43.226.136.0/22 +43.226.140.0/22 +43.226.144.0/22 +43.226.148.0/22 +43.226.152.0/22 +43.226.156.0/22 +43.226.160.0/22 +43.226.164.0/22 +43.226.168.0/22 +43.226.172.0/22 +43.226.176.0/22 +43.226.180.0/22 +43.226.184.0/22 +43.226.188.0/22 +43.226.192.0/22 +43.226.196.0/22 +43.226.200.0/22 +43.226.204.0/22 +43.226.208.0/22 +43.226.212.0/22 +43.226.236.0/22 +43.226.240.0/22 +43.226.244.0/22 +43.226.248.0/22 +43.226.252.0/22 +43.227.0.0/22 +43.227.4.0/22 +43.227.8.0/22 +43.227.32.0/22 +43.227.36.0/22 +43.227.40.0/22 +43.227.44.0/22 +43.227.48.0/22 +43.227.52.0/22 +43.227.56.0/22 +43.227.60.0/22 +43.227.64.0/22 +43.227.68.0/22 +43.227.72.0/22 +43.227.76.0/22 +43.227.80.0/22 +43.227.84.0/22 +43.227.88.0/22 +43.227.92.0/22 +43.227.96.0/22 +43.227.100.0/22 +43.227.104.0/22 +43.227.136.0/22 +43.227.140.0/22 +43.227.144.0/22 +43.227.152.0/22 +43.227.156.0/22 +43.227.160.0/22 +43.227.164.0/22 +43.227.168.0/22 +43.227.172.0/22 +43.227.176.0/22 +43.227.180.0/22 +43.227.188.0/22 +43.227.192.0/22 +43.227.196.0/22 +43.227.200.0/22 +43.227.204.0/22 +43.227.208.0/22 +43.227.212.0/22 +43.227.216.0/22 +43.227.220.0/22 +43.227.232.0/22 +43.227.248.0/22 +43.227.252.0/22 +43.228.0.0/22 +43.228.4.0/22 +43.228.8.0/22 +43.228.12.0/22 +43.228.16.0/22 +43.228.20.0/22 +43.228.24.0/22 +43.228.28.0/22 +43.228.32.0/22 +43.228.36.0/22 +43.228.40.0/22 +43.228.44.0/22 +43.228.48.0/22 +43.228.52.0/22 +43.228.56.0/22 +43.228.60.0/22 +43.228.64.0/22 +43.228.68.0/22 +43.228.76.0/22 +43.228.100.0/22 +43.228.116.0/22 +43.228.120.0/22 +43.228.132.0/22 +43.228.136.0/22 +43.228.148.0/22 +43.228.152.0/22 +43.228.188.0/22 +43.228.204.0/22 +43.228.240.0/22 +43.229.40.0/22 +43.229.48.0/22 +43.229.56.0/22 +43.229.96.0/22 +43.229.136.0/22 +43.229.140.0/22 +43.229.144.0/22 +43.229.168.0/22 +43.229.172.0/22 +43.229.176.0/22 +43.229.180.0/22 +43.229.184.0/22 +43.229.188.0/22 +43.229.192.0/22 +43.229.196.0/22 +43.229.216.0/22 +43.229.220.0/22 +43.229.232.0/22 +43.229.236.0/22 +43.230.20.0/22 +43.230.32.0/22 +43.230.68.0/22 +43.230.72.0/22 +43.230.124.0/22 +43.230.136.0/22 +43.230.220.0/22 +43.230.224.0/20 +43.230.240.0/22 +43.230.244.0/22 +43.230.248.0/22 +43.230.252.0/22 +43.231.32.0/22 +43.231.36.0/22 +43.231.40.0/22 +43.231.44.0/22 +43.231.80.0/22 +43.231.84.0/22 +43.231.88.0/22 +43.231.92.0/22 +43.231.96.0/22 +43.231.100.0/22 +43.231.104.0/22 +43.231.108.0/22 +43.231.136.0/22 +43.231.140.0/22 +43.231.144.0/22 +43.231.148.0/22 +43.231.152.0/22 +43.231.156.0/22 +43.231.160.0/22 +43.231.164.0/22 +43.231.168.0/22 +43.231.172.0/22 +43.231.176.0/22 +43.231.180.0/22 +43.236.0.0/22 +43.236.4.0/22 +43.236.8.0/22 +43.236.12.0/22 +43.236.16.0/22 +43.236.20.0/22 +43.236.24.0/22 +43.236.28.0/22 +43.236.32.0/22 +43.236.36.0/22 +43.236.40.0/22 +43.236.44.0/22 +43.236.48.0/22 +43.236.52.0/22 +43.236.56.0/22 +43.236.60.0/22 +43.236.64.0/22 +43.236.68.0/22 +43.236.72.0/22 +43.236.76.0/22 +43.236.80.0/22 +43.236.84.0/22 +43.236.88.0/22 +43.236.92.0/22 +43.236.96.0/22 +43.236.100.0/22 +43.236.104.0/22 +43.236.108.0/22 +43.236.112.0/22 +43.236.116.0/22 +43.236.120.0/22 +43.236.124.0/22 +43.236.128.0/22 +43.236.132.0/22 +43.236.136.0/22 +43.236.140.0/22 +43.236.144.0/22 +43.236.148.0/22 +43.236.152.0/22 +43.236.156.0/22 +43.236.160.0/22 +43.236.164.0/22 +43.236.168.0/22 +43.236.172.0/22 +43.236.176.0/22 +43.236.180.0/22 +43.236.184.0/22 +43.236.188.0/22 +43.236.192.0/22 +43.236.196.0/22 +43.236.200.0/22 +43.236.204.0/22 +43.236.208.0/22 +43.236.212.0/22 +43.236.216.0/22 +43.236.220.0/22 +43.236.224.0/22 +43.236.228.0/22 +43.236.232.0/22 +43.236.236.0/22 +43.236.240.0/22 +43.236.244.0/22 +43.236.248.0/22 +43.236.252.0/22 +43.237.0.0/22 +43.237.4.0/22 +43.237.8.0/22 +43.237.12.0/22 +43.237.16.0/22 +43.237.20.0/22 +43.237.24.0/22 +43.237.28.0/22 +43.237.32.0/22 +43.237.36.0/22 +43.237.40.0/22 +43.237.44.0/22 +43.237.48.0/22 +43.237.52.0/22 +43.237.56.0/22 +43.237.60.0/22 +43.237.64.0/22 +43.237.68.0/22 +43.237.72.0/22 +43.237.76.0/22 +43.237.80.0/22 +43.237.84.0/22 +43.237.88.0/22 +43.237.92.0/22 +43.237.96.0/22 +43.237.100.0/22 +43.237.104.0/22 +43.237.108.0/22 +43.237.112.0/22 +43.237.116.0/22 +43.237.120.0/22 +43.237.124.0/22 +43.237.128.0/22 +43.237.132.0/22 +43.237.136.0/22 +43.237.140.0/22 +43.237.144.0/22 +43.237.148.0/22 +43.237.152.0/22 +43.237.156.0/22 +43.237.160.0/22 +43.237.164.0/22 +43.237.168.0/22 +43.237.172.0/22 +43.237.176.0/22 +43.237.180.0/22 +43.237.184.0/22 +43.237.188.0/22 +43.237.192.0/22 +43.237.200.0/22 +43.237.204.0/22 +43.237.208.0/22 +43.237.212.0/22 +43.237.216.0/22 +43.237.220.0/22 +43.237.224.0/22 +43.237.228.0/22 +43.237.232.0/22 +43.237.236.0/22 +43.237.240.0/22 +43.237.244.0/22 +43.237.248.0/22 +43.237.252.0/22 +43.238.0.0/22 +43.238.4.0/22 +43.238.8.0/22 +43.238.12.0/22 +43.238.16.0/22 +43.238.20.0/22 +43.238.24.0/22 +43.238.28.0/22 +43.238.32.0/22 +43.238.36.0/22 +43.238.40.0/22 +43.238.44.0/22 +43.238.48.0/22 +43.238.52.0/22 +43.238.56.0/22 +43.238.60.0/22 +43.238.64.0/22 +43.238.68.0/22 +43.238.72.0/22 +43.238.76.0/22 +43.238.80.0/22 +43.238.84.0/22 +43.238.88.0/22 +43.238.92.0/22 +43.238.96.0/22 +43.238.100.0/22 +43.238.104.0/22 +43.238.108.0/22 +43.238.112.0/22 +43.238.116.0/22 +43.238.120.0/22 +43.238.124.0/22 +43.238.128.0/22 +43.238.132.0/22 +43.238.136.0/22 +43.238.140.0/22 +43.238.144.0/22 +43.238.148.0/22 +43.238.152.0/22 +43.238.156.0/22 +43.238.160.0/22 +43.238.164.0/22 +43.238.168.0/22 +43.238.172.0/22 +43.238.176.0/22 +43.238.180.0/22 +43.238.184.0/22 +43.238.188.0/22 +43.238.192.0/22 +43.238.196.0/22 +43.238.200.0/22 +43.238.204.0/22 +43.238.208.0/22 +43.238.212.0/22 +43.238.216.0/22 +43.238.220.0/22 +43.238.224.0/22 +43.238.228.0/22 +43.238.232.0/22 +43.238.236.0/22 +43.238.240.0/22 +43.238.244.0/22 +43.238.248.0/22 +43.238.252.0/22 +43.239.0.0/22 +43.239.4.0/22 +43.239.8.0/22 +43.239.12.0/22 +43.239.16.0/22 +43.239.20.0/22 +43.239.24.0/22 +43.239.28.0/22 +43.239.32.0/22 +43.239.36.0/22 +43.239.40.0/22 +43.239.44.0/22 +43.239.48.0/22 +43.239.116.0/22 +43.239.120.0/22 +43.239.172.0/22 +43.239.176.0/22 +43.240.0.0/22 +43.240.56.0/22 +43.240.60.0/22 +43.240.68.0/22 +43.240.72.0/22 +43.240.76.0/22 +43.240.84.0/22 +43.240.124.0/22 +43.240.128.0/22 +43.240.132.0/22 +43.240.136.0/22 +43.240.144.0/22 +43.240.156.0/22 +43.240.160.0/22 +43.240.164.0/22 +43.240.168.0/22 +43.240.172.0/22 +43.240.176.0/22 +43.240.180.0/22 +43.240.184.0/22 +43.240.188.0/22 +43.240.192.0/22 +43.240.196.0/22 +43.240.200.0/22 +43.240.204.0/22 +43.240.208.0/22 +43.240.212.0/22 +43.240.216.0/22 +43.240.220.0/22 +43.240.240.0/22 +43.240.244.0/22 +43.240.248.0/22 +43.240.252.0/22 +43.241.0.0/22 +43.241.4.0/22 +43.241.8.0/22 +43.241.12.0/22 +43.241.16.0/22 +43.241.20.0/22 +43.241.48.0/22 +43.241.76.0/22 +43.241.80.0/22 +43.241.84.0/22 +43.241.88.0/22 +43.241.92.0/22 +43.241.112.0/22 +43.241.168.0/22 +43.241.172.0/22 +43.241.176.0/22 +43.241.180.0/22 +43.241.184.0/22 +43.241.208.0/22 +43.241.212.0/22 +43.241.216.0/22 +43.241.220.0/22 +43.241.224.0/22 +43.241.228.0/22 +43.241.232.0/22 +43.241.236.0/22 +43.241.240.0/22 +43.241.248.0/22 +43.241.252.0/22 +43.242.8.0/22 +43.242.12.0/22 +43.242.16.0/21 +43.242.24.0/22 +43.242.28.0/22 +43.242.48.0/22 +43.242.52.0/22 +43.242.56.0/22 +43.242.60.0/22 +43.242.64.0/22 +43.242.72.0/22 +43.242.76.0/22 +43.242.80.0/22 +43.242.84.0/22 +43.242.88.0/22 +43.242.92.0/22 +43.242.96.0/22 +43.242.144.0/22 +43.242.148.0/22 +43.242.152.0/22 +43.242.156.0/22 +43.242.160.0/22 +43.242.164.0/22 +43.242.168.0/22 +43.242.180.0/22 +43.242.188.0/22 +43.242.192.0/22 +43.242.196.0/22 +43.242.204.0/22 +43.242.216.0/22 +43.242.220.0/22 +43.242.252.0/22 +43.243.4.0/22 +43.243.8.0/22 +43.243.12.0/22 +43.243.16.0/22 +43.243.88.0/22 +43.243.128.0/22 +43.243.136.0/22 +43.243.144.0/22 +43.243.148.0/22 +43.243.156.0/22 +43.243.180.0/22 +43.243.228.0/22 +43.243.232.0/22 +43.243.244.0/22 +43.246.0.0/22 +43.246.4.0/22 +43.246.8.0/22 +43.246.12.0/22 +43.246.16.0/22 +43.246.20.0/22 +43.246.24.0/22 +43.246.28.0/22 +43.246.32.0/22 +43.246.36.0/22 +43.246.40.0/22 +43.246.44.0/22 +43.246.48.0/22 +43.246.52.0/22 +43.246.56.0/22 +43.246.60.0/22 +43.246.64.0/22 +43.246.68.0/22 +43.246.72.0/22 +43.246.76.0/22 +43.246.80.0/22 +43.246.84.0/22 +43.246.88.0/22 +43.246.92.0/22 +43.246.96.0/22 +43.246.112.0/22 +43.246.228.0/22 +43.247.4.0/22 +43.247.8.0/22 +43.247.44.0/22 +43.247.48.0/22 +43.247.68.0/22 +43.247.76.0/22 +43.247.84.0/22 +43.247.88.0/22 +43.247.92.0/22 +43.247.96.0/22 +43.247.100.0/22 +43.247.108.0/22 +43.247.112.0/22 +43.247.148.0/22 +43.247.152.0/22 +43.247.176.0/22 +43.247.180.0/22 +43.247.184.0/22 +43.247.188.0/22 +43.247.196.0/22 +43.247.200.0/22 +43.247.204.0/22 +43.247.208.0/22 +43.247.212.0/22 +43.247.216.0/22 +43.247.220.0/22 +43.247.224.0/22 +43.247.228.0/22 +43.247.232.0/22 +43.247.236.0/22 +43.247.240.0/22 +43.247.244.0/22 +43.247.248.0/22 +43.247.252.0/22 +43.248.0.0/22 +43.248.4.0/22 +43.248.20.0/22 +43.248.28.0/22 +43.248.48.0/22 +43.248.76.0/22 +43.248.80.0/22 +43.248.84.0/22 +43.248.88.0/22 +43.248.92.0/22 +43.248.96.0/22 +43.248.100.0/22 +43.248.104.0/22 +43.248.108.0/22 +43.248.112.0/22 +43.248.116.0/22 +43.248.120.0/22 +43.248.124.0/22 +43.248.128.0/22 +43.248.132.0/22 +43.248.136.0/22 +43.248.140.0/22 +43.248.144.0/22 +43.248.148.0/22 +43.248.176.0/22 +43.248.180.0/22 +43.248.184.0/22 +43.248.188.0/22 +43.248.192.0/22 +43.248.196.0/22 +43.248.200.0/22 +43.248.204.0/22 +43.248.208.0/22 +43.248.228.0/22 +43.248.232.0/22 +43.248.244.0/22 +43.249.4.0/22 +43.249.120.0/22 +43.249.132.0/22 +43.249.136.0/22 +43.249.144.0/22 +43.249.148.0/22 +43.249.152.0/22 +43.249.156.0/22 +43.249.160.0/22 +43.249.164.0/22 +43.249.168.0/22 +43.249.192.0/22 +43.249.236.0/22 +43.250.4.0/22 +43.250.12.0/22 +43.250.16.0/22 +43.250.20.0/22 +43.250.28.0/22 +43.250.32.0/22 +43.250.36.0/22 +43.250.72.0/22 +43.250.96.0/22 +43.250.100.0/22 +43.250.104.0/22 +43.250.108.0/22 +43.250.112.0/22 +43.250.116.0/22 +43.250.128.0/22 +43.250.144.0/22 +43.250.148.0/22 +43.250.160.0/22 +43.250.168.0/22 +43.250.172.0/22 +43.250.176.0/22 +43.250.180.0/23 +43.250.200.0/22 +43.250.212.0/22 +43.250.216.0/22 +43.250.220.0/22 +43.250.236.0/22 +43.250.244.0/22 +43.251.4.0/22 +43.251.8.0/22 +43.251.36.0/22 +43.251.100.0/22 +43.251.116.0/22 +43.251.192.0/22 +43.251.232.0/22 +43.251.236.0/22 +43.251.244.0/22 +43.252.48.0/22 +43.252.56.0/22 +43.254.0.0/22 +43.254.4.0/22 +43.254.8.0/22 +43.254.24.0/22 +43.254.36.0/22 +43.254.44.0/22 +43.254.52.0/22 +43.254.64.0/22 +43.254.72.0/22 +43.254.84.0/22 +43.254.88.0/22 +43.254.92.0/22 +43.254.100.0/22 +43.254.104.0/22 +43.254.112.0/22 +43.254.116.0/22 +43.254.128.0/22 +43.254.136.0/22 +43.254.140.0/22 +43.254.144.0/22 +43.254.148.0/22 +43.254.152.0/22 +43.254.156.0/22 +43.254.168.0/22 +43.254.172.0/22 +43.254.180.0/22 +43.254.184.0/22 +43.254.188.0/22 +43.254.192.0/22 +43.254.196.0/22 +43.254.200.0/22 +43.254.208.0/22 +43.254.220.0/22 +43.254.224.0/22 +43.254.228.0/22 +43.254.232.0/22 +43.254.236.0/22 +43.254.240.0/22 +43.254.248.0/22 +43.254.252.0/22 +43.255.0.0/22 +43.255.4.0/22 +43.255.8.0/22 +43.255.16.0/22 +43.255.48.0/22 +43.255.64.0/22 +43.255.68.0/22 +43.255.72.0/22 +43.255.76.0/22 +43.255.84.0/22 +43.255.96.0/22 +43.255.144.0/22 +43.255.176.0/22 +43.255.184.0/22 +43.255.192.0/22 +43.255.200.0/22 +43.255.204.0/22 +43.255.208.0/22 +43.255.212.0/22 +43.255.224.0/22 +43.255.228.0/22 +43.255.232.0/22 +43.255.244.0/22 +45.40.192.0/18 +45.65.16.0/22 +45.65.20.0/22 +45.65.24.0/22 +45.65.28.0/22 +45.112.132.0/22 +45.112.188.0/22 +45.112.208.0/22 +45.112.212.0/22 +45.112.216.0/22 +45.112.220.0/22 +45.112.228.0/22 +45.112.232.0/22 +45.112.236.0/22 +45.113.12.0/22 +45.113.16.0/22 +45.113.20.0/22 +45.113.24.0/22 +45.113.28.0/22 +45.113.40.0/22 +45.113.52.0/22 +45.113.56.0/22 +45.113.72.0/22 +45.113.144.0/22 +45.113.148.0/22 +45.113.168.0/22 +45.113.176.0/22 +45.113.184.0/22 +45.113.200.0/22 +45.113.204.0/22 +45.113.208.0/22 +45.113.212.0/22 +45.113.216.0/22 +45.113.220.0/22 +45.113.240.0/22 +45.113.252.0/22 +45.114.0.0/22 +45.114.32.0/22 +45.114.40.0/22 +45.114.52.0/22 +45.114.96.0/22 +45.114.124.0/22 +45.114.136.0/22 +45.114.196.0/22 +45.114.200.0/22 +45.114.228.0/22 +45.114.252.0/22 +45.115.18.0/23 +45.115.44.0/22 +45.115.100.0/22 +45.115.120.0/22 +45.115.132.0/22 +45.115.144.0/22 +45.115.156.0/22 +45.115.164.0/22 +45.115.200.0/22 +45.115.212.0/22 +45.115.228.0/22 +45.115.236.0/22 +45.115.244.0/22 +45.115.248.0/22 +45.116.16.0/22 +45.116.24.0/22 +45.116.32.0/22 +45.116.36.0/22 +45.116.52.0/22 +45.116.96.0/22 +45.116.100.0/22 +45.116.140.0/22 +45.116.152.0/22 +45.116.208.0/22 +45.117.8.0/22 +45.117.20.0/22 +45.117.68.0/22 +45.117.124.0/22 +45.117.252.0/22 +45.119.52.0/22 +45.119.60.0/22 +45.119.64.0/22 +45.119.68.0/22 +45.119.72.0/22 +45.119.104.0/22 +45.119.116.0/22 +45.119.232.0/22 +45.120.100.0/22 +45.120.140.0/22 +45.120.164.0/22 +45.120.240.0/22 +45.121.52.0/22 +45.121.64.0/22 +45.121.68.0/22 +45.121.72.0/22 +45.121.92.0/22 +45.121.96.0/22 +45.121.172.0/22 +45.121.176.0/22 +45.121.212.0/22 +45.121.240.0/22 +45.121.244.0/22 +45.121.248.0/22 +45.121.252.0/22 +45.122.0.0/22 +45.122.4.0/22 +45.122.8.0/22 +45.122.12.0/22 +45.122.16.0/22 +45.122.20.0/22 +45.122.24.0/22 +45.122.28.0/22 +45.122.32.0/22 +45.122.36.0/22 +45.122.40.0/22 +45.122.60.0/22 +45.122.64.0/22 +45.122.68.0/22 +45.122.72.0/22 +45.122.76.0/22 +45.122.80.0/22 +45.122.84.0/22 +45.122.88.0/22 +45.122.92.0/22 +45.122.96.0/21 +45.122.104.0/22 +45.122.108.0/22 +45.122.112.0/22 +45.122.116.0/22 +45.122.160.0/22 +45.122.164.0/22 +45.122.168.0/22 +45.122.172.0/22 +45.122.176.0/22 +45.122.180.0/22 +45.122.184.0/22 +45.122.188.0/22 +45.122.192.0/22 +45.122.196.0/22 +45.122.200.0/22 +45.122.204.0/22 +45.122.208.0/22 +45.122.212.0/22 +45.122.216.0/22 +45.123.28.0/22 +45.123.32.0/22 +45.123.36.0/22 +45.123.44.0/22 +45.123.48.0/22 +45.123.52.0/22 +45.123.56.0/22 +45.123.60.0/22 +45.123.64.0/22 +45.123.68.0/22 +45.123.72.0/22 +45.123.76.0/22 +45.123.80.0/22 +45.123.84.0/22 +45.123.88.0/22 +45.123.120.0/22 +45.123.128.0/22 +45.123.132.0/22 +45.123.136.0/22 +45.123.148.0/22 +45.123.152.0/22 +45.123.156.0/22 +45.123.164.0/22 +45.123.168.0/22 +45.123.172.0/22 +45.123.176.0/22 +45.123.180.0/22 +45.123.184.0/22 +45.123.204.0/22 +45.123.212.0/22 +45.123.224.0/22 +45.123.228.0/22 +45.123.232.0/22 +45.123.236.0/22 +45.123.240.0/22 +45.123.244.0/22 +45.123.248.0/22 +45.123.252.0/22 +45.124.0.0/22 +45.124.20.0/22 +45.124.28.0/22 +45.124.32.0/22 +45.124.36.0/22 +45.124.44.0/22 +45.124.68.0/22 +45.124.76.0/22 +45.124.80.0/22 +45.124.100.0/22 +45.124.124.0/22 +45.124.172.0/22 +45.124.176.0/22 +45.124.208.0/22 +45.124.248.0/22 +45.125.16.0/22 +45.125.24.0/22 +45.125.44.0/22 +45.125.52.0/22 +45.125.56.0/22 +45.125.76.0/22 +45.125.80.0/22 +45.125.84.0/22 +45.125.88.0/22 +45.125.92.0/22 +45.125.96.0/22 +45.125.100.0/22 +45.125.136.0/22 +45.126.48.0/22 +45.126.52.0/22 +45.126.100.0/22 +45.126.108.0/22 +45.126.112.0/22 +45.126.116.0/22 +45.126.120.0/22 +45.126.212.0/22 +45.126.220.0/22 +45.127.8.0/22 +45.127.12.0/22 +45.127.128.0/22 +45.127.144.0/22 +45.127.148.0/22 +45.127.156.0/22 +45.127.216.0/22 +45.248.8.0/22 +45.248.80.0/22 +45.248.84.0/22 +45.248.88.0/22 +45.248.96.0/22 +45.248.100.0/22 +45.248.104.0/22 +45.248.108.0/22 +45.248.128.0/22 +45.248.132.0/22 +45.248.204.0/22 +45.248.208.0/22 +45.248.212.0/22 +45.248.216.0/22 +45.248.220.0/22 +45.248.224.0/22 +45.248.228.0/22 +45.248.232.0/22 +45.248.236.0/22 +45.248.240.0/22 +45.248.244.0/22 +45.248.248.0/22 +45.248.252.0/22 +45.249.0.0/22 +45.249.4.0/22 +45.249.12.0/22 +45.249.16.0/22 +45.249.20.0/22 +45.249.24.0/22 +45.249.28.0/22 +45.249.32.0/22 +45.249.36.0/22 +45.249.112.0/22 +45.249.188.0/22 +45.249.192.0/22 +45.249.196.0/22 +45.249.200.0/22 +45.249.204.0/22 +45.249.208.0/22 +45.249.212.0/22 +45.250.12.0/22 +45.250.16.0/22 +45.250.28.0/22 +45.250.32.0/22 +45.250.36.0/22 +45.250.40.0/22 +45.250.76.0/22 +45.250.80.0/22 +45.250.84.0/22 +45.250.88.0/22 +45.250.92.0/22 +45.250.96.0/22 +45.250.104.0/22 +45.250.108.0/22 +45.250.112.0/22 +45.250.116.0/22 +45.250.120.0/22 +45.250.124.0/22 +45.250.128.0/22 +45.250.132.0/22 +45.250.136.0/22 +45.250.140.0/22 +45.250.144.0/22 +45.250.148.0/22 +45.250.152.0/22 +45.250.164.0/22 +45.250.180.0/22 +45.250.184.0/22 +45.250.188.0/22 +45.250.192.0/22 +45.251.0.0/22 +45.251.8.0/22 +45.251.16.0/22 +45.251.20.0/22 +45.251.52.0/22 +45.251.84.0/22 +45.251.88.0/22 +45.251.92.0/22 +45.251.96.0/22 +45.251.100.0/22 +45.251.120.0/22 +45.251.124.0/22 +45.251.136.0/22 +45.251.140.0/22 +45.251.144.0/22 +45.251.148.0/22 +45.251.152.0/22 +45.251.156.0/22 +45.251.160.0/22 +45.251.164.0/22 +45.251.168.0/22 +45.251.172.0/22 +45.251.176.0/22 +45.251.180.0/22 +45.251.184.0/22 +45.251.188.0/22 +45.251.192.0/22 +45.251.196.0/22 +45.251.200.0/22 +45.251.204.0/22 +45.251.208.0/22 +45.251.212.0/22 +45.251.216.0/22 +45.251.220.0/22 +45.251.224.0/22 +45.251.240.0/22 +45.252.0.0/22 +45.252.4.0/22 +45.252.8.0/22 +45.252.12.0/22 +45.252.16.0/22 +45.252.20.0/22 +45.252.24.0/22 +45.252.28.0/22 +45.252.32.0/22 +45.252.36.0/22 +45.252.40.0/22 +45.252.44.0/22 +45.252.48.0/22 +45.252.84.0/22 +45.252.88.0/22 +45.252.92.0/22 +45.252.96.0/22 +45.252.100.0/22 +45.252.104.0/22 +45.252.108.0/22 +45.252.112.0/22 +45.252.116.0/22 +45.252.120.0/22 +45.252.124.0/22 +45.252.128.0/22 +45.252.132.0/22 +45.252.136.0/22 +45.252.140.0/22 +45.252.144.0/22 +45.252.148.0/22 +45.252.152.0/22 +45.252.156.0/22 +45.252.160.0/22 +45.252.164.0/22 +45.252.168.0/22 +45.252.172.0/22 +45.252.176.0/22 +45.252.192.0/22 +45.252.196.0/22 +45.252.200.0/22 +45.252.204.0/22 +45.252.208.0/22 +45.252.212.0/22 +45.252.216.0/22 +45.252.220.0/22 +45.252.224.0/22 +45.252.228.0/22 +45.252.232.0/22 +45.253.0.0/22 +45.253.4.0/22 +45.253.8.0/22 +45.253.12.0/22 +45.253.16.0/22 +45.253.20.0/22 +45.253.24.0/22 +45.253.28.0/22 +45.253.32.0/22 +45.253.36.0/22 +45.253.40.0/22 +45.253.44.0/22 +45.253.48.0/22 +45.253.52.0/22 +45.253.56.0/22 +45.253.60.0/22 +45.253.64.0/22 +45.253.68.0/22 +45.253.72.0/22 +45.253.76.0/22 +45.253.80.0/22 +45.253.84.0/22 +45.253.92.0/22 +45.253.96.0/22 +45.253.100.0/22 +45.253.104.0/22 +45.253.108.0/22 +45.253.112.0/22 +45.253.116.0/22 +45.253.120.0/22 +45.253.132.0/22 +45.253.136.0/22 +45.253.140.0/22 +45.253.144.0/22 +45.253.148.0/22 +45.253.152.0/22 +45.253.156.0/22 +45.253.160.0/22 +45.253.164.0/22 +45.253.168.0/22 +45.253.172.0/22 +45.253.176.0/22 +45.253.180.0/22 +45.253.184.0/22 +45.253.188.0/22 +45.253.192.0/22 +45.253.196.0/22 +45.253.200.0/22 +45.253.204.0/22 +45.253.208.0/22 +45.253.212.0/22 +45.253.216.0/22 +45.253.220.0/22 +45.253.224.0/22 +45.253.228.0/22 +45.253.232.0/22 +45.253.236.0/22 +45.253.240.0/22 +45.253.246.0/23 +45.254.0.0/22 +45.254.4.0/22 +45.254.8.0/22 +45.254.12.0/22 +45.254.16.0/22 +45.254.20.0/22 +45.254.24.0/22 +45.254.28.0/22 +45.254.40.0/22 +45.254.48.0/22 +45.254.52.0/22 +45.254.56.0/22 +45.254.60.0/22 +45.254.64.0/22 +45.254.68.0/22 +45.254.72.0/22 +45.254.76.0/22 +45.254.80.0/22 +45.254.84.0/22 +45.254.88.0/22 +45.254.92.0/22 +45.254.96.0/22 +45.254.100.0/22 +45.254.104.0/22 +45.254.108.0/22 +45.254.112.0/22 +45.254.116.0/22 +45.254.120.0/22 +45.254.124.0/22 +45.254.128.0/22 +45.254.132.0/22 +45.254.136.0/22 +45.254.140.0/22 +45.254.144.0/22 +45.254.148.0/22 +45.254.152.0/22 +45.254.156.0/22 +45.254.160.0/22 +45.254.164.0/22 +45.254.168.0/22 +45.254.172.0/22 +45.254.176.0/22 +45.254.180.0/22 +45.254.184.0/22 +45.254.188.0/22 +45.254.192.0/22 +45.254.196.0/22 +45.254.200.0/22 +45.254.204.0/22 +45.254.208.0/22 +45.254.212.0/22 +45.254.216.0/22 +45.254.220.0/22 +45.254.224.0/22 +45.254.228.0/22 +45.254.236.0/22 +45.254.240.0/22 +45.254.248.0/22 +45.255.0.0/22 +45.255.4.0/22 +45.255.8.0/22 +45.255.12.0/22 +45.255.16.0/22 +45.255.20.0/22 +45.255.24.0/22 +45.255.28.0/22 +45.255.32.0/22 +45.255.36.0/22 +45.255.40.0/22 +45.255.44.0/22 +45.255.48.0/22 +45.255.52.0/22 +45.255.56.0/22 +45.255.60.0/22 +45.255.64.0/22 +45.255.68.0/22 +45.255.72.0/22 +45.255.76.0/22 +45.255.80.0/22 +45.255.84.0/22 +45.255.88.0/22 +45.255.92.0/22 +45.255.96.0/22 +45.255.100.0/22 +45.255.104.0/22 +45.255.108.0/22 +45.255.112.0/22 +45.255.116.0/22 +45.255.120.0/22 +45.255.136.0/22 +45.255.140.0/22 +45.255.144.0/22 +45.255.148.0/22 +45.255.152.0/22 +45.255.156.0/22 +45.255.160.0/22 +45.255.164.0/22 +45.255.168.0/22 +45.255.172.0/22 +45.255.176.0/22 +45.255.180.0/22 +45.255.184.0/22 +45.255.188.0/22 +45.255.192.0/22 +45.255.196.0/22 +45.255.200.0/22 +45.255.204.0/22 +45.255.208.0/22 +45.255.212.0/22 +45.255.216.0/22 +45.255.220.0/22 +45.255.224.0/22 +45.255.228.0/22 +45.255.232.0/22 +45.255.236.0/22 +45.255.240.0/22 +45.255.244.0/22 +45.255.248.0/22 +47.92.0.0/14 +47.96.0.0/11 +49.4.0.0/17 +49.4.128.0/17 +49.5.0.0/16 +49.6.0.0/15 +49.51.0.0/16 +49.52.0.0/14 +49.64.0.0/11 +49.112.0.0/13 +49.120.0.0/14 +49.128.0.0/24 +49.128.2.0/23 +49.128.4.0/22 +49.140.0.0/15 +49.152.0.0/14 +49.208.0.0/15 +49.210.0.0/15 +49.213.60.0/23 +49.213.62.0/23 +49.220.0.0/14 +49.232.0.0/14 +49.239.0.0/19 +49.239.32.0/20 +49.239.48.0/21 +49.239.56.0/22 +49.239.60.0/23 +49.239.62.0/23 +49.239.192.0/18 +49.246.224.0/19 +52.80.0.0/15 +52.82.0.0/15 +52.130.0.0/15 +54.222.0.0/15 +57.176.0.0/15 +58.14.0.0/15 +58.16.0.0/16 +58.17.0.0/17 +58.17.128.0/17 +58.18.0.0/16 +58.19.0.0/16 +58.20.0.0/16 +58.21.0.0/16 +58.22.0.0/15 +58.24.0.0/15 +58.30.0.0/15 +58.32.0.0/13 +58.40.0.0/15 +58.42.0.0/16 +58.43.0.0/16 +58.44.0.0/14 +58.48.0.0/13 +58.56.0.0/15 +58.58.0.0/16 +58.59.0.0/17 +58.59.128.0/17 +58.60.0.0/14 +58.65.232.0/21 +58.66.0.0/15 +58.68.128.0/18 +58.68.192.0/19 +58.68.224.0/19 +58.82.0.0/17 +58.83.0.0/17 +58.83.128.0/17 +58.87.64.0/18 +58.99.128.0/17 +58.100.0.0/15 +58.116.0.0/14 +58.128.0.0/13 +58.144.0.0/16 +58.154.0.0/15 +58.192.0.0/15 +58.194.0.0/15 +58.196.0.0/15 +58.198.0.0/15 +58.200.0.0/13 +58.208.0.0/12 +58.240.0.0/15 +58.242.0.0/15 +58.244.0.0/15 +58.246.0.0/15 +58.248.0.0/13 +59.32.0.0/13 +59.40.0.0/15 +59.42.0.0/16 +59.43.0.0/16 +59.44.0.0/14 +59.48.0.0/16 +59.49.0.0/17 +59.49.128.0/17 +59.50.0.0/16 +59.51.0.0/17 +59.51.128.0/17 +59.52.0.0/14 +59.56.0.0/14 +59.60.0.0/15 +59.62.0.0/15 +59.64.0.0/14 +59.68.0.0/14 +59.72.0.0/15 +59.74.0.0/15 +59.76.0.0/16 +59.77.0.0/16 +59.78.0.0/15 +59.80.0.0/15 +59.82.0.0/16 +59.83.0.0/17 +59.83.128.0/18 +59.83.192.0/19 +59.83.224.0/21 +59.83.232.0/24 +59.83.233.0/24 +59.83.234.0/23 +59.83.236.0/22 +59.83.240.0/20 +59.107.0.0/17 +59.107.128.0/17 +59.108.0.0/15 +59.110.0.0/15 +59.151.0.0/17 +59.152.16.0/22 +59.152.20.0/22 +59.152.24.0/22 +59.152.28.0/22 +59.152.32.0/22 +59.152.36.0/22 +59.152.64.0/22 +59.152.68.0/22 +59.152.72.0/22 +59.152.76.0/22 +59.152.112.0/22 +59.152.116.0/22 +59.153.4.0/22 +59.153.32.0/22 +59.153.60.0/22 +59.153.64.0/22 +59.153.68.0/22 +59.153.72.0/22 +59.153.92.0/22 +59.153.116.0/22 +59.153.136.0/22 +59.153.152.0/22 +59.153.164.0/22 +59.153.168.0/22 +59.153.172.0/22 +59.153.176.0/22 +59.153.180.0/22 +59.153.184.0/22 +59.153.188.0/22 +59.153.192.0/22 +59.155.0.0/16 +59.172.0.0/15 +59.174.0.0/15 +59.191.0.0/17 +59.192.0.0/10 +60.0.0.0/13 +60.8.0.0/15 +60.10.0.0/16 +60.11.0.0/16 +60.12.0.0/16 +60.13.0.0/18 +60.13.64.0/18 +60.13.128.0/17 +60.14.0.0/15 +60.16.0.0/13 +60.24.0.0/14 +60.28.0.0/15 +60.30.0.0/16 +60.31.0.0/16 +60.55.0.0/16 +60.63.0.0/16 +60.160.0.0/15 +60.162.0.0/15 +60.164.0.0/15 +60.166.0.0/15 +60.168.0.0/13 +60.176.0.0/12 +60.194.0.0/15 +60.200.0.0/14 +60.204.0.0/16 +60.205.0.0/16 +60.206.0.0/15 +60.208.0.0/13 +60.216.0.0/15 +60.218.0.0/15 +60.220.0.0/14 +60.232.0.0/15 +60.235.0.0/16 +60.245.128.0/17 +60.247.0.0/17 +60.247.128.0/17 +60.252.0.0/16 +60.253.128.0/17 +60.255.0.0/16 +61.4.80.0/22 +61.4.84.0/22 +61.4.88.0/21 +61.4.176.0/20 +61.8.160.0/20 +61.14.212.0/22 +61.14.216.0/22 +61.14.220.0/22 +61.14.240.0/22 +61.14.244.0/22 +61.28.0.0/20 +61.28.16.0/20 +61.28.32.0/19 +61.28.64.0/18 +61.29.128.0/18 +61.29.192.0/19 +61.29.224.0/20 +61.29.240.0/22 +61.29.248.0/22 +61.45.128.0/18 +61.45.224.0/20 +61.47.128.0/18 +61.48.0.0/14 +61.52.0.0/15 +61.54.0.0/16 +61.55.0.0/16 +61.87.192.0/18 +61.128.0.0/15 +61.130.0.0/15 +61.132.0.0/16 +61.133.0.0/17 +61.133.128.0/17 +61.134.0.0/18 +61.134.64.0/19 +61.134.96.0/19 +61.134.128.0/18 +61.134.192.0/18 +61.135.0.0/16 +61.136.0.0/18 +61.136.64.0/18 +61.136.128.0/17 +61.137.0.0/17 +61.137.128.0/17 +61.138.0.0/18 +61.138.64.0/18 +61.138.128.0/18 +61.138.192.0/18 +61.139.0.0/17 +61.139.128.0/18 +61.139.192.0/18 +61.140.0.0/14 +61.144.0.0/14 +61.148.0.0/15 +61.150.0.0/15 +61.152.0.0/16 +61.153.0.0/16 +61.154.0.0/15 +61.156.0.0/16 +61.157.0.0/16 +61.158.0.0/17 +61.158.128.0/17 +61.159.0.0/18 +61.159.64.0/18 +61.159.128.0/17 +61.160.0.0/16 +61.161.0.0/18 +61.161.64.0/18 +61.161.128.0/17 +61.162.0.0/16 +61.163.0.0/16 +61.164.0.0/16 +61.165.0.0/16 +61.166.0.0/16 +61.167.0.0/16 +61.168.0.0/16 +61.169.0.0/16 +61.170.0.0/15 +61.172.0.0/14 +61.176.0.0/16 +61.177.0.0/16 +61.178.0.0/16 +61.179.0.0/16 +61.180.0.0/17 +61.180.128.0/17 +61.181.0.0/16 +61.182.0.0/16 +61.183.0.0/16 +61.184.0.0/14 +61.188.0.0/16 +61.189.0.0/17 +61.189.128.0/17 +61.190.0.0/15 +61.232.0.0/14 +61.236.0.0/15 +61.240.0.0/14 +62.234.0.0/16 +68.79.0.0/18 +69.230.192.0/18 +69.231.128.0/18 +69.234.192.0/18 +69.235.128.0/18 +71.131.192.0/18 +71.132.0.0/18 +71.136.64.0/18 +71.137.0.0/18 +81.68.0.0/14 +82.156.0.0/15 +94.191.0.0/17 +101.0.0.0/22 +101.1.0.0/22 +101.2.172.0/22 +101.4.0.0/14 +101.16.0.0/12 +101.33.128.0/17 +101.34.0.0/15 +101.36.0.0/18 +101.36.64.0/19 +101.36.128.0/17 +101.37.0.0/16 +101.38.0.0/15 +101.40.0.0/15 +101.42.0.0/15 +101.48.0.0/16 +101.49.0.0/16 +101.50.8.0/22 +101.50.12.0/22 +101.50.56.0/22 +101.52.0.0/16 +101.53.100.0/22 +101.54.0.0/16 +101.55.224.0/21 +101.64.0.0/13 +101.72.0.0/14 +101.76.0.0/15 +101.78.0.0/22 +101.78.32.0/19 +101.80.0.0/12 +101.96.0.0/21 +101.96.8.0/22 +101.96.16.0/20 +101.96.128.0/17 +101.99.96.0/19 +101.101.64.0/19 +101.101.100.0/24 +101.101.102.0/23 +101.101.104.0/21 +101.101.112.0/20 +101.102.64.0/19 +101.102.100.0/23 +101.102.102.0/24 +101.102.104.0/21 +101.102.112.0/20 +101.104.0.0/14 +101.110.64.0/19 +101.110.96.0/20 +101.110.116.0/22 +101.110.120.0/21 +101.120.0.0/14 +101.124.0.0/16 +101.125.0.0/16 +101.126.0.0/16 +101.128.0.0/22 +101.128.8.0/21 +101.128.16.0/20 +101.128.32.0/19 +101.129.0.0/16 +101.130.0.0/15 +101.132.0.0/14 +101.144.0.0/12 +101.192.0.0/14 +101.196.0.0/16 +101.197.0.0/16 +101.198.0.0/15 +101.200.0.0/15 +101.203.128.0/19 +101.203.160.0/21 +101.203.172.0/22 +101.203.176.0/20 +101.204.0.0/14 +101.224.0.0/13 +101.232.0.0/15 +101.234.64.0/21 +101.234.76.0/22 +101.234.80.0/20 +101.234.96.0/19 +101.236.0.0/14 +101.240.0.0/14 +101.244.0.0/16 +101.245.0.0/16 +101.246.0.0/15 +101.248.0.0/15 +101.251.0.0/22 +101.251.8.0/21 +101.251.16.0/20 +101.251.32.0/19 +101.251.64.0/18 +101.251.128.0/17 +101.252.0.0/15 +101.254.0.0/16 +103.1.8.0/22 +103.1.20.0/22 +103.1.24.0/22 +103.1.72.0/22 +103.1.88.0/22 +103.1.168.0/22 +103.2.108.0/22 +103.2.156.0/22 +103.2.164.0/22 +103.2.188.0/23 +103.2.200.0/22 +103.2.204.0/22 +103.2.208.0/22 +103.2.212.0/22 +103.3.84.0/22 +103.3.88.0/22 +103.3.92.0/22 +103.3.96.0/22 +103.3.100.0/22 +103.3.104.0/22 +103.3.108.0/22 +103.3.112.0/22 +103.3.116.0/22 +103.3.120.0/22 +103.3.124.0/22 +103.3.128.0/22 +103.3.132.0/22 +103.3.136.0/22 +103.3.140.0/22 +103.3.148.0/22 +103.3.152.0/22 +103.3.156.0/22 +103.4.56.0/22 +103.4.168.0/22 +103.4.184.0/22 +103.4.224.0/22 +103.5.36.0/22 +103.5.52.0/22 +103.5.56.0/22 +103.5.152.0/22 +103.5.168.0/22 +103.5.192.0/22 +103.5.252.0/22 +103.6.76.0/22 +103.6.108.0/22 +103.6.220.0/22 +103.6.228.0/22 +103.7.28.0/22 +103.7.140.0/22 +103.7.212.0/22 +103.7.216.0/22 +103.7.220.0/22 +103.8.0.0/22 +103.8.4.0/22 +103.8.8.0/22 +103.8.32.0/22 +103.8.52.0/22 +103.8.68.0/22 +103.8.108.0/22 +103.8.156.0/22 +103.8.200.0/22 +103.8.204.0/22 +103.8.220.0/22 +103.9.8.0/22 +103.9.24.0/22 +103.9.108.0/22 +103.9.152.0/22 +103.9.248.0/22 +103.9.252.0/22 +103.10.0.0/22 +103.10.16.0/22 +103.10.84.0/22 +103.10.140.0/22 +103.11.16.0/22 +103.11.168.0/22 +103.11.180.0/22 +103.12.32.0/22 +103.12.92.0/22 +103.12.98.0/23 +103.12.136.0/22 +103.12.184.0/22 +103.12.232.0/22 +103.13.12.0/22 +103.13.124.0/22 +103.13.196.0/22 +103.13.244.0/22 +103.14.84.0/22 +103.14.100.0/22 +103.14.132.0/22 +103.14.136.0/22 +103.14.156.0/22 +103.14.240.0/22 +103.15.4.0/22 +103.15.8.0/22 +103.15.16.0/22 +103.15.96.0/22 +103.15.200.0/22 +103.16.52.0/22 +103.16.80.0/22 +103.16.84.0/22 +103.16.88.0/22 +103.16.108.0/22 +103.16.124.0/22 +103.17.40.0/22 +103.17.64.0/22 +103.17.120.0/22 +103.17.136.0/22 +103.17.160.0/22 +103.17.204.0/22 +103.17.228.0/22 +103.18.186.0/23 +103.18.192.0/22 +103.18.206.0/23 +103.18.208.0/22 +103.18.212.0/22 +103.18.224.0/22 +103.19.12.0/22 +103.19.40.0/22 +103.19.44.0/22 +103.19.50.0/23 +103.19.64.0/22 +103.19.68.0/22 +103.19.72.0/22 +103.19.232.0/22 +103.20.12.0/22 +103.20.32.0/22 +103.20.44.0/22 +103.20.68.0/22 +103.20.112.0/22 +103.20.128.0/22 +103.20.160.0/22 +103.20.248.0/22 +103.21.98.0/23 +103.21.102.0/23 +103.21.112.0/22 +103.21.116.0/22 +103.21.136.0/22 +103.21.140.0/22 +103.21.176.0/22 +103.21.208.0/22 +103.21.240.0/22 +103.22.0.0/22 +103.22.4.0/22 +103.22.8.0/22 +103.22.12.0/22 +103.22.16.0/22 +103.22.20.0/22 +103.22.24.0/22 +103.22.28.0/22 +103.22.32.0/22 +103.22.36.0/22 +103.22.40.0/22 +103.22.44.0/22 +103.22.48.0/22 +103.22.52.0/22 +103.22.56.0/22 +103.22.60.0/22 +103.22.64.0/22 +103.22.68.0/22 +103.22.72.0/22 +103.22.76.0/22 +103.22.80.0/22 +103.22.84.0/22 +103.22.88.0/22 +103.22.92.0/22 +103.22.100.0/22 +103.22.104.0/22 +103.22.108.0/22 +103.22.112.0/22 +103.22.116.0/22 +103.22.120.0/22 +103.22.124.0/22 +103.22.188.0/22 +103.22.228.0/22 +103.22.252.0/22 +103.23.8.0/22 +103.23.56.0/22 +103.23.160.0/22 +103.23.164.0/22 +103.23.176.0/22 +103.23.228.0/22 +103.24.24.0/22 +103.24.116.0/22 +103.24.128.0/22 +103.24.144.0/22 +103.24.176.0/22 +103.24.184.0/22 +103.24.220.0/22 +103.24.228.0/22 +103.24.252.0/22 +103.25.8.0/23 +103.25.20.0/22 +103.25.24.0/22 +103.25.28.0/22 +103.25.32.0/22 +103.25.36.0/22 +103.25.40.0/22 +103.25.48.0/22 +103.25.64.0/22 +103.25.68.0/22 +103.25.148.0/22 +103.25.156.0/22 +103.25.216.0/22 +103.26.0.0/22 +103.26.64.0/22 +103.26.76.0/22 +103.26.132.0/22 +103.26.156.0/22 +103.26.160.0/22 +103.26.228.0/22 +103.26.240.0/22 +103.27.4.0/22 +103.27.12.0/22 +103.27.24.0/22 +103.27.56.0/22 +103.27.96.0/22 +103.27.184.0/22 +103.27.212.0/22 +103.27.240.0/22 +103.28.4.0/22 +103.28.8.0/22 +103.28.184.0/22 +103.28.204.0/22 +103.28.212.0/22 +103.29.16.0/22 +103.29.24.0/23 +103.29.29.0/24 +103.29.128.0/22 +103.29.132.0/22 +103.29.136.0/22 +103.29.236.0/23 +103.30.20.0/22 +103.30.96.0/22 +103.30.104.0/23 +103.30.106.0/23 +103.30.148.0/22 +103.30.200.0/22 +103.30.228.0/22 +103.30.236.0/22 +103.31.0.0/22 +103.31.48.0/22 +103.31.52.0/22 +103.31.56.0/22 +103.31.60.0/22 +103.31.64.0/22 +103.31.68.0/22 +103.31.148.0/22 +103.31.160.0/22 +103.31.168.0/22 +103.31.200.0/22 +103.31.236.0/22 +103.31.242.0/23 +103.32.0.0/22 +103.32.4.0/22 +103.32.8.0/22 +103.32.12.0/22 +103.32.16.0/22 +103.32.20.0/22 +103.32.24.0/22 +103.32.28.0/22 +103.32.32.0/22 +103.32.36.0/22 +103.32.40.0/22 +103.32.44.0/22 +103.32.48.0/22 +103.32.52.0/22 +103.32.56.0/22 +103.32.60.0/22 +103.32.64.0/22 +103.32.68.0/22 +103.32.72.0/22 +103.32.76.0/22 +103.32.80.0/22 +103.32.84.0/22 +103.32.88.0/22 +103.32.92.0/22 +103.32.96.0/22 +103.32.100.0/22 +103.32.104.0/22 +103.32.108.0/22 +103.32.112.0/22 +103.32.116.0/22 +103.32.120.0/22 +103.32.124.0/22 +103.32.128.0/22 +103.32.132.0/22 +103.32.136.0/22 +103.32.140.0/22 +103.32.144.0/22 +103.32.148.0/22 +103.32.152.0/22 +103.32.156.0/22 +103.32.160.0/22 +103.32.164.0/22 +103.32.168.0/22 +103.32.172.0/22 +103.32.176.0/22 +103.32.180.0/22 +103.32.184.0/22 +103.32.188.0/22 +103.32.192.0/22 +103.32.196.0/22 +103.32.200.0/22 +103.32.204.0/22 +103.32.208.0/22 +103.32.212.0/22 +103.32.216.0/22 +103.32.220.0/22 +103.32.224.0/22 +103.32.228.0/22 +103.32.232.0/22 +103.32.236.0/22 +103.32.240.0/22 +103.32.244.0/22 +103.32.248.0/22 +103.32.252.0/22 +103.33.0.0/22 +103.33.4.0/22 +103.33.8.0/22 +103.33.12.0/22 +103.33.16.0/22 +103.33.20.0/22 +103.33.24.0/22 +103.33.28.0/22 +103.33.32.0/22 +103.33.36.0/22 +103.33.40.0/22 +103.33.44.0/22 +103.33.48.0/22 +103.33.52.0/22 +103.33.56.0/22 +103.33.60.0/22 +103.33.64.0/22 +103.33.68.0/22 +103.33.72.0/22 +103.33.76.0/22 +103.33.80.0/22 +103.33.84.0/22 +103.33.88.0/22 +103.33.92.0/22 +103.33.96.0/22 +103.33.100.0/22 +103.33.104.0/22 +103.33.108.0/22 +103.33.112.0/22 +103.33.116.0/22 +103.33.120.0/22 +103.33.124.0/22 +103.33.128.0/22 +103.33.132.0/22 +103.33.136.0/22 +103.33.140.0/22 +103.33.144.0/22 +103.33.148.0/22 +103.33.152.0/22 +103.33.156.0/22 +103.33.160.0/22 +103.33.164.0/22 +103.33.168.0/22 +103.33.172.0/22 +103.33.176.0/22 +103.33.180.0/22 +103.33.184.0/22 +103.33.188.0/22 +103.33.192.0/22 +103.33.196.0/22 +103.33.200.0/22 +103.33.204.0/22 +103.33.208.0/22 +103.33.212.0/22 +103.33.216.0/22 +103.33.220.0/22 +103.33.224.0/22 +103.33.228.0/22 +103.33.232.0/22 +103.33.236.0/22 +103.33.240.0/22 +103.33.244.0/22 +103.33.248.0/22 +103.33.252.0/22 +103.34.0.0/22 +103.34.4.0/22 +103.34.8.0/22 +103.34.12.0/22 +103.34.16.0/22 +103.34.20.0/22 +103.34.24.0/22 +103.34.28.0/22 +103.34.32.0/22 +103.34.36.0/22 +103.34.40.0/22 +103.34.44.0/22 +103.34.48.0/22 +103.34.52.0/22 +103.34.56.0/22 +103.34.60.0/22 +103.34.64.0/22 +103.34.68.0/22 +103.34.72.0/22 +103.34.76.0/22 +103.34.80.0/22 +103.34.84.0/22 +103.34.88.0/22 +103.34.92.0/22 +103.34.96.0/22 +103.34.100.0/22 +103.34.104.0/22 +103.34.108.0/22 +103.34.112.0/22 +103.34.116.0/22 +103.34.120.0/22 +103.34.124.0/22 +103.34.128.0/22 +103.34.132.0/22 +103.34.136.0/22 +103.34.140.0/22 +103.34.144.0/22 +103.34.148.0/22 +103.34.152.0/22 +103.34.156.0/22 +103.34.160.0/22 +103.34.164.0/22 +103.34.168.0/22 +103.34.172.0/22 +103.34.176.0/22 +103.34.180.0/22 +103.34.184.0/22 +103.34.188.0/22 +103.34.192.0/22 +103.34.196.0/22 +103.34.200.0/22 +103.34.204.0/22 +103.34.208.0/22 +103.34.212.0/22 +103.34.216.0/22 +103.34.220.0/22 +103.34.224.0/22 +103.34.228.0/22 +103.34.232.0/22 +103.34.236.0/22 +103.34.240.0/22 +103.34.244.0/22 +103.34.248.0/22 +103.34.252.0/22 +103.35.0.0/22 +103.35.4.0/22 +103.35.8.0/22 +103.35.12.0/22 +103.35.16.0/22 +103.35.20.0/22 +103.35.24.0/22 +103.35.28.0/22 +103.35.32.0/22 +103.35.36.0/22 +103.35.40.0/22 +103.35.44.0/22 +103.35.48.0/22 +103.35.104.0/22 +103.35.116.0/22 +103.35.180.0/22 +103.35.220.0/22 +103.36.28.0/22 +103.36.36.0/22 +103.36.56.0/22 +103.36.60.0/22 +103.36.64.0/22 +103.36.72.0/22 +103.36.96.0/22 +103.36.132.0/22 +103.36.136.0/22 +103.36.160.0/22 +103.36.164.0/22 +103.36.168.0/22 +103.36.172.0/22 +103.36.176.0/22 +103.36.180.0/22 +103.36.184.0/22 +103.36.188.0/22 +103.36.192.0/22 +103.36.196.0/22 +103.36.200.0/22 +103.36.204.0/22 +103.36.208.0/22 +103.36.212.0/22 +103.36.216.0/22 +103.36.220.0/22 +103.36.224.0/22 +103.36.228.0/22 +103.36.232.0/22 +103.36.236.0/22 +103.36.240.0/22 +103.36.244.0/22 +103.37.12.0/22 +103.37.16.0/22 +103.37.24.0/22 +103.37.44.0/22 +103.37.52.0/22 +103.37.56.0/22 +103.37.72.0/22 +103.37.100.0/22 +103.37.104.0/22 +103.37.136.0/22 +103.37.140.0/22 +103.37.144.0/22 +103.37.148.0/22 +103.37.152.0/22 +103.37.156.0/22 +103.37.160.0/22 +103.37.164.0/22 +103.37.172.0/22 +103.37.176.0/22 +103.37.188.0/22 +103.37.208.0/22 +103.37.212.0/22 +103.37.216.0/21 +103.37.252.0/22 +103.38.0.0/22 +103.38.32.0/22 +103.38.40.0/22 +103.38.44.0/22 +103.38.56.0/22 +103.38.76.0/22 +103.38.84.0/22 +103.38.92.0/22 +103.38.96.0/22 +103.38.116.0/22 +103.38.132.0/22 +103.38.140.0/22 +103.38.224.0/22 +103.38.228.0/22 +103.38.232.0/22 +103.39.64.0/22 +103.39.88.0/22 +103.39.100.0/22 +103.39.104.0/22 +103.39.160.0/22 +103.39.164.0/22 +103.39.168.0/22 +103.39.172.0/22 +103.39.176.0/22 +103.39.180.0/22 +103.39.184.0/22 +103.39.188.0/22 +103.39.200.0/22 +103.39.204.0/22 +103.39.208.0/22 +103.39.212.0/22 +103.39.216.0/22 +103.39.220.0/22 +103.39.224.0/22 +103.39.228.0/22 +103.39.232.0/22 +103.40.12.0/22 +103.40.16.0/22 +103.40.20.0/22 +103.40.24.0/22 +103.40.28.0/22 +103.40.32.0/22 +103.40.36.0/22 +103.40.40.0/22 +103.40.44.0/22 +103.40.88.0/22 +103.40.158.0/23 +103.40.174.0/23 +103.40.192.0/22 +103.40.212.0/22 +103.40.220.0/22 +103.40.228.0/22 +103.40.232.0/22 +103.40.236.0/22 +103.40.240.0/22 +103.40.244.0/22 +103.40.248.0/22 +103.40.252.0/22 +103.41.0.0/22 +103.41.16.0/22 +103.41.52.0/22 +103.41.116.0/22 +103.41.140.0/22 +103.41.148.0/22 +103.41.152.0/22 +103.41.160.0/22 +103.41.164.0/22 +103.41.220.0/22 +103.41.224.0/22 +103.41.228.0/22 +103.41.232.0/22 +103.42.8.0/22 +103.42.24.0/22 +103.42.28.0/22 +103.42.32.0/22 +103.42.64.0/22 +103.42.68.0/22 +103.42.76.0/22 +103.42.104.0/22 +103.42.180.0/22 +103.42.232.0/22 +103.43.16.0/22 +103.43.96.0/22 +103.43.100.0/22 +103.43.104.0/22 +103.43.124.0/22 +103.43.132.0/22 +103.43.184.0/22 +103.43.192.0/22 +103.43.196.0/22 +103.43.208.0/22 +103.43.220.0/22 +103.43.224.0/22 +103.43.240.0/22 +103.44.56.0/22 +103.44.80.0/22 +103.44.120.0/22 +103.44.124.0/22 +103.44.132.0/22 +103.44.144.0/22 +103.44.168.0/22 +103.44.176.0/22 +103.44.180.0/22 +103.44.184.0/22 +103.44.188.0/22 +103.44.192.0/22 +103.44.196.0/22 +103.44.200.0/21 +103.44.224.0/22 +103.44.236.0/22 +103.44.240.0/22 +103.44.244.0/22 +103.44.248.0/22 +103.44.252.0/22 +103.45.0.0/22 +103.45.4.0/22 +103.45.8.0/22 +103.45.12.0/22 +103.45.16.0/22 +103.45.20.0/22 +103.45.24.0/22 +103.45.28.0/22 +103.45.32.0/22 +103.45.36.0/22 +103.45.40.0/22 +103.45.44.0/22 +103.45.48.0/22 +103.45.52.0/22 +103.45.56.0/22 +103.45.60.0/22 +103.45.72.0/22 +103.45.76.0/22 +103.45.80.0/22 +103.45.84.0/22 +103.45.88.0/22 +103.45.92.0/22 +103.45.96.0/22 +103.45.100.0/22 +103.45.104.0/22 +103.45.108.0/22 +103.45.112.0/22 +103.45.116.0/22 +103.45.120.0/22 +103.45.124.0/22 +103.45.128.0/22 +103.45.132.0/22 +103.45.136.0/22 +103.45.140.0/22 +103.45.144.0/22 +103.45.148.0/22 +103.45.152.0/22 +103.45.156.0/22 +103.45.160.0/22 +103.45.164.0/22 +103.45.168.0/22 +103.45.172.0/22 +103.45.176.0/22 +103.45.180.0/22 +103.45.184.0/22 +103.45.188.0/22 +103.45.192.0/22 +103.45.196.0/22 +103.45.200.0/22 +103.45.204.0/22 +103.45.208.0/22 +103.45.212.0/22 +103.45.216.0/22 +103.45.220.0/22 +103.45.224.0/22 +103.45.248.0/22 +103.46.0.0/22 +103.46.12.0/22 +103.46.16.0/22 +103.46.20.0/22 +103.46.24.0/22 +103.46.28.0/22 +103.46.32.0/22 +103.46.36.0/22 +103.46.40.0/22 +103.46.44.0/22 +103.46.48.0/22 +103.46.52.0/22 +103.46.56.0/22 +103.46.60.0/22 +103.46.64.0/22 +103.46.68.0/22 +103.46.72.0/22 +103.46.76.0/22 +103.46.80.0/22 +103.46.84.0/22 +103.46.88.0/22 +103.46.92.0/22 +103.46.96.0/22 +103.46.100.0/22 +103.46.104.0/22 +103.46.108.0/22 +103.46.112.0/22 +103.46.116.0/22 +103.46.120.0/22 +103.46.124.0/22 +103.46.128.0/22 +103.46.132.0/22 +103.46.136.0/22 +103.46.152.0/22 +103.46.156.0/22 +103.46.160.0/22 +103.46.164.0/22 +103.46.168.0/22 +103.46.172.0/22 +103.46.176.0/22 +103.46.180.0/22 +103.46.244.0/22 +103.46.248.0/22 +103.47.4.0/22 +103.47.20.0/22 +103.47.36.0/22 +103.47.40.0/22 +103.47.48.0/22 +103.47.80.0/22 +103.47.96.0/22 +103.47.108.0/22 +103.47.116.0/22 +103.47.120.0/22 +103.47.136.0/22 +103.47.140.0/22 +103.47.212.0/22 +103.48.52.0/22 +103.48.92.0/22 +103.48.148.0/22 +103.48.152.0/22 +103.48.156.0/22 +103.48.202.0/23 +103.48.216.0/22 +103.48.220.0/22 +103.48.224.0/22 +103.48.228.0/22 +103.48.232.0/22 +103.48.236.0/22 +103.48.240.0/22 +103.48.244.0/22 +103.49.12.0/22 +103.49.20.0/22 +103.49.72.0/22 +103.49.76.0/22 +103.49.96.0/22 +103.49.108.0/22 +103.49.176.0/22 +103.49.180.0/22 +103.49.196.0/22 +103.50.36.0/22 +103.50.44.0/22 +103.50.48.0/22 +103.50.52.0/22 +103.50.56.0/22 +103.50.60.0/22 +103.50.64.0/22 +103.50.68.0/22 +103.50.72.0/22 +103.50.108.0/22 +103.50.112.0/22 +103.50.116.0/22 +103.50.120.0/22 +103.50.124.0/22 +103.50.132.0/22 +103.50.136.0/22 +103.50.140.0/22 +103.50.172.0/22 +103.50.176.0/22 +103.50.180.0/22 +103.50.184.0/22 +103.50.188.0/22 +103.50.192.0/22 +103.50.196.0/22 +103.50.200.0/22 +103.50.220.0/22 +103.50.224.0/22 +103.50.228.0/22 +103.50.232.0/22 +103.50.236.0/22 +103.50.240.0/22 +103.50.244.0/22 +103.50.248.0/22 +103.51.62.0/23 +103.52.40.0/22 +103.52.72.0/22 +103.52.76.0/22 +103.52.80.0/22 +103.52.84.0/22 +103.52.96.0/22 +103.52.100.0/22 +103.52.104.0/22 +103.52.160.0/22 +103.52.164.0/22 +103.52.172.0/22 +103.52.176.0/22 +103.52.184.0/22 +103.52.196.0/22 +103.53.64.0/22 +103.53.68.0/22 +103.53.92.0/22 +103.53.100.0/22 +103.53.124.0/22 +103.53.128.0/22 +103.53.132.0/22 +103.53.136.0/22 +103.53.140.0/22 +103.53.144.0/22 +103.53.180.0/22 +103.53.204.0/22 +103.53.208.0/22 +103.53.212.0/22 +103.53.236.0/22 +103.53.248.0/22 +103.54.8.0/22 +103.54.48.0/22 +103.54.160.0/22 +103.54.164.0/22 +103.54.212.0/22 +103.54.240.0/22 +103.55.80.0/22 +103.55.120.0/22 +103.55.152.0/22 +103.55.172.0/22 +103.55.204.0/22 +103.55.208.0/22 +103.55.228.0/22 +103.55.236.0/22 +103.56.8.0/22 +103.56.16.0/22 +103.56.20.0/22 +103.56.32.0/22 +103.56.56.0/22 +103.56.60.0/22 +103.56.72.0/22 +103.56.76.0/22 +103.56.94.0/23 +103.56.100.0/22 +103.56.104.0/22 +103.56.140.0/22 +103.56.152.0/22 +103.56.184.0/22 +103.56.200.0/22 +103.57.12.0/22 +103.57.52.0/22 +103.57.56.0/22 +103.57.76.0/22 +103.57.136.0/22 +103.57.196.0/22 +103.58.24.0/22 +103.59.76.0/22 +103.59.100.0/22 +103.59.112.0/22 +103.59.116.0/22 +103.59.120.0/22 +103.59.124.0/22 +103.59.128.0/22 +103.59.148.0/22 +103.59.164.0/22 +103.59.168.0/23 +103.60.32.0/22 +103.60.44.0/22 +103.60.164.0/22 +103.60.228.0/22 +103.60.236.0/22 +103.61.60.0/22 +103.61.104.0/22 +103.61.140.0/22 +103.61.152.0/22 +103.61.156.0/22 +103.61.160.0/22 +103.61.172.0/22 +103.61.176.0/22 +103.61.188.0/22 +103.62.24.0/22 +103.62.52.0/22 +103.62.72.0/22 +103.62.76.0/22 +103.62.80.0/22 +103.62.84.0/22 +103.62.88.0/22 +103.62.96.0/22 +103.62.100.0/22 +103.62.104.0/22 +103.62.108.0/22 +103.62.112.0/22 +103.62.116.0/22 +103.62.120.0/22 +103.62.124.0/22 +103.62.128.0/22 +103.62.132.0/22 +103.62.156.0/22 +103.62.160.0/22 +103.62.164.0/22 +103.62.168.0/22 +103.62.172.0/22 +103.62.176.0/22 +103.62.180.0/22 +103.62.184.0/22 +103.62.188.0/22 +103.62.192.0/22 +103.62.204.0/22 +103.62.208.0/22 +103.62.212.0/22 +103.62.216.0/22 +103.62.220.0/22 +103.62.224.0/22 +103.63.32.0/22 +103.63.36.0/22 +103.63.40.0/22 +103.63.44.0/22 +103.63.48.0/22 +103.63.52.0/22 +103.63.56.0/22 +103.63.60.0/22 +103.63.64.0/22 +103.63.68.0/22 +103.63.72.0/22 +103.63.76.0/22 +103.63.80.0/22 +103.63.84.0/22 +103.63.88.0/22 +103.63.140.0/22 +103.63.144.0/22 +103.63.152.0/22 +103.63.160.0/22 +103.63.164.0/22 +103.63.168.0/22 +103.63.172.0/22 +103.63.176.0/22 +103.63.180.0/22 +103.63.184.0/22 +103.63.192.0/22 +103.63.196.0/22 +103.63.200.0/22 +103.63.204.0/22 +103.63.208.0/22 +103.63.240.0/22 +103.63.244.0/22 +103.63.248.0/22 +103.63.252.0/22 +103.64.0.0/22 +103.64.4.0/22 +103.64.24.0/22 +103.64.28.0/22 +103.64.32.0/22 +103.64.36.0/22 +103.64.40.0/22 +103.64.44.0/22 +103.64.48.0/22 +103.64.52.0/22 +103.64.56.0/22 +103.64.60.0/22 +103.64.64.0/22 +103.64.68.0/22 +103.64.72.0/22 +103.64.76.0/22 +103.64.80.0/22 +103.64.84.0/22 +103.64.88.0/22 +103.64.92.0/22 +103.64.96.0/22 +103.64.100.0/22 +103.64.104.0/22 +103.64.108.0/22 +103.64.112.0/22 +103.64.116.0/22 +103.64.120.0/22 +103.64.124.0/22 +103.64.140.0/22 +103.64.144.0/22 +103.64.152.0/22 +103.64.156.0/22 +103.64.160.0/22 +103.64.164.0/22 +103.64.168.0/22 +103.64.172.0/22 +103.64.176.0/22 +103.64.180.0/22 +103.64.184.0/22 +103.64.188.0/22 +103.64.192.0/22 +103.64.196.0/22 +103.64.200.0/22 +103.64.204.0/22 +103.64.208.0/22 +103.64.212.0/22 +103.64.216.0/22 +103.64.220.0/22 +103.64.224.0/22 +103.64.228.0/22 +103.64.232.0/22 +103.64.236.0/22 +103.64.240.0/22 +103.64.244.0/22 +103.64.248.0/22 +103.64.252.0/22 +103.65.0.0/22 +103.65.4.0/22 +103.65.8.0/22 +103.65.12.0/22 +103.65.16.0/22 +103.65.48.0/22 +103.65.52.0/22 +103.65.56.0/22 +103.65.60.0/22 +103.65.64.0/22 +103.65.68.0/22 +103.65.72.0/22 +103.65.76.0/22 +103.65.80.0/22 +103.65.84.0/22 +103.65.88.0/22 +103.65.92.0/22 +103.65.100.0/22 +103.65.104.0/22 +103.65.108.0/22 +103.65.112.0/22 +103.65.144.0/22 +103.65.148.0/22 +103.65.152.0/22 +103.65.156.0/22 +103.65.160.0/22 +103.65.164.0/22 +103.65.168.0/22 +103.65.172.0/22 +103.65.204.0/23 +103.65.206.0/23 +103.65.224.0/23 +103.66.32.0/22 +103.66.40.0/22 +103.66.92.0/22 +103.66.108.0/22 +103.66.200.0/22 +103.66.216.0/22 +103.66.240.0/22 +103.66.244.0/22 +103.66.248.0/22 +103.66.252.0/22 +103.67.0.0/22 +103.67.4.0/22 +103.67.8.0/22 +103.67.52.0/23 +103.67.100.0/22 +103.67.104.0/22 +103.67.108.0/22 +103.67.112.0/22 +103.67.116.0/22 +103.67.120.0/22 +103.67.124.0/22 +103.67.128.0/22 +103.67.132.0/22 +103.67.136.0/22 +103.67.140.0/22 +103.67.144.0/22 +103.67.148.0/22 +103.67.172.0/22 +103.67.192.0/22 +103.67.212.0/22 +103.67.252.0/22 +103.68.64.0/22 +103.68.88.0/22 +103.68.100.0/22 +103.68.128.0/22 +103.68.192.0/22 +103.69.16.0/22 +103.69.62.0/23 +103.69.116.0/22 +103.70.8.0/22 +103.70.14.0/23 +103.70.148.0/22 +103.70.220.0/22 +103.70.224.0/22 +103.70.236.0/22 +103.70.252.0/22 +103.71.0.0/22 +103.71.48.0/22 +103.71.68.0/22 +103.71.72.0/22 +103.71.80.0/22 +103.71.84.0/22 +103.71.88.0/22 +103.71.120.0/22 +103.71.124.0/22 +103.71.128.0/22 +103.71.144.0/22 +103.71.196.0/22 +103.71.200.0/22 +103.71.232.0/22 +103.72.12.0/22 +103.72.16.0/22 +103.72.20.0/22 +103.72.24.0/22 +103.72.28.0/22 +103.72.32.0/22 +103.72.36.0/22 +103.72.40.0/22 +103.72.44.0/22 +103.72.48.0/22 +103.72.52.0/22 +103.72.112.0/22 +103.72.116.0/22 +103.72.120.0/22 +103.72.124.0/22 +103.72.128.0/22 +103.72.132.0/22 +103.72.148.0/22 +103.72.172.0/22 +103.72.180.0/22 +103.72.224.0/22 +103.72.228.0/22 +103.72.232.0/22 +103.72.236.0/22 +103.72.240.0/22 +103.72.244.0/22 +103.72.248.0/22 +103.72.252.0/22 +103.73.0.0/22 +103.73.4.0/22 +103.73.8.0/22 +103.73.12.0/22 +103.73.16.0/22 +103.73.20.0/22 +103.73.24.0/22 +103.73.28.0/22 +103.73.48.0/22 +103.73.116.0/22 +103.73.120.0/22 +103.73.128.0/22 +103.73.132.0/22 +103.73.136.0/22 +103.73.140.0/22 +103.73.144.0/22 +103.73.168.0/22 +103.73.176.0/22 +103.73.204.0/22 +103.73.208.0/22 +103.73.240.0/22 +103.73.244.0/22 +103.73.248.0/22 +103.74.24.0/22 +103.74.28.0/22 +103.74.32.0/22 +103.74.36.0/22 +103.74.40.0/22 +103.74.44.0/22 +103.74.48.0/22 +103.74.56.0/22 +103.74.60.0/22 +103.74.80.0/22 +103.74.124.0/22 +103.74.148.0/22 +103.74.152.0/22 +103.74.156.0/22 +103.74.204.0/22 +103.74.232.0/22 +103.75.82.0/23 +103.75.88.0/22 +103.75.92.0/22 +103.75.104.0/22 +103.75.108.0/22 +103.75.112.0/22 +103.75.120.0/22 +103.75.128.0/22 +103.75.144.0/22 +103.75.152.0/22 +103.75.236.0/24 +103.76.60.0/22 +103.76.64.0/22 +103.76.68.0/22 +103.76.72.0/22 +103.76.92.0/22 +103.76.216.0/22 +103.76.220.0/22 +103.76.224.0/22 +103.77.28.0/22 +103.77.52.0/22 +103.77.56.0/22 +103.77.72.0/22 +103.77.88.0/22 +103.77.92.0/22 +103.77.132.0/22 +103.77.148.0/22 +103.77.220.0/22 +103.78.56.0/22 +103.78.60.0/22 +103.78.64.0/22 +103.78.68.0/22 +103.78.124.0/22 +103.78.172.0/22 +103.78.176.0/22 +103.78.196.0/22 +103.78.228.0/22 +103.79.24.0/22 +103.79.28.0/22 +103.79.36.0/22 +103.79.40.0/22 +103.79.44.0/22 +103.79.56.0/22 +103.79.60.0/22 +103.79.64.0/22 +103.79.68.0/22 +103.79.80.0/22 +103.79.84.0/22 +103.79.136.0/22 +103.79.188.0/22 +103.79.192.0/22 +103.79.196.0/22 +103.79.200.0/22 +103.79.204.0/22 +103.79.208.0/22 +103.79.212.0/22 +103.79.228.0/23 +103.80.28.0/22 +103.80.44.0/22 +103.80.72.0/22 +103.80.176.0/22 +103.80.180.0/22 +103.80.184.0/22 +103.80.192.0/22 +103.80.200.0/22 +103.80.232.0/22 +103.81.4.0/22 +103.81.8.0/22 +103.81.16.0/22 +103.81.20.0/22 +103.81.44.0/22 +103.81.48.0/22 +103.81.96.0/22 +103.81.120.0/22 +103.81.148.0/22 +103.81.164.0/22 +103.81.168.0/22 +103.81.183.0/24 +103.81.184.0/22 +103.81.200.0/22 +103.81.232.0/22 +103.82.52.0/22 +103.82.60.0/22 +103.82.68.0/22 +103.82.84.0/22 +103.82.104.0/22 +103.82.224.0/22 +103.82.236.0/22 +103.83.44.0/22 +103.83.52.0/22 +103.83.60.0/22 +103.83.64.0/22 +103.83.72.0/22 +103.83.112.0/22 +103.83.120.0/22 +103.83.180.0/22 +103.84.0.0/22 +103.84.12.0/22 +103.84.16.0/22 +103.84.20.0/22 +103.84.24.0/22 +103.84.28.0/22 +103.84.48.0/22 +103.84.64.0/22 +103.84.72.0/22 +103.84.136.0/22 +103.84.170.0/23 +103.85.20.0/22 +103.85.24.0/22 +103.85.44.0/22 +103.85.48.0/22 +103.85.84.0/22 +103.85.136.0/22 +103.85.144.0/22 +103.85.164.0/22 +103.85.168.0/22 +103.85.172.0/22 +103.85.176.0/22 +103.85.186.0/23 +103.85.224.0/22 +103.86.28.0/22 +103.86.32.0/22 +103.86.60.0/22 +103.86.84.0/22 +103.86.204.0/22 +103.86.208.0/22 +103.86.212.0/22 +103.86.216.0/22 +103.86.220.0/22 +103.86.224.0/22 +103.86.228.0/22 +103.86.232.0/22 +103.86.236.0/22 +103.86.240.0/22 +103.86.244.0/22 +103.86.248.0/22 +103.86.252.0/22 +103.87.0.0/22 +103.87.4.0/22 +103.87.20.0/22 +103.87.32.0/22 +103.87.96.0/22 +103.87.132.0/22 +103.87.180.0/22 +103.87.224.0/22 +103.88.4.0/22 +103.88.8.0/22 +103.88.12.0/22 +103.88.16.0/22 +103.88.20.0/22 +103.88.32.0/22 +103.88.36.0/22 +103.88.60.0/22 +103.88.64.0/22 +103.88.72.0/22 +103.88.96.0/22 +103.88.164.0/22 +103.88.212.0/22 +103.89.28.0/22 +103.89.96.0/22 +103.89.100.0/22 +103.89.104.0/22 +103.89.108.0/22 +103.89.112.0/22 +103.89.116.0/22 +103.89.148.0/22 +103.89.172.0/22 +103.89.184.0/22 +103.89.188.0/22 +103.89.192.0/22 +103.89.196.0/22 +103.89.200.0/22 +103.89.204.0/22 +103.89.208.0/22 +103.89.212.0/22 +103.89.216.0/22 +103.89.220.0/22 +103.89.224.0/22 +103.89.228.0/22 +103.90.51.0/24 +103.90.52.0/22 +103.90.56.0/23 +103.90.92.0/22 +103.90.100.0/22 +103.90.104.0/22 +103.90.108.0/22 +103.90.112.0/22 +103.90.116.0/22 +103.90.120.0/22 +103.90.124.0/22 +103.90.128.0/22 +103.90.132.0/22 +103.90.152.0/22 +103.90.168.0/22 +103.90.176.0/22 +103.90.188.0/22 +103.90.192.0/22 +103.91.36.0/22 +103.91.40.0/22 +103.91.108.0/22 +103.91.112.0/23 +103.91.138.0/23 +103.91.152.0/22 +103.91.176.0/22 +103.91.200.0/22 +103.91.208.0/22 +103.91.212.0/22 +103.91.236.0/22 +103.91.252.0/22 +103.92.0.0/22 +103.92.4.0/22 +103.92.8.0/22 +103.92.12.0/22 +103.92.48.0/22 +103.92.52.0/22 +103.92.56.0/22 +103.92.60.0/22 +103.92.64.0/22 +103.92.68.0/22 +103.92.72.0/22 +103.92.76.0/22 +103.92.80.0/22 +103.92.86.0/24 +103.92.88.0/22 +103.92.108.0/22 +103.92.124.0/22 +103.92.132.0/22 +103.92.156.0/22 +103.92.164.0/22 +103.92.168.0/22 +103.92.172.0/22 +103.92.176.0/22 +103.92.180.0/22 +103.92.184.0/22 +103.92.188.0/22 +103.92.192.0/22 +103.92.236.0/22 +103.92.240.0/22 +103.92.244.0/22 +103.92.248.0/22 +103.92.252.0/22 +103.93.0.0/22 +103.93.4.0/22 +103.93.28.0/22 +103.93.84.0/22 +103.93.142.0/23 +103.93.152.0/22 +103.93.180.0/22 +103.93.204.0/22 +103.94.12.0/22 +103.94.20.0/22 +103.94.28.0/22 +103.94.32.0/22 +103.94.36.0/22 +103.94.40.0/22 +103.94.44.0/22 +103.94.72.0/22 +103.94.88.0/22 +103.94.116.0/22 +103.94.160.0/22 +103.94.200.0/22 +103.95.52.0/22 +103.95.68.0/22 +103.95.88.0/22 +103.95.92.0/22 +103.95.128.0/22 +103.95.136.0/22 +103.95.140.0/22 +103.95.144.0/22 +103.95.152.0/22 +103.95.216.0/22 +103.95.220.0/22 +103.95.224.0/22 +103.95.236.0/22 +103.95.240.0/22 +103.95.244.0/22 +103.95.248.0/22 +103.95.252.0/22 +103.96.8.0/22 +103.96.124.0/22 +103.96.136.0/22 +103.96.140.0/24 +103.96.152.0/22 +103.96.156.0/22 +103.96.160.0/22 +103.96.164.0/22 +103.96.168.0/22 +103.96.172.0/22 +103.96.176.0/22 +103.96.180.0/22 +103.96.184.0/22 +103.96.188.0/22 +103.96.192.0/22 +103.96.196.0/22 +103.96.200.0/22 +103.96.204.0/22 +103.96.208.0/22 +103.96.212.0/22 +103.96.216.0/22 +103.96.224.0/23 +103.97.8.0/22 +103.97.12.0/22 +103.97.16.0/20 +103.97.32.0/22 +103.97.36.0/22 +103.97.40.0/22 +103.97.56.0/22 +103.97.60.0/22 +103.97.64.0/22 +103.97.68.0/22 +103.97.72.0/22 +103.97.112.0/22 +103.97.116.0/22 +103.97.128.0/22 +103.97.144.0/22 +103.97.148.0/22 +103.97.188.0/22 +103.97.192.0/22 +103.97.228.0/23 +103.98.0.0/23 +103.98.28.0/23 +103.98.40.0/22 +103.98.44.0/22 +103.98.48.0/22 +103.98.56.0/22 +103.98.80.0/22 +103.98.88.0/22 +103.98.92.0/22 +103.98.96.0/22 +103.98.100.0/22 +103.98.124.0/22 +103.98.136.0/22 +103.98.140.0/22 +103.98.144.0/22 +103.98.164.0/22 +103.98.168.0/22 +103.98.180.0/22 +103.98.196.0/22 +103.98.216.0/22 +103.98.220.0/22 +103.98.224.0/22 +103.98.228.0/22 +103.98.232.0/22 +103.98.240.0/22 +103.98.244.0/22 +103.98.248.0/22 +103.98.252.0/22 +103.99.40.0/23 +103.99.52.0/22 +103.99.56.0/22 +103.99.60.0/22 +103.99.76.0/22 +103.99.104.0/22 +103.99.116.0/22 +103.99.120.0/22 +103.99.152.0/22 +103.99.220.0/22 +103.99.232.0/22 +103.99.236.0/22 +103.100.0.0/22 +103.100.32.0/22 +103.100.40.0/22 +103.100.48.0/22 +103.100.52.0/22 +103.100.56.0/22 +103.100.60.0/22 +103.100.64.0/22 +103.100.68.0/22 +103.100.88.0/22 +103.100.116.0/22 +103.100.144.0/22 +103.100.236.0/22 +103.100.240.0/22 +103.100.248.0/22 +103.100.252.0/22 +103.101.8.0/22 +103.101.12.0/22 +103.101.60.0/22 +103.101.120.0/22 +103.101.124.0/22 +103.101.144.0/22 +103.101.148.0/22 +103.101.180.0/22 +103.101.184.0/22 +103.102.76.0/22 +103.102.80.0/22 +103.102.168.0/22 +103.102.172.0/22 +103.102.180.0/22 +103.102.184.0/22 +103.102.188.0/22 +103.102.192.0/22 +103.102.196.0/22 +103.102.200.0/22 +103.102.208.0/22 +103.102.212.0/22 +103.103.12.0/22 +103.103.16.0/22 +103.103.36.0/22 +103.103.72.0/22 +103.103.188.0/22 +103.103.200.0/22 +103.103.204.0/22 +103.103.220.0/22 +103.103.224.0/21 +103.103.232.0/22 +103.103.248.0/21 +103.104.0.0/21 +103.104.36.0/22 +103.104.40.0/22 +103.104.64.0/22 +103.104.104.0/22 +103.104.152.0/22 +103.104.188.0/22 +103.104.198.0/23 +103.104.252.0/22 +103.105.0.0/22 +103.105.4.0/22 +103.105.12.0/22 +103.105.16.0/22 +103.105.23.0/24 +103.105.60.0/22 +103.105.116.0/22 +103.105.132.0/22 +103.105.180.0/22 +103.105.184.0/22 +103.105.200.0/22 +103.105.204.0/22 +103.105.220.0/22 +103.106.36.0/22 +103.106.40.0/22 +103.106.44.0/22 +103.106.60.0/22 +103.106.68.0/22 +103.106.96.0/22 +103.106.120.0/22 +103.106.128.0/22 +103.106.132.0/22 +103.106.160.0/22 +103.106.196.0/22 +103.106.202.0/23 +103.106.212.0/22 +103.106.252.0/22 +103.107.0.0/22 +103.107.28.0/22 +103.107.32.0/22 +103.107.44.0/22 +103.107.72.0/22 +103.107.108.0/22 +103.107.164.0/22 +103.107.168.0/22 +103.107.188.0/22 +103.107.192.0/22 +103.107.208.0/22 +103.107.212.0/22 +103.107.216.0/22 +103.107.220.0/22 +103.108.52.0/22 +103.108.160.0/22 +103.108.164.0/22 +103.108.192.0/22 +103.108.196.0/22 +103.108.208.0/22 +103.108.212.0/22 +103.108.224.0/22 +103.108.244.0/22 +103.109.20.0/22 +103.109.48.0/22 +103.109.88.0/22 +103.109.106.0/23 +103.109.248.0/22 +103.110.92.0/22 +103.110.116.0/22 +103.110.132.0/22 +103.110.136.0/22 +103.110.152.0/22 +103.110.156.0/22 +103.110.188.0/22 +103.110.204.0/22 +103.111.64.0/22 +103.111.172.0/22 +103.111.252.0/22 +103.112.68.0/22 +103.112.72.0/22 +103.112.88.0/22 +103.112.92.0/22 +103.112.108.0/22 +103.112.112.0/22 +103.112.116.0/22 +103.112.140.0/22 +103.112.172.0/22 +103.112.184.0/22 +103.113.4.0/22 +103.113.92.0/22 +103.113.144.0/22 +103.113.220.0/22 +103.113.232.0/22 +103.113.236.0/22 +103.114.4.0/22 +103.114.28.0/22 +103.114.68.0/22 +103.114.72.0/22 +103.114.100.0/22 +103.114.148.0/22 +103.114.156.0/22 +103.114.176.0/22 +103.114.212.0/22 +103.114.236.0/22 +103.114.240.0/22 +103.115.16.0/22 +103.115.40.0/22 +103.115.44.0/22 +103.115.48.0/22 +103.115.52.0/22 +103.115.56.0/22 +103.115.60.0/22 +103.115.64.0/22 +103.115.68.0/22 +103.115.92.0/22 +103.115.120.0/22 +103.115.148.0/22 +103.115.248.0/22 +103.116.40.0/22 +103.116.64.0/22 +103.116.76.0/22 +103.116.92.0/22 +103.116.120.0/22 +103.116.128.0/22 +103.116.138.0/23 +103.116.148.0/22 +103.116.184.0/22 +103.116.206.0/23 +103.116.220.0/22 +103.116.224.0/22 +103.116.228.0/22 +103.117.16.0/22 +103.117.72.0/22 +103.117.88.0/22 +103.117.188.0/22 +103.117.220.0/22 +103.118.52.0/22 +103.118.56.0/22 +103.118.60.0/22 +103.118.64.0/22 +103.118.68.0/22 +103.118.72.0/22 +103.118.88.0/22 +103.118.173.0/24 +103.118.192.0/22 +103.118.196.0/22 +103.118.200.0/22 +103.118.204.0/22 +103.118.208.0/22 +103.118.212.0/22 +103.118.216.0/22 +103.118.220.0/22 +103.118.240.0/22 +103.118.244.0/22 +103.118.248.0/22 +103.118.252.0/22 +103.119.0.0/22 +103.119.12.0/22 +103.119.16.0/22 +103.119.28.0/22 +103.119.104.0/22 +103.119.115.0/24 +103.119.156.0/22 +103.119.180.0/22 +103.119.200.0/22 +103.119.224.0/22 +103.120.52.0/22 +103.120.72.0/22 +103.120.88.0/22 +103.120.96.0/22 +103.120.100.0/22 +103.120.140.0/22 +103.120.196.0/22 +103.120.224.0/22 +103.121.52.0/22 +103.121.160.0/22 +103.121.164.0/22 +103.121.250.0/24 +103.121.252.0/22 +103.122.48.0/22 +103.122.176.0/22 +103.122.192.0/22 +103.122.240.0/22 +103.123.4.0/22 +103.123.56.0/22 +103.123.88.0/22 +103.123.92.0/22 +103.123.116.0/22 +103.123.176.0/22 +103.123.200.0/22 +103.123.204.0/22 +103.123.208.0/22 +103.123.212.0/22 +103.124.24.0/22 +103.124.48.0/22 +103.124.64.0/22 +103.124.212.0/22 +103.124.216.0/22 +103.125.20.0/22 +103.125.44.0/22 +103.125.132.0/22 +103.125.164.0/22 +103.125.196.0/22 +103.125.236.0/22 +103.125.248.0/22 +103.126.0.0/22 +103.126.16.0/22 +103.126.44.0/22 +103.126.100.0/22 +103.126.124.0/22 +103.126.128.0/22 +103.126.132.0/22 +103.126.208.0/22 +103.130.132.0/22 +103.130.160.0/22 +103.130.228.0/22 +103.131.20.0/22 +103.131.36.0/22 +103.131.138.0/23 +103.131.152.0/22 +103.131.168.0/22 +103.131.176.0/22 +103.131.224.0/22 +103.131.228.0/22 +103.131.240.0/22 +103.132.22.0/23 +103.132.48.0/22 +103.132.60.0/22 +103.132.64.0/20 +103.132.80.0/22 +103.132.104.0/21 +103.132.112.0/21 +103.132.120.0/22 +103.132.160.0/22 +103.132.164.0/22 +103.132.188.0/22 +103.132.208.0/22 +103.132.212.0/22 +103.132.234.0/23 +103.133.12.0/22 +103.133.40.0/22 +103.133.128.0/22 +103.133.176.0/22 +103.133.232.0/22 +103.134.196.0/22 +103.134.232.0/23 +103.135.80.0/22 +103.135.124.0/22 +103.135.148.0/22 +103.135.156.0/22 +103.135.160.0/22 +103.135.164.0/22 +103.135.176.0/22 +103.135.184.0/22 +103.135.192.0/22 +103.135.196.0/22 +103.135.236.0/22 +103.136.128.0/22 +103.136.232.0/22 +103.137.58.0/23 +103.137.60.0/24 +103.137.76.0/22 +103.137.136.0/23 +103.137.180.0/22 +103.137.236.0/22 +103.138.2.0/23 +103.138.12.0/23 +103.138.80.0/22 +103.138.134.0/23 +103.138.156.0/23 +103.138.208.0/23 +103.138.220.0/23 +103.138.248.0/23 +103.139.0.0/23 +103.139.2.0/23 +103.139.22.0/23 +103.139.92.0/23 +103.139.134.0/23 +103.139.136.0/23 +103.139.172.0/23 +103.139.204.0/23 +103.139.212.0/23 +103.140.8.0/23 +103.140.14.0/23 +103.140.126.0/23 +103.140.140.0/23 +103.140.144.0/23 +103.140.152.0/23 +103.140.192.0/23 +103.140.228.0/23 +103.141.10.0/23 +103.141.58.0/23 +103.141.128.0/23 +103.141.186.0/23 +103.141.242.0/23 +103.142.28.0/23 +103.142.58.0/23 +103.142.82.0/23 +103.142.96.0/23 +103.142.102.0/23 +103.142.122.0/23 +103.142.128.0/23 +103.142.140.0/23 +103.142.154.0/23 +103.142.156.0/23 +103.142.172.0/23 +103.142.180.0/23 +103.142.186.0/23 +103.142.220.0/23 +103.142.234.0/23 +103.142.238.0/23 +103.142.248.0/23 +103.143.16.0/23 +103.143.18.0/23 +103.143.74.0/23 +103.143.120.0/23 +103.143.124.0/23 +103.143.132.0/23 +103.143.134.0/23 +103.143.174.0/23 +103.143.228.0/23 +103.144.40.0/23 +103.144.52.0/23 +103.144.66.0/23 +103.144.70.0/23 +103.144.72.0/23 +103.144.136.0/23 +103.144.158.0/23 +103.144.240.0/23 +103.145.38.0/23 +103.145.42.0/23 +103.145.60.0/23 +103.145.92.0/23 +103.145.94.0/23 +103.145.98.0/23 +103.145.188.0/23 +103.145.190.0/23 +103.146.72.0/23 +103.146.90.0/23 +103.146.124.0/23 +103.146.126.0/23 +103.146.138.0/23 +103.146.236.0/23 +103.146.252.0/23 +103.147.12.0/23 +103.147.124.0/23 +103.147.198.0/23 +103.147.206.0/23 +103.148.174.0/23 +103.149.6.0/23 +103.149.17.0/24 +103.149.44.0/23 +103.149.132.0/23 +103.149.144.0/23 +103.149.181.0/24 +103.149.210.0/23 +103.149.214.0/23 +103.149.220.0/23 +103.149.242.0/23 +103.149.244.0/23 +103.149.246.0/23 +103.150.10.0/23 +103.150.24.0/23 +103.150.66.0/23 +103.150.72.0/23 +103.150.122.0/23 +103.150.126.0/23 +103.150.128.0/23 +103.150.130.0/23 +103.150.146.0/23 +103.150.164.0/23 +103.150.172.0/23 +103.150.180.0/23 +103.150.200.0/23 +103.150.210.0/23 +103.150.214.0/23 +103.150.216.0/23 +103.150.244.0/23 +103.151.4.0/23 +103.151.44.0/23 +103.151.142.0/23 +103.151.148.0/23 +103.151.150.0/23 +103.151.158.0/23 +103.151.216.0/23 +103.151.228.0/23 +103.152.28.0/23 +103.152.30.0/23 +103.152.56.0/23 +103.152.76.0/23 +103.152.112.0/23 +103.152.120.0/23 +103.152.122.0/23 +103.152.152.0/23 +103.152.168.0/23 +103.152.170.0/23 +103.152.186.0/23 +103.152.190.0/23 +103.152.192.0/23 +103.152.200.0/23 +103.152.208.0/23 +103.152.224.0/23 +103.152.246.0/23 +103.152.250.0/23 +103.153.4.0/23 +103.153.36.0/23 +103.153.100.0/23 +103.153.114.0/23 +103.153.122.0/23 +103.153.132.0/23 +103.153.138.0/23 +103.153.146.0/23 +103.153.160.0/23 +103.154.18.0/23 +103.154.30.0/23 +103.154.32.0/23 +103.154.40.0/23 +103.154.66.0/23 +103.154.162.0/23 +103.154.164.0/23 +103.154.168.0/23 +103.155.14.0/23 +103.155.34.0/23 +103.155.48.0/23 +103.155.76.0/23 +103.155.100.0/23 +103.155.110.0/23 +103.155.214.0/23 +103.155.248.0/23 +103.156.28.0/23 +103.156.68.0/23 +103.156.78.0/23 +103.156.104.0/23 +103.156.158.0/23 +103.156.174.0/23 +103.156.186.0/23 +103.156.228.0/23 +103.157.30.0/23 +103.157.174.0/23 +103.157.212.0/23 +103.157.234.0/23 +103.157.254.0/23 +103.158.0.0/23 +103.158.8.0/23 +103.158.16.0/23 +103.158.74.0/23 +103.158.190.0/23 +103.158.200.0/23 +103.158.224.0/23 +103.159.122.0/23 +103.159.124.0/23 +103.159.134.0/23 +103.159.142.0/23 +103.160.32.0/23 +103.160.34.0/23 +103.160.112.0/23 +103.160.114.0/23 +103.160.244.0/23 +103.160.254.0/23 +103.161.14.0/23 +103.161.102.0/23 +103.161.208.0/23 +103.161.220.0/23 +103.161.254.0/23 +103.162.10.0/23 +103.162.32.0/23 +103.162.116.0/23 +103.163.28.0/23 +103.163.32.0/23 +103.163.46.0/23 +103.163.74.0/23 +103.163.180.0/23 +103.164.4.0/23 +103.164.32.0/23 +103.164.40.0/23 +103.164.42.0/23 +103.164.64.0/23 +103.164.76.0/23 +103.164.178.0/23 +103.165.44.0/23 +103.165.52.0/23 +103.165.82.0/23 +103.165.110.0/23 +103.166.20.0/23 +103.166.50.0/23 +103.166.52.0/23 +103.166.54.0/23 +103.166.84.0/23 +103.166.138.0/23 +103.167.0.0/23 +103.167.36.0/23 +103.167.100.0/23 +103.168.98.0/23 +103.168.170.0/23 +103.169.50.0/23 +103.169.62.0/23 +103.169.108.0/23 +103.169.162.0/23 +103.169.202.0/23 +103.169.216.0/23 +103.170.4.0/23 +103.170.72.0/23 +103.170.134.0/23 +103.170.210.0/23 +103.170.212.0/23 +103.171.32.0/23 +103.171.166.0/23 +103.171.214.0/23 +103.172.32.0/23 +103.172.160.0/23 +103.172.191.0/24 +103.173.102.0/23 +103.173.182.0/23 +103.173.184.0/23 +103.174.94.0/23 +103.175.14.0/23 +103.175.98.0/23 +103.175.114.0/23 +103.175.118.0/23 +103.176.52.0/23 +103.176.222.0/23 +103.176.244.0/23 +103.177.28.0/23 +103.177.44.0/23 +103.177.70.0/23 +103.177.136.0/23 +103.177.162.0/23 +103.178.56.0/23 +103.178.240.0/23 +103.179.76.0/23 +103.179.78.0/23 +103.180.108.0/23 +103.180.226.0/23 +103.181.164.0/23 +103.181.234.0/23 +103.183.26.0/23 +103.183.66.0/23 +103.183.122.0/23 +103.183.124.0/23 +103.184.46.0/23 +103.184.60.0/23 +103.185.78.0/23 +103.185.80.0/23 +103.185.228.0/23 +103.186.4.0/23 +103.186.108.0/23 +103.186.112.0/23 +103.186.136.0/23 +103.186.158.0/23 +103.186.162.0/23 +103.186.228.0/23 +103.189.92.0/23 +103.189.140.0/23 +103.189.152.0/23 +103.189.154.0/23 +103.190.20.0/23 +103.190.71.0/24 +103.190.104.0/23 +103.190.116.0/23 +103.190.118.0/23 +103.190.122.0/23 +103.191.102.0/23 +103.191.242.0/23 +103.192.0.0/22 +103.192.4.0/22 +103.192.8.0/22 +103.192.12.0/22 +103.192.16.0/22 +103.192.20.0/22 +103.192.24.0/22 +103.192.28.0/22 +103.192.48.0/22 +103.192.52.0/22 +103.192.56.0/22 +103.192.84.0/22 +103.192.88.0/22 +103.192.92.0/22 +103.192.96.0/22 +103.192.100.0/22 +103.192.104.0/22 +103.192.108.0/22 +103.192.112.0/22 +103.192.128.0/22 +103.192.132.0/22 +103.192.136.0/22 +103.192.140.0/22 +103.192.144.0/22 +103.192.164.0/22 +103.192.188.0/22 +103.192.208.0/22 +103.192.212.0/22 +103.192.216.0/22 +103.192.252.0/22 +103.193.40.0/22 +103.193.44.0/22 +103.193.120.0/22 +103.193.140.0/22 +103.193.160.0/22 +103.193.188.0/22 +103.193.192.0/22 +103.193.212.0/22 +103.193.216.0/22 +103.193.220.0/22 +103.193.224.0/22 +103.193.228.0/22 +103.193.232.0/22 +103.193.236.0/22 +103.194.16.0/22 +103.195.104.0/22 +103.195.112.0/22 +103.195.148.0/22 +103.195.152.0/22 +103.195.160.0/22 +103.196.64.0/22 +103.196.72.0/22 +103.196.88.0/22 +103.196.92.0/22 +103.196.96.0/22 +103.196.168.0/22 +103.196.204.0/22 +103.197.0.0/22 +103.197.180.0/22 +103.197.228.0/22 +103.198.20.0/22 +103.198.60.0/22 +103.198.64.0/22 +103.198.72.0/22 +103.198.124.0/22 +103.198.156.0/22 +103.198.180.0/22 +103.198.196.0/22 +103.198.216.0/22 +103.198.220.0/22 +103.198.224.0/22 +103.198.228.0/22 +103.198.232.0/22 +103.198.236.0/22 +103.198.240.0/22 +103.198.244.0/22 +103.199.164.0/22 +103.199.196.0/22 +103.199.228.0/22 +103.199.248.0/22 +103.199.252.0/22 +103.200.52.0/22 +103.200.64.0/22 +103.200.68.0/22 +103.200.136.0/22 +103.200.140.0/22 +103.200.144.0/22 +103.200.148.0/22 +103.200.152.0/22 +103.200.156.0/22 +103.200.160.0/22 +103.200.164.0/22 +103.200.168.0/22 +103.200.172.0/22 +103.200.176.0/22 +103.200.180.0/22 +103.200.184.0/22 +103.200.188.0/22 +103.200.192.0/22 +103.200.220.0/22 +103.200.224.0/22 +103.200.228.0/22 +103.200.232.0/22 +103.200.236.0/22 +103.200.240.0/22 +103.200.244.0/22 +103.200.248.0/22 +103.200.252.0/22 +103.201.0.0/22 +103.201.4.0/22 +103.201.8.0/22 +103.201.12.0/22 +103.201.16.0/22 +103.201.20.0/22 +103.201.28.0/22 +103.201.32.0/22 +103.201.36.0/22 +103.201.40.0/22 +103.201.44.0/22 +103.201.48.0/22 +103.201.52.0/22 +103.201.56.0/22 +103.201.60.0/22 +103.201.64.0/22 +103.201.76.0/22 +103.201.80.0/22 +103.201.84.0/22 +103.201.88.0/22 +103.201.92.0/22 +103.201.96.0/22 +103.201.100.0/22 +103.201.104.0/22 +103.201.108.0/22 +103.201.112.0/22 +103.201.116.0/22 +103.201.120.0/22 +103.201.152.0/22 +103.201.156.0/22 +103.201.160.0/22 +103.201.164.0/22 +103.201.168.0/22 +103.201.172.0/22 +103.201.176.0/22 +103.201.180.0/22 +103.201.184.0/22 +103.201.188.0/22 +103.201.192.0/22 +103.201.196.0/22 +103.201.200.0/22 +103.201.204.0/22 +103.201.208.0/22 +103.201.212.0/22 +103.201.216.0/22 +103.201.220.0/22 +103.201.224.0/22 +103.201.228.0/22 +103.201.232.0/22 +103.201.236.0/22 +103.201.240.0/22 +103.201.244.0/22 +103.201.248.0/22 +103.201.252.0/22 +103.202.0.0/22 +103.202.4.0/22 +103.202.8.0/22 +103.202.12.0/22 +103.202.16.0/22 +103.202.20.0/22 +103.202.24.0/22 +103.202.28.0/22 +103.202.32.0/22 +103.202.36.0/22 +103.202.40.0/22 +103.202.44.0/22 +103.202.56.0/22 +103.202.60.0/22 +103.202.64.0/22 +103.202.68.0/22 +103.202.72.0/22 +103.202.76.0/22 +103.202.80.0/22 +103.202.84.0/22 +103.202.88.0/22 +103.202.92.0/22 +103.202.96.0/22 +103.202.100.0/22 +103.202.104.0/22 +103.202.108.0/22 +103.202.112.0/22 +103.202.116.0/22 +103.202.120.0/22 +103.202.124.0/22 +103.202.128.0/22 +103.202.132.0/22 +103.202.136.0/22 +103.202.140.0/22 +103.202.144.0/22 +103.202.152.0/22 +103.202.156.0/22 +103.202.160.0/22 +103.202.164.0/22 +103.202.168.0/22 +103.202.172.0/22 +103.202.176.0/22 +103.202.180.0/22 +103.202.184.0/22 +103.202.188.0/22 +103.202.192.0/22 +103.202.196.0/22 +103.202.200.0/22 +103.202.204.0/22 +103.202.212.0/22 +103.202.228.0/22 +103.202.236.0/22 +103.202.240.0/22 +103.202.244.0/22 +103.202.248.0/22 +103.202.252.0/22 +103.203.0.0/22 +103.203.4.0/22 +103.203.8.0/22 +103.203.12.0/22 +103.203.16.0/22 +103.203.20.0/22 +103.203.24.0/22 +103.203.28.0/22 +103.203.32.0/22 +103.203.56.0/22 +103.203.96.0/22 +103.203.100.0/22 +103.203.104.0/22 +103.203.108.0/22 +103.203.112.0/22 +103.203.116.0/22 +103.203.120.0/22 +103.203.124.0/22 +103.203.128.0/22 +103.203.140.0/22 +103.203.164.0/22 +103.203.168.0/22 +103.203.192.0/22 +103.203.200.0/22 +103.203.212.0/22 +103.203.216.0/22 +103.204.24.0/22 +103.204.72.0/22 +103.204.88.0/22 +103.204.112.0/22 +103.204.136.0/22 +103.204.140.0/22 +103.204.144.0/22 +103.204.148.0/22 +103.204.152.0/22 +103.204.196.0/22 +103.204.216.0/23 +103.204.232.0/22 +103.204.236.0/22 +103.205.4.0/22 +103.205.8.0/22 +103.205.40.0/22 +103.205.44.0/22 +103.205.52.0/22 +103.205.108.0/22 +103.205.116.0/22 +103.205.120.0/22 +103.205.136.0/22 +103.205.162.0/24 +103.205.188.0/22 +103.205.192.0/22 +103.205.196.0/22 +103.205.200.0/22 +103.205.236.0/22 +103.205.248.0/22 +103.205.252.0/22 +103.206.0.0/22 +103.206.44.0/22 +103.206.148.0/22 +103.207.48.0/22 +103.207.104.0/22 +103.207.184.0/22 +103.207.188.0/22 +103.207.192.0/22 +103.207.196.0/22 +103.207.200.0/22 +103.207.204.0/22 +103.207.208.0/22 +103.207.212.0/22 +103.207.220.0/22 +103.207.228.0/22 +103.207.232.0/22 +103.208.12.0/22 +103.208.16.0/22 +103.208.28.0/22 +103.208.40.0/22 +103.208.44.0/22 +103.208.48.0/22 +103.209.112.0/22 +103.209.136.0/22 +103.209.200.0/22 +103.209.208.0/22 +103.209.216.0/22 +103.210.96.0/22 +103.210.156.0/22 +103.210.160.0/22 +103.210.164.0/22 +103.210.168.0/22 +103.210.172.0/22 +103.210.176.0/22 +103.210.180.0/22 +103.210.184.0/22 +103.210.188.0/22 +103.210.216.0/22 +103.211.44.0/22 +103.211.96.0/22 +103.211.156.0/22 +103.211.164.0/22 +103.211.194.0/23 +103.211.220.0/22 +103.211.224.0/22 +103.211.248.0/22 +103.212.0.0/22 +103.212.4.0/22 +103.212.8.0/22 +103.212.12.0/22 +103.212.44.0/22 +103.212.48.0/22 +103.212.84.0/22 +103.212.100.0/22 +103.212.108.0/22 +103.212.148.0/22 +103.212.164.0/22 +103.212.196.0/22 +103.212.200.0/22 +103.212.228.0/22 +103.212.252.0/22 +103.213.40.0/22 +103.213.44.0/22 +103.213.48.0/22 +103.213.52.0/22 +103.213.56.0/22 +103.213.60.0/22 +103.213.64.0/19 +103.213.96.0/22 +103.213.132.0/22 +103.213.136.0/22 +103.213.140.0/22 +103.213.144.0/22 +103.213.148.0/22 +103.213.152.0/22 +103.213.156.0/22 +103.213.160.0/19 +103.213.196.0/23 +103.213.198.0/23 +103.213.226.0/23 +103.213.232.0/23 +103.214.48.0/22 +103.214.84.0/22 +103.214.212.0/22 +103.214.240.0/22 +103.214.244.0/22 +103.215.28.0/22 +103.215.32.0/22 +103.215.36.0/22 +103.215.44.0/22 +103.215.48.0/22 +103.215.100.0/22 +103.215.108.0/22 +103.215.116.0/22 +103.215.120.0/22 +103.215.140.0/22 +103.216.4.0/22 +103.216.8.0/22 +103.216.12.0/22 +103.216.16.0/22 +103.216.20.0/22 +103.216.24.0/22 +103.216.28.0/22 +103.216.32.0/22 +103.216.36.0/22 +103.216.40.0/22 +103.216.44.0/22 +103.216.64.0/22 +103.216.108.0/22 +103.216.136.0/22 +103.216.152.0/22 +103.216.156.0/23 +103.216.224.0/22 +103.216.228.0/22 +103.216.240.0/22 +103.216.244.0/22 +103.216.248.0/22 +103.216.252.0/22 +103.217.0.0/22 +103.217.4.0/22 +103.217.8.0/22 +103.217.12.0/22 +103.217.16.0/22 +103.217.20.0/22 +103.217.24.0/22 +103.217.28.0/22 +103.217.32.0/22 +103.217.36.0/22 +103.217.40.0/22 +103.217.44.0/22 +103.217.48.0/22 +103.217.52.0/22 +103.217.56.0/22 +103.217.60.0/22 +103.217.168.0/22 +103.217.180.0/22 +103.217.184.0/22 +103.217.188.0/22 +103.217.192.0/22 +103.217.196.0/22 +103.217.200.0/22 +103.217.204.0/22 +103.218.8.0/22 +103.218.12.0/22 +103.218.16.0/22 +103.218.20.0/22 +103.218.28.0/22 +103.218.32.0/22 +103.218.36.0/22 +103.218.40.0/22 +103.218.44.0/22 +103.218.48.0/22 +103.218.52.0/22 +103.218.56.0/22 +103.218.60.0/22 +103.218.64.0/22 +103.218.68.0/22 +103.218.72.0/22 +103.218.76.0/22 +103.218.80.0/22 +103.218.84.0/22 +103.218.88.0/22 +103.218.92.0/22 +103.218.178.0/23 +103.218.192.0/22 +103.218.196.0/22 +103.218.200.0/22 +103.218.204.0/22 +103.218.208.0/22 +103.218.212.0/22 +103.218.216.0/22 +103.219.24.0/22 +103.219.28.0/22 +103.219.32.0/22 +103.219.36.0/22 +103.219.64.0/22 +103.219.84.0/22 +103.219.88.0/22 +103.219.92.0/22 +103.219.96.0/22 +103.219.100.0/22 +103.219.176.0/22 +103.219.184.0/22 +103.220.48.0/22 +103.220.52.0/22 +103.220.56.0/22 +103.220.60.0/22 +103.220.64.0/22 +103.220.92.0/22 +103.220.96.0/22 +103.220.100.0/22 +103.220.104.0/22 +103.220.108.0/22 +103.220.116.0/22 +103.220.120.0/22 +103.220.124.0/22 +103.220.128.0/22 +103.220.132.0/22 +103.220.136.0/22 +103.220.140.0/22 +103.220.144.0/22 +103.220.148.0/22 +103.220.152.0/22 +103.220.160.0/22 +103.220.164.0/22 +103.220.168.0/22 +103.220.172.0/22 +103.220.176.0/22 +103.220.180.0/22 +103.220.184.0/22 +103.220.188.0/22 +103.220.192.0/22 +103.220.196.0/22 +103.220.200.0/22 +103.220.240.0/22 +103.220.244.0/22 +103.220.248.0/22 +103.220.252.0/22 +103.221.0.0/22 +103.221.4.0/22 +103.221.8.0/22 +103.221.12.0/22 +103.221.16.0/22 +103.221.20.0/22 +103.221.24.0/22 +103.221.28.0/22 +103.221.32.0/22 +103.221.36.0/22 +103.221.40.0/22 +103.221.44.0/22 +103.221.48.0/22 +103.221.88.0/22 +103.221.92.0/22 +103.221.96.0/22 +103.221.100.0/22 +103.221.104.0/22 +103.221.108.0/22 +103.221.112.0/22 +103.221.116.0/22 +103.221.120.0/22 +103.221.124.0/22 +103.221.128.0/22 +103.221.132.0/22 +103.221.136.0/22 +103.221.140.0/22 +103.221.144.0/22 +103.221.148.0/22 +103.221.152.0/22 +103.221.156.0/22 +103.221.160.0/22 +103.221.164.0/22 +103.221.168.0/22 +103.221.172.0/22 +103.221.176.0/22 +103.221.180.0/22 +103.221.184.0/22 +103.221.188.0/22 +103.221.192.0/22 +103.221.196.0/22 +103.221.200.0/22 +103.221.204.0/22 +103.222.0.0/22 +103.222.4.0/22 +103.222.8.0/22 +103.222.12.0/22 +103.222.16.0/22 +103.222.24.0/22 +103.222.28.0/22 +103.222.32.0/22 +103.222.36.0/22 +103.222.40.0/22 +103.222.44.0/22 +103.222.48.0/22 +103.222.52.0/22 +103.222.56.0/22 +103.222.60.0/22 +103.222.64.0/22 +103.222.68.0/22 +103.222.72.0/22 +103.222.76.0/22 +103.222.80.0/22 +103.222.84.0/22 +103.222.88.0/22 +103.222.92.0/22 +103.222.96.0/22 +103.222.100.0/22 +103.222.104.0/22 +103.222.108.0/22 +103.222.112.0/22 +103.222.116.0/22 +103.222.120.0/22 +103.222.124.0/22 +103.222.128.0/22 +103.222.132.0/22 +103.222.136.0/22 +103.222.140.0/22 +103.222.144.0/22 +103.222.148.0/22 +103.222.152.0/22 +103.222.156.0/22 +103.222.160.0/22 +103.222.164.0/22 +103.222.168.0/22 +103.222.172.0/22 +103.222.176.0/22 +103.222.180.0/22 +103.222.184.0/22 +103.222.188.0/22 +103.222.192.0/22 +103.222.196.0/22 +103.222.200.0/22 +103.222.204.0/22 +103.222.208.0/22 +103.222.212.0/22 +103.222.216.0/22 +103.222.220.0/22 +103.222.224.0/22 +103.222.228.0/22 +103.222.232.0/22 +103.222.240.0/22 +103.222.244.0/22 +103.223.16.0/22 +103.223.20.0/22 +103.223.24.0/22 +103.223.28.0/22 +103.223.32.0/22 +103.223.36.0/22 +103.223.40.0/22 +103.223.44.0/22 +103.223.48.0/22 +103.223.52.0/22 +103.223.56.0/22 +103.223.60.0/22 +103.223.64.0/22 +103.223.68.0/22 +103.223.72.0/22 +103.223.76.0/22 +103.223.80.0/22 +103.223.84.0/22 +103.223.88.0/22 +103.223.92.0/22 +103.223.96.0/22 +103.223.100.0/22 +103.223.104.0/22 +103.223.108.0/22 +103.223.112.0/22 +103.223.116.0/22 +103.223.120.0/22 +103.223.124.0/22 +103.223.128.0/22 +103.223.132.0/22 +103.223.140.0/22 +103.223.144.0/22 +103.223.148.0/22 +103.223.152.0/22 +103.223.156.0/22 +103.223.160.0/22 +103.223.164.0/22 +103.223.168.0/22 +103.223.172.0/22 +103.223.176.0/22 +103.223.180.0/22 +103.223.188.0/22 +103.223.192.0/22 +103.223.196.0/22 +103.223.200.0/22 +103.223.204.0/22 +103.223.208.0/22 +103.223.212.0/22 +103.223.216.0/22 +103.223.220.0/22 +103.223.224.0/22 +103.223.228.0/22 +103.223.232.0/22 +103.223.236.0/22 +103.223.240.0/22 +103.223.244.0/22 +103.223.248.0/22 +103.223.252.0/22 +103.224.0.0/22 +103.224.40.0/22 +103.224.44.0/22 +103.224.60.0/22 +103.224.80.0/22 +103.224.220.0/22 +103.224.224.0/22 +103.224.228.0/22 +103.224.232.0/22 +103.225.18.0/24 +103.225.84.0/22 +103.226.16.0/22 +103.226.40.0/22 +103.226.56.0/22 +103.226.60.0/22 +103.226.80.0/22 +103.226.116.0/23 +103.226.132.0/22 +103.226.156.0/22 +103.226.180.0/22 +103.226.196.0/22 +103.227.48.0/22 +103.227.72.0/22 +103.227.76.0/22 +103.227.80.0/22 +103.227.100.0/22 +103.227.120.0/22 +103.227.132.0/22 +103.227.136.0/22 +103.227.196.0/22 +103.227.204.0/22 +103.227.212.0/22 +103.227.228.0/22 +103.228.12.0/22 +103.228.88.0/22 +103.228.136.0/22 +103.228.160.0/22 +103.228.176.0/22 +103.228.204.0/22 +103.228.208.0/22 +103.228.228.0/22 +103.228.232.0/22 +103.229.20.0/22 +103.229.60.0/22 +103.229.136.0/22 +103.229.148.0/22 +103.229.172.0/22 +103.229.212.0/22 +103.229.216.0/22 +103.229.220.0/22 +103.229.228.0/22 +103.229.236.0/22 +103.229.240.0/22 +103.230.0.0/22 +103.230.28.0/22 +103.230.44.0/22 +103.230.96.0/22 +103.230.110.0/23 +103.230.196.0/22 +103.230.200.0/22 +103.230.204.0/22 +103.230.212.0/22 +103.230.236.0/22 +103.231.16.0/22 +103.231.20.0/22 +103.231.64.0/22 +103.231.68.0/22 +103.231.180.0/22 +103.231.184.0/22 +103.231.244.0/22 +103.232.4.0/22 +103.232.144.0/22 +103.232.166.0/23 +103.232.188.0/22 +103.232.212.0/22 +103.233.4.0/22 +103.233.44.0/22 +103.233.52.0/22 +103.233.104.0/22 +103.233.128.0/22 +103.233.136.0/22 +103.233.162.0/23 +103.233.178.0/23 +103.233.228.0/22 +103.234.0.0/22 +103.234.20.0/22 +103.234.56.0/22 +103.234.128.0/22 +103.234.172.0/22 +103.234.180.0/22 +103.234.244.0/22 +103.235.48.0/22 +103.235.56.0/22 +103.235.60.0/22 +103.235.80.0/22 +103.235.84.0/22 +103.235.100.0/22 +103.235.128.0/22 +103.235.132.0/22 +103.235.136.0/22 +103.235.140.0/22 +103.235.144.0/22 +103.235.148.0/22 +103.235.184.0/22 +103.235.192.0/22 +103.235.200.0/22 +103.235.220.0/22 +103.235.224.0/22 +103.235.228.0/22 +103.235.232.0/22 +103.235.236.0/22 +103.235.240.0/22 +103.235.244.0/22 +103.235.248.0/22 +103.235.252.0/22 +103.236.0.0/22 +103.236.4.0/22 +103.236.8.0/22 +103.236.12.0/22 +103.236.16.0/22 +103.236.20.0/22 +103.236.24.0/22 +103.236.28.0/22 +103.236.32.0/22 +103.236.36.0/22 +103.236.40.0/22 +103.236.44.0/22 +103.236.48.0/22 +103.236.52.0/22 +103.236.56.0/22 +103.236.60.0/22 +103.236.64.0/22 +103.236.68.0/22 +103.236.72.0/22 +103.236.76.0/22 +103.236.80.0/22 +103.236.84.0/22 +103.236.88.0/22 +103.236.92.0/22 +103.236.96.0/22 +103.236.116.0/23 +103.236.120.0/22 +103.236.184.0/22 +103.236.220.0/22 +103.236.232.0/22 +103.236.240.0/22 +103.236.244.0/22 +103.236.248.0/22 +103.236.252.0/22 +103.237.0.0/22 +103.237.4.0/22 +103.237.8.0/22 +103.237.12.0/22 +103.237.24.0/22 +103.237.28.0/22 +103.237.68.0/22 +103.237.88.0/22 +103.237.92.0/23 +103.237.152.0/22 +103.237.176.0/22 +103.237.180.0/22 +103.237.184.0/22 +103.237.188.0/22 +103.237.192.0/22 +103.237.196.0/22 +103.237.200.0/22 +103.237.204.0/22 +103.237.208.0/22 +103.237.212.0/22 +103.237.216.0/22 +103.237.220.0/22 +103.237.224.0/22 +103.237.228.0/22 +103.237.232.0/22 +103.237.236.0/22 +103.237.240.0/22 +103.237.244.0/22 +103.237.248.0/22 +103.237.252.0/22 +103.238.0.0/22 +103.238.4.0/22 +103.238.16.0/22 +103.238.20.0/22 +103.238.24.0/22 +103.238.28.0/22 +103.238.32.0/22 +103.238.36.0/22 +103.238.40.0/22 +103.238.44.0/22 +103.238.48.0/22 +103.238.52.0/22 +103.238.56.0/22 +103.238.88.0/22 +103.238.92.0/22 +103.238.96.0/22 +103.238.132.0/22 +103.238.140.0/22 +103.238.144.0/22 +103.238.152.0/23 +103.238.160.0/22 +103.238.164.0/22 +103.238.168.0/22 +103.238.172.0/22 +103.238.176.0/22 +103.238.180.0/22 +103.238.184.0/22 +103.238.188.0/22 +103.238.196.0/22 +103.238.204.0/22 +103.238.252.0/22 +103.239.0.0/22 +103.239.44.0/22 +103.239.68.0/22 +103.239.152.0/22 +103.239.156.0/22 +103.239.180.0/22 +103.239.184.0/22 +103.239.192.0/22 +103.239.196.0/22 +103.239.204.0/22 +103.239.208.0/22 +103.239.224.0/22 +103.239.244.0/22 +103.240.16.0/22 +103.240.36.0/22 +103.240.42.0/23 +103.240.72.0/22 +103.240.84.0/22 +103.240.124.0/22 +103.240.172.0/22 +103.240.188.0/22 +103.240.200.0/23 +103.240.202.0/23 +103.240.244.0/22 +103.241.12.0/22 +103.241.92.0/22 +103.241.96.0/22 +103.241.160.0/22 +103.241.172.0/23 +103.241.184.0/22 +103.241.188.0/22 +103.241.220.0/22 +103.242.64.0/22 +103.242.128.0/22 +103.242.132.0/22 +103.242.160.0/22 +103.242.168.0/22 +103.242.172.0/22 +103.242.176.0/22 +103.242.200.0/22 +103.242.212.0/22 +103.242.220.0/22 +103.242.240.0/22 +103.243.136.0/22 +103.243.252.0/22 +103.244.16.0/22 +103.244.26.0/23 +103.244.58.0/23 +103.244.60.0/22 +103.244.64.0/22 +103.244.68.0/22 +103.244.72.0/22 +103.244.76.0/22 +103.244.80.0/22 +103.244.84.0/22 +103.244.116.0/22 +103.244.164.0/22 +103.244.232.0/22 +103.244.252.0/22 +103.245.23.0/24 +103.245.24.0/23 +103.245.52.0/22 +103.245.60.0/22 +103.245.80.0/22 +103.245.124.0/22 +103.245.128.0/22 +103.246.8.0/22 +103.246.12.0/22 +103.246.120.0/22 +103.246.124.0/22 +103.246.132.0/22 +103.246.152.0/22 +103.246.156.0/22 +103.247.168.0/22 +103.247.172.0/22 +103.247.176.0/22 +103.247.191.0/24 +103.247.200.0/22 +103.247.212.0/22 +103.248.0.0/23 +103.248.64.0/22 +103.248.100.0/22 +103.248.124.0/22 +103.248.152.0/22 +103.248.168.0/22 +103.248.192.0/22 +103.248.212.0/22 +103.248.224.0/22 +103.249.8.0/22 +103.249.12.0/22 +103.249.52.0/22 +103.249.104.0/22 +103.249.128.0/22 +103.249.136.0/22 +103.249.144.0/22 +103.249.164.0/22 +103.249.168.0/22 +103.249.172.0/22 +103.249.176.0/22 +103.249.188.0/22 +103.249.192.0/22 +103.249.244.0/22 +103.249.252.0/22 +103.250.32.0/22 +103.250.104.0/22 +103.250.124.0/22 +103.250.180.0/22 +103.250.192.0/22 +103.250.216.0/22 +103.250.224.0/22 +103.250.236.0/22 +103.250.248.0/22 +103.250.252.0/22 +103.251.32.0/22 +103.251.84.0/22 +103.251.96.0/22 +103.251.124.0/22 +103.251.128.0/22 +103.251.160.0/22 +103.251.192.0/22 +103.251.204.0/22 +103.251.240.0/22 +103.252.28.0/22 +103.252.36.0/22 +103.252.64.0/22 +103.252.96.0/22 +103.252.104.0/22 +103.252.172.0/22 +103.252.204.0/22 +103.252.208.0/22 +103.252.232.0/22 +103.252.248.0/22 +103.253.4.0/22 +103.253.60.0/22 +103.253.204.0/22 +103.253.220.0/22 +103.253.224.0/22 +103.253.232.0/22 +103.254.8.0/22 +103.254.20.0/22 +103.254.64.0/22 +103.254.68.0/22 +103.254.72.0/22 +103.254.76.0/22 +103.254.112.0/22 +103.254.176.0/22 +103.254.188.0/22 +103.254.196.0/24 +103.254.220.0/22 +103.255.56.0/22 +103.255.68.0/22 +103.255.88.0/22 +103.255.92.0/22 +103.255.136.0/22 +103.255.140.0/22 +103.255.184.0/22 +103.255.200.0/22 +103.255.208.0/23 +103.255.212.0/22 +103.255.228.0/22 +106.0.0.0/24 +106.0.2.0/23 +106.0.4.0/22 +106.0.8.0/21 +106.0.16.0/20 +106.0.44.0/22 +106.0.64.0/18 +106.2.0.0/15 +106.4.0.0/14 +106.8.0.0/15 +106.11.0.0/16 +106.12.0.0/15 +106.14.0.0/15 +106.16.0.0/12 +106.32.0.0/12 +106.48.0.0/15 +106.50.0.0/16 +106.52.0.0/14 +106.56.0.0/13 +106.74.0.0/16 +106.75.0.0/16 +106.80.0.0/12 +106.108.0.0/14 +106.112.0.0/13 +106.120.0.0/13 +106.224.0.0/12 +109.244.0.0/16 +110.6.0.0/15 +110.16.0.0/14 +110.34.40.0/22 +110.34.44.0/22 +110.40.0.0/14 +110.44.12.0/22 +110.44.144.0/20 +110.48.0.0/16 +110.51.0.0/16 +110.52.0.0/15 +110.56.0.0/13 +110.64.0.0/15 +110.72.0.0/15 +110.75.0.0/17 +110.75.128.0/19 +110.75.160.0/19 +110.75.192.0/18 +110.76.0.0/19 +110.76.32.0/19 +110.76.132.0/22 +110.76.156.0/22 +110.76.184.0/22 +110.76.192.0/18 +110.77.0.0/17 +110.80.0.0/13 +110.88.0.0/14 +110.92.68.0/22 +110.93.32.0/19 +110.94.0.0/15 +110.96.0.0/11 +110.152.0.0/14 +110.156.0.0/15 +110.165.32.0/19 +110.166.0.0/15 +110.172.192.0/18 +110.173.0.0/19 +110.173.32.0/20 +110.173.64.0/19 +110.173.96.0/19 +110.173.192.0/19 +110.176.0.0/13 +110.184.0.0/13 +110.192.0.0/11 +110.228.0.0/14 +110.232.32.0/19 +110.236.0.0/15 +110.240.0.0/12 +111.0.0.0/10 +111.66.0.0/16 +111.67.192.0/20 +111.68.64.0/19 +111.72.0.0/13 +111.85.0.0/16 +111.92.248.0/22 +111.92.252.0/22 +111.112.0.0/15 +111.114.0.0/15 +111.116.0.0/15 +111.118.200.0/21 +111.119.64.0/18 +111.119.128.0/19 +111.120.0.0/14 +111.124.0.0/16 +111.126.0.0/15 +111.128.0.0/11 +111.160.0.0/13 +111.170.0.0/16 +111.172.0.0/14 +111.176.0.0/13 +111.186.0.0/15 +111.192.0.0/12 +111.208.0.0/14 +111.212.0.0/14 +111.221.28.0/24 +111.221.128.0/17 +111.222.0.0/16 +111.223.4.0/22 +111.223.8.0/22 +111.223.12.0/22 +111.223.16.0/22 +111.223.240.0/22 +111.223.248.0/22 +111.224.0.0/14 +111.228.0.0/14 +111.235.96.0/19 +111.235.156.0/22 +111.235.160.0/19 +112.0.0.0/10 +112.64.0.0/15 +112.66.0.0/15 +112.73.0.0/16 +112.74.0.0/15 +112.80.0.0/13 +112.88.0.0/13 +112.96.0.0/15 +112.98.0.0/15 +112.100.0.0/14 +112.109.128.0/17 +112.111.0.0/16 +112.112.0.0/14 +112.116.0.0/15 +112.122.0.0/15 +112.124.0.0/14 +112.128.0.0/14 +112.132.0.0/16 +112.137.48.0/21 +112.192.0.0/14 +112.224.0.0/11 +113.0.0.0/13 +113.8.0.0/15 +113.11.192.0/19 +113.12.0.0/14 +113.16.0.0/15 +113.18.0.0/16 +113.21.232.0/22 +113.21.236.0/22 +113.24.0.0/14 +113.31.0.0/16 +113.44.0.0/14 +113.48.0.0/14 +113.52.160.0/19 +113.52.228.0/22 +113.54.0.0/15 +113.56.0.0/15 +113.58.0.0/16 +113.59.0.0/17 +113.59.224.0/22 +113.62.0.0/15 +113.64.0.0/11 +113.96.0.0/12 +113.112.0.0/13 +113.120.0.0/13 +113.128.0.0/15 +113.130.96.0/20 +113.130.112.0/21 +113.132.0.0/14 +113.136.0.0/13 +113.192.40.0/23 +113.194.0.0/15 +113.197.100.0/22 +113.200.0.0/15 +113.202.0.0/16 +113.204.0.0/14 +113.208.96.0/19 +113.208.128.0/17 +113.209.0.0/16 +113.212.0.0/18 +113.212.100.0/22 +113.212.184.0/21 +113.213.0.0/17 +113.214.0.0/15 +113.218.0.0/15 +113.220.0.0/14 +113.224.0.0/12 +113.240.0.0/13 +113.248.0.0/14 +114.28.0.0/16 +114.31.64.0/22 +114.31.68.0/22 +114.54.0.0/15 +114.60.0.0/14 +114.64.0.0/14 +114.68.0.0/16 +114.79.64.0/18 +114.80.0.0/12 +114.96.0.0/13 +114.104.0.0/14 +114.110.0.0/20 +114.110.64.0/18 +114.111.0.0/19 +114.111.160.0/20 +114.111.176.0/20 +114.112.0.0/17 +114.112.128.0/17 +114.113.0.0/16 +114.114.0.0/15 +114.116.0.0/16 +114.117.0.0/17 +114.117.128.0/17 +114.118.0.0/16 +114.119.0.0/17 +114.119.192.0/21 +114.119.200.0/22 +114.119.204.0/22 +114.119.208.0/20 +114.119.224.0/19 +114.132.0.0/16 +114.135.0.0/16 +114.138.0.0/15 +114.141.64.0/21 +114.141.80.0/22 +114.141.84.0/22 +114.141.128.0/18 +114.142.136.0/21 +114.196.0.0/15 +114.198.248.0/21 +114.208.0.0/14 +114.212.0.0/15 +114.214.0.0/16 +114.215.0.0/16 +114.216.0.0/13 +114.224.0.0/12 +114.240.0.0/12 +115.24.0.0/14 +115.28.0.0/15 +115.31.64.0/22 +115.31.68.0/22 +115.31.72.0/22 +115.31.76.0/22 +115.32.0.0/14 +115.42.56.0/22 +115.44.0.0/15 +115.46.0.0/16 +115.47.0.0/16 +115.48.0.0/12 +115.69.64.0/20 +115.84.0.0/18 +115.85.192.0/18 +115.100.0.0/14 +115.104.0.0/14 +115.120.0.0/14 +115.124.16.0/20 +115.148.0.0/14 +115.152.0.0/15 +115.154.0.0/15 +115.156.0.0/15 +115.158.0.0/16 +115.159.0.0/16 +115.166.64.0/19 +115.168.0.0/14 +115.172.0.0/14 +115.180.0.0/16 +115.181.0.0/16 +115.182.0.0/16 +115.183.0.0/16 +115.187.0.0/22 +115.187.4.0/22 +115.187.8.0/22 +115.187.12.0/22 +115.190.0.0/15 +115.192.0.0/11 +115.224.0.0/12 +116.0.8.0/21 +116.0.24.0/21 +116.1.0.0/16 +116.2.0.0/15 +116.4.0.0/14 +116.8.0.0/14 +116.13.0.0/16 +116.16.0.0/12 +116.50.0.0/20 +116.52.0.0/14 +116.56.0.0/15 +116.58.128.0/20 +116.58.208.0/20 +116.60.0.0/14 +116.66.0.0/18 +116.66.64.0/19 +116.66.96.0/20 +116.66.112.0/21 +116.66.120.0/24 +116.66.121.0/24 +116.66.122.0/24 +116.66.123.0/24 +116.66.124.0/22 +116.68.136.0/22 +116.68.140.0/22 +116.68.176.0/22 +116.68.180.0/22 +116.69.0.0/16 +116.70.0.0/17 +116.76.0.0/15 +116.78.0.0/15 +116.85.0.0/16 +116.89.144.0/20 +116.89.240.0/22 +116.90.80.0/20 +116.90.184.0/21 +116.95.0.0/16 +116.112.0.0/14 +116.116.0.0/15 +116.128.0.0/10 +116.192.0.0/16 +116.193.16.0/20 +116.193.32.0/19 +116.193.164.0/22 +116.193.176.0/21 +116.194.0.0/15 +116.196.0.0/17 +116.196.128.0/18 +116.196.192.0/18 +116.197.160.0/22 +116.197.164.0/22 +116.198.0.0/16 +116.199.0.0/17 +116.199.128.0/19 +116.204.0.0/17 +116.204.132.0/22 +116.205.0.0/16 +116.207.0.0/16 +116.208.0.0/14 +116.212.160.0/20 +116.213.44.0/22 +116.213.64.0/18 +116.213.128.0/17 +116.214.32.0/19 +116.214.64.0/20 +116.214.128.0/17 +116.215.0.0/16 +116.216.0.0/14 +116.224.0.0/12 +116.242.0.0/15 +116.244.0.0/15 +116.246.0.0/15 +116.248.0.0/15 +116.251.64.0/18 +116.252.0.0/15 +116.254.104.0/22 +116.254.108.0/22 +116.254.128.0/17 +116.255.128.0/17 +117.8.0.0/13 +117.21.0.0/16 +117.22.0.0/15 +117.24.0.0/13 +117.32.0.0/13 +117.40.0.0/14 +117.44.0.0/15 +117.48.0.0/17 +117.48.128.0/17 +117.49.0.0/16 +117.50.0.0/15 +117.53.48.0/20 +117.53.176.0/20 +117.57.0.0/16 +117.58.0.0/17 +117.59.0.0/16 +117.60.0.0/14 +117.64.0.0/13 +117.72.0.0/15 +117.74.64.0/20 +117.74.80.0/20 +117.74.128.0/17 +117.75.0.0/16 +117.76.0.0/14 +117.80.0.0/12 +117.100.0.0/15 +117.103.16.0/20 +117.103.40.0/21 +117.103.72.0/21 +117.103.128.0/20 +117.104.168.0/21 +117.106.0.0/15 +117.112.0.0/13 +117.120.64.0/18 +117.120.128.0/17 +117.121.0.0/17 +117.121.128.0/18 +117.121.192.0/21 +117.122.128.0/17 +117.124.0.0/14 +117.128.0.0/14 +117.132.0.0/15 +117.134.0.0/17 +117.134.128.0/18 +117.135.0.0/16 +117.136.0.0/13 +117.144.0.0/12 +117.160.0.0/11 +118.24.0.0/15 +118.26.0.0/19 +118.26.32.0/22 +118.26.40.0/21 +118.26.48.0/21 +118.26.56.0/21 +118.26.64.0/19 +118.26.96.0/21 +118.26.112.0/21 +118.26.120.0/21 +118.26.128.0/22 +118.26.133.0/24 +118.26.134.0/23 +118.26.136.0/21 +118.26.160.0/20 +118.26.188.0/22 +118.26.192.0/18 +118.28.0.0/15 +118.30.0.0/16 +118.31.0.0/16 +118.64.0.0/15 +118.66.0.0/16 +118.67.112.0/20 +118.72.0.0/13 +118.80.0.0/15 +118.84.0.0/15 +118.88.32.0/19 +118.88.64.0/18 +118.88.128.0/17 +118.89.0.0/16 +118.91.240.0/20 +118.102.16.0/20 +118.102.32.0/21 +118.103.164.0/22 +118.103.168.0/22 +118.103.172.0/22 +118.103.176.0/22 +118.112.0.0/13 +118.120.0.0/14 +118.124.0.0/15 +118.126.0.0/16 +118.127.128.0/19 +118.132.0.0/14 +118.144.0.0/14 +118.178.0.0/16 +118.180.0.0/14 +118.184.0.0/17 +118.184.128.0/17 +118.186.0.0/15 +118.188.0.0/16 +118.190.0.0/16 +118.191.0.0/21 +118.191.8.0/22 +118.191.12.0/24 +118.191.13.0/24 +118.191.14.0/23 +118.191.16.0/21 +118.191.24.0/21 +118.191.32.0/19 +118.191.64.0/20 +118.191.80.0/22 +118.191.84.0/22 +118.191.88.0/21 +118.191.96.0/19 +118.191.128.0/19 +118.191.160.0/20 +118.191.176.0/20 +118.191.192.0/20 +118.191.208.0/24 +118.191.209.0/24 +118.191.210.0/23 +118.191.212.0/22 +118.191.216.0/22 +118.191.220.0/23 +118.191.222.0/24 +118.191.223.0/24 +118.191.224.0/24 +118.191.225.0/24 +118.191.226.0/23 +118.191.228.0/22 +118.191.232.0/21 +118.191.240.0/20 +118.192.0.0/16 +118.193.0.0/21 +118.193.8.0/21 +118.193.48.0/21 +118.193.96.0/19 +118.193.128.0/17 +118.194.0.0/17 +118.194.128.0/18 +118.194.192.0/19 +118.194.224.0/22 +118.194.240.0/21 +118.195.0.0/17 +118.195.128.0/17 +118.196.0.0/14 +118.202.0.0/15 +118.204.0.0/14 +118.212.0.0/16 +118.213.0.0/16 +118.215.192.0/18 +118.224.0.0/14 +118.228.0.0/15 +118.230.0.0/16 +118.239.0.0/16 +118.242.0.0/16 +118.244.0.0/14 +118.248.0.0/13 +119.0.0.0/15 +119.2.0.0/19 +119.2.128.0/17 +119.3.0.0/16 +119.4.0.0/14 +119.10.0.0/17 +119.15.136.0/21 +119.16.0.0/16 +119.18.192.0/20 +119.18.208.0/21 +119.18.224.0/24 +119.18.225.0/24 +119.18.226.0/24 +119.18.227.0/24 +119.18.228.0/22 +119.18.232.0/23 +119.18.234.0/24 +119.18.235.0/24 +119.18.236.0/23 +119.18.238.0/23 +119.18.240.0/20 +119.19.0.0/16 +119.20.0.0/14 +119.27.64.0/18 +119.27.128.0/19 +119.27.160.0/19 +119.27.192.0/18 +119.28.0.0/15 +119.30.48.0/20 +119.31.192.0/19 +119.32.0.0/14 +119.36.0.0/16 +119.37.0.0/17 +119.37.128.0/18 +119.37.192.0/18 +119.38.0.0/17 +119.38.128.0/18 +119.38.192.0/20 +119.38.208.0/20 +119.38.224.0/19 +119.39.0.0/16 +119.40.0.0/18 +119.40.64.0/20 +119.40.128.0/17 +119.41.0.0/16 +119.42.0.0/19 +119.42.128.0/21 +119.42.136.0/21 +119.42.224.0/19 +119.44.0.0/18 +119.44.64.0/18 +119.44.128.0/17 +119.45.0.0/16 +119.48.0.0/13 +119.57.0.0/16 +119.58.0.0/16 +119.59.128.0/17 +119.60.0.0/16 +119.61.0.0/16 +119.62.0.0/16 +119.63.32.0/19 +119.75.208.0/20 +119.78.0.0/15 +119.80.0.0/16 +119.82.208.0/20 +119.84.0.0/14 +119.88.0.0/14 +119.96.0.0/13 +119.108.0.0/15 +119.112.0.0/13 +119.120.0.0/13 +119.128.0.0/12 +119.144.0.0/14 +119.148.160.0/20 +119.148.176.0/20 +119.151.192.0/18 +119.160.200.0/21 +119.161.120.0/22 +119.161.124.0/22 +119.161.128.0/17 +119.162.0.0/15 +119.164.0.0/14 +119.176.0.0/12 +119.232.0.0/16 +119.233.0.0/17 +119.233.128.0/17 +119.235.128.0/18 +119.248.0.0/14 +119.252.96.0/21 +119.252.240.0/20 +119.253.0.0/16 +119.254.0.0/15 +120.0.0.0/12 +120.24.0.0/14 +120.30.0.0/16 +120.31.0.0/16 +120.32.0.0/13 +120.40.0.0/14 +120.44.0.0/15 +120.46.0.0/16 +120.47.0.0/16 +120.48.0.0/15 +120.52.0.0/16 +120.53.0.0/16 +120.54.0.0/15 +120.64.0.0/14 +120.68.0.0/14 +120.72.32.0/19 +120.72.128.0/17 +120.76.0.0/14 +120.80.0.0/13 +120.88.8.0/21 +120.90.0.0/15 +120.92.0.0/16 +120.94.0.0/16 +120.95.0.0/16 +120.128.0.0/14 +120.132.0.0/17 +120.132.128.0/17 +120.133.0.0/16 +120.134.0.0/15 +120.136.16.0/22 +120.136.20.0/22 +120.136.128.0/18 +120.137.0.0/17 +120.143.128.0/19 +120.192.0.0/10 +121.0.8.0/21 +121.0.16.0/20 +121.4.0.0/15 +121.8.0.0/13 +121.16.0.0/13 +121.24.0.0/14 +121.28.0.0/15 +121.30.0.0/16 +121.31.0.0/16 +121.32.0.0/14 +121.36.0.0/16 +121.37.0.0/16 +121.38.0.0/15 +121.40.0.0/14 +121.46.0.0/18 +121.46.76.0/22 +121.46.128.0/18 +121.46.192.0/18 +121.47.0.0/16 +121.48.0.0/15 +121.50.8.0/21 +121.51.0.0/16 +121.52.160.0/19 +121.52.208.0/20 +121.52.224.0/19 +121.54.176.0/21 +121.54.188.0/22 +121.55.0.0/18 +121.56.0.0/15 +121.58.0.0/17 +121.58.136.0/21 +121.58.144.0/20 +121.58.160.0/21 +121.59.0.0/16 +121.60.0.0/14 +121.68.0.0/14 +121.76.0.0/15 +121.79.128.0/18 +121.89.0.0/16 +121.91.104.0/21 +121.100.128.0/17 +121.101.0.0/18 +121.101.208.0/20 +121.192.0.0/16 +121.193.0.0/16 +121.194.0.0/15 +121.196.0.0/14 +121.200.192.0/21 +121.201.0.0/16 +121.204.0.0/14 +121.224.0.0/12 +121.248.0.0/14 +121.255.0.0/16 +122.0.64.0/18 +122.0.128.0/17 +122.4.0.0/14 +122.8.0.0/17 +122.8.192.0/18 +122.9.0.0/16 +122.10.128.0/22 +122.10.132.0/23 +122.10.136.0/23 +122.10.164.0/22 +122.10.168.0/21 +122.10.176.0/20 +122.10.192.0/22 +122.10.200.0/21 +122.10.208.0/21 +122.10.216.0/22 +122.10.228.0/22 +122.10.232.0/21 +122.10.240.0/22 +122.11.0.0/17 +122.12.0.0/16 +122.13.0.0/16 +122.14.0.0/17 +122.14.128.0/18 +122.14.192.0/18 +122.48.0.0/16 +122.49.0.0/18 +122.51.0.0/16 +122.64.0.0/11 +122.96.0.0/15 +122.102.0.0/20 +122.102.64.0/20 +122.102.80.0/20 +122.112.0.0/19 +122.112.32.0/19 +122.112.64.0/18 +122.112.128.0/17 +122.113.0.0/16 +122.114.0.0/16 +122.115.0.0/20 +122.115.16.0/20 +122.115.32.0/19 +122.115.64.0/18 +122.115.128.0/19 +122.115.160.0/19 +122.115.192.0/19 +122.115.224.0/20 +122.115.240.0/20 +122.119.0.0/16 +122.128.100.0/22 +122.128.120.0/21 +122.136.0.0/13 +122.144.128.0/17 +122.152.192.0/18 +122.156.0.0/14 +122.188.0.0/14 +122.192.0.0/14 +122.198.0.0/18 +122.198.64.0/22 +122.198.68.0/22 +122.198.72.0/21 +122.198.80.0/20 +122.198.96.0/19 +122.198.128.0/17 +122.200.40.0/22 +122.200.44.0/22 +122.200.64.0/18 +122.201.48.0/20 +122.204.0.0/14 +122.224.0.0/12 +122.240.0.0/13 +122.248.24.0/21 +122.248.48.0/20 +122.255.64.0/21 +123.0.128.0/18 +123.4.0.0/14 +123.8.0.0/13 +123.49.128.0/17 +123.50.160.0/19 +123.52.0.0/14 +123.56.0.0/15 +123.58.0.0/20 +123.58.16.0/20 +123.58.32.0/19 +123.58.64.0/19 +123.58.96.0/19 +123.58.128.0/18 +123.58.224.0/20 +123.58.240.0/20 +123.59.0.0/16 +123.60.0.0/16 +123.61.0.0/16 +123.62.0.0/16 +123.64.0.0/11 +123.96.0.0/15 +123.98.0.0/17 +123.99.128.0/17 +123.100.0.0/19 +123.101.0.0/16 +123.103.0.0/17 +123.108.88.0/23 +123.108.128.0/20 +123.108.208.0/20 +123.112.0.0/12 +123.128.0.0/13 +123.136.80.0/20 +123.137.0.0/16 +123.138.0.0/15 +123.144.0.0/14 +123.148.0.0/16 +123.149.0.0/16 +123.150.0.0/15 +123.152.0.0/13 +123.160.0.0/14 +123.164.0.0/14 +123.168.0.0/14 +123.172.0.0/15 +123.174.0.0/15 +123.176.60.0/22 +123.176.80.0/20 +123.177.0.0/16 +123.178.0.0/15 +123.180.0.0/14 +123.184.0.0/14 +123.188.0.0/14 +123.196.0.0/15 +123.199.128.0/17 +123.206.0.0/15 +123.232.0.0/14 +123.242.0.0/17 +123.242.192.0/22 +123.242.196.0/22 +123.244.0.0/14 +123.249.0.0/17 +123.249.128.0/17 +123.253.52.0/23 +123.254.96.0/22 +123.254.100.0/22 +124.6.64.0/18 +124.14.0.0/20 +124.14.16.0/21 +124.14.24.0/21 +124.14.32.0/20 +124.14.48.0/22 +124.14.52.0/22 +124.14.56.0/21 +124.14.64.0/18 +124.14.128.0/17 +124.15.0.0/16 +124.16.0.0/15 +124.20.0.0/16 +124.21.0.0/20 +124.21.16.0/20 +124.21.32.0/19 +124.21.64.0/18 +124.21.128.0/17 +124.22.0.0/15 +124.28.192.0/18 +124.29.0.0/17 +124.31.0.0/16 +124.40.112.0/20 +124.40.128.0/18 +124.40.192.0/19 +124.40.240.0/22 +124.42.0.0/17 +124.42.128.0/17 +124.47.0.0/18 +124.64.0.0/15 +124.66.0.0/17 +124.67.0.0/16 +124.68.0.0/18 +124.68.64.0/18 +124.68.128.0/17 +124.69.0.0/16 +124.70.0.0/15 +124.72.0.0/16 +124.73.0.0/16 +124.74.0.0/15 +124.76.0.0/14 +124.88.0.0/16 +124.89.0.0/17 +124.89.128.0/17 +124.90.0.0/15 +124.92.0.0/14 +124.108.8.0/21 +124.108.40.0/21 +124.109.96.0/21 +124.112.0.0/15 +124.114.0.0/15 +124.116.0.0/16 +124.117.0.0/16 +124.118.0.0/15 +124.126.0.0/15 +124.128.0.0/13 +124.147.128.0/17 +124.150.137.0/24 +124.151.0.0/16 +124.152.0.0/16 +124.160.0.0/16 +124.161.0.0/16 +124.162.0.0/16 +124.163.0.0/16 +124.164.0.0/14 +124.172.0.0/15 +124.174.0.0/15 +124.192.0.0/15 +124.196.0.0/16 +124.197.56.0/21 +124.200.0.0/16 +124.201.0.0/16 +124.202.0.0/15 +124.204.0.0/14 +124.220.0.0/14 +124.224.0.0/16 +124.225.0.0/16 +124.226.0.0/15 +124.228.0.0/14 +124.232.0.0/15 +124.234.0.0/15 +124.236.0.0/14 +124.240.0.0/17 +124.240.128.0/18 +124.242.0.0/16 +124.243.192.0/18 +124.248.0.0/17 +124.249.0.0/16 +124.250.0.0/15 +124.254.0.0/18 +125.31.192.0/18 +125.32.0.0/16 +125.33.0.0/16 +125.34.0.0/16 +125.35.0.0/17 +125.35.128.0/17 +125.36.0.0/14 +125.40.0.0/13 +125.58.128.0/17 +125.61.128.0/17 +125.62.0.0/18 +125.64.0.0/13 +125.72.0.0/16 +125.73.0.0/16 +125.74.0.0/15 +125.76.0.0/17 +125.76.128.0/17 +125.77.0.0/16 +125.78.0.0/15 +125.80.0.0/13 +125.88.0.0/13 +125.96.0.0/15 +125.98.0.0/16 +125.104.0.0/13 +125.112.0.0/12 +125.169.0.0/16 +125.171.0.0/16 +125.208.0.0/18 +125.210.0.0/16 +125.211.0.0/16 +125.213.0.0/17 +125.214.96.0/19 +125.215.0.0/18 +125.216.0.0/15 +125.218.0.0/16 +125.219.0.0/16 +125.220.0.0/15 +125.222.0.0/15 +125.254.128.0/18 +125.254.192.0/18 +128.108.0.0/16 +129.28.0.0/16 +129.204.0.0/16 +129.211.0.0/16 +132.232.0.0/16 +134.175.0.0/16 +137.59.59.0/24 +137.59.88.0/22 +138.252.72.0/23 +138.252.78.0/23 +138.252.96.0/23 +138.252.118.0/23 +138.252.162.0/23 +139.5.56.0/22 +139.5.60.0/22 +139.5.80.0/22 +139.5.92.0/22 +139.5.108.0/22 +139.5.128.0/22 +139.5.160.0/22 +139.5.192.0/22 +139.5.204.0/22 +139.5.212.0/22 +139.5.244.0/22 +139.9.0.0/16 +139.129.0.0/16 +139.148.0.0/16 +139.155.0.0/16 +139.159.0.0/16 +139.170.0.0/16 +139.176.0.0/16 +139.183.0.0/16 +139.186.0.0/16 +139.189.0.0/16 +139.196.0.0/14 +139.200.0.0/13 +139.208.0.0/13 +139.217.0.0/16 +139.219.0.0/16 +139.220.0.0/15 +139.224.0.0/16 +139.226.0.0/15 +140.75.0.0/16 +140.143.0.0/16 +140.179.0.0/16 +140.205.0.0/16 +140.206.0.0/15 +140.210.0.0/17 +140.210.128.0/17 +140.224.0.0/16 +140.237.0.0/16 +140.240.0.0/16 +140.243.0.0/16 +140.246.0.0/16 +140.249.0.0/16 +140.250.0.0/16 +140.255.0.0/16 +142.86.0.0/16 +143.64.0.0/16 +144.0.0.0/16 +144.7.0.0/16 +144.12.0.0/16 +144.48.64.0/22 +144.48.88.0/22 +144.48.156.0/22 +144.48.180.0/22 +144.48.184.0/22 +144.48.204.0/22 +144.48.208.0/22 +144.48.212.0/22 +144.48.220.0/22 +144.48.252.0/22 +144.52.0.0/16 +144.79.4.0/23 +144.79.10.0/23 +144.79.28.0/23 +144.79.42.0/23 +144.79.54.0/23 +144.79.70.0/23 +144.79.84.0/23 +144.79.118.0/23 +144.79.148.0/23 +144.123.0.0/16 +144.255.0.0/16 +146.56.192.0/18 +146.196.56.0/22 +146.196.68.0/22 +146.196.72.0/22 +146.196.92.0/22 +146.196.112.0/22 +146.196.116.0/22 +146.196.124.0/22 +148.70.0.0/16 +149.41.0.0/16 +150.0.0.0/16 +150.115.0.0/16 +150.121.0.0/16 +150.122.0.0/16 +150.129.136.0/22 +150.129.192.0/22 +150.129.252.0/22 +150.138.0.0/15 +150.158.0.0/16 +150.223.0.0/16 +150.242.0.0/22 +150.242.4.0/22 +150.242.8.0/22 +150.242.28.0/22 +150.242.44.0/22 +150.242.48.0/22 +150.242.52.0/22 +150.242.56.0/22 +150.242.76.0/22 +150.242.80.0/22 +150.242.92.0/22 +150.242.96.0/22 +150.242.112.0/22 +150.242.116.0/22 +150.242.120.0/22 +150.242.152.0/22 +150.242.156.0/22 +150.242.160.0/22 +150.242.164.0/22 +150.242.168.0/22 +150.242.184.0/22 +150.242.188.0/22 +150.242.192.0/22 +150.242.212.0/22 +150.242.224.0/22 +150.242.232.0/22 +150.242.236.0/22 +150.242.240.0/22 +150.242.244.0/22 +150.242.248.0/22 +150.248.0.0/16 +150.255.0.0/16 +151.158.14.0/23 +151.158.72.0/23 +151.158.78.0/23 +151.158.80.0/23 +151.158.122.0/23 +152.104.128.0/17 +152.136.0.0/16 +153.0.0.0/16 +153.3.0.0/16 +153.34.0.0/15 +153.36.0.0/15 +153.99.0.0/16 +153.101.0.0/16 +153.118.0.0/15 +154.8.128.0/17 +157.0.0.0/16 +157.10.34.0/23 +157.10.36.0/23 +157.10.112.0/23 +157.10.118.0/23 +157.10.130.0/23 +157.10.218.0/23 +157.10.220.0/23 +157.10.246.0/23 +157.15.74.0/23 +157.15.94.0/23 +157.15.100.0/23 +157.15.102.0/23 +157.15.104.0/23 +157.15.200.0/23 +157.18.0.0/16 +157.20.136.0/23 +157.20.194.0/23 +157.20.246.0/23 +157.61.0.0/16 +157.66.42.0/23 +157.66.70.0/23 +157.66.88.0/23 +157.66.90.0/23 +157.66.92.0/23 +157.66.94.0/23 +157.66.164.0/23 +157.66.244.0/23 +157.119.8.0/22 +157.119.12.0/22 +157.119.16.0/22 +157.119.28.0/22 +157.119.132.0/22 +157.119.136.0/22 +157.119.140.0/22 +157.119.144.0/22 +157.119.148.0/22 +157.119.152.0/22 +157.119.156.0/22 +157.119.160.0/22 +157.119.164.0/22 +157.119.172.0/22 +157.119.192.0/22 +157.119.196.0/22 +157.119.240.0/22 +157.119.252.0/22 +157.122.0.0/16 +157.148.0.0/16 +157.156.0.0/16 +157.255.0.0/16 +158.60.0.0/16 +158.79.0.0/16 +158.140.252.0/22 +159.27.0.0/16 +159.75.0.0/16 +159.226.0.0/16 +160.19.76.0/23 +160.19.82.0/23 +160.19.208.0/22 +160.19.212.0/22 +160.19.216.0/22 +160.20.16.0/23 +160.20.18.0/23 +160.20.48.0/22 +160.20.130.0/23 +160.22.58.0/23 +160.22.82.0/23 +160.22.148.0/23 +160.22.188.0/23 +160.22.224.0/23 +160.22.230.0/23 +160.22.244.0/23 +160.22.246.0/23 +160.25.10.0/23 +160.25.12.0/23 +160.25.20.0/23 +160.25.194.0/23 +160.30.40.0/23 +160.30.148.0/23 +160.30.150.0/23 +160.30.194.0/23 +160.30.196.0/23 +160.30.198.0/23 +160.30.230.0/23 +160.187.223.0/24 +160.187.252.0/23 +160.187.254.0/23 +160.191.0.0/23 +160.191.104.0/23 +160.191.110.0/23 +160.202.60.0/22 +160.202.148.0/22 +160.202.152.0/22 +160.202.168.0/22 +160.202.212.0/22 +160.202.216.0/22 +160.202.220.0/22 +160.202.224.0/22 +160.202.228.0/22 +160.202.232.0/22 +160.202.236.0/22 +160.202.240.0/22 +160.202.244.0/22 +160.202.248.0/22 +160.202.252.0/22 +160.250.14.0/23 +160.250.16.0/23 +160.250.18.0/23 +160.250.24.0/23 +160.250.84.0/23 +160.250.90.0/23 +160.250.102.0/23 +160.250.104.0/23 +160.250.160.0/23 +160.250.170.0/23 +160.250.214.0/23 +160.250.252.0/23 +161.120.0.0/16 +161.189.0.0/16 +161.207.0.0/16 +161.248.20.0/23 +161.248.42.0/23 +161.248.84.0/23 +161.248.92.0/23 +161.248.108.0/23 +161.248.110.0/23 +161.248.112.0/23 +161.248.136.0/23 +162.14.0.0/16 +162.105.0.0/16 +163.0.0.0/16 +163.47.4.0/22 +163.53.0.0/22 +163.53.4.0/22 +163.53.8.0/22 +163.53.12.0/22 +163.53.36.0/22 +163.53.40.0/22 +163.53.44.0/22 +163.53.48.0/22 +163.53.52.0/22 +163.53.56.0/22 +163.53.60.0/22 +163.53.64.0/22 +163.53.88.0/22 +163.53.92.0/22 +163.53.96.0/22 +163.53.100.0/22 +163.53.104.0/22 +163.53.108.0/22 +163.53.112.0/22 +163.53.116.0/22 +163.53.120.0/22 +163.53.124.0/22 +163.53.128.0/22 +163.53.132.0/22 +163.53.136.0/22 +163.53.160.0/22 +163.53.164.0/22 +163.53.168.0/22 +163.53.172.0/22 +163.53.188.0/22 +163.53.240.0/22 +163.61.62.0/23 +163.61.113.0/24 +163.61.178.0/23 +163.61.202.0/23 +163.61.214.0/23 +163.125.0.0/16 +163.128.30.0/23 +163.128.152.0/23 +163.128.236.0/23 +163.142.0.0/16 +163.177.0.0/16 +163.179.0.0/16 +163.204.0.0/16 +163.223.28.0/23 +163.223.32.0/23 +163.223.124.0/23 +163.223.156.0/23 +163.223.173.0/24 +163.223.178.0/23 +163.223.216.0/23 +163.223.222.0/23 +163.227.34.0/23 +163.227.40.0/23 +163.227.74.0/23 +163.227.76.0/23 +163.227.78.0/23 +163.227.80.0/23 +163.228.0.0/16 +164.52.0.0/17 +165.99.4.0/24 +165.99.42.0/23 +165.101.4.0/23 +165.101.66.0/23 +165.101.70.0/23 +165.101.122.0/23 +165.101.144.0/23 +165.101.170.0/23 +165.101.208.0/23 +165.101.244.0/23 +166.111.0.0/16 +167.139.0.0/16 +167.189.0.0/16 +167.220.244.0/22 +168.160.0.0/16 +170.179.0.0/16 +171.8.0.0/13 +171.34.0.0/15 +171.36.0.0/14 +171.40.0.0/13 +171.80.0.0/14 +171.84.0.0/14 +171.88.0.0/13 +171.104.0.0/13 +171.112.0.0/14 +171.116.0.0/14 +171.120.0.0/13 +171.208.0.0/12 +172.81.192.0/18 +175.0.0.0/12 +175.16.0.0/13 +175.24.0.0/16 +175.25.0.0/16 +175.26.0.0/16 +175.27.0.0/16 +175.30.0.0/15 +175.42.0.0/15 +175.44.0.0/16 +175.46.0.0/15 +175.48.0.0/12 +175.64.0.0/11 +175.102.0.0/16 +175.106.128.0/17 +175.111.144.0/22 +175.111.148.0/22 +175.111.152.0/22 +175.111.156.0/22 +175.111.160.0/22 +175.111.164.0/22 +175.111.168.0/22 +175.111.172.0/22 +175.111.184.0/22 +175.146.0.0/15 +175.148.0.0/14 +175.152.0.0/14 +175.158.96.0/22 +175.160.0.0/12 +175.176.156.0/22 +175.176.176.0/22 +175.176.188.0/22 +175.178.0.0/16 +175.184.128.0/18 +175.185.0.0/16 +175.186.0.0/15 +175.188.0.0/14 +180.76.0.0/16 +180.77.0.0/16 +180.78.0.0/15 +180.84.0.0/15 +180.86.0.0/16 +180.88.0.0/14 +180.94.56.0/21 +180.94.96.0/20 +180.94.120.0/22 +180.94.124.0/22 +180.95.128.0/17 +180.96.0.0/11 +180.129.128.0/17 +180.130.0.0/16 +180.136.0.0/13 +180.148.16.0/21 +180.148.152.0/21 +180.148.216.0/21 +180.148.224.0/19 +180.149.128.0/19 +180.150.160.0/19 +180.152.0.0/13 +180.160.0.0/12 +180.178.112.0/22 +180.178.116.0/22 +180.178.192.0/18 +180.184.0.0/15 +180.186.0.0/16 +180.187.0.0/16 +180.188.0.0/20 +180.188.16.0/20 +180.188.32.0/20 +180.188.48.0/20 +180.188.64.0/18 +180.189.148.0/22 +180.200.252.0/22 +180.201.0.0/16 +180.202.0.0/15 +180.208.0.0/15 +180.210.212.0/22 +180.210.224.0/19 +180.212.0.0/15 +180.222.224.0/19 +180.223.0.0/16 +180.233.0.0/18 +180.233.64.0/19 +180.233.144.0/22 +180.235.64.0/19 +180.235.112.0/22 +182.16.144.0/22 +182.16.148.0/22 +182.16.192.0/19 +182.18.0.0/17 +182.23.184.0/21 +182.23.200.0/21 +182.32.0.0/12 +182.48.96.0/19 +182.49.0.0/16 +182.50.0.0/20 +182.50.112.0/20 +182.51.0.0/16 +182.54.0.0/17 +182.54.244.0/22 +182.61.0.0/16 +182.80.0.0/14 +182.84.0.0/14 +182.88.0.0/14 +182.92.0.0/16 +182.96.0.0/12 +182.112.0.0/12 +182.128.0.0/12 +182.144.0.0/13 +182.157.0.0/16 +182.160.64.0/19 +182.174.0.0/15 +182.200.0.0/13 +182.236.128.0/17 +182.237.24.0/22 +182.237.28.0/22 +182.238.0.0/16 +182.239.0.0/19 +182.240.0.0/13 +182.254.0.0/16 +182.255.60.0/22 +183.0.0.0/10 +183.64.0.0/13 +183.78.160.0/22 +183.78.164.0/22 +183.78.180.0/22 +183.81.172.0/22 +183.81.180.0/22 +183.84.0.0/15 +183.91.128.0/22 +183.91.136.0/21 +183.91.144.0/20 +183.92.0.0/14 +183.128.0.0/11 +183.160.0.0/13 +183.168.0.0/15 +183.170.0.0/16 +183.172.0.0/14 +183.182.0.0/19 +183.184.0.0/13 +183.192.0.0/10 +188.131.128.0/17 +192.51.172.0/23 +192.51.188.0/24 +192.55.46.0/23 +192.55.68.0/22 +192.102.204.0/22 +192.124.154.0/24 +192.140.128.0/22 +192.140.132.0/22 +192.140.136.0/22 +192.140.156.0/22 +192.140.160.0/22 +192.140.164.0/22 +192.140.168.0/22 +192.140.172.0/22 +192.140.176.0/22 +192.140.180.0/22 +192.140.184.0/22 +192.140.188.0/22 +192.140.192.0/22 +192.140.196.0/22 +192.140.200.0/22 +192.140.204.0/22 +192.140.208.0/22 +192.140.212.0/22 +192.144.128.0/17 +192.197.113.0/24 +192.232.34.0/23 +192.232.44.0/23 +192.232.46.0/23 +193.112.0.0/16 +193.119.0.0/19 +198.175.100.0/22 +199.212.57.0/24 +202.0.100.0/23 +202.0.122.0/23 +202.0.176.0/22 +202.3.128.0/23 +202.4.128.0/19 +202.4.252.0/22 +202.5.208.0/22 +202.5.212.0/22 +202.5.216.0/22 +202.6.6.0/23 +202.6.66.0/23 +202.6.72.0/23 +202.6.87.0/24 +202.6.88.0/23 +202.6.92.0/23 +202.6.103.0/24 +202.6.108.0/24 +202.6.110.0/23 +202.6.114.0/24 +202.6.176.0/20 +202.6.202.0/23 +202.8.0.0/24 +202.8.2.0/23 +202.8.4.0/23 +202.8.12.0/24 +202.8.24.0/24 +202.8.77.0/24 +202.8.128.0/19 +202.8.192.0/20 +202.9.32.0/24 +202.9.34.0/23 +202.9.48.0/23 +202.9.51.0/24 +202.9.52.0/23 +202.9.54.0/24 +202.9.57.0/24 +202.9.58.0/23 +202.10.64.0/20 +202.10.112.0/22 +202.10.116.0/22 +202.10.120.0/22 +202.10.124.0/22 +202.12.1.0/24 +202.12.2.0/24 +202.12.17.0/24 +202.12.18.0/24 +202.12.72.0/24 +202.12.84.0/23 +202.12.96.0/24 +202.12.98.0/23 +202.12.106.0/24 +202.12.111.0/24 +202.12.116.0/24 +202.14.64.0/23 +202.14.69.0/24 +202.14.73.0/24 +202.14.74.0/23 +202.14.76.0/24 +202.14.78.0/23 +202.14.88.0/24 +202.14.97.0/24 +202.14.104.0/23 +202.14.108.0/23 +202.14.111.0/24 +202.14.114.0/23 +202.14.118.0/23 +202.14.124.0/23 +202.14.127.0/24 +202.14.129.0/24 +202.14.135.0/24 +202.14.136.0/24 +202.14.149.0/24 +202.14.151.0/24 +202.14.157.0/24 +202.14.158.0/23 +202.14.169.0/24 +202.14.170.0/23 +202.14.172.0/22 +202.14.176.0/24 +202.14.184.0/23 +202.14.208.0/23 +202.14.213.0/24 +202.14.219.0/24 +202.14.220.0/24 +202.14.222.0/23 +202.14.225.0/24 +202.14.226.0/23 +202.14.231.0/24 +202.14.235.0/24 +202.14.236.0/23 +202.14.238.0/24 +202.14.239.0/24 +202.14.246.0/24 +202.14.251.0/24 +202.20.66.0/24 +202.20.79.0/24 +202.20.87.0/24 +202.20.88.0/23 +202.20.90.0/24 +202.20.94.0/23 +202.20.114.0/24 +202.20.117.0/24 +202.20.120.0/24 +202.20.125.0/24 +202.20.126.0/24 +202.20.127.0/24 +202.21.48.0/22 +202.21.52.0/22 +202.21.56.0/22 +202.21.60.0/22 +202.21.131.0/24 +202.21.132.0/24 +202.21.141.0/24 +202.21.142.0/24 +202.21.147.0/24 +202.21.148.0/24 +202.21.150.0/23 +202.21.152.0/23 +202.21.154.0/24 +202.21.156.0/24 +202.22.248.0/22 +202.22.252.0/22 +202.27.12.0/24 +202.27.14.0/24 +202.27.136.0/23 +202.36.226.0/24 +202.38.0.0/23 +202.38.2.0/23 +202.38.8.0/21 +202.38.48.0/20 +202.38.64.0/19 +202.38.96.0/19 +202.38.128.0/23 +202.38.130.0/23 +202.38.132.0/23 +202.38.134.0/24 +202.38.135.0/24 +202.38.136.0/23 +202.38.140.0/23 +202.38.142.0/23 +202.38.146.0/23 +202.38.149.0/24 +202.38.150.0/23 +202.38.152.0/23 +202.38.154.0/23 +202.38.156.0/24 +202.38.158.0/23 +202.38.164.0/22 +202.38.168.0/23 +202.38.170.0/24 +202.38.176.0/23 +202.38.184.0/21 +202.38.192.0/18 +202.40.4.0/23 +202.40.7.0/24 +202.40.15.0/24 +202.40.135.0/24 +202.40.136.0/24 +202.40.140.0/24 +202.40.143.0/24 +202.40.144.0/23 +202.40.150.0/24 +202.40.155.0/24 +202.40.156.0/24 +202.40.158.0/23 +202.40.162.0/24 +202.41.8.0/23 +202.41.11.0/24 +202.41.12.0/23 +202.41.128.0/24 +202.41.130.0/23 +202.41.152.0/21 +202.41.192.0/24 +202.41.196.0/22 +202.41.200.0/22 +202.41.240.0/20 +202.43.76.0/22 +202.43.144.0/20 +202.44.16.0/20 +202.44.48.0/22 +202.44.67.0/24 +202.44.74.0/24 +202.44.97.0/24 +202.44.129.0/24 +202.44.132.0/23 +202.44.146.0/23 +202.45.0.0/23 +202.45.2.0/24 +202.45.15.0/24 +202.45.16.0/20 +202.46.16.0/23 +202.46.18.0/24 +202.46.20.0/23 +202.46.32.0/19 +202.46.128.0/24 +202.46.224.0/20 +202.47.82.0/23 +202.47.96.0/22 +202.47.100.0/22 +202.47.104.0/22 +202.47.108.0/22 +202.47.126.0/24 +202.47.128.0/24 +202.47.130.0/23 +202.52.33.0/24 +202.52.34.0/24 +202.52.47.0/24 +202.52.143.0/24 +202.53.140.0/24 +202.53.143.0/24 +202.57.192.0/22 +202.57.196.0/22 +202.57.200.0/22 +202.57.204.0/22 +202.57.212.0/22 +202.57.216.0/22 +202.57.240.0/20 +202.58.0.0/24 +202.58.104.0/22 +202.58.112.0/22 +202.58.122.0/23 +202.59.0.0/24 +202.59.1.0/24 +202.59.212.0/22 +202.59.236.0/24 +202.59.240.0/24 +202.60.48.0/21 +202.60.96.0/21 +202.60.112.0/20 +202.60.132.0/22 +202.60.136.0/21 +202.60.144.0/20 +202.61.68.0/22 +202.61.76.0/22 +202.61.88.0/22 +202.61.123.0/24 +202.61.127.0/24 +202.62.112.0/22 +202.62.248.0/22 +202.62.252.0/24 +202.62.255.0/24 +202.63.80.0/24 +202.63.81.0/24 +202.63.82.0/23 +202.63.84.0/22 +202.63.88.0/21 +202.63.160.0/19 +202.63.248.0/22 +202.63.253.0/24 +202.65.0.0/21 +202.65.8.0/23 +202.65.96.0/22 +202.65.100.0/22 +202.65.104.0/22 +202.65.108.0/22 +202.66.168.0/22 +202.67.0.0/22 +202.69.4.0/22 +202.69.16.0/20 +202.70.0.0/19 +202.70.96.0/20 +202.70.192.0/20 +202.71.32.0/22 +202.71.36.0/22 +202.71.40.0/22 +202.71.44.0/22 +202.72.40.0/21 +202.72.80.0/20 +202.72.112.0/22 +202.72.116.0/22 +202.72.120.0/22 +202.72.124.0/22 +202.73.128.0/22 +202.73.240.0/22 +202.73.244.0/22 +202.73.248.0/22 +202.73.252.0/22 +202.74.8.0/21 +202.74.36.0/24 +202.74.42.0/24 +202.74.52.0/24 +202.74.80.0/20 +202.74.254.0/23 +202.75.208.0/20 +202.75.252.0/22 +202.76.252.0/22 +202.77.80.0/21 +202.77.92.0/22 +202.78.8.0/21 +202.79.224.0/21 +202.79.248.0/22 +202.80.192.0/21 +202.80.200.0/21 +202.81.0.0/22 +202.81.176.0/22 +202.81.180.0/22 +202.81.184.0/22 +202.81.188.0/22 +202.83.252.0/22 +202.84.0.0/22 +202.84.4.0/22 +202.84.8.0/21 +202.84.16.0/23 +202.84.22.0/24 +202.84.24.0/21 +202.85.208.0/20 +202.86.249.0/24 +202.86.252.0/22 +202.87.80.0/20 +202.88.32.0/22 +202.89.8.0/21 +202.89.96.0/22 +202.89.108.0/22 +202.89.119.0/24 +202.89.232.0/21 +202.90.16.0/22 +202.90.20.0/22 +202.90.24.0/22 +202.90.28.0/22 +202.90.37.0/24 +202.90.96.0/22 +202.90.100.0/22 +202.90.104.0/22 +202.90.108.0/22 +202.90.112.0/20 +202.90.193.0/24 +202.90.196.0/24 +202.90.205.0/24 +202.90.224.0/21 +202.90.232.0/21 +202.91.0.0/22 +202.91.96.0/20 +202.91.176.0/20 +202.91.224.0/19 +202.92.8.0/21 +202.92.48.0/20 +202.92.252.0/22 +202.93.252.0/22 +202.94.74.0/24 +202.94.81.0/24 +202.94.92.0/22 +202.95.240.0/21 +202.96.0.0/18 +202.96.64.0/21 +202.96.72.0/21 +202.96.80.0/20 +202.96.96.0/21 +202.96.104.0/21 +202.96.112.0/20 +202.96.128.0/21 +202.96.136.0/21 +202.96.144.0/20 +202.96.160.0/21 +202.96.168.0/21 +202.96.176.0/20 +202.96.192.0/21 +202.96.200.0/21 +202.96.208.0/20 +202.96.224.0/21 +202.96.232.0/21 +202.96.240.0/20 +202.97.0.0/21 +202.97.8.0/21 +202.97.16.0/20 +202.97.32.0/19 +202.97.64.0/19 +202.97.96.0/20 +202.97.112.0/20 +202.97.128.0/18 +202.97.192.0/19 +202.97.224.0/21 +202.97.232.0/21 +202.97.240.0/20 +202.98.0.0/21 +202.98.8.0/21 +202.98.16.0/20 +202.98.32.0/21 +202.98.40.0/21 +202.98.48.0/20 +202.98.64.0/19 +202.98.96.0/21 +202.98.104.0/21 +202.98.112.0/20 +202.98.128.0/19 +202.98.160.0/21 +202.98.168.0/21 +202.98.176.0/20 +202.98.192.0/21 +202.98.200.0/21 +202.98.208.0/20 +202.98.224.0/21 +202.98.232.0/21 +202.98.240.0/20 +202.99.0.0/18 +202.99.64.0/19 +202.99.96.0/21 +202.99.104.0/21 +202.99.112.0/20 +202.99.128.0/19 +202.99.160.0/21 +202.99.168.0/21 +202.99.176.0/20 +202.99.192.0/21 +202.99.200.0/21 +202.99.208.0/20 +202.99.224.0/21 +202.99.232.0/21 +202.99.240.0/20 +202.100.0.0/21 +202.100.8.0/21 +202.100.16.0/20 +202.100.32.0/19 +202.100.64.0/21 +202.100.72.0/21 +202.100.80.0/20 +202.100.96.0/21 +202.100.104.0/21 +202.100.112.0/20 +202.100.128.0/21 +202.100.136.0/21 +202.100.144.0/20 +202.100.160.0/21 +202.100.168.0/21 +202.100.176.0/20 +202.100.192.0/21 +202.100.200.0/21 +202.100.208.0/20 +202.100.224.0/19 +202.101.0.0/18 +202.101.64.0/19 +202.101.96.0/19 +202.101.128.0/18 +202.101.192.0/19 +202.101.224.0/21 +202.101.232.0/21 +202.101.240.0/20 +202.102.0.0/19 +202.102.32.0/19 +202.102.64.0/18 +202.102.128.0/21 +202.102.136.0/21 +202.102.144.0/20 +202.102.160.0/19 +202.102.192.0/21 +202.102.200.0/21 +202.102.208.0/20 +202.102.224.0/21 +202.102.232.0/21 +202.102.240.0/20 +202.103.0.0/21 +202.103.8.0/21 +202.103.16.0/20 +202.103.32.0/19 +202.103.64.0/19 +202.103.96.0/21 +202.103.104.0/21 +202.103.112.0/20 +202.103.128.0/18 +202.103.192.0/19 +202.103.224.0/21 +202.103.232.0/21 +202.103.240.0/20 +202.104.0.0/15 +202.106.0.0/16 +202.107.0.0/17 +202.107.128.0/17 +202.108.0.0/16 +202.109.0.0/16 +202.110.0.0/18 +202.110.64.0/18 +202.110.128.0/18 +202.110.192.0/18 +202.111.0.0/17 +202.111.128.0/19 +202.111.160.0/19 +202.111.192.0/18 +202.112.0.0/16 +202.113.0.0/20 +202.113.16.0/20 +202.113.32.0/19 +202.113.64.0/18 +202.113.128.0/18 +202.113.192.0/19 +202.113.224.0/20 +202.113.240.0/20 +202.114.0.0/19 +202.114.32.0/19 +202.114.64.0/18 +202.114.128.0/17 +202.115.0.0/19 +202.115.32.0/19 +202.115.64.0/18 +202.115.128.0/17 +202.116.0.0/19 +202.116.32.0/20 +202.116.48.0/20 +202.116.64.0/19 +202.116.96.0/19 +202.116.128.0/17 +202.117.0.0/18 +202.117.64.0/18 +202.117.128.0/17 +202.118.0.0/19 +202.118.32.0/19 +202.118.64.0/18 +202.118.128.0/17 +202.119.0.0/19 +202.119.32.0/19 +202.119.64.0/20 +202.119.80.0/20 +202.119.96.0/19 +202.119.128.0/17 +202.120.0.0/18 +202.120.64.0/18 +202.120.128.0/17 +202.121.0.0/16 +202.122.0.0/21 +202.122.32.0/21 +202.122.64.0/19 +202.122.112.0/21 +202.122.120.0/21 +202.122.132.0/24 +202.123.96.0/20 +202.123.116.0/22 +202.123.120.0/22 +202.124.16.0/21 +202.124.24.0/22 +202.125.107.0/24 +202.125.109.0/24 +202.125.112.0/20 +202.125.176.0/20 +202.127.0.0/23 +202.127.2.0/24 +202.127.3.0/24 +202.127.4.0/24 +202.127.5.0/24 +202.127.6.0/23 +202.127.12.0/22 +202.127.16.0/20 +202.127.40.0/21 +202.127.48.0/20 +202.127.112.0/20 +202.127.128.0/20 +202.127.144.0/20 +202.127.192.0/23 +202.127.194.0/23 +202.127.196.0/22 +202.127.200.0/21 +202.127.212.0/22 +202.127.216.0/21 +202.127.224.0/19 +202.129.208.0/24 +202.130.0.0/19 +202.130.39.0/24 +202.130.224.0/19 +202.131.16.0/21 +202.131.48.0/20 +202.131.208.0/20 +202.133.32.0/20 +202.134.58.0/24 +202.134.128.0/20 +202.134.208.0/22 +202.134.212.0/22 +202.134.216.0/22 +202.134.220.0/22 +202.136.48.0/20 +202.136.72.0/23 +202.136.80.0/23 +202.136.208.0/20 +202.136.224.0/20 +202.136.248.0/22 +202.137.231.0/24 +202.140.140.0/22 +202.140.144.0/22 +202.140.148.0/22 +202.140.152.0/22 +202.140.156.0/22 +202.141.160.0/19 +202.142.16.0/20 +202.143.4.0/22 +202.143.16.0/20 +202.143.32.0/20 +202.143.56.0/21 +202.143.100.0/22 +202.143.104.0/22 +202.144.196.0/22 +202.146.160.0/20 +202.146.184.0/23 +202.146.186.0/24 +202.146.188.0/22 +202.146.196.0/22 +202.146.200.0/21 +202.147.144.0/20 +202.148.32.0/20 +202.148.64.0/19 +202.148.96.0/19 +202.149.32.0/19 +202.149.160.0/19 +202.149.224.0/19 +202.150.16.0/20 +202.150.32.0/20 +202.150.56.0/22 +202.150.192.0/20 +202.150.224.0/19 +202.151.0.0/22 +202.151.33.0/24 +202.151.128.0/19 +202.152.176.0/20 +202.153.0.0/22 +202.153.7.0/24 +202.153.48.0/20 +202.157.192.0/19 +202.158.160.0/19 +202.158.242.0/24 +202.160.140.0/22 +202.160.156.0/22 +202.160.176.0/20 +202.162.67.0/24 +202.162.75.0/24 +202.164.0.0/20 +202.164.96.0/19 +202.165.176.0/20 +202.165.208.0/20 +202.165.239.0/24 +202.165.240.0/23 +202.165.243.0/24 +202.165.245.0/24 +202.165.251.0/24 +202.165.252.0/22 +202.166.224.0/19 +202.168.80.0/22 +202.168.128.0/22 +202.168.132.0/22 +202.168.136.0/22 +202.168.140.0/22 +202.168.160.0/20 +202.168.176.0/20 +202.170.128.0/19 +202.170.216.0/21 +202.170.224.0/19 +202.171.216.0/21 +202.171.232.0/24 +202.171.235.0/24 +202.172.0.0/22 +202.172.7.0/24 +202.173.0.0/22 +202.173.6.0/24 +202.173.8.0/21 +202.173.112.0/22 +202.173.224.0/19 +202.174.64.0/20 +202.174.124.0/22 +202.176.224.0/19 +202.179.160.0/22 +202.179.164.0/22 +202.179.168.0/22 +202.179.172.0/22 +202.179.240.0/20 +202.180.128.0/19 +202.180.208.0/21 +202.181.8.0/22 +202.181.28.0/22 +202.181.112.0/20 +202.182.32.0/20 +202.182.192.0/19 +202.189.0.0/18 +202.189.80.0/20 +202.189.184.0/21 +202.191.0.0/24 +202.191.68.0/22 +202.191.72.0/21 +202.191.80.0/20 +202.192.0.0/13 +202.200.0.0/14 +202.204.0.0/14 +203.0.4.0/22 +203.0.10.0/23 +203.0.18.0/24 +203.0.24.0/24 +203.0.42.0/23 +203.0.45.0/24 +203.0.46.0/23 +203.0.81.0/24 +203.0.82.0/23 +203.0.90.0/23 +203.0.96.0/23 +203.0.104.0/21 +203.0.114.0/23 +203.0.122.0/24 +203.0.128.0/24 +203.0.130.0/23 +203.0.132.0/22 +203.0.137.0/24 +203.0.142.0/24 +203.0.144.0/24 +203.0.146.0/24 +203.0.148.0/24 +203.0.150.0/23 +203.0.152.0/24 +203.0.177.0/24 +203.0.224.0/24 +203.1.4.0/22 +203.1.18.0/24 +203.1.26.0/23 +203.1.65.0/24 +203.1.66.0/23 +203.1.70.0/23 +203.1.76.0/23 +203.1.90.0/24 +203.1.97.0/24 +203.1.98.0/23 +203.1.100.0/22 +203.1.108.0/24 +203.1.253.0/24 +203.1.254.0/24 +203.2.64.0/21 +203.2.73.0/24 +203.2.112.0/21 +203.2.126.0/23 +203.2.140.0/24 +203.2.150.0/24 +203.2.152.0/22 +203.2.156.0/23 +203.2.160.0/21 +203.2.180.0/23 +203.2.196.0/23 +203.2.209.0/24 +203.2.214.0/23 +203.2.226.0/23 +203.2.229.0/24 +203.2.236.0/23 +203.3.68.0/24 +203.3.72.0/23 +203.3.75.0/24 +203.3.80.0/21 +203.3.96.0/22 +203.3.105.0/24 +203.3.112.0/21 +203.3.120.0/24 +203.3.123.0/24 +203.3.135.0/24 +203.3.139.0/24 +203.3.143.0/24 +203.4.132.0/23 +203.4.134.0/24 +203.4.151.0/24 +203.4.152.0/22 +203.4.174.0/23 +203.4.180.0/24 +203.4.186.0/24 +203.4.205.0/24 +203.4.208.0/22 +203.4.227.0/24 +203.4.230.0/23 +203.5.4.0/23 +203.5.7.0/24 +203.5.8.0/23 +203.5.11.0/24 +203.5.21.0/24 +203.5.22.0/24 +203.5.44.0/24 +203.5.46.0/23 +203.5.52.0/22 +203.5.56.0/23 +203.5.60.0/23 +203.5.114.0/23 +203.5.118.0/24 +203.5.120.0/24 +203.5.172.0/24 +203.5.180.0/23 +203.5.182.0/24 +203.5.185.0/24 +203.5.186.0/24 +203.5.188.0/23 +203.5.190.0/24 +203.5.195.0/24 +203.5.214.0/23 +203.5.218.0/23 +203.6.131.0/24 +203.6.136.0/24 +203.6.138.0/23 +203.6.142.0/24 +203.6.150.0/23 +203.6.157.0/24 +203.6.159.0/24 +203.6.224.0/20 +203.6.248.0/23 +203.7.129.0/24 +203.7.138.0/23 +203.7.147.0/24 +203.7.150.0/23 +203.7.158.0/24 +203.7.192.0/23 +203.7.200.0/24 +203.8.0.0/24 +203.8.8.0/24 +203.8.23.0/24 +203.8.70.0/24 +203.8.82.0/24 +203.8.86.0/23 +203.8.91.0/24 +203.8.110.0/23 +203.8.115.0/24 +203.8.166.0/23 +203.8.169.0/24 +203.8.173.0/24 +203.8.184.0/24 +203.8.186.0/23 +203.8.190.0/23 +203.8.192.0/24 +203.8.197.0/24 +203.8.198.0/23 +203.8.203.0/24 +203.8.209.0/24 +203.8.210.0/23 +203.8.212.0/22 +203.8.217.0/24 +203.8.220.0/24 +203.9.32.0/24 +203.9.36.0/23 +203.9.57.0/24 +203.9.63.0/24 +203.9.65.0/24 +203.9.70.0/23 +203.9.72.0/24 +203.9.75.0/24 +203.9.76.0/23 +203.9.96.0/22 +203.9.100.0/23 +203.9.108.0/24 +203.9.158.0/24 +203.10.34.0/24 +203.10.56.0/24 +203.10.74.0/23 +203.10.84.0/22 +203.10.88.0/24 +203.10.95.0/24 +203.10.125.0/24 +203.11.70.0/24 +203.11.76.0/22 +203.11.82.0/24 +203.11.84.0/22 +203.11.100.0/22 +203.11.109.0/24 +203.11.117.0/24 +203.11.122.0/24 +203.11.126.0/24 +203.11.136.0/22 +203.11.141.0/24 +203.11.142.0/23 +203.11.180.0/22 +203.11.208.0/22 +203.12.16.0/24 +203.12.19.0/24 +203.12.24.0/24 +203.12.57.0/24 +203.12.65.0/24 +203.12.66.0/24 +203.12.70.0/23 +203.12.87.0/24 +203.12.100.0/23 +203.12.103.0/24 +203.12.114.0/24 +203.12.118.0/24 +203.12.130.0/24 +203.12.137.0/24 +203.12.196.0/22 +203.12.211.0/24 +203.12.219.0/24 +203.12.226.0/24 +203.12.240.0/22 +203.13.18.0/24 +203.13.24.0/24 +203.13.44.0/23 +203.13.88.0/23 +203.13.92.0/22 +203.13.173.0/24 +203.13.224.0/23 +203.13.227.0/24 +203.13.233.0/24 +203.14.24.0/22 +203.14.33.0/24 +203.14.56.0/24 +203.14.61.0/24 +203.14.62.0/24 +203.14.104.0/24 +203.14.114.0/23 +203.14.118.0/24 +203.14.162.0/24 +203.14.192.0/24 +203.14.194.0/23 +203.14.214.0/24 +203.14.231.0/24 +203.14.246.0/24 +203.15.0.0/20 +203.15.20.0/23 +203.15.22.0/24 +203.15.87.0/24 +203.15.88.0/23 +203.15.105.0/24 +203.15.112.0/21 +203.15.130.0/23 +203.15.149.0/24 +203.15.151.0/24 +203.15.156.0/22 +203.15.174.0/24 +203.15.227.0/24 +203.15.232.0/21 +203.15.240.0/23 +203.15.246.0/24 +203.16.10.0/24 +203.16.12.0/23 +203.16.16.0/21 +203.16.27.0/24 +203.16.38.0/24 +203.16.49.0/24 +203.16.50.0/23 +203.16.58.0/24 +203.16.63.0/24 +203.16.133.0/24 +203.16.161.0/24 +203.16.162.0/24 +203.16.186.0/23 +203.16.228.0/24 +203.16.238.0/24 +203.16.240.0/24 +203.16.245.0/24 +203.17.2.0/24 +203.17.18.0/24 +203.17.28.0/24 +203.17.39.0/24 +203.17.56.0/24 +203.17.74.0/23 +203.17.88.0/23 +203.17.136.0/24 +203.17.164.0/24 +203.17.187.0/24 +203.17.190.0/23 +203.17.231.0/24 +203.17.233.0/24 +203.17.248.0/24 +203.17.249.0/24 +203.17.255.0/24 +203.18.2.0/23 +203.18.4.0/24 +203.18.7.0/24 +203.18.31.0/24 +203.18.37.0/24 +203.18.48.0/23 +203.18.52.0/24 +203.18.72.0/22 +203.18.80.0/23 +203.18.87.0/24 +203.18.100.0/23 +203.18.105.0/24 +203.18.107.0/24 +203.18.110.0/24 +203.18.129.0/24 +203.18.131.0/24 +203.18.132.0/23 +203.18.144.0/24 +203.18.153.0/24 +203.18.199.0/24 +203.18.208.0/24 +203.18.211.0/24 +203.18.215.0/24 +203.19.1.0/24 +203.19.18.0/24 +203.19.24.0/24 +203.19.30.0/24 +203.19.32.0/21 +203.19.41.0/24 +203.19.44.0/23 +203.19.46.0/24 +203.19.58.0/24 +203.19.60.0/23 +203.19.64.0/24 +203.19.68.0/24 +203.19.72.0/24 +203.19.101.0/24 +203.19.111.0/24 +203.19.131.0/24 +203.19.133.0/24 +203.19.144.0/24 +203.19.147.0/24 +203.19.149.0/24 +203.19.156.0/24 +203.19.176.0/24 +203.19.178.0/23 +203.19.208.0/24 +203.19.228.0/22 +203.19.233.0/24 +203.19.242.0/24 +203.19.248.0/23 +203.19.255.0/24 +203.20.17.0/24 +203.20.40.0/23 +203.20.44.0/24 +203.20.48.0/24 +203.20.61.0/24 +203.20.65.0/24 +203.20.84.0/23 +203.20.89.0/24 +203.20.106.0/23 +203.20.115.0/24 +203.20.117.0/24 +203.20.118.0/23 +203.20.122.0/24 +203.20.126.0/23 +203.20.135.0/24 +203.20.136.0/21 +203.20.150.0/24 +203.20.230.0/24 +203.20.232.0/24 +203.20.236.0/24 +203.21.0.0/23 +203.21.2.0/24 +203.21.8.0/24 +203.21.10.0/24 +203.21.18.0/24 +203.21.33.0/24 +203.21.34.0/24 +203.21.41.0/24 +203.21.44.0/24 +203.21.68.0/24 +203.21.82.0/24 +203.21.96.0/22 +203.21.124.0/24 +203.21.136.0/23 +203.21.145.0/24 +203.21.206.0/24 +203.22.24.0/24 +203.22.28.0/23 +203.22.31.0/24 +203.22.68.0/24 +203.22.76.0/24 +203.22.78.0/24 +203.22.84.0/24 +203.22.87.0/24 +203.22.92.0/22 +203.22.99.0/24 +203.22.106.0/24 +203.22.122.0/23 +203.22.131.0/24 +203.22.163.0/24 +203.22.166.0/24 +203.22.170.0/24 +203.22.176.0/21 +203.22.194.0/24 +203.22.242.0/23 +203.22.245.0/24 +203.22.246.0/24 +203.22.252.0/23 +203.23.0.0/24 +203.23.47.0/24 +203.23.61.0/24 +203.23.62.0/23 +203.23.73.0/24 +203.23.85.0/24 +203.23.92.0/22 +203.23.98.0/24 +203.23.107.0/24 +203.23.112.0/24 +203.23.130.0/24 +203.23.140.0/23 +203.23.172.0/24 +203.23.182.0/24 +203.23.186.0/23 +203.23.192.0/24 +203.23.197.0/24 +203.23.198.0/24 +203.23.204.0/22 +203.23.224.0/24 +203.23.226.0/23 +203.23.228.0/22 +203.23.249.0/24 +203.23.251.0/24 +203.24.13.0/24 +203.24.18.0/24 +203.24.27.0/24 +203.24.43.0/24 +203.24.56.0/24 +203.24.58.0/24 +203.24.67.0/24 +203.24.74.0/24 +203.24.79.0/24 +203.24.80.0/23 +203.24.84.0/23 +203.24.86.0/24 +203.24.90.0/24 +203.24.111.0/24 +203.24.112.0/24 +203.24.116.0/24 +203.24.122.0/23 +203.24.145.0/24 +203.24.152.0/23 +203.24.157.0/24 +203.24.161.0/24 +203.24.167.0/24 +203.24.186.0/23 +203.24.199.0/24 +203.24.202.0/24 +203.24.212.0/23 +203.24.217.0/24 +203.24.219.0/24 +203.24.244.0/24 +203.25.19.0/24 +203.25.20.0/23 +203.25.46.0/24 +203.25.48.0/21 +203.25.64.0/23 +203.25.91.0/24 +203.25.99.0/24 +203.25.100.0/24 +203.25.106.0/24 +203.25.131.0/24 +203.25.135.0/24 +203.25.138.0/24 +203.25.147.0/24 +203.25.153.0/24 +203.25.154.0/23 +203.25.164.0/24 +203.25.166.0/24 +203.25.174.0/23 +203.25.180.0/24 +203.25.182.0/24 +203.25.191.0/24 +203.25.199.0/24 +203.25.200.0/24 +203.25.202.0/23 +203.25.208.0/20 +203.25.229.0/24 +203.25.235.0/24 +203.25.236.0/24 +203.25.242.0/24 +203.26.12.0/24 +203.26.34.0/24 +203.26.49.0/24 +203.26.50.0/24 +203.26.55.0/24 +203.26.56.0/23 +203.26.60.0/24 +203.26.65.0/24 +203.26.68.0/24 +203.26.76.0/24 +203.26.80.0/24 +203.26.84.0/24 +203.26.97.0/24 +203.26.102.0/23 +203.26.115.0/24 +203.26.116.0/24 +203.26.129.0/24 +203.26.143.0/24 +203.26.144.0/24 +203.26.148.0/23 +203.26.154.0/24 +203.26.158.0/23 +203.26.170.0/24 +203.26.173.0/24 +203.26.176.0/24 +203.26.185.0/24 +203.26.202.0/23 +203.26.210.0/24 +203.26.214.0/24 +203.26.222.0/24 +203.26.224.0/24 +203.26.228.0/24 +203.26.232.0/24 +203.27.0.0/24 +203.27.10.0/24 +203.27.15.0/24 +203.27.16.0/24 +203.27.20.0/24 +203.27.22.0/23 +203.27.40.0/24 +203.27.45.0/24 +203.27.53.0/24 +203.27.65.0/24 +203.27.66.0/24 +203.27.81.0/24 +203.27.88.0/24 +203.27.102.0/24 +203.27.109.0/24 +203.27.117.0/24 +203.27.121.0/24 +203.27.122.0/23 +203.27.125.0/24 +203.27.200.0/24 +203.27.202.0/24 +203.27.233.0/24 +203.27.241.0/24 +203.27.250.0/24 +203.28.10.0/24 +203.28.12.0/24 +203.28.33.0/24 +203.28.34.0/23 +203.28.43.0/24 +203.28.44.0/24 +203.28.54.0/24 +203.28.56.0/24 +203.28.73.0/24 +203.28.74.0/24 +203.28.76.0/24 +203.28.86.0/24 +203.28.88.0/24 +203.28.112.0/24 +203.28.131.0/24 +203.28.136.0/24 +203.28.140.0/24 +203.28.145.0/24 +203.28.165.0/24 +203.28.169.0/24 +203.28.170.0/24 +203.28.178.0/23 +203.28.185.0/24 +203.28.187.0/24 +203.28.196.0/24 +203.28.226.0/23 +203.28.239.0/24 +203.29.2.0/24 +203.29.8.0/23 +203.29.13.0/24 +203.29.14.0/24 +203.29.28.0/24 +203.29.46.0/24 +203.29.57.0/24 +203.29.61.0/24 +203.29.63.0/24 +203.29.69.0/24 +203.29.73.0/24 +203.29.81.0/24 +203.29.90.0/24 +203.29.95.0/24 +203.29.100.0/24 +203.29.103.0/24 +203.29.112.0/24 +203.29.120.0/22 +203.29.182.0/23 +203.29.187.0/24 +203.29.189.0/24 +203.29.190.0/24 +203.29.205.0/24 +203.29.210.0/24 +203.29.217.0/24 +203.29.227.0/24 +203.29.231.0/24 +203.29.233.0/24 +203.29.234.0/24 +203.29.248.0/24 +203.29.254.0/23 +203.30.16.0/23 +203.30.25.0/24 +203.30.27.0/24 +203.30.29.0/24 +203.30.66.0/24 +203.30.81.0/24 +203.30.87.0/24 +203.30.111.0/24 +203.30.121.0/24 +203.30.123.0/24 +203.30.152.0/24 +203.30.156.0/24 +203.30.162.0/24 +203.30.173.0/24 +203.30.175.0/24 +203.30.187.0/24 +203.30.194.0/24 +203.30.217.0/24 +203.30.220.0/24 +203.30.222.0/24 +203.30.232.0/23 +203.30.235.0/24 +203.30.240.0/23 +203.30.246.0/24 +203.30.250.0/23 +203.31.45.0/24 +203.31.46.0/24 +203.31.49.0/24 +203.31.51.0/24 +203.31.54.0/23 +203.31.69.0/24 +203.31.72.0/24 +203.31.80.0/24 +203.31.85.0/24 +203.31.97.0/24 +203.31.105.0/24 +203.31.106.0/24 +203.31.108.0/23 +203.31.124.0/24 +203.31.162.0/24 +203.31.174.0/24 +203.31.177.0/24 +203.31.181.0/24 +203.31.187.0/24 +203.31.189.0/24 +203.31.204.0/24 +203.31.220.0/24 +203.31.222.0/23 +203.31.225.0/24 +203.31.229.0/24 +203.31.248.0/23 +203.31.253.0/24 +203.32.20.0/24 +203.32.48.0/23 +203.32.56.0/24 +203.32.60.0/24 +203.32.62.0/24 +203.32.68.0/23 +203.32.76.0/24 +203.32.81.0/24 +203.32.84.0/23 +203.32.95.0/24 +203.32.102.0/24 +203.32.105.0/24 +203.32.130.0/24 +203.32.133.0/24 +203.32.140.0/24 +203.32.152.0/24 +203.32.186.0/23 +203.32.192.0/24 +203.32.196.0/24 +203.32.203.0/24 +203.32.204.0/23 +203.32.212.0/24 +203.33.4.0/24 +203.33.7.0/24 +203.33.8.0/21 +203.33.21.0/24 +203.33.26.0/24 +203.33.32.0/24 +203.33.63.0/24 +203.33.64.0/24 +203.33.67.0/24 +203.33.68.0/24 +203.33.73.0/24 +203.33.79.0/24 +203.33.100.0/24 +203.33.122.0/24 +203.33.129.0/24 +203.33.131.0/24 +203.33.145.0/24 +203.33.156.0/24 +203.33.158.0/23 +203.33.174.0/24 +203.33.185.0/24 +203.33.200.0/24 +203.33.202.0/23 +203.33.204.0/24 +203.33.206.0/23 +203.33.214.0/23 +203.33.224.0/23 +203.33.226.0/24 +203.33.233.0/24 +203.33.243.0/24 +203.33.250.0/24 +203.34.4.0/24 +203.34.21.0/24 +203.34.27.0/24 +203.34.39.0/24 +203.34.48.0/23 +203.34.54.0/24 +203.34.56.0/23 +203.34.67.0/24 +203.34.69.0/24 +203.34.76.0/24 +203.34.92.0/24 +203.34.106.0/24 +203.34.113.0/24 +203.34.147.0/24 +203.34.150.0/24 +203.34.152.0/23 +203.34.161.0/24 +203.34.162.0/24 +203.34.187.0/24 +203.34.192.0/21 +203.34.204.0/22 +203.34.232.0/24 +203.34.240.0/24 +203.34.242.0/24 +203.34.245.0/24 +203.34.251.0/24 +203.55.2.0/23 +203.55.4.0/24 +203.55.10.0/24 +203.55.13.0/24 +203.55.22.0/24 +203.55.30.0/24 +203.55.93.0/24 +203.55.101.0/24 +203.55.109.0/24 +203.55.110.0/24 +203.55.116.0/23 +203.55.119.0/24 +203.55.128.0/23 +203.55.146.0/23 +203.55.192.0/24 +203.55.196.0/24 +203.55.218.0/23 +203.55.221.0/24 +203.55.224.0/24 +203.56.1.0/24 +203.56.4.0/24 +203.56.12.0/24 +203.56.24.0/24 +203.56.38.0/24 +203.56.40.0/24 +203.56.46.0/24 +203.56.48.0/21 +203.56.68.0/23 +203.56.82.0/23 +203.56.84.0/23 +203.56.95.0/24 +203.56.110.0/24 +203.56.121.0/24 +203.56.161.0/24 +203.56.169.0/24 +203.56.172.0/23 +203.56.175.0/24 +203.56.183.0/24 +203.56.185.0/24 +203.56.187.0/24 +203.56.192.0/24 +203.56.198.0/24 +203.56.201.0/24 +203.56.208.0/23 +203.56.210.0/24 +203.56.214.0/24 +203.56.216.0/24 +203.56.227.0/24 +203.56.228.0/24 +203.56.231.0/24 +203.56.232.0/24 +203.56.240.0/24 +203.56.252.0/24 +203.56.254.0/24 +203.57.5.0/24 +203.57.6.0/24 +203.57.12.0/23 +203.57.28.0/24 +203.57.39.0/24 +203.57.46.0/24 +203.57.58.0/24 +203.57.61.0/24 +203.57.66.0/24 +203.57.69.0/24 +203.57.70.0/23 +203.57.73.0/24 +203.57.90.0/24 +203.57.101.0/24 +203.57.109.0/24 +203.57.123.0/24 +203.57.157.0/24 +203.57.200.0/24 +203.57.202.0/24 +203.57.206.0/24 +203.57.222.0/24 +203.57.224.0/20 +203.57.246.0/23 +203.57.249.0/24 +203.57.253.0/24 +203.57.254.0/23 +203.62.2.0/24 +203.62.131.0/24 +203.62.139.0/24 +203.62.161.0/24 +203.62.197.0/24 +203.62.228.0/22 +203.62.234.0/24 +203.62.246.0/24 +203.76.160.0/22 +203.76.168.0/22 +203.76.208.0/22 +203.76.212.0/22 +203.76.216.0/22 +203.76.240.0/22 +203.76.244.0/22 +203.77.180.0/22 +203.78.48.0/20 +203.78.156.0/22 +203.79.0.0/20 +203.79.32.0/20 +203.80.4.0/23 +203.80.32.0/20 +203.80.57.0/24 +203.80.129.0/24 +203.80.132.0/22 +203.80.136.0/21 +203.80.144.0/20 +203.81.0.0/21 +203.81.16.0/20 +203.81.244.0/22 +203.82.0.0/23 +203.82.16.0/21 +203.82.112.0/22 +203.82.116.0/22 +203.82.120.0/22 +203.82.124.0/22 +203.82.224.0/22 +203.82.228.0/22 +203.82.232.0/22 +203.82.236.0/22 +203.83.0.0/22 +203.83.8.0/22 +203.83.12.0/22 +203.83.56.0/21 +203.83.224.0/20 +203.86.0.0/19 +203.86.32.0/19 +203.86.64.0/20 +203.86.80.0/20 +203.86.96.0/19 +203.86.250.0/24 +203.86.254.0/23 +203.88.32.0/19 +203.88.192.0/19 +203.89.8.0/21 +203.89.100.0/22 +203.89.133.0/24 +203.89.136.0/22 +203.89.144.0/24 +203.90.8.0/22 +203.90.12.0/22 +203.90.128.0/19 +203.90.160.0/19 +203.90.192.0/19 +203.91.32.0/19 +203.91.96.0/20 +203.91.120.0/21 +203.92.0.0/22 +203.92.6.0/24 +203.92.160.0/19 +203.93.0.0/22 +203.93.4.0/22 +203.93.8.0/24 +203.93.9.0/24 +203.93.10.0/23 +203.93.12.0/22 +203.93.16.0/20 +203.93.32.0/19 +203.93.64.0/18 +203.93.128.0/21 +203.93.136.0/22 +203.93.140.0/24 +203.93.141.0/24 +203.93.142.0/23 +203.93.144.0/20 +203.93.160.0/19 +203.93.192.0/18 +203.94.0.0/22 +203.94.4.0/22 +203.94.8.0/21 +203.94.16.0/20 +203.95.0.0/21 +203.95.96.0/20 +203.95.112.0/20 +203.95.128.0/18 +203.95.200.0/22 +203.95.204.0/22 +203.95.208.0/22 +203.95.224.0/19 +203.99.8.0/21 +203.99.16.0/20 +203.99.80.0/20 +203.100.32.0/20 +203.100.48.0/21 +203.100.58.0/24 +203.100.60.0/24 +203.100.63.0/24 +203.100.80.0/20 +203.100.96.0/19 +203.100.192.0/20 +203.104.32.0/20 +203.105.96.0/19 +203.105.128.0/19 +203.107.0.0/17 +203.110.160.0/19 +203.110.208.0/20 +203.110.232.0/23 +203.110.234.0/24 +203.114.80.0/22 +203.114.84.0/22 +203.114.88.0/22 +203.114.92.0/22 +203.114.244.0/22 +203.118.192.0/19 +203.118.241.0/24 +203.118.248.0/22 +203.119.24.0/21 +203.119.32.0/22 +203.119.80.0/22 +203.119.85.0/24 +203.119.113.0/24 +203.119.114.0/23 +203.119.116.0/22 +203.119.120.0/21 +203.119.128.0/17 +203.123.58.0/24 +203.128.32.0/19 +203.128.96.0/19 +203.128.224.0/21 +203.129.8.0/21 +203.130.32.0/19 +203.132.32.0/19 +203.134.240.0/21 +203.135.96.0/20 +203.135.112.0/20 +203.135.160.0/20 +203.142.219.0/24 +203.142.224.0/19 +203.144.96.0/19 +203.145.0.0/19 +203.148.0.0/18 +203.148.64.0/20 +203.148.80.0/22 +203.148.86.0/23 +203.149.92.0/22 +203.152.64.0/19 +203.152.128.0/19 +203.153.0.0/22 +203.156.192.0/18 +203.158.16.0/21 +203.160.52.0/22 +203.160.104.0/21 +203.160.129.0/24 +203.160.192.0/19 +203.161.0.0/22 +203.161.183.0/24 +203.161.192.0/19 +203.166.160.0/19 +203.167.28.0/22 +203.168.0.0/19 +203.170.58.0/23 +203.171.0.0/22 +203.171.208.0/24 +203.171.224.0/20 +203.174.4.0/24 +203.174.6.0/24 +203.174.7.0/24 +203.174.96.0/19 +203.175.128.0/19 +203.175.192.0/18 +203.176.0.0/18 +203.176.64.0/19 +203.176.168.0/21 +203.184.80.0/20 +203.185.189.0/24 +203.187.160.0/19 +203.189.0.0/23 +203.189.6.0/23 +203.189.112.0/22 +203.189.192.0/19 +203.189.240.0/22 +203.190.96.0/20 +203.190.249.0/24 +203.191.0.0/23 +203.191.2.0/24 +203.191.5.0/24 +203.191.7.0/24 +203.191.16.0/20 +203.191.64.0/18 +203.191.133.0/24 +203.191.144.0/21 +203.191.152.0/21 +203.192.0.0/19 +203.193.224.0/19 +203.194.120.0/21 +203.195.64.0/19 +203.195.112.0/21 +203.195.128.0/17 +203.196.0.0/21 +203.196.8.0/21 +203.196.28.0/22 +203.201.181.0/24 +203.201.182.0/24 +203.202.236.0/22 +203.205.64.0/19 +203.205.128.0/17 +203.207.64.0/20 +203.207.80.0/21 +203.207.88.0/22 +203.207.92.0/22 +203.207.96.0/20 +203.207.112.0/20 +203.207.128.0/18 +203.207.192.0/21 +203.207.200.0/21 +203.207.208.0/20 +203.207.224.0/19 +203.208.32.0/19 +203.209.224.0/19 +203.212.0.0/20 +203.212.80.0/20 +203.215.232.0/21 +203.217.164.0/22 +203.223.16.0/21 +204.52.191.0/24 +210.2.0.0/20 +210.2.16.0/20 +210.5.0.0/19 +210.5.56.0/21 +210.5.128.0/20 +210.5.144.0/20 +210.7.56.0/22 +210.7.60.0/22 +210.12.0.0/18 +210.12.64.0/18 +210.12.128.0/18 +210.12.192.0/18 +210.13.0.0/18 +210.13.64.0/18 +210.13.128.0/17 +210.14.64.0/19 +210.14.112.0/20 +210.14.128.0/19 +210.14.160.0/19 +210.14.192.0/19 +210.14.224.0/19 +210.15.0.0/19 +210.15.32.0/19 +210.15.64.0/19 +210.15.96.0/19 +210.15.128.0/18 +210.16.104.0/22 +210.16.128.0/18 +210.21.0.0/17 +210.21.128.0/17 +210.22.0.0/16 +210.23.32.0/19 +210.25.0.0/16 +210.26.0.0/15 +210.28.0.0/14 +210.32.0.0/14 +210.36.0.0/14 +210.40.0.0/13 +210.51.0.0/16 +210.52.0.0/18 +210.52.64.0/18 +210.52.128.0/17 +210.53.0.0/17 +210.53.128.0/17 +210.56.192.0/19 +210.72.0.0/17 +210.72.128.0/19 +210.72.160.0/19 +210.72.192.0/18 +210.73.0.0/19 +210.73.32.0/19 +210.73.64.0/18 +210.73.128.0/17 +210.74.0.0/19 +210.74.32.0/19 +210.74.64.0/19 +210.74.96.0/19 +210.74.128.0/19 +210.74.160.0/19 +210.74.192.0/18 +210.75.0.0/17 +210.75.128.0/19 +210.75.160.0/19 +210.75.192.0/19 +210.75.224.0/19 +210.76.0.0/19 +210.76.32.0/19 +210.76.64.0/18 +210.76.128.0/18 +210.76.192.0/19 +210.76.224.0/19 +210.77.0.0/19 +210.77.32.0/19 +210.77.64.0/19 +210.77.96.0/19 +210.77.128.0/17 +210.78.0.0/19 +210.78.32.0/19 +210.78.64.0/18 +210.78.128.0/19 +210.78.160.0/19 +210.78.192.0/18 +210.79.64.0/18 +210.79.224.0/19 +210.82.0.0/15 +210.87.72.0/23 +210.87.114.0/23 +210.87.128.0/20 +210.87.144.0/20 +210.87.160.0/19 +210.185.192.0/18 +210.192.96.0/19 +211.64.0.0/14 +211.68.0.0/15 +211.70.0.0/15 +211.80.0.0/16 +211.81.0.0/16 +211.82.0.0/16 +211.83.0.0/16 +211.84.0.0/15 +211.86.0.0/15 +211.88.0.0/16 +211.89.0.0/16 +211.90.0.0/15 +211.92.0.0/15 +211.94.0.0/15 +211.96.0.0/15 +211.98.0.0/16 +211.99.0.0/18 +211.99.64.0/19 +211.99.96.0/19 +211.99.128.0/17 +211.100.0.0/16 +211.101.0.0/18 +211.101.64.0/18 +211.101.128.0/17 +211.102.0.0/16 +211.103.0.0/17 +211.103.128.0/17 +211.136.0.0/14 +211.140.0.0/15 +211.142.0.0/17 +211.142.128.0/17 +211.143.0.0/16 +211.144.0.0/15 +211.146.0.0/16 +211.147.0.0/17 +211.147.128.0/18 +211.147.192.0/20 +211.147.208.0/20 +211.147.224.0/19 +211.148.0.0/14 +211.152.0.0/15 +211.154.0.0/16 +211.155.0.0/18 +211.155.64.0/19 +211.155.96.0/19 +211.155.128.0/17 +211.156.0.0/18 +211.156.64.0/20 +211.156.80.0/20 +211.156.96.0/19 +211.156.128.0/19 +211.156.160.0/20 +211.156.176.0/20 +211.156.192.0/18 +211.157.0.0/16 +211.158.0.0/15 +211.160.0.0/14 +211.164.0.0/15 +211.166.0.0/16 +211.167.0.0/17 +211.167.128.0/19 +211.167.160.0/20 +211.167.176.0/20 +211.167.192.0/18 +212.64.0.0/17 +212.129.128.0/17 +218.0.0.0/16 +218.1.0.0/16 +218.2.0.0/15 +218.4.0.0/15 +218.6.0.0/16 +218.7.0.0/16 +218.8.0.0/15 +218.10.0.0/16 +218.11.0.0/16 +218.12.0.0/16 +218.13.0.0/16 +218.14.0.0/15 +218.16.0.0/14 +218.20.0.0/16 +218.21.0.0/17 +218.21.128.0/17 +218.22.0.0/15 +218.24.0.0/15 +218.26.0.0/16 +218.27.0.0/16 +218.28.0.0/15 +218.30.0.0/15 +218.56.0.0/14 +218.60.0.0/15 +218.62.0.0/17 +218.62.128.0/17 +218.63.0.0/16 +218.64.0.0/15 +218.66.0.0/16 +218.67.0.0/17 +218.67.128.0/17 +218.68.0.0/15 +218.70.0.0/15 +218.72.0.0/14 +218.76.0.0/15 +218.78.0.0/15 +218.80.0.0/14 +218.84.0.0/14 +218.88.0.0/13 +218.96.0.0/15 +218.98.0.0/17 +218.98.128.0/18 +218.98.192.0/19 +218.98.224.0/19 +218.99.0.0/16 +218.100.88.0/21 +218.100.96.0/19 +218.100.128.0/17 +218.104.0.0/17 +218.104.128.0/19 +218.104.160.0/19 +218.104.192.0/21 +218.104.200.0/21 +218.104.208.0/20 +218.104.224.0/19 +218.105.0.0/16 +218.106.0.0/15 +218.108.0.0/16 +218.109.0.0/16 +218.185.192.0/19 +218.185.240.0/21 +218.192.0.0/16 +218.193.0.0/16 +218.194.0.0/16 +218.195.0.0/16 +218.196.0.0/14 +218.200.0.0/14 +218.204.0.0/15 +218.206.0.0/15 +218.240.0.0/14 +218.244.0.0/18 +218.244.64.0/19 +218.244.96.0/19 +218.244.128.0/17 +218.245.0.0/16 +218.246.0.0/15 +218.249.0.0/16 +219.72.0.0/16 +219.82.0.0/16 +219.83.128.0/17 +219.90.68.0/22 +219.90.72.0/22 +219.90.76.0/22 +219.128.0.0/12 +219.144.0.0/14 +219.148.0.0/16 +219.149.0.0/17 +219.149.128.0/18 +219.149.192.0/18 +219.150.0.0/19 +219.150.32.0/19 +219.150.64.0/19 +219.150.96.0/20 +219.150.112.0/20 +219.150.128.0/17 +219.151.0.0/19 +219.151.32.0/19 +219.151.64.0/18 +219.151.128.0/17 +219.152.0.0/15 +219.154.0.0/15 +219.156.0.0/15 +219.158.0.0/17 +219.158.128.0/17 +219.159.0.0/18 +219.159.64.0/18 +219.159.128.0/17 +219.216.0.0/15 +219.218.0.0/15 +219.220.0.0/16 +219.221.0.0/16 +219.222.0.0/15 +219.224.0.0/15 +219.226.0.0/16 +219.227.0.0/16 +219.228.0.0/15 +219.230.0.0/15 +219.232.0.0/14 +219.236.0.0/15 +219.238.0.0/15 +219.242.0.0/15 +219.244.0.0/14 +220.101.192.0/18 +220.112.0.0/14 +220.152.128.0/17 +220.154.0.0/16 +220.155.0.0/16 +220.158.240.0/22 +220.160.0.0/11 +220.192.0.0/15 +220.194.0.0/15 +220.196.0.0/14 +220.200.0.0/13 +220.231.0.0/18 +220.231.128.0/17 +220.232.64.0/18 +220.234.0.0/16 +220.242.0.0/15 +220.247.136.0/21 +220.248.0.0/14 +220.252.0.0/16 +221.0.0.0/15 +221.2.0.0/16 +221.3.0.0/17 +221.3.128.0/17 +221.4.0.0/16 +221.5.0.0/17 +221.5.128.0/17 +221.6.0.0/16 +221.7.0.0/19 +221.7.32.0/19 +221.7.64.0/19 +221.7.96.0/19 +221.7.128.0/17 +221.8.0.0/15 +221.10.0.0/16 +221.11.0.0/17 +221.11.128.0/18 +221.11.192.0/19 +221.11.224.0/19 +221.12.0.0/17 +221.12.128.0/18 +221.13.0.0/18 +221.13.64.0/19 +221.13.96.0/19 +221.13.128.0/17 +221.14.0.0/15 +221.122.0.0/15 +221.128.128.0/17 +221.129.0.0/16 +221.130.0.0/15 +221.133.224.0/19 +221.136.0.0/16 +221.137.0.0/16 +221.172.0.0/14 +221.176.0.0/13 +221.192.0.0/15 +221.194.0.0/16 +221.195.0.0/16 +221.196.0.0/15 +221.198.0.0/16 +221.199.0.0/19 +221.199.32.0/20 +221.199.48.0/20 +221.199.64.0/18 +221.199.128.0/18 +221.199.192.0/20 +221.199.224.0/19 +221.200.0.0/14 +221.204.0.0/15 +221.206.0.0/16 +221.207.0.0/18 +221.207.64.0/18 +221.207.128.0/17 +221.208.0.0/14 +221.212.0.0/16 +221.213.0.0/16 +221.214.0.0/15 +221.216.0.0/13 +221.224.0.0/13 +221.232.0.0/14 +221.236.0.0/15 +221.238.0.0/16 +221.239.0.0/17 +221.239.128.0/17 +222.16.0.0/15 +222.18.0.0/15 +222.20.0.0/15 +222.22.0.0/16 +222.23.0.0/16 +222.24.0.0/15 +222.26.0.0/15 +222.28.0.0/14 +222.32.0.0/11 +222.64.0.0/13 +222.72.0.0/15 +222.74.0.0/16 +222.75.0.0/16 +222.76.0.0/14 +222.80.0.0/15 +222.82.0.0/16 +222.83.0.0/17 +222.83.128.0/17 +222.84.0.0/16 +222.85.0.0/17 +222.85.128.0/17 +222.86.0.0/15 +222.88.0.0/15 +222.90.0.0/15 +222.92.0.0/14 +222.125.0.0/16 +222.126.128.0/17 +222.128.0.0/14 +222.132.0.0/14 +222.136.0.0/13 +222.160.0.0/15 +222.162.0.0/16 +222.163.0.0/19 +222.163.32.0/19 +222.163.64.0/18 +222.163.128.0/17 +222.168.0.0/15 +222.170.0.0/15 +222.172.0.0/17 +222.172.128.0/17 +222.173.0.0/16 +222.174.0.0/15 +222.176.0.0/13 +222.184.0.0/13 +222.192.0.0/14 +222.196.0.0/15 +222.198.0.0/16 +222.199.0.0/16 +222.200.0.0/14 +222.204.0.0/15 +222.206.0.0/15 +222.208.0.0/13 +222.216.0.0/15 +222.218.0.0/16 +222.219.0.0/16 +222.220.0.0/15 +222.222.0.0/15 +222.240.0.0/13 +222.248.0.0/16 +222.249.0.0/17 +222.249.128.0/19 +222.249.160.0/20 +222.249.176.0/20 +222.249.192.0/18 +223.0.0.0/15 +223.2.0.0/15 +223.4.0.0/14 +223.8.0.0/13 +223.20.0.0/15 +223.27.184.0/22 +223.29.208.0/22 +223.29.252.0/22 +223.64.0.0/11 +223.96.0.0/12 +223.112.0.0/14 +223.116.0.0/15 +223.120.128.0/17 +223.121.128.0/17 +223.123.208.0/20 +223.123.224.0/19 +223.124.0.0/14 +223.128.0.0/15 +223.144.0.0/12 +223.160.0.0/14 +223.166.0.0/15 +223.192.0.0/15 +223.198.0.0/15 +223.201.0.0/16 +223.202.0.0/15 +223.208.0.0/14 +223.212.0.0/15 +223.214.0.0/15 +223.220.0.0/15 +223.223.176.0/21 +223.223.184.0/21 +223.223.192.0/20 +223.240.0.0/13 +223.248.0.0/14 +223.252.128.0/17 +223.254.0.0/16 +223.255.0.0/17 +223.255.236.0/22 +223.255.252.0/23 diff --git a/luci-app-flowproxy/root/usr/share/flowproxy/generate_nft.sh b/luci-app-flowproxy/root/usr/share/flowproxy/generate_nft.sh new file mode 100755 index 000000000..dcf0e1f18 --- /dev/null +++ b/luci-app-flowproxy/root/usr/share/flowproxy/generate_nft.sh @@ -0,0 +1,215 @@ +#!/bin/sh +# Generate nftables configuration for flowproxy + +. /lib/functions.sh + +[ -n "$UCI_CONFIG_DIR" ] && export UCI_CONFIG_DIR + +CONFIG="flowproxy" +NFT_TABLE="flowproxy" +OUTPUT_FILE="/tmp/flowproxy/nft.conf" + +mkdir -p "$(dirname "$OUTPUT_FILE")" + +ENABLED_SETS=" " + +log_debug() { + [ "$FLOWPROXY_LOG_LEVEL" = "debug" ] && echo "DEBUG: $*" >&2 +} + +gen_set_definition() { + local section="$1" + local type enabled auto_gen file_path elems is_interval + + enabled=$(uci -q get "$CONFIG.$section.enabled") + [ "$enabled" = "0" ] && { log_debug "Set $section is disabled, skipping"; return; } + + log_debug "Generating set: $section" + ENABLED_SETS="${ENABLED_SETS}@${section} " + type=$(uci -q get "$CONFIG.$section.type") + [ -z "$type" ] && type="ipv4_addr" + + if [ "$section" = "private_dst_ip_v4" ]; then + auto_gen=$(uci -q get "$CONFIG.$section.auto_generate") + if [ "$auto_gen" = "1" ] || [ -z "$auto_gen" ]; then + elems="10.0.0.0/8, 127.0.0.0/8, 169.254.0.0/16, 172.16.0.0/12, 192.168.0.0/16" + fi + fi + + local uci_elems="" + for e in $(uci -q get "$CONFIG.$section.elements"); do + [ -n "$uci_elems" ] && uci_elems="${uci_elems}, " + uci_elems="${uci_elems}${e}" + done + [ -n "$uci_elems" ] && { [ -n "$elems" ] && elems="${elems}, "; elems="${elems}${uci_elems}"; } + + file_path=$(uci -q get "$CONFIG.$section.file_path") + download_url=$(uci -q get "$CONFIG.$section.download_url") + if [ -n "$download_url" ] && [ -n "$file_path" ]; then + if [ ! -f "$file_path" ]; then + echo "Downloading $section data from $download_url to $file_path..." >&2 + wget -q -O "$file_path" "$download_url" --timeout=10 --no-check-certificate + [ $? -ne 0 ] && { echo "Failed to download $section data" >&2; rm -f "$file_path"; } + fi + fi + + if [ -n "$file_path" ] && [ -f "$file_path" ]; then + local file_elems=$(get_file_elements "$file_path") + if [ -n "$file_elems" ]; then + [ -n "$elems" ] && elems="${elems}, " + elems="${elems}${file_elems}" + fi + fi + + case "$type" in "ipv4_addr"|"inet_service"|"ether_addr") is_interval=1 ;; *) is_interval=0 ;; esac + [ "$is_interval" = "0" ] && { case "$elems" in */*|*-*) is_interval=1 ;; esac; } + + printf "\tset %s {\n" "$section" + printf "\t\ttype %s\n" "$type" + [ "$is_interval" = "1" ] && printf "\t\tflags interval\n" + [ -n "$elems" ] && printf "\t\telements = { %s }\n" "$elems" + printf "\t}\n\n" +} + +get_file_elements() { + local file_path="$1" + [ ! -f "$file_path" ] && return + + if [ "$FLOWPROXY_PREVIEW" = "1" ]; then + local total=$(wc -l < "$file_path") + if [ "$total" -gt 100 ]; then + awk 'BEGIN { count=0 } + !/^($|#)/ { + if (count < 100) { + if (count > 0) { + printf ", " + if (count % 2 == 0) printf "\n\t\t\t " + } + printf "%s", $0 + count++ + } + } + END { printf ", ... (%d more items omitted for preview)", '"$total"'-100 }' "$file_path" + return + fi + fi + + awk 'BEGIN { count=0 } + !/^($|#)/ { + if (count > 0) { + printf ", " + if (count % 2 == 0) printf "\n\t\t\t " + } + printf "%s", $0 + count++ + } + END { print "" }' "$file_path" +} + +process_rule() { + local section="$1"; local proto="$2" + local enabled match_type match_value action counter + + enabled=$(uci -q get "$CONFIG.$section.enabled"); [ "$enabled" = "0" ] && { log_debug "Rule $section is disabled, skipping"; return; } + match_type=$(uci -q get "$CONFIG.$section.match_type") + [ -z "$match_type" ] && match_type="dst_ip" + match_value=$(uci -q get "$CONFIG.$section.match_value") + + log_debug "Processing $proto rule: $section ($match_type=$match_value)" + action=$(uci -q get "$CONFIG.$section.action"); [ -z "$action" ] && action="return" + counter=$(uci -q get "$CONFIG.$section.counter") + [ -z "$match_value" ] && return + + case "$match_value" in + @*) + local set_ref=$(echo "$match_value" | cut -d' ' -f1) + if ! echo "$ENABLED_SETS" | grep -q " ${set_ref} "; then + log_debug "Skipping rule $section: set ${set_ref} is not defined or disabled" + return + fi + ;; + esac + + match_value=$(echo "$match_value" | sed -E 's/ (return|accept|drop)$//g') + local segment="" + case "$match_type" in + src_mac) segment="ether saddr $match_value ip protocol $proto" ;; + src_ip) segment="ip saddr $match_value ip protocol $proto" ;; + dst_ip) segment="ip daddr $match_value ip protocol $proto" ;; + src_port) segment="ip protocol $proto $proto sport $match_value" ;; + dst_port) segment="ip protocol $proto $proto dport $match_value" ;; + *) segment="$match_value ip protocol $proto" ;; + esac + + local line="$segment"; [ "$counter" = "1" ] && line="$line counter"; line="$line $action" + [ -n "$line" ] && echo " $line" +} + +SECTIONS_SET=$(uci -q show "$CONFIG" | grep "=nftset" | cut -d'.' -f2 | cut -d'=' -f1) +SECTIONS_TCP=$(uci -q show "$CONFIG" | grep "=tcp_rule" | cut -d'.' -f2 | cut -d'=' -f1) +SECTIONS_UDP=$(uci -q show "$CONFIG" | grep "=udp_rule" | cut -d'.' -f2 | cut -d'=' -f1) + +if [ "$1" = "runtime" ]; then + TRAFFIC_MARK=$(uci -q get "$CONFIG.global.traffic_mark" || echo "0x666") + ROUTING_TABLE=$(uci -q get "$CONFIG.global.routing_table" || echo "888") + echo "--- [ nftables live rules ] ---" + nft list table inet "$CONFIG" 2>/dev/null | awk 'BEGIN { count=0; skip=0 } + /elements = \{/ { print $0; skip=1; next } + skip == 1 && /\}/ { printf "\t\t\t ... (items truncated for preview)\n"; print $0; skip=0; next } + skip == 1 { count++; if (count < 20) print $0; next } + { print $0 }' || echo "(table not found)" + echo "" + echo "--- [ ip rule list ] ---" + ip rule show 2>/dev/null + echo "" + echo "--- [ ip route table $ROUTING_TABLE ] ---" + ip route show table "$ROUTING_TABLE" 2>/dev/null || echo "(table empty)" + exit 0 +fi + +cat > "$OUTPUT_FILE" << EOF +#!/usr/sbin/nft -f +table inet $NFT_TABLE +flush table inet $NFT_TABLE + +table inet $NFT_TABLE { +EOF + +for s in $SECTIONS_SET; do + gen_set_definition "$s" >> "$OUTPUT_FILE" +done + +TCP_ENABLED=$(uci -q get "$CONFIG.global.tcp_enabled" || echo "1") +UDP_ENABLED=$(uci -q get "$CONFIG.global.udp_enabled" || echo "1") +TRAFFIC_MARK=$(uci -q get "$CONFIG.global.traffic_mark" || echo "0x666") +PROXY_SERVER_IP_ADDR=$(uci -q get "$CONFIG.global.proxy_server_ip_addr") + +if [ "$TCP_ENABLED" = "1" ]; then + cat >> "$OUTPUT_FILE" << EOF + chain LAN_MARKFLOW_TCP { + type filter hook prerouting priority mangle; policy accept; + fib daddr type { unspec, local, anycast, multicast } counter return +EOF + if [ -n "$PROXY_SERVER_IP_ADDR" ]; then + echo " ip saddr $PROXY_SERVER_IP_ADDR ip protocol tcp counter return" >> "$OUTPUT_FILE" + fi + for s in $SECTIONS_TCP; do process_rule "$s" "tcp" >> "$OUTPUT_FILE"; done + echo " ip protocol tcp counter meta mark set $TRAFFIC_MARK" >> "$OUTPUT_FILE" + echo " }" >> "$OUTPUT_FILE" +fi + +if [ "$UDP_ENABLED" = "1" ]; then + cat >> "$OUTPUT_FILE" << EOF + chain LAN_MARKFLOW_UDP { + type filter hook prerouting priority mangle; policy accept; + fib daddr type { unspec, local, anycast, multicast } counter return +EOF + if [ -n "$PROXY_SERVER_IP_ADDR" ]; then + echo " ip saddr $PROXY_SERVER_IP_ADDR ip protocol udp counter return" >> "$OUTPUT_FILE" + fi + for s in $SECTIONS_UDP; do process_rule "$s" "udp" >> "$OUTPUT_FILE"; done + echo " ip protocol udp counter meta mark set $TRAFFIC_MARK" >> "$OUTPUT_FILE" + echo " }" >> "$OUTPUT_FILE" +fi +echo "}" >> "$OUTPUT_FILE" +cat "$OUTPUT_FILE" diff --git a/luci-app-flowproxy/root/usr/share/luci/menu.d/luci-app-flowproxy.json b/luci-app-flowproxy/root/usr/share/luci/menu.d/luci-app-flowproxy.json new file mode 100644 index 000000000..eb7cf8d21 --- /dev/null +++ b/luci-app-flowproxy/root/usr/share/luci/menu.d/luci-app-flowproxy.json @@ -0,0 +1,11 @@ +{ + "admin/services/flowproxy": { + "title": "FlowProxy", + "description": "LuCI Support for FlowProxy Traffic Diversion", + "index": 50, + "action": { + "type": "view", + "path": "flowproxy/flowproxy" + } + } +} \ No newline at end of file diff --git a/luci-app-flowproxy/root/usr/share/rpcd/acl.d/luci-app-flowproxy.json b/luci-app-flowproxy/root/usr/share/rpcd/acl.d/luci-app-flowproxy.json new file mode 100644 index 000000000..c9d691f19 --- /dev/null +++ b/luci-app-flowproxy/root/usr/share/rpcd/acl.d/luci-app-flowproxy.json @@ -0,0 +1,26 @@ +{ + "luci-app-flowproxy": { + "description": "Grant access to flowproxy configuration", + "read": { + "uci": [ "flowproxy" ], + "file": { + "/usr/share/flowproxy/*": [ "read" ] + }, + "ubus": { + "luci.flowproxy": [ "*" ], + "network.interface": [ "dump" ] + } + }, + "write": { + "uci": [ "flowproxy" ], + "file": { + "/usr/bin/wget": [ "exec" ], + "/usr/bin/wc": [ "exec" ], + "/usr/share/flowproxy/generate_nft.sh": [ "exec" ] + }, + "ubus": { + "luci.flowproxy": [ "*" ] + } + } + } +} diff --git a/luci-app-flowproxy/root/usr/share/rpcd/ucode/luci.flowproxy b/luci-app-flowproxy/root/usr/share/rpcd/ucode/luci.flowproxy new file mode 100755 index 000000000..16893ce19 --- /dev/null +++ b/luci-app-flowproxy/root/usr/share/rpcd/ucode/luci.flowproxy @@ -0,0 +1,175 @@ +'use strict'; + +import { access, readfile, writefile, stat } from 'fs'; +import { cursor } from 'uci'; +import { connect } from 'ubus'; + +const UCI_CONFIG = 'flowproxy'; +const STATE_FILE = '/var/run/flowproxy.running'; +const IP_CACHE = '/tmp/flowproxy/lan_ip.cache'; +const LOG_FILE = '/var/log/flowproxy.log'; +const NFT_TABLE = 'flowproxy'; + +// 辅助函数:安全 trim +function safe_trim(str) { + return (type(str) === 'string') ? trim(str) : ''; +} + +const methods = { + get_status: { + call: function() { + // 1. 快速探测 + let is_running = access(STATE_FILE, 'f'); + + // 2. 自愈:检查内核状态并同步标记文件 + let tcp_active = (system('nft list chain inet ' + NFT_TABLE + ' LAN_MARKFLOW_TCP >/dev/null 2>&1') === 0); + let udp_active = (system('nft list chain inet ' + NFT_TABLE + ' LAN_MARKFLOW_UDP >/dev/null 2>&1') === 0); + let real_running = (tcp_active || udp_active); + + if (real_running && !is_running) { + try { writefile(STATE_FILE, ''); } catch(e) {} + } else if (!real_running && is_running) { + try { system('rm -f ' + STATE_FILE); } catch(e) {} + } + + // 3. IP 获取 (带缓存) + let lan_ip = readfile(IP_CACHE) || ''; + if (!lan_ip) { + try { + let ubus_conn = connect(); + if (ubus_conn) { + let ifaces = ubus_conn.call('network.interface', 'dump'); + if (type(ifaces?.interface) === 'array') { + // 优先寻找名为 'lan' 的接口,或者寻找拥有 ipv4 地址的第一个非回环接口 + let fallback_ip = ''; + for (let iface in ifaces.interface) { + if (iface.interface === 'lan' && iface['ipv4-address']?.[0]?.address) { + lan_ip = iface['ipv4-address'][0].address; + break; + } + if (!fallback_ip && iface.interface !== 'loopback' && iface['ipv4-address']?.[0]?.address) { + fallback_ip = iface['ipv4-address'][0].address; + } + } + if (!lan_ip) lan_ip = fallback_ip; + } + + if (lan_ip) { + system('mkdir -p /tmp/flowproxy'); + writefile(IP_CACHE, lan_ip); + } + ubus_conn.disconnect(); + } + } catch (e) {} + } + + let uci_cursor = cursor(); + + let proxy_server_ip_addr = uci_cursor.get(UCI_CONFIG, 'global', 'proxy_server_ip_addr') || ''; + let dns_running = (uci_cursor.get(UCI_CONFIG, 'dns_backup') ? 1 : 0); + + return { + running: real_running ? 1 : 0, + dns_running: dns_running, + enabled: int(uci_cursor.get(UCI_CONFIG, 'global', 'enabled') || '0'), + proxy_server_ip_addr: proxy_server_ip_addr, + proxy_server_dns_port: uci_cursor.get(UCI_CONFIG, 'global', 'proxy_server_dns_port') || '5353', + lan_ip: safe_trim(lan_ip), + interface: uci_cursor.get(UCI_CONFIG, 'global', 'interface') || 'br-lan', + traffic_mark: uci_cursor.get(UCI_CONFIG, 'global', 'traffic_mark') || '0x666', + nft: { tcp: tcp_active ? 1 : 0, udp: udp_active ? 1 : 0 } + }; + } + }, + + get_logs: { + args: { lines: 100 }, + call: function(request) { + let lines = request.args?.lines ?? 100; + let logs = []; + try { + if (access(LOG_FILE, 'r')) { + let log_stat = stat(LOG_FILE); + let content = ''; + if (log_stat && log_stat.size > 65536) { + let fd = popen('tail -c 65536 ' + LOG_FILE); + if (fd) { + content = fd.read('all'); + fd.close(); + } + } else { + content = readfile(LOG_FILE); + } + if (content) { + let log_lines = split(content, "\n"); + let total = length(log_lines); + let start = (total > lines) ? (total - lines) : 0; + for (let i = start; i < total; i++) { + if (log_lines[i]) push(logs, log_lines[i]); + } + } + } + } catch (e) {} + return { logs }; + } + }, + + generate_nft_config: { + call: function() { + system('mkdir -p /tmp/flowproxy'); + system('FLOWPROXY_PREVIEW=1 /usr/share/flowproxy/generate_nft.sh 2>&1'); + return { config: safe_trim(readfile('/tmp/flowproxy/nft.conf') || '') }; + } + }, + + get_runtime_config: { + call: function() { + let res_file = '/tmp/flowproxy/runtime.tmp'; + let dns_file = '/tmp/flowproxy/dns_runtime.tmp'; + + system('mkdir -p /tmp/flowproxy'); + system('/usr/share/flowproxy/generate_nft.sh runtime > ' + res_file + ' 2>&1'); + let nft_runtime = readfile(res_file) || "(failed)"; + system('rm -f ' + res_file); + + system('uci show dhcp.@dnsmasq[0] | grep -E "noresolv|dns_redirect|server" | sed -E "s/^dhcp\\.[^.]*\\.([^=]*)=(.*)/\\1: \\2/; s/\\x27//g; s/#/:/g" > ' + dns_file + ' 2>&1'); + let dns_out = readfile(dns_file); + system('rm -f ' + dns_file); + + let dns_runtime = "\n--- [ DNSmasq Runtime Configuration ] ---\n"; + dns_runtime += (dns_out || "(no active dnsmasq overrides)"); + + return { runtime: safe_trim(nft_runtime + dns_runtime) }; + } + }, + + get_interfaces: { + call: function() { + let interfaces = []; + try { + let ubus_conn = connect(); + if (ubus_conn) { + // 使用 network.device status 以获取所有物理设备 (包括 eth0 等 bridge 成员) + let dev_status = ubus_conn.call('network.device', 'status'); + if (dev_status) { + for (let name in dev_status) { + push(interfaces, { name: name }); + } + } + ubus_conn.disconnect(); + } + } catch (e) {} + return { interfaces }; + } + }, + + start_service: { call: function() { return { result: (system('/etc/init.d/flowproxy start >/dev/null 2>&1') === 0) }; } }, + stop_service: { call: function() { return { result: (system('/etc/init.d/flowproxy stop >/dev/null 2>&1') === 0) }; } }, + restart_service: { call: function() { return { result: (system('/etc/init.d/flowproxy restart >/dev/null 2>&1') === 0) }; } }, + clear_logs: { call: function() { try { writefile(LOG_FILE, ''); return { result: true }; } catch(e) { return { result: false }; } } } +}; + +return { 'luci.flowproxy': methods }; +reload_service() { + restart +} diff --git a/luci-app-frpc-next/Makefile b/luci-app-frpc-next/Makefile new file mode 100644 index 000000000..6a9723254 --- /dev/null +++ b/luci-app-frpc-next/Makefile @@ -0,0 +1,32 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=luci-app-frpc-next +PKG_VERSION:=1.0.0 +PKG_RELEASE:=1 + +PKG_LICENSE:=MIT +PKG_MAINTAINER:=Dante + +LUCI_TITLE:=LuCI support for frp client (v0.68.x/v0.69.x+) +LUCI_DEPENDS:=+frpc-next +curl +LUCI_PKGARCH:=all + +include $(TOPDIR)/feeds/luci/luci.mk + +define Package/$(PKG_NAME) + $(call Package/luci/webtemplate) + TITLE:=$(LUCI_TITLE) + DEPENDS:=$(LUCI_DEPENDS) + PROVIDES:=luci-app-frpc + CONFLICTS:=luci-app-frpc +endef + +define Package/$(PKG_NAME)/postinst +#!/bin/sh +[ -n "$${IPKG_INSTROOT}" ] || { + chmod 0755 /etc/init.d/frpc /etc/hotplug.d/iface/99-frpc 2>/dev/null || true +} +exit 0 +endef + +# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-app-frpc-next/htdocs/luci-static/resources/view/frpc/log.js b/luci-app-frpc-next/htdocs/luci-static/resources/view/frpc/log.js new file mode 100644 index 000000000..f5c0a95f9 --- /dev/null +++ b/luci-app-frpc-next/htdocs/luci-static/resources/view/frpc/log.js @@ -0,0 +1,44 @@ +'use strict'; +'require view'; +'require rpc'; +'require poll'; + +const callFrpcLog = rpc.declare({ + object: 'luci.frpc', + method: 'get_log' +}); + +return view.extend({ + handleSaveApply: null, + handleSave: null, + handleReset: null, + + render: function() { + const area = E('textarea', { + id: 'frpc_log_content', + style: 'width:100%; height:500px; background:#f4f4f4; color:#333; padding:10px; border:1px solid #ccc; border-radius:3px; font-family:monospace; font-size:12px; overflow-y:auto; white-space:pre-wrap; word-break:break-all; margin-top:10px;', + readonly: 'readonly' + }, _('Loading logs...')); + + poll.add(() => this.updateLogs(), 5); + + return E('div', { 'class': 'cbi-map' }, [ + E('h2', {}, _('Frp Client Title') + ' - ' + _('Log')), + E('div', { 'class': 'cbi-map-descr' }, _('Real-time background system logs of the active frpc process, helping you diagnose server handshake and protocol errors.')), + E('fieldset', { 'class': 'cbi-section' }, [ + E('legend', {}, _('Logs')), + E('div', { 'class': 'cbi-section-node' }, area) + ]) + ]); + }, + + updateLogs: function() { + return callFrpcLog().then(function(res) { + const area = document.getElementById('frpc_log_content'); + if (area) { + area.value = res && res.log ? res.log : _('No logs available...'); + area.scrollTop = area.scrollHeight; + } + }); + } +}); diff --git a/luci-app-frpc-next/htdocs/luci-static/resources/view/frpc/overview.js b/luci-app-frpc-next/htdocs/luci-static/resources/view/frpc/overview.js new file mode 100644 index 000000000..f22aabb46 --- /dev/null +++ b/luci-app-frpc-next/htdocs/luci-static/resources/view/frpc/overview.js @@ -0,0 +1,294 @@ +'use strict'; +'require view'; +'require rpc'; +'require poll'; +'require ui'; + +const callFrpcStatus = rpc.declare({ + object: 'luci.frpc', + method: 'get_status' +}); + +const callAdoptProcess = rpc.declare({ + object: 'luci.frpc', + method: 'adopt_process' +}); + +const callServiceAction = rpc.declare({ + object: 'luci.frpc', + method: 'service_action', + params: [ 'action' ] +}); + +const callRuntimeInfo = rpc.declare({ + object: 'luci.frpc', + method: 'get_runtime_info' +}); + +function renderState(status) { + let text = _('Unknown'); + let color = '#999'; + + if (status.state === 'managed') { + text = _('Running'); + color = 'green'; + } else if (status.state === 'unmanaged') { + text = _('Running (Unmanaged)'); + color = 'orange'; + } else if (status.state === 'stopped') { + text = _('Stopped'); + color = 'red'; + } + + if (status.pid) + text += ' [PID: ' + status.pid + ']'; + + return { text, color }; +} + +function flattenProxies(statusObj) { + const rows = []; + if (!statusObj || typeof statusObj !== 'object') + return rows; + + Object.keys(statusObj).forEach((ptype) => { + const arr = statusObj[ptype]; + if (!Array.isArray(arr)) + return; + arr.forEach((p) => { + if (!p || typeof p !== 'object') + return; + rows.push({ + name: p.name || '-', + type: p.type || ptype || '-', + status: p.status || '-', + local: p.local_addr || '-', + remote: p.remote_addr || '-', + err: p.err || '' + }); + }); + }); + + return rows; +} + +return view.extend({ + handleSaveApply: null, + handleSave: null, + handleReset: null, + + load: function() { + return Promise.all([ callFrpcStatus(), callRuntimeInfo() ]); + }, + + render: function(data) { + const status = data && data[0] ? data[0] : {}; + const runtime = data && data[1] ? data[1] : {}; + const stateInfo = renderState(status || {}); + + const container = E('div', { 'class': 'cbi-map' }, [ + E('h2', {}, _('Frp Client Title') + ' - ' + _('Overview')), + E('div', { 'class': 'cbi-map-descr' }, _('Overview of the local frpc service state, active process PID, loaded config files, and detailed online proxy information.')) + ]); + + // Service Status Section (Aligned with lucky style) + const statusSection = E('fieldset', { 'class': 'cbi-section' }, [ + E('legend', {}, _('Service Status')), + E('div', { 'class': 'cbi-section-node' }, [ + E('table', { 'class': 'table cbi-section-table' }, [ + E('tr', { 'class': 'tr' }, [ + E('td', { 'class': 'td left', 'width': '33%' }, _('Current Status')), + E('td', { 'class': 'td left' }, [ + E('span', { id: 'frpc-status-text', 'style': 'font-weight:bold; color:' + stateInfo.color + '; margin-right:10px;' }, stateInfo.text), + E('button', { + id: 'frpc-restart-btn', + 'class': 'btn cbi-button cbi-button-apply', + 'style': 'display:' + ((status.state === 'managed' || status.state === 'unmanaged') ? 'inline-block' : 'none') + ';', + click: ui.createHandlerFn(this, function(ev) { + if (!ev || !ev.currentTarget) return; + const btn = ev.currentTarget; + btn.disabled = true; + ui.addNotification(null, E('p', _('Restarting FRP Client, please wait...')), 'info'); + return callServiceAction('restart').then(function(res) { + btn.disabled = false; + if (res && res.success) { + ui.addNotification(null, E('p', _('Service restarted successfully.')), 'info'); + } else { + ui.addNotification(null, E('p', _('Failed to restart service.')), 'error'); + } + }).catch(function(err) { + btn.disabled = false; + ui.addNotification(null, E('p', _('An error occurred: ') + err.message), 'error'); + }); + }) + }, _('Restart')) + ]) + ]), + E('tr', { 'class': 'tr' }, [ + E('td', { 'class': 'td left' }, _('Generated Runtime Config')), + E('td', { 'class': 'td left', id: 'frpc-runtime-config' }, status.runtime_config || '-') + ]), + E('tr', { 'class': 'tr' }, [ + E('td', { 'class': 'td left' }, _('Configured Proxies')), + E('td', { 'class': 'td left', id: 'frpc-proxy-count' }, String(status.proxy_count || 0)) + ]), + E('tr', { 'class': 'tr' }, [ + E('td', { 'class': 'td left' }, _('frpc Version')), + E('td', { 'class': 'td left', id: 'frpc-version' }, status.version || '-') + ]) + ]) + ]) + ]); + container.appendChild(statusSection); + + const proxyRows = flattenProxies(runtime.status); + const runtimeSection = E('fieldset', { + 'class': 'cbi-section', + id: 'frpc-runtime-section', + style: (status.state === 'managed') ? '' : 'display:none' + }, [ + E('legend', {}, _('Runtime Details')), + E('div', { 'class': 'cbi-section-node' }, [ + E('table', { 'class': 'table cbi-section-table' }, [ + E('tr', { 'class': 'tr' }, [ + E('td', { 'class': 'td left', 'width': '33%' }, _('Web Panel')), + E('td', { 'class': 'td left' }, [ + E('span', { id: 'frpc-web-api' }, [ + runtime.web_url ? E('a', { + 'class': 'btn cbi-button', + href: runtime.web_url, + target: '_blank', + rel: 'noopener noreferrer' + }, _('Open')) : '-' + ]) + ]) + ]), + E('tr', { 'class': 'tr' }, [ + E('td', { 'class': 'td left' }, _('Connected Server')), + E('td', { 'class': 'td left' }, [ + E('span', { id: 'frpc-connected-server' }, (runtime.server_addr && runtime.server_port) ? (runtime.server_addr + ':' + runtime.server_port) : '-'), + E('div', { 'class': 'cbi-value-description', style: 'margin: 4px 0 0 0;' }, _('Connect to FRP server')) + ]) + ]), + E('tr', { 'class': 'tr' }, [ + E('td', { 'class': 'td left' }, _('Proxy Runtime List')), + E('td', { 'class': 'td left' }, [ + E('div', { 'class': 'cbi-value-description', style: 'margin: 0 0 6px 0;' }, _('Running proxy list')), + E('div', { + id: 'frpc-proxy-list-wrap', + style: 'max-height:220px; overflow:auto;' + }, proxyRows.length > 0 ? E('table', { 'class': 'table cbi-section-table' }, [ + E('tr', { 'class': 'tr table-titles' }, [ + E('th', { 'class': 'th' }, _('Name')), + E('th', { 'class': 'th' }, _('Type')), + E('th', { 'class': 'th' }, _('Status')), + E('th', { 'class': 'th' }, _('Local')), + E('th', { 'class': 'th' }, _('Remote')), + E('th', { 'class': 'th' }, _('Error')) + ]), + ...proxyRows.map((row) => E('tr', { 'class': 'tr' }, [ + E('td', { 'class': 'td' }, row.name), + E('td', { 'class': 'td' }, row.type), + E('td', { 'class': 'td' }, row.status), + E('td', { 'class': 'td' }, row.local), + E('td', { 'class': 'td' }, row.remote), + E('td', { 'class': 'td' }, row.err || '-') + ])) + ]) : E('div', {}, _('No running proxies'))) + ]) + ]) + ]) + ]) + ]); + container.appendChild(runtimeSection); + + poll.add(() => Promise.all([callFrpcStatus(), callRuntimeInfo()]).then((res) => { + const s = res[0] || {}; + const r = res[1] || {}; + const next = renderState(s); + + const statusNode = document.getElementById('frpc-status-text'); + if (statusNode) { + statusNode.textContent = next.text; + statusNode.style.color = next.color; + } + + const restartBtnNode = document.getElementById('frpc-restart-btn'); + if (restartBtnNode) { + if (s.state === 'managed' || s.state === 'unmanaged') { + restartBtnNode.style.display = 'inline-block'; + } else { + restartBtnNode.style.display = 'none'; + } + } + + const runtimeConfigNode = document.getElementById('frpc-runtime-config'); + if (runtimeConfigNode) + runtimeConfigNode.textContent = s.runtime_config || '-'; + + const proxyCountNode = document.getElementById('frpc-proxy-count'); + if (proxyCountNode) + proxyCountNode.textContent = String(s.proxy_count || 0); + + const versionNode = document.getElementById('frpc-version'); + if (versionNode) + versionNode.textContent = s.version || '-'; + + const runtimeSectionNode = document.getElementById('frpc-runtime-section'); + if (runtimeSectionNode) + runtimeSectionNode.style.display = (s.state === 'managed') ? '' : 'none'; + + const webNode = document.getElementById('frpc-web-api'); + if (webNode) { + if (r.web_url) { + webNode.innerHTML = ''; + webNode.appendChild(E('a', { + 'class': 'btn cbi-button', + href: r.web_url, + target: '_blank', + rel: 'noopener noreferrer' + }, _('Open'))); + } else { + webNode.textContent = '-'; + } + } + + const serverNode = document.getElementById('frpc-connected-server'); + if (serverNode) + serverNode.textContent = (r.server_addr && r.server_port) ? (r.server_addr + ':' + r.server_port) : '-'; + + const listWrap = document.getElementById('frpc-proxy-list-wrap'); + if (listWrap) { + const rows = flattenProxies(r.status); + listWrap.innerHTML = ''; + if (rows.length === 0) { + listWrap.appendChild(E('div', {}, _('No running proxies'))); + } else { + const table = E('table', { 'class': 'table cbi-section-table' }, [ + E('tr', { 'class': 'tr table-titles' }, [ + E('th', { 'class': 'th' }, _('Name')), + E('th', { 'class': 'th' }, _('Type')), + E('th', { 'class': 'th' }, _('Status')), + E('th', { 'class': 'th' }, _('Local')), + E('th', { 'class': 'th' }, _('Remote')), + E('th', { 'class': 'th' }, _('Error')) + ]) + ]); + rows.forEach((row) => { + table.appendChild(E('tr', { 'class': 'tr' }, [ + E('td', { 'class': 'td' }, row.name), + E('td', { 'class': 'td' }, row.type), + E('td', { 'class': 'td' }, row.status), + E('td', { 'class': 'td' }, row.local), + E('td', { 'class': 'td' }, row.remote), + E('td', { 'class': 'td' }, row.err || '-') + ])); + }); + listWrap.appendChild(table); + } + } + }), 5); + + return container; + } +}); diff --git a/luci-app-frpc-next/htdocs/luci-static/resources/view/frpc/settings.js b/luci-app-frpc-next/htdocs/luci-static/resources/view/frpc/settings.js new file mode 100644 index 000000000..79d459428 --- /dev/null +++ b/luci-app-frpc-next/htdocs/luci-static/resources/view/frpc/settings.js @@ -0,0 +1,276 @@ +'use strict'; +'require view'; +'require rpc'; +'require ui'; + +const callGetConfig = rpc.declare({ + object: 'luci.frpc', + method: 'get_config' +}); + +const callSaveConfig = rpc.declare({ + object: 'luci.frpc', + method: 'save_config', + params: [ 'config' ] +}); + +const callValidateConfig = rpc.declare({ + object: 'luci.frpc', + method: 'validate_config', + params: [ 'config' ] +}); + +const callStatus = rpc.declare({ + object: 'luci.frpc', + method: 'get_status' +}); + +const callSetEnabled = rpc.declare({ + object: 'luci.frpc', + method: 'set_enabled', + params: [ 'enabled' ] +}); + +const callServiceAction = rpc.declare({ + object: 'luci.frpc', + method: 'service_action', + params: [ 'action' ] +}); + +function parseErrorPosition(errText) { + const s = String(errText || ''); + let m = s.match(/line\s+(\d+)\s*[,;:]?\s*(?:col|column)\s+(\d+)/i); + if (m) + return { line: +m[1], col: +m[2] }; + + m = s.match(/at\s+line\s+(\d+)\s*[,;:]?\s*column\s+(\d+)/i); + if (m) + return { line: +m[1], col: +m[2] }; + + m = s.match(/line\s+(\d+)/i); + if (m) + return { line: +m[1], col: null }; + + return null; +} + +return view.extend({ + _validateTimer: null, + _errorLine: null, + + injectStyle: function() { + if (document.getElementById('frpc_editor_style')) + return; + + const css = [ + '.frpc-editor-wrap{border:1px solid #ccc;border-radius:4px;overflow:hidden;background:#fff;max-width:900px;box-sizing:border-box;}', + '.frpc-editor-main{display:flex;min-height:400px;max-height:65vh;}', + '.frpc-editor-gutter{width:48px;background:#f7f7f7;color:#888;border-right:1px solid #e5e5e5;overflow:hidden;font:13px/1.5 monospace;padding:12px 6px;text-align:right;user-select:none;box-sizing:border-box;}', + '.frpc-editor-gutter-line{height:1.5em;line-height:1.5;}', + '.frpc-editor-gutter-line.err{background:#ffe8e8;color:#b00020;font-weight:700;}', + '.frpc-editor-input-wrap{flex:1;background:#fff;position:relative;}', + '.frpc-editor-input{width:100%;min-height:100%;box-sizing:border-box;border:0;outline:none;resize:vertical;overflow-wrap:anywhere;white-space:pre;word-break:keep-all;font:13px/1.5 monospace;padding:12px;margin:0;display:block;}' + ].join('\n'); + + document.head.appendChild(E('style', { id: 'frpc_editor_style' }, css)); + }, + + refreshEditor: function() { + const ta = document.getElementById('frpc_config'); + const gutter = document.getElementById('frpc_editor_gutter'); + if (!ta || !gutter) + return; + + const text = ta.value || ''; + const lineCount = Math.max(1, text.split('\n').length); + gutter.innerHTML = ''; + for (let i = 1; i <= lineCount; i++) { + gutter.appendChild(E('div', { + 'class': 'frpc-editor-gutter-line' + (this._errorLine === i ? ' err' : '') + }, String(i))); + } + }, + + renderEditor: function(configText) { + const gutter = E('div', { id: 'frpc_editor_gutter', 'class': 'frpc-editor-gutter' }); + const ta = E('textarea', { + id: 'frpc_config', + class: 'frpc-editor-input', + spellcheck: 'false', + wrap: 'off' + }, configText || ''); + + ta.addEventListener('keydown', function(ev) { + if (ev.keyCode === 9) { // Tab key + ev.preventDefault(); + const start = this.selectionStart; + const end = this.selectionEnd; + const val = this.value; + this.value = val.substring(0, start) + ' ' + val.substring(end); + this.selectionStart = this.selectionEnd = start + 2; + } + }); + + ta.addEventListener('input', L.bind(function() { + this.refreshEditor(); + this.scheduleValidate(); + }, this)); + + ta.addEventListener('scroll', function() { + gutter.scrollTop = ta.scrollTop; + }); + + window.setTimeout(L.bind(function() { this.refreshEditor(); }, this), 0); + + const inputWrap = E('div', { 'class': 'frpc-editor-input-wrap' }, [ ta ]); + + return E('div', { 'class': 'frpc-editor-wrap' }, [ + E('div', { 'class': 'frpc-editor-main' }, [ gutter, inputWrap ]) + ]); + }, + + setValidateHint: function(ok, message, pos) { + const hint = document.getElementById('frpc_validate_hint'); + if (!hint) + return; + + hint.style.color = ok ? 'green' : 'red'; + hint.textContent = message; + this._errorLine = (!ok && pos && pos.line) ? pos.line : null; + this.refreshEditor(); + }, + + runValidate: function() { + const content = document.getElementById('frpc_config')?.value || ''; + if (!content.trim()) { + this.setValidateHint(true, _('Configuration is empty.')); + return Promise.resolve(); + } + + return callValidateConfig(content).then(L.bind(function(res) { + if (res && res.success) { + this.setValidateHint(true, _('Configuration is valid.')); + return; + } + + const err = (res && res.error) ? String(res.error).trim() : _('Unknown error'); + const pos = parseErrorPosition(err); + let msg = _('Verification failed: ') + err; + if (pos && pos.line) + msg += ' (' + _('Line') + ' ' + pos.line + (pos.col ? ', ' + _('Column') + ' ' + pos.col : '') + ')'; + this.setValidateHint(false, msg, pos); + }, this)); + }, + + scheduleValidate: function() { + if (this._validateTimer) + window.clearTimeout(this._validateTimer); + + this._validateTimer = window.setTimeout(L.bind(function() { + this.runValidate().catch(function() {}); + }, this), 700); + }, + + load: function() { + return Promise.all([ callGetConfig(), callStatus() ]); + }, + + render: function(data) { + this.injectStyle(); + const cfg = data && data[0] ? data[0] : {}; + const st = data && data[1] ? data[1] : {}; + const configText = cfg.config || ''; + const enabled = (st.enabled === 1 || st.enabled === true); + + window.setTimeout(L.bind(function() { + this.runValidate().catch(function() {}); + }, this), 0); + + return E('div', { 'class': 'cbi-map' }, [ + E('h2', {}, _('Frp Client Title') + ' - ' + _('Settings')), + E('div', { 'class': 'cbi-map-descr' }, _('Configure the Frp client parameters. Complete the server link details and local port forwarding rules to build an intranet penetration channel.')), + E('div', { 'class': 'cbi-section' }, [ + E('h3', { 'class': 'cbi-section-title' }, _('Service Control')), + E('div', { 'class': 'cbi-value' }, [ + E('label', { 'class': 'cbi-value-title' }, _('Enabled')), + E('div', { 'class': 'cbi-value-field' }, [ + E('input', { + id: 'frpc_enabled', + type: 'checkbox', + checked: enabled ? 'checked' : null + }) + ]) + ]) + ]), + E('div', { 'class': 'cbi-section' }, [ + E('h3', { 'class': 'cbi-section-title' }, _('Configuration Editor')), + this.renderEditor(configText) + ]), + E('div', { 'class': 'cbi-section frpc-editor-buttons' }, [ + E('button', { + 'class': 'btn cbi-button cbi-button-apply', + click: ui.createHandlerFn(this, function() { + return this.runValidate(); + }) + }, _('Verify Configuration')), + E('span', { id: 'frpc_validate_hint', style: 'margin-left:12px;' }, '') + ]) + ]); + }, + + validateAndSave: function() { + const configText = document.getElementById('frpc_config')?.value || ''; + const enabledCheckbox = document.getElementById('frpc_enabled'); + const on = enabledCheckbox && enabledCheckbox.checked ? 1 : 0; + + ui.showModal(null, [ E('p', { 'class': 'spinning' }, [ _('Applying changes...') ]) ]); + + return callValidateConfig(configText).then(L.bind(function(res) { + if (!res || !res.success) { + ui.hideModal(); + const err = (res && res.error) ? String(res.error).trim() : _('Unknown error'); + this.setValidateHint(false, _('Verification failed: ') + err, parseErrorPosition(err)); + ui.addNotification(null, E('pre', { style: 'white-space:pre-wrap; margin:0;' }, _('frpc config verify failed:\n') + err), 'danger'); + throw new Error('frpc verify failed'); + } + + this.setValidateHint(true, _('Configuration is valid.')); + + return callSetEnabled(on).then(L.bind(function(setRes) { + if (!setRes || !setRes.success) { + ui.hideModal(); + ui.addNotification(null, E('p', _('Failed to update service enable state.')), 'danger'); + throw new Error('frpc set enabled failed'); + } + + return callSaveConfig(configText).then(L.bind(function(saveRes) { + ui.hideModal(); + if (saveRes && saveRes.success) { + if (on === 0) { + return callServiceAction('stop'); + } else { + if (saveRes.applied === false) { + ui.addNotification(null, E('p', _('Configuration saved, but service is not running or reload failed. Please force restart service.')), 'warning'); + } + } + return; + } + + ui.addNotification(null, E('p', _('Configuration save failed: ') + (saveRes && saveRes.error ? saveRes.error : _('Unknown error'))), 'danger'); + throw new Error('frpc config save failed'); + }, this)); + }, this)); + }, this)).catch(function(err) { + ui.hideModal(); + throw err; + }); + }, + + handleSave: function() { + return this.validateAndSave(); + }, + + handleSaveApply: function() { + return this.validateAndSave(); + } +}); diff --git a/luci-app-frpc-next/po/zh-cn b/luci-app-frpc-next/po/zh-cn new file mode 120000 index 000000000..8d69574dd --- /dev/null +++ b/luci-app-frpc-next/po/zh-cn @@ -0,0 +1 @@ +zh_Hans \ No newline at end of file diff --git a/luci-app-frpc-next/po/zh_Hans/frpc.po b/luci-app-frpc-next/po/zh_Hans/frpc.po new file mode 100644 index 000000000..764f2b4e6 --- /dev/null +++ b/luci-app-frpc-next/po/zh_Hans/frpc.po @@ -0,0 +1,342 @@ +msgid "" +msgstr "" +"Project-Id-Version: luci-app-frpc\n" +"PO-Revision-Date: 2026-05-19 12:00+0800\n" +"Last-Translator: Dante \n" +"Language-Team: Chinese (Simplified)\n" +"Language: zh_Hans\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Transfer-Encoding: 8bit\n" + +msgid "Service Status" +msgstr "服务运行状态" + +msgid "Current Status" +msgstr "当前状态" + +msgid "Adopting process, please wait..." +msgstr "正在接管进程,请稍候..." + +msgid "Kill and Adopt Rogue Process" +msgstr "杀死并接管孤儿进程" + +msgid "Proxy Health" +msgstr "穿透隧道健康度" + +msgid "Configuration View (/var/etc/frpc.toml)" +msgstr "运行配置查看 (/var/etc/frpc.toml)" + +msgid "Overview" +msgstr "概览" + +msgid "Unknown" +msgstr "未知" + +msgid "Running" +msgstr "运行中" + +msgid "Running (Unmanaged)" +msgstr "运行中 (非托管)" + +msgid "Stopped" +msgstr "已停止" + +msgid "Name" +msgstr "名称" + +msgid "Type" +msgstr "类型" + +msgid "Status" +msgstr "状态" + +msgid "Today Traffic (In/Out)" +msgstr "今日流量 (入/出)" + +msgid "Error Message" +msgstr "报错信息" + +msgid "No data (Service stopped or API not configured)" +msgstr "暂无数据 (服务未启动或 API 未配置)" + +msgid "No proxies configured" +msgstr "没有配置任何隧道" + +msgid "Frp Client" +msgstr "Frp客户端" + +msgid "Open frp Console" +msgstr "打开 frp 控制台" + +msgid "Global Settings" +msgstr "全局配置" + +msgid "Basic Settings" +msgstr "基本设置" + +msgid "Admin API (Required for Hot Reload)" +msgstr "管理 API (热重载必须)" + +msgid "Recommended 0.0.0.0 for LAN access, 127.0.0.1 for local only." +msgstr "推荐设置 0.0.0.0 以便从 LAN 访问,127.0.0.1 仅限本地访问" + +msgid "Log Settings" +msgstr "日志设置" + +msgid "Enable" +msgstr "启用" + +msgid "Server Address" +msgstr "服务器地址" + +msgid "Server Port" +msgstr "服务器端口" + +msgid "Default 7000" +msgstr "默认 7000" + +msgid "Token" +msgstr "令牌" + +msgid "Transport Protocol" +msgstr "传输协议" + +msgid "Admin Address" +msgstr "管理地址" + +msgid "Recommended 127.0.0.1" +msgstr "推荐 127.0.0.1" + +msgid "Admin Port" +msgstr "管理端口" + +msgid "Admin User" +msgstr "管理用户名" + +msgid "Admin Password" +msgstr "管理密码" + +msgid "Log File" +msgstr "日志路径" + +msgid "Leave empty to use system log" +msgstr "留空则输出到系统日志" + +msgid "Log Level" +msgstr "日志级别" + +msgid "Max Days" +msgstr "保留天数" + +msgid "Proxies" +msgstr "穿透列表" + +msgid "Local IP" +msgstr "本地 IP" + +msgid "Local Port" +msgstr "本地端口" + +msgid "Remote Port" +msgstr "远程端口" + +msgid "Custom Domains" +msgstr "自定义域名" + +msgid "Use Encryption" +msgstr "开启加密" + +msgid "Use Compression" +msgstr "开启压缩" + +msgid "No logs available..." +msgstr "暂无日志..." + +msgid "Real-time Logs" +msgstr "实时日志" + +msgid "Log Viewer" +msgstr "日志查看" + +msgid "Frp Client Overview" +msgstr "Frp客户端概览" + +msgid "Overview of frpc runtime state, generated config, and proxy count." +msgstr "展示 frpc 运行状态、生成配置路径与代理数量。" + +msgid "Generated Runtime Config" +msgstr "运行配置" + +msgid "Configured Proxies" +msgstr "代理数量" + +msgid "Frp Client Settings" +msgstr "Frp客户端设置" + +msgid "Configuration saved successfully." +msgstr "配置保存成功。" + +msgid "Configuration save failed: " +msgstr "配置保存失败:" + +msgid "Unknown error" +msgstr "未知错误" + +msgid "Log" +msgstr "日志" + +msgid "Verify Configuration" +msgstr "校验客户端配置" + +msgid "Configuration is empty." +msgstr "配置为空。" + +msgid "Configuration is valid." +msgstr "配置校验通过。" + +msgid "Verification failed: " +msgstr "配置校验失败:" + +msgid "Service Status" +msgstr "服务状态" + +msgid "Logs" +msgstr "日志" + +msgid "Frp Client overview of runtime state, generated config, and proxy count." +msgstr "Frp Client 运行状态概览,包含生成配置路径和代理数量。" + +msgid "Single TOML editor with syntax highlight, line numbers and error position hints." +msgstr "单一 TOML 编辑器,支持语法高亮、行号和错误位置提示。" + +msgid "Line" +msgstr "行" + +msgid "Column" +msgstr "列" + +msgid "frpc Version" +msgstr "frpc 版本" + + +msgid "frpc config verify failed:\n" +msgstr "frpc 配置校验失败:\n" + +msgid "Frp Client Log" +msgstr "Frp客户端日志" + + +msgid "Service Control" +msgstr "服务控制" + +msgid "Enabled" +msgstr "启用" + +msgid "Actions" +msgstr "操作" + +msgid "Start" +msgstr "启动" + +msgid "Stop" +msgstr "停止" + +msgid "Restart" +msgstr "重启" + +msgid "Service enable state updated." +msgstr "服务启用状态已更新。" + +msgid "Failed to update service enable state." +msgstr "更新服务启用状态失败。" + +msgid "Configuration Editor" +msgstr "配置修改" + +msgid "Runtime Details" +msgstr "运行详情" + +msgid "Web API" +msgstr "Web API" + +msgid "Connected Server" +msgstr "连接服务器" + +msgid "Web API Status JSON" +msgstr "Web API 状态 JSON" + +msgid "Proxy Runtime List" +msgstr "代理运行列表" + +msgid "Local" +msgstr "本地地址" + +msgid "Remote" +msgstr "远程地址" + +msgid "Error" +msgstr "错误" + +msgid "No running proxies" +msgstr "暂无运行中的代理" + +msgid "Connect to FRP server" +msgstr "连接FRP服务端" + +msgid "Running proxy list" +msgstr "运行的代理列表" + +msgid "Web Panel" +msgstr "Web面板" + +msgid "Loading logs..." +msgstr "日志加载中..." + +msgid "Showing the last 100 lines of frpc service logs." +msgstr "显示 frpc 服务最近 100 行日志。" + +msgid "Open" +msgstr "打开" + +msgid "Failed to apply service state." +msgstr "应用服务状态失败。" + +msgid "Restarting service, please wait..." +msgstr "正在重启服务,请稍候..." + +msgid "Restart and Take Over" +msgstr "重启并接管" + +msgid "Restart Service" +msgstr "重启服务" + +msgid "Force Restart" +msgstr "强制重启" + +msgid "Force restarting service, please wait..." +msgstr "正在强制重启服务,请稍候..." + +msgid "Hide Preview" +msgstr "关闭预览" + +msgid "Configuration saved and applied successfully." +msgstr "配置已保存并生效。" + +msgid "Configuration saved, but apply failed. Please force restart service." +msgstr "配置已保存,但生效失败,请强制重启服务。" + +msgid "Configuration saved, but service is not running or reload failed. Please force restart service." +msgstr "配置已保存,但服务未运行或重载失败,请强制重启服务。" + +msgid "Overview of the local frpc service state, active process PID, loaded config files, and detailed online proxy information." +msgstr "展示 frpc 客户端本地服务运行状态、活动进程 PID、当前加载的配置文件以及在线穿透隧道的实时统计与健康度参数。" + +msgid "Configure the Frp client parameters. Complete the server link details and local port forwarding rules to build an intranet penetration channel." +msgstr "配置 Frp 客户端的核心参数。支持一键式服务状态启用控制,并提供具备语法高亮、实时语法校验、行号提示的专业级 TOML 配置文件编辑器。" + +msgid "Real-time background system logs of the active frpc process, helping you diagnose server handshake and protocol errors." +msgstr "实时查询当前活跃 frpc 进程的后台系统日志,方便您快速诊断与 frp 服务端的握手协议及穿透连接异常。" + +msgid "Frp Client Title" +msgstr "Frp 客户端" diff --git a/luci-app-frpc-next/root/etc/config/frpc b/luci-app-frpc-next/root/etc/config/frpc new file mode 100644 index 000000000..c52c6a020 --- /dev/null +++ b/luci-app-frpc-next/root/etc/config/frpc @@ -0,0 +1,2 @@ +config frpc 'main' + option enabled '0' diff --git a/luci-app-frpc-next/root/etc/hotplug.d/iface/99-frpc b/luci-app-frpc-next/root/etc/hotplug.d/iface/99-frpc new file mode 100755 index 000000000..c7487f7f6 --- /dev/null +++ b/luci-app-frpc-next/root/etc/hotplug.d/iface/99-frpc @@ -0,0 +1,25 @@ +#!/bin/sh + +[ "$ACTION" = "ifup" ] || exit 0 +[ "$INTERFACE" = "loopback" ] && exit 0 + +# Skip if frpc is not enabled +[ "$(uci -q get frpc.main.enabled)" = "1" ] || exit 0 + +# Skip if frpc process is already running +if pidof /usr/bin/frpc >/dev/null 2>&1 || pidof frpc >/dev/null 2>&1; then + exit 0 +fi + +LOCK=/tmp/frpc_hotplug.lock + +# Debounce: avoid duplicate concurrent starts within 5 seconds +if [ -f "$LOCK" ]; then + ts=$(cat "$LOCK" 2>/dev/null) + [ -n "$ts" ] && [ $(( $(date +%s) - ts )) -lt 5 ] && exit 0 +fi + +date +%s > "$LOCK" + +logger -t frpc-hotplug "${INTERFACE:-$DEVICE} ifup: frpc is enabled but not running, starting service" +/etc/init.d/frpc start >/dev/null 2>&1 & diff --git a/luci-app-frpc-next/root/etc/init.d/frpc b/luci-app-frpc-next/root/etc/init.d/frpc new file mode 100755 index 000000000..b1148619c --- /dev/null +++ b/luci-app-frpc-next/root/etc/init.d/frpc @@ -0,0 +1,50 @@ +#!/bin/sh /etc/rc.common + +START=90 +STOP=10 +USE_PROCD=1 + +PROG=/usr/bin/frpc +CONF_FILE=/etc/config/frpc.toml + +is_enabled() { + local enabled + config_load frpc + config_get_bool enabled "main" "enabled" 0 + [ "$enabled" -eq 1 ] +} + +start_service() { + is_enabled || return 0 + + if [ ! -s "$CONF_FILE" ]; then + logger -t frpc "Config file missing or empty: $CONF_FILE" + return 1 + fi + + procd_open_instance + procd_set_param command "$PROG" -c "$CONF_FILE" + procd_set_param respawn + procd_set_param stdout 1 + procd_set_param stderr 1 + procd_close_instance +} + +reload_service() { + if ! is_enabled; then + stop + return 0 + fi + + if [ ! -s "$CONF_FILE" ]; then + logger -t frpc "Config file missing or empty: $CONF_FILE" + stop + return 1 + fi + + restart +} + +service_triggers() { + procd_add_reload_trigger "frpc" +} diff --git a/luci-app-frpc-next/root/usr/share/luci/menu.d/luci-app-frpc.json b/luci-app-frpc-next/root/usr/share/luci/menu.d/luci-app-frpc.json new file mode 100644 index 000000000..cb413060f --- /dev/null +++ b/luci-app-frpc-next/root/usr/share/luci/menu.d/luci-app-frpc.json @@ -0,0 +1,37 @@ +{ + "admin/services/frpc": { + "title": "Frp Client", + "order": 90, + "action": { + "type": "firstchild" + }, + "depends": { + "acl": [ "luci-app-frpc" ], + "uci": { "frpc": true } + } + }, + "admin/services/frpc/overview": { + "title": "Overview", + "order": 10, + "action": { + "type": "view", + "path": "frpc/overview" + } + }, + "admin/services/frpc/settings": { + "title": "Settings", + "order": 20, + "action": { + "type": "view", + "path": "frpc/settings" + } + }, + "admin/services/frpc/log": { + "title": "Log", + "order": 30, + "action": { + "type": "view", + "path": "frpc/log" + } + } +} diff --git a/luci-app-frpc-next/root/usr/share/rpcd/acl.d/luci-app-frpc.json b/luci-app-frpc-next/root/usr/share/rpcd/acl.d/luci-app-frpc.json new file mode 100644 index 000000000..af0301be3 --- /dev/null +++ b/luci-app-frpc-next/root/usr/share/rpcd/acl.d/luci-app-frpc.json @@ -0,0 +1,37 @@ +{ + "luci-app-frpc": { + "description": "Grant access to frpc RPC methods", + "read": { + "ubus": { + "luci.frpc": [ + "get_status", + "get_runtime_info", + "get_log", + "get_config" + ] + }, + "uci": [ + "frpc" + ] + }, + "write": { + "ubus": { + "luci.frpc": [ + "adopt_process", + "validate_config", + "set_enabled", + "service_action", + "save_config" + ] + }, + "uci": [ + "frpc" + ], + "file": { + "/etc/config/frpc.toml": [ "read", "write" ], + "/var/etc/frpc.toml": [ "read" ], + "/var/log/frpc.log": [ "read" ] + } + } + } +} diff --git a/luci-app-frpc-next/root/usr/share/rpcd/ucode/luci.frpc b/luci-app-frpc-next/root/usr/share/rpcd/ucode/luci.frpc new file mode 100644 index 000000000..ac81f0e4c --- /dev/null +++ b/luci-app-frpc-next/root/usr/share/rpcd/ucode/luci.frpc @@ -0,0 +1,283 @@ +'use strict'; + +import { connect } from 'ubus'; +import * as fs from 'fs'; + +const PROCD_SERVICE_NAME = 'frpc'; +const CONFIG_FILE = '/etc/config/frpc.toml'; +const RUNTIME_CONFIG_FILE = '/etc/config/frpc.toml'; + +function get_procd_status() { + let u = connect(); + if (!u) + return { running: false }; + + let res = u.call('service', 'list', { name: PROCD_SERVICE_NAME }); + if (res && res[PROCD_SERVICE_NAME] && res[PROCD_SERVICE_NAME].instances) { + let inst = res[PROCD_SERVICE_NAME].instances.instance1; + if (inst && inst.running) + return { running: true, pid: inst.pid }; + } + + return { running: false }; +} + +function get_rogue_pid(managed_pid) { + let p = fs.popen('pgrep -x frpc', 'r'); + if (!p) + return null; + + let pid_str = p.read('all'); + p.close(); + + if (!pid_str) + return null; + + let pids = pid_str.trim().split('\n'); + for (let i = 0; i < length(pids); i++) { + let pid = pids[i]; + if (pid != '' && (managed_pid == null || pid != (managed_pid + ''))) + return pid; + } + + return null; +} + +function count_proxies(config) { + if (!config) + return 0; + + let parts = split(config, '[[proxies]]'); + return (parts && length(parts) > 0) ? (length(parts) - 1) : 0; +} + +function verify_config(config) { + fs.writefile('/tmp/frpc_test.toml', config || ''); + let p = fs.popen("/usr/bin/frpc verify -c /tmp/frpc_test.toml 2>&1", 'r'); + if (!p) { + fs.unlink('/tmp/frpc_test.toml'); + return { success: false, error: 'failed to validate config' }; + } + + let output = p.read('all') || ''; + let code = p.close(); + fs.unlink('/tmp/frpc_test.toml'); + + if (code !== 0) + return { success: false, error: output || 'verify failed' }; + + return { success: true }; +} + +function get_frpc_version() { + system("/bin/sh -c '/usr/bin/frpc --version >/tmp/frpc_version.out 2>&1 || /usr/bin/frpc -v >/tmp/frpc_version.out 2>&1'"); + let out = fs.readfile('/tmp/frpc_version.out') || ''; + fs.unlink('/tmp/frpc_version.out'); + + if (!out) + return ''; + + let line = split(out, '\n')[0] || ''; + if (!line) + return ''; + line = replace(line, /^[ \t\r\n]+/, ''); + line = replace(line, /[ \t\r\n]+$/, ''); + return line; +} + +function get_enabled() { + let p = fs.popen("/bin/sh -c \"uci -q get frpc.main.enabled 2>/dev/null || echo 0\"", 'r'); + if (!p) + return 0; + let out = p.read('all') || '0'; + p.close(); + out = replace(out, /^[ \t\r\n]+/, ''); + out = replace(out, /[ \t\r\n]+$/, ''); + return (out === '1') ? 1 : 0; +} + +function toml_get(key, defv) { + let p = fs.popen("/bin/sh -c \"grep -F '" + key + "' " + CONFIG_FILE + " 2>/dev/null | head -n1 | cut -d= -f2-\"", 'r'); + if (!p) + return defv; + + let out = p.read('all') || ''; + p.close(); + out = replace(out, /^[ \t\r\n]+/, ''); + out = replace(out, /[ \t\r\n]+$/, ''); + out = replace(out, /^\"/, ''); + out = replace(out, /\"$/, ''); + return out ? out : defv; +} + +function get_runtime_info() { + let status = get_procd_status(); + if (!status.running) + return { running: false }; + + let addr = toml_get('webServer.addr', '127.0.0.1'); + let port = toml_get('webServer.port', '7400'); + let user = toml_get('webServer.user', ''); + let pass = toml_get('webServer.password', ''); + let auth = (user && pass) ? ("-u '" + user + ":" + pass + "' ") : ''; + + system("/bin/sh -c \"curl -s " + auth + "http://" + addr + ":" + port + "/api/status >/tmp/frpc_web_status.json 2>/tmp/frpc_web_err\""); + system("/bin/sh -c \"curl -s " + auth + "http://" + addr + ":" + port + "/api/config >/tmp/frpc_web_config.txt 2>>/tmp/frpc_web_err\""); + + let raw_status = fs.readfile('/tmp/frpc_web_status.json') || ''; + let raw_config = fs.readfile('/tmp/frpc_web_config.txt') || ''; + let raw_err = fs.readfile('/tmp/frpc_web_err') || ''; + fs.unlink('/tmp/frpc_web_status.json'); + fs.unlink('/tmp/frpc_web_config.txt'); + fs.unlink('/tmp/frpc_web_err'); + + let status_obj = {}; + if (raw_status) { + try { status_obj = json(raw_status); } catch (e) {} + } + + let server_addr = ''; + let server_port = ''; + if (raw_config) { + let m1 = match(raw_config, /serverAddr[ \t]*=[ \t]*\"([^\"]+)\"/); + let m2 = match(raw_config, /serverPort[ \t]*=[ \t]*([0-9]+)/); + if (m1 && length(m1) > 1) server_addr = m1[1]; + if (m2 && length(m2) > 1) server_port = m2[1]; + } + + let lan_ip = ''; + let u = connect(); + if (u) { + let lan_st = u.call('network.interface.lan', 'status', {}); + if (lan_st && lan_st['ipv4-address'] && length(lan_st['ipv4-address']) > 0) + lan_ip = lan_st['ipv4-address'][0].address || ''; + } + + let web_host = addr; + if (addr == '0.0.0.0' || addr == '127.0.0.1' || addr == '::') + web_host = lan_ip || '127.0.0.1'; + let web_url = 'http://' + web_host + ':' + port; + + return { + running: true, + web_addr: addr, + web_port: int(port), + web_url: web_url, + server_addr: server_addr, + server_port: server_port ? int(server_port) : 0, + raw_status: raw_status, + status: status_obj, + error: raw_err + }; +} + +const methods = { + get_status: { + call: function() { + let procd_st = get_procd_status(); + let rogue_pid = get_rogue_pid(procd_st.pid); + + let state = 'stopped'; + if (procd_st.running) + state = 'managed'; + else if (rogue_pid) + state = 'unmanaged'; + + let config = fs.readfile(CONFIG_FILE) || ''; + + return { + state: state, + pid: procd_st.pid || rogue_pid, + config_exists: !!fs.stat(CONFIG_FILE), + runtime_config: RUNTIME_CONFIG_FILE, + proxy_count: count_proxies(config), + version: get_frpc_version(), + enabled: get_enabled() + }; + } + }, + + adopt_process: { + call: function() { + fs.popen('killall -9 frpc', 'r').close(); + let rc = system('/etc/init.d/frpc start >/dev/null 2>&1'); + return { success: (rc === 0) }; + } + }, + + get_log: { + call: function() { + let p = fs.popen('logread -e frpc | tail -n 100', 'r'); + if (!p) + return { log: '' }; + let log = p.read('all'); + p.close(); + return { log: log || '' }; + } + }, + + get_runtime_info: { + call: function() { + return get_runtime_info(); + } + }, + + get_config: { + call: function() { + if (!fs.stat(CONFIG_FILE)) + return { config: '' }; + return { config: fs.readfile(CONFIG_FILE) || '' }; + } + }, + + validate_config: { + args: { config: '' }, + call: function(req) { + let config = req.args?.config ?? ''; + return verify_config(config); + } + }, + + set_enabled: { + args: { enabled: 0 }, + call: function(req) { + let enabled = (int(req.args?.enabled ?? 0) === 1) ? '1' : '0'; + let cmd = "/bin/sh -c \"uci -q set frpc.main.enabled=" + enabled + " && uci -q commit frpc\""; + let rc = system(cmd); + return { success: (rc === 0), enabled: int(enabled) }; + } + }, + + service_action: { + args: { action: '' }, + call: function(req) { + let action = req.args?.action ?? ''; + if (action != 'start' && action != 'stop' && action != 'restart' && action != 'reload') + return { success: false, error: 'invalid action' }; + let rc = system('/etc/init.d/frpc ' + action + ' >/dev/null 2>&1'); + return { success: (rc === 0), applied: (rc === 0) }; + } + }, + + save_config: { + args: { config: '' }, + call: function(req) { + let config = req.args?.config ?? ''; + let vr = verify_config(config); + if (!vr.success) + return vr; + + if (!fs.writefile(CONFIG_FILE, config)) + return { success: false, error: 'unable to write config file (/etc/config/frpc.toml)' }; + + let rc = system('/etc/init.d/frpc reload >/dev/null 2>&1'); + return { + success: true, + saved: true, + applied: (rc === 0) + }; + } + } +}; + +return { 'luci.frpc': methods }; diff --git a/luci-app-linkback/Makefile b/luci-app-linkback/Makefile new file mode 100644 index 000000000..043ce8788 --- /dev/null +++ b/luci-app-linkback/Makefile @@ -0,0 +1,29 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright (C) 2026 Dante +# +# This is free software, licensed under the Apache License, Version 2.0 . +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=luci-app-linkback +PKG_VERSION:=1.0.0 +PKG_RELEASE:=1 +PKG_MAINTAINER:=Dante + +LUCI_TITLE:=LuCI support for Multi-WAN LinkBack Failover/Failback +LUCI_DEPENDS:=+luci-base +ucode +ucode-mod-fs +ucode-mod-uci +ucode-mod-ubus +linkback +LUCI_PKGARCH:=all + +define Package/$(PKG_NAME)/postinst +#!/sh +[ -n "$${IPKG_INSTROOT}" ] || { + /etc/init.d/rpcd restart +} +exit 0 +endef + +include $(TOPDIR)/feeds/luci/luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-app-linkback/htdocs/luci-static/resources/view/linkback/log.js b/luci-app-linkback/htdocs/luci-static/resources/view/linkback/log.js new file mode 100644 index 000000000..993440d2a --- /dev/null +++ b/luci-app-linkback/htdocs/luci-static/resources/view/linkback/log.js @@ -0,0 +1,44 @@ +'use strict'; +'require view'; +'require rpc'; +'require poll'; + +var callGetLog = rpc.declare({ + object: 'luci.linkback', + method: 'get_log' +}); + +return view.extend({ + handleSaveApply: null, + handleSave: null, + handleReset: null, + + render: function() { + var area = E('textarea', { + id: 'linkback_log_content', + style: 'width:100%; height:500px; background:#f4f4f4; color:#333; padding:10px; border:1px solid #ccc; border-radius:3px; font-family:monospace; font-size:12px; overflow-y:auto; white-space:pre-wrap; word-break:break-all; margin-top:10px;', + readonly: 'readonly' + }, _('Loading logs...')); + + poll.add(L.bind(this.updateLogs, this), 5); + + return E('div', { 'class': 'cbi-map' }, [ + E('h2', {}, _('LinkBack 链路守护') + ' - ' + _('Log')), + E('div', { 'class': 'cbi-map-descr' }, _('Real-time routing adjustments and health check state transitions from the linkbackd daemon.')), + E('fieldset', { 'class': 'cbi-section' }, [ + E('legend', {}, _('System Logs')), + E('div', { 'class': 'cbi-section-node' }, area) + ]) + ]); + }, + + updateLogs: function() { + return callGetLog().then(function(res) { + var area = document.getElementById('linkback_log_content'); + if (area) { + area.value = res && res.log ? res.log : _('No logs available.'); + area.scrollTop = area.scrollHeight; + } + }); + } +}); diff --git a/luci-app-linkback/htdocs/luci-static/resources/view/linkback/overview.js b/luci-app-linkback/htdocs/luci-static/resources/view/linkback/overview.js new file mode 100644 index 000000000..bff14b6a5 --- /dev/null +++ b/luci-app-linkback/htdocs/luci-static/resources/view/linkback/overview.js @@ -0,0 +1,261 @@ +'use strict'; +'require view'; +'require rpc'; +'require poll'; +'require ui'; +'require dom'; + +var callGetStatus = rpc.declare({ + object: 'luci.linkback', + method: 'get_status' +}); + +var callManageService = rpc.declare({ + object: 'luci.linkback', + method: 'manage_service', + params: [ 'action' ] +}); + +return view.extend({ + handleSaveApply: null, + handleSave: null, + handleReset: null, + + injectStyle: function() { + if (document.getElementById('linkback_status_style')) + return; + + var css = [ + '.linkback-dot{display:inline-block;width:10px;height:10px;border-radius:50%;margin-right:6px;vertical-align:middle}', + '.linkback-dot-green{background-color:#4CAF50;box-shadow:0 0 6px #4CAF50}', + '.linkback-dot-red{background-color:#f44336;box-shadow:0 0 6px #f44336}', + '.linkback-dot-grey{background-color:#9e9e9e}', + '.linkback-indicator{display:inline-flex;align-items:center;padding:4px 10px;border-radius:12px;font-size:11px;font-weight:bold;background-color:rgba(0,0,0,.05)}', + '.linkback-badge{display:inline-block;padding:4px 8px;border-radius:4px;font-size:11px;font-weight:bold;color:#fff;text-align:center}', + '.linkback-badge-active{background-color:#4CAF50}', + '.linkback-badge-standby{background-color:#2196F3}', + '.linkback-badge-faulted{background-color:#f44336}' + ].join(''); + + document.head.appendChild(E('style', { id: 'linkback_status_style' }, css)); + }, + + load: function() { + return callGetStatus(); + }, + + render: function(status) { + this.injectStyle(); + + var container = E('div', { 'class': 'cbi-map' }, [ + E('h2', {}, _('LinkBack 链路守护') + ' - ' + _('Overview')), + E('div', { 'class': 'cbi-map-descr' }, _('Real-time health state, priority mapping, and service control for Multi-WAN default routing metrics.')) + ]); + + // --- Service Status Section (Aligned with lucky style) --- + var stateText = _('Collecting...'); + var stateColor = '#999'; + + if (status && status.links && status.links.length > 0) { + stateText = _('Running'); + stateColor = 'green'; + } else { + stateText = _('Stopped'); + stateColor = 'red'; + } + + var isRunning = (status && status.links && status.links.length > 0); + + var statusSection = E('fieldset', { 'class': 'cbi-section' }, [ + E('legend', {}, _('Service Status')), + E('div', { 'class': 'cbi-section-node' }, [ + E('table', { 'class': 'table cbi-section-table' }, [ + E('tr', { 'class': 'tr' }, [ + E('td', { 'class': 'td left', 'width': '33%' }, _('Running State')), + E('td', { 'class': 'td left' }, [ + E('span', { + id: 'linkback-service-state', + style: 'font-weight:bold; color:' + stateColor + '; margin-right:15px;' + }, stateText), + E('button', { + id: 'linkback-restart-btn', + 'class': 'btn cbi-button cbi-button-apply', + style: 'display:' + (isRunning ? 'inline-block' : 'none') + ';', + click: ui.createHandlerFn(this, 'handleServiceAction', 'restart') + }, _('Restart')) + ]) + ]) + ]) + ]) + ]); + container.appendChild(statusSection); + + // --- Link Status Section (Aligned with lucky style) --- + var linkSection = E('fieldset', { 'class': 'cbi-section' }, [ + E('legend', {}, _('Link Status')), + E('div', { 'class': 'cbi-section-node' }, [ + E('div', { id: 'linkback-status-box' }, [ + E('p', { 'class': 'spinning' }, _('Loading real-time link status...')) + ]) + ]) + ]); + container.appendChild(linkSection); + + // Initial render + this.updateStatusView(status); + + // Start polling every 3 seconds + poll.add(L.bind(function() { + return callGetStatus().then(L.bind(function(res) { + this.updateStatusView(res); + }, this)); + }, this), 3); + + return container; + }, + + updateStatusView: function(status) { + var box = document.getElementById('linkback-status-box'); + if (!box) + return; + + // Update service state indicator + var stateEl = document.getElementById('linkback-service-state'); + if (stateEl) { + if (status && status.links && status.links.length > 0) { + stateEl.textContent = _('Running'); + stateEl.style.color = 'green'; + } else { + stateEl.textContent = _('Stopped'); + stateEl.style.color = 'red'; + } + } + + var restartBtn = document.getElementById('linkback-restart-btn'); + if (restartBtn) { + if (status && status.links && status.links.length > 0) { + restartBtn.style.display = 'inline-block'; + } else { + restartBtn.style.display = 'none'; + } + } + + if (!status || !status.links || status.links.length === 0) { + dom.content(box, [ + E('p', { style: 'color:#f44336; font-weight:bold; padding:20px;' }, + _('LinkBack daemon is not running or no links are configured. Please check Settings page.')) + ]); + return; + } + + var activeLink = status.active_link || 'none'; + + // Create standard LuCI section table + var table = E('table', { 'class': 'table cbi-section-table' }, [ + E('tr', { 'class': 'tr table-titles' }, [ + E('th', { 'class': 'th', 'style': 'text-align:center; width:5%;' }, '#'), + E('th', { 'class': 'th', 'style': 'text-align:left;' }, _('Link Name')), + E('th', { 'class': 'th', 'style': 'text-align:left;' }, _('Status')), + E('th', { 'class': 'th', 'style': 'text-align:left;' }, _('Routing Attributes')), + E('th', { 'class': 'th', 'style': 'text-align:left;' }, _('Latency Details')) + ]) + ]); + + status.links.forEach(function(link, index) { + var roleTitle = ''; + var roleClass = ''; + + if (link.is_up && link.healthy) { + if (link.name === activeLink) { + roleTitle = _('Active'); + roleClass = 'linkback-badge-active'; + } else { + roleTitle = _('Standby'); + roleClass = 'linkback-badge-standby'; + } + } else { + roleTitle = _('Faulted'); + roleClass = 'linkback-badge-faulted'; + } + + // Health check indicators + var checkBadges = []; + + if (link.check_type === 'ping' && link.ping) { + var dotClass = link.ping.ok ? 'linkback-dot-green' : 'linkback-dot-red'; + checkBadges.push(E('span', { 'class': 'linkback-indicator', 'style': 'margin-bottom:4px; margin-right:6px;' }, [ + E('span', { 'class': 'linkback-dot ' + dotClass }), + 'Ping: ' + (link.ping.ok ? link.ping.rtt + 'ms' : _('Failed')) + ])); + } + else if (link.check_type === 'dns' && link.dns) { + var dotClass = link.dns.ok ? 'linkback-dot-green' : 'linkback-dot-red'; + checkBadges.push(E('span', { 'class': 'linkback-indicator', 'style': 'margin-bottom:4px; margin-right:6px;' }, [ + E('span', { 'class': 'linkback-dot ' + dotClass }), + 'DNS: ' + (link.dns.ok ? link.dns.rtt + 'ms' : _('Failed')) + ])); + } + else if (link.check_type === 'tcp' && link.tcp) { + var dotClass = link.tcp.ok ? 'linkback-dot-green' : 'linkback-dot-red'; + checkBadges.push(E('span', { 'class': 'linkback-indicator', 'style': 'margin-bottom:4px; margin-right:6px;' }, [ + E('span', { 'class': 'linkback-dot ' + dotClass }), + 'TCP: ' + (link.tcp.ok ? link.tcp.rtt + 'ms' : _('Failed')) + ])); + } + + if (checkBadges.length === 0) { + checkBadges.push(E('span', { 'style': 'color:#999;' }, '-')); + } + + // Route and metric attributes + var routeDetails = E('div', { 'style': 'font-size:12px; line-height:1.6;' }, [ + E('div', {}, [ + E('strong', {}, _('Gateway') + ': '), + link.gateway || '-' + ]), + E('div', {}, [ + E('strong', {}, _('Priority') + ': '), + String(link.priority), + ' | ', + E('strong', {}, _('Metric') + ': '), + link.metric + ' → ' + link.current_metric + ]) + ]); + + var row = E('tr', { 'class': 'tr' }, [ + E('td', { 'class': 'td', 'style': 'text-align:center; font-weight:bold; vertical-align:middle;' }, String(index + 1)), + E('td', { 'class': 'td', 'style': 'font-weight:bold; vertical-align:middle;' }, [ + E('span', { 'style': 'font-size:14px;' }, link.name), + link.device ? E('span', { 'style': 'font-size:11px; color:#666; margin-left:6px; background:#eee; padding:2px 4px; border-radius:3px;' }, link.device) : '' + ]), + E('td', { 'class': 'td', 'style': 'vertical-align:middle;' }, [ + E('span', { 'class': 'linkback-badge ' + roleClass }, roleTitle) + ]), + E('td', { 'class': 'td', 'style': 'vertical-align:middle;' }, routeDetails), + E('td', { 'class': 'td', 'style': 'vertical-align:middle;' }, E('div', { 'style': 'display:flex; flex-wrap:wrap; align-items:center;' }, checkBadges)) + ]); + + table.appendChild(row); + }); + + dom.content(box, [ table ]); + }, + + handleServiceAction: function(action) { + ui.showModal(null, [ + E('p', { 'class': 'spinning' }, _('Executing service action: %s ...').format(action)) + ]); + + return callManageService(action).then(function(res) { + ui.hideModal(); + if (res && res.success) { + ui.addNotification(null, E('p', _('Service action completed successfully.')), 'info'); + } else { + ui.addNotification(null, E('p', _('Failed to execute service action.')), 'error'); + } + }).catch(function(err) { + ui.hideModal(); + ui.addNotification(null, E('p', _('RPC error: %s').format(err.message)), 'error'); + }); + } +}); diff --git a/luci-app-linkback/htdocs/luci-static/resources/view/linkback/settings.js b/luci-app-linkback/htdocs/luci-static/resources/view/linkback/settings.js new file mode 100644 index 000000000..5b6f2a574 --- /dev/null +++ b/luci-app-linkback/htdocs/luci-static/resources/view/linkback/settings.js @@ -0,0 +1,429 @@ +'use strict'; +'require view'; +'require uci'; +'require form'; +'require ui'; + +return view.extend({ + load: function() { + return Promise.all([ + uci.load('linkback'), + uci.load('network') + ]); + }, + + // Comprehensive validation: check all conditions required for the service + // to be safely enabled. Returns an error message string, or null if OK. + _validateServiceConfig: function() { + var link_sections = uci.sections('linkback', 'link') || []; + + // Rule 1: At least 2 interfaces + if (link_sections.length < 2) { + return _('Cannot enable service: At least 2 monitored WAN interfaces must be configured for failover switcher.'); + } + + // Rule 2: ALL interfaces must have a health check configured + for (var i = 0; i < link_sections.length; i++) { + var s_id = link_sections[i]['.name']; + var iface_name = uci.get('linkback', s_id, 'name') || s_id; + var has_check = uci.get('linkback', s_id, 'ping_targets') || + uci.get('linkback', s_id, 'dns_server') || + uci.get('linkback', s_id, 'tcp_target'); + if (!has_check) { + return _('Cannot enable service: Interface "%s" has no health check configured.').format(iface_name); + } + } + + // Rule 3: No duplicate priorities + var priorities = {}; + for (var i = 0; i < link_sections.length; i++) { + var s_id = link_sections[i]['.name']; + var iface_name = uci.get('linkback', s_id, 'name') || s_id; + var prio = uci.get('linkback', s_id, 'priority') || '1'; + if (priorities[prio]) { + return _('Cannot enable service: Interfaces "%s" and "%s" have the same priority %s.').format(priorities[prio], iface_name, prio); + } + priorities[prio] = iface_name; + } + + return null; + }, + + render: function() { + var m, s, o; + var self = this; + + // 智能判断当前是否为中文环境,并提供实时校验的翻译 fallback + var is_zh = (_('Base Metric') === '默认跃点' || _('Base Metric') === '默认跃点 (Metric)'); + var t_priority_empty = is_zh ? '优先级不能为空。' : _('Priority must not be empty.'); + var t_priority_conflict = is_zh ? '优先级 %s 与接口 "%s" 冲突。优先级必须是唯一的。' : _('Priority %s conflicts with interface "%s". Priorities must be unique.'); + + + // Helper function to expand table column controls and eliminate right empty space + var makeTableColumnExpand = function(opt, width) { + var origRender = opt.render; + opt.render = function(option_index, section_id, in_table) { + return Promise.resolve(origRender.call(this, option_index, section_id, in_table)).then(function(node) { + if (in_table && node) { + if (width) { + node.style.width = width; + } + var input = node.querySelector('input, select, .cbi-dropdown'); + if (input) { + input.style.width = '100%'; + input.style.maxWidth = 'none'; + } + } + return node; + }); + }; + }; + + m = new form.Map('linkback', + _('LinkBack 链路守护') + ' - ' + _('Settings'), + _('Configure Multi-WAN failover service, health check parameters, and monitored link interfaces.')); + + // --- Global Settings Section --- + s = m.section(form.TypedSection, 'global', _('Global Settings')); + s.anonymous = true; + + // Enable switch (总开关) - must be the first option + o = s.option(form.Flag, 'enabled', _('Enable Service'), + _('Master switch to enable or disable the LinkBack failover daemon.')); + o.rmempty = false; + // Intercept at UCI write level to validate before enabling. + o.write = function(section_id, value) { + if (value === '1') { + var err = self._validateServiceConfig(); + if (err) { + ui.addNotification(null, E('p', err), 'error'); + uci.set('linkback', section_id, 'enabled', '0'); + return; + } + } + uci.set('linkback', section_id, 'enabled', value); + }; + + // --- Monitored Links Section --- + s = m.section(form.GridSection, 'link', _('Monitored WAN Interfaces'), + _('Add and prioritize your WAN interfaces. Lower priority number means higher preference (e.g., 1 = primary, 2 = backup).')); + s.anonymous = true; + s.addremove = true; + + // Custom dynamic Modal title for gorgeous UX + s.modaltitle = function(section_id) { + var parent_title = _('LinkBack 链路守护') + ' - ' + _('Settings'); + var is_new = (this.map.addedSection === section_id) || !uci.get('linkback', section_id, 'name'); + if (is_new) { + return parent_title + ' - ' + _('Add Monitored Interface'); + } else { + var name = uci.get('linkback', section_id, 'name') || section_id; + return parent_title + ' - ' + _('Edit Monitored Interface') + ' (' + name + ')'; + } + }; + + // When service is already enabled and user modifies/deletes links, + // re-validate on the GridSection level. If the resulting config is invalid, + // show a warning and auto-disable the service to maintain safety. + var origRemove = s.handleRemove; + s.handleRemove = function(section_id, ev) { + return origRemove.apply(this, arguments).then(function() { + var enabled = uci.get('linkback', '@global[0]', 'enabled'); + if (enabled === '1') { + var err = self._validateServiceConfig(); + if (err) { + ui.addNotification(null, E('p', + _('Service has been auto-disabled because the configuration is no longer valid: ') + err + ), 'warning'); + uci.set('linkback', '@global[0]', 'enabled', '0'); + } + } + }); + }; + + // 1. Enabled (Enabled as the first column) + o = s.option(form.Flag, 'enabled', _('Enabled')); + o.default = '1'; + o.rmempty = false; + makeTableColumnExpand(o, '8%'); + + // 2. Interface name - dynamic dropdown (No description for main column) + o = s.option(form.ListValue, 'name', _('Interface')); + o.rmempty = false; + + // Once-off load of all network interfaces safely avoiding race conditions + var network_interfaces = {}; + uci.sections('network', 'interface').forEach(function(sec) { + var n = sec['.name']; + if (n !== 'loopback' && n !== 'lan') { + network_interfaces[n] = true; + o.value(n); + } + }); + + // Safeguard to show already configured interfaces even if they were deleted from network config + uci.sections('linkback', 'link').forEach(function(sec) { + if (sec.name && !network_interfaces[sec.name]) { + o.value(sec.name, _('%s (configured)').format(sec.name)); + } + }); + + // 动态隐藏已被配置的接口:通过在 renderWidget 中进行局部变量过滤与实例化 ui.Select, + // 完全不修改全局的 this.keylist 和 this.keyvalues,保证 100% 线程安全和无副作用 + o.renderWidget = function(section_id, option_index, cfgvalue) { + // 找出已经被其他 Section 选中的网卡(已配置接口名) + var used_names = {}; + uci.sections('linkback', 'link').forEach(function(sec) { + if (sec['.name'] !== section_id && sec.name) { + used_names[sec.name] = true; + } + }); + + // 动态生成仅针对当前渲染 section_id 的 choices 和 keylist + var filtered_choices = {}; + var filtered_keylist = []; + if (Array.isArray(this.keylist)) { + for (var i = 0; i < this.keylist.length; i++) { + var key = this.keylist[i]; + if (!used_names[key]) { + filtered_keylist.push(key); + filtered_choices[key] = this.vallist[i]; + } + } + } + + // 判断当前是编辑已有配置还是添加新配置 + // 如果在 UCI 中已经保存了 name,则是编辑状态,此时网卡不可编辑 + var is_edit = !!uci.get('linkback', section_id, 'name'); + + // 直接在局部变量中实例化 ui.Select,避免任何时序与引用问题 + var widget = new ui.Select((cfgvalue != null) ? cfgvalue : this.default, filtered_choices, { + id: this.cbid(section_id), + size: this.size, + sort: filtered_keylist, + widget: this.widget, + optional: this.optional, + orientation: this.orientation, + placeholder: this.placeholder, + validate: (typeof(this.getValidator) === 'function') ? this.getValidator(section_id) : (this.validate ? this.validate.bind(this, section_id) : null), + disabled: is_edit ? true : ((this.readonly != null) ? this.readonly : this.map.readonly) + }); + + return widget.render(); + }; + + o.validate = function(section_id, value) { + var added = false; + uci.sections('linkback', 'link').forEach(function(sec) { + if (sec['.name'] !== section_id && sec.name === value) { + added = true; + } + }); + if (added) { + return _('This interface has already been configured.'); + } + return true; + }; + + makeTableColumnExpand(o, '25%'); + + // 3. Priority (No description for main column) + o = s.option(form.Value, 'priority', _('Priority')); + o.datatype = 'uinteger'; + o.default = '1'; + o.rmempty = false; + o.validate = function(section_id, value) { + if (value == null || value === '') { + return t_priority_empty; + } + var self_opt = this; + var has_conflict = false; + var conflicting_iface = ''; + uci.sections('linkback', 'link').forEach(function(sec) { + var sid = sec['.name']; + if (sid !== section_id) { + var other_val = self_opt.formvalue(sid); + if (other_val == null || other_val === '') { + other_val = uci.get('linkback', sid, 'priority'); + } + if (other_val != null && other_val !== '' && String(other_val) === String(value)) { + has_conflict = true; + conflicting_iface = uci.get('linkback', sid, 'name') || sid; + } + } + }); + if (has_conflict) { + return t_priority_conflict.format(value, conflicting_iface); + } + return true; + }; + makeTableColumnExpand(o, '15%'); + + // 4. Metric (Read-only, generated from priority * 10) + var metric_title = _('Base Metric'); + if (metric_title === '默认跃点 (Metric)') { + metric_title = '默认跃点'; + } + o = s.option(form.DummyValue, 'metric', metric_title); + o.cfgvalue = function(section_id) { + var prio = uci.get('linkback', section_id, 'priority'); + var prio_val = parseInt(prio, 10); + if (isNaN(prio_val) || prio_val <= 0) { + prio_val = 1; + } + return prio_val * 10; + }; + makeTableColumnExpand(o, '15%'); + + // 5. Dummy display option for Check Type in main Grid table (read-only) + o = s.option(form.DummyValue, 'check_type_disp', _('Check Type')); + o.modalonly = false; + o.cfgvalue = function(section_id) { + if (uci.get('linkback', section_id, 'ping_targets')) + return _('Ping Probe'); + if (uci.get('linkback', section_id, 'dns_server')) + return _('DNS Probe'); + if (uci.get('linkback', section_id, 'tcp_target')) + return _('TCP Probe'); + return _('-- Not Configured --'); + }; + makeTableColumnExpand(o, '20%'); + + // 6. Check Type Dropdown (Virtual field, Modal only to avoid Save & Apply side-effects) + o = s.option(form.ListValue, 'check_type', _('Check Type')); + o.value('ping', _('Ping Probe')); + o.value('dns', _('DNS Probe')); + o.value('tcp', _('TCP Probe')); + o.default = 'ping'; + o.rmempty = false; + o.modalonly = true; + + // Derive the check type from which probe target is configured in UCI. + o.cfgvalue = function(section_id) { + if (uci.get('linkback', section_id, 'ping_targets')) + return 'ping'; + if (uci.get('linkback', section_id, 'dns_server')) + return 'dns'; + if (uci.get('linkback', section_id, 'tcp_target')) + return 'tcp'; + return 'ping'; // Default to ping if not configured + }; + + // Only write when the check type actually CHANGES from the current state. + o.write = function(section_id, value) { + var current = uci.get('linkback', section_id, 'ping_targets') ? 'ping' : + (uci.get('linkback', section_id, 'dns_server') ? 'dns' : + (uci.get('linkback', section_id, 'tcp_target') ? 'tcp' : '')); + var next = (value == null) ? 'ping' : String(value); + + // No change - do nothing + if (next === current) { + return; + } + + // Clear old type's fields and any legacy weights/thresholds + uci.remove('linkback', section_id, 'weight_threshold'); + uci.remove('linkback', section_id, 'ping_weight'); + uci.remove('linkback', section_id, 'dns_weight'); + uci.remove('linkback', section_id, 'tcp_weight'); + + if (current === 'ping' || current === '') { + uci.remove('linkback', section_id, 'ping_targets'); + } + if (current === 'dns' || current === '') { + uci.remove('linkback', section_id, 'dns_server'); + uci.remove('linkback', section_id, 'dns_domain'); + } + if (current === 'tcp' || current === '') { + uci.remove('linkback', section_id, 'tcp_target'); + uci.remove('linkback', section_id, 'tcp_port'); + } + }; + + // 7. Ping Probe Parameters + o = s.option(form.Value, 'ping_targets', _('Ping Targets'), + _('Comma-separated list of IPs to ping (e.g., 223.5.5.5,8.8.8.8).')); + o.rmempty = true; + o.modalonly = true; + o.depends('check_type', 'ping'); + o.validate = function(section_id, value) { + if (!value) return true; + var ips = value.replace(/\s+/g, '').split(','); + for (var i = 0; i < ips.length; i++) { + var ipPattern = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/; + if (!ipPattern.test(ips[i])) { + return _('Invalid IP address: "%s"').format(ips[i]); + } + } + return true; + }; + o.write = function(section_id, value) { + if (value != null) { + var cleaned = String(value).replace(/\s+/g, ''); + uci.set('linkback', section_id, 'ping_targets', cleaned); + } else { + uci.remove('linkback', section_id, 'ping_targets'); + } + }; + + // 7. DNS Probe Parameters + o = s.option(form.Value, 'dns_server', _('DNS Server'), + _('DNS server IP for UDP query probe (e.g., 119.29.29.29).')); + o.datatype = 'ip4addr'; + o.rmempty = true; + o.modalonly = true; + o.depends('check_type', 'dns'); + + o = s.option(form.Value, 'dns_domain', _('DNS Domain'), + _('Domain name to resolve for DNS probe (e.g., www.baidu.com).')); + o.rmempty = true; + o.modalonly = true; + o.depends('check_type', 'dns'); + + // 8. TCP Probe Parameters + o = s.option(form.Value, 'tcp_target', _('TCP Target'), + _('Target IP for TCP handshake probe.')); + o.datatype = 'ip4addr'; + o.rmempty = true; + o.modalonly = true; + o.depends('check_type', 'tcp'); + + o = s.option(form.Value, 'tcp_port', _('TCP Port'), + _('Target port for TCP handshake probe.')); + o.datatype = 'port'; + o.rmempty = true; + o.modalonly = true; + o.depends('check_type', 'tcp'); + + // 9. Individual health check options (Modal only) + o = s.option(form.Value, 'check_interval', _('Check Interval (s)'), + _('Time in seconds between each health check cycle for this link.')); + o.datatype = 'uinteger'; + o.default = '5'; + o.rmempty = false; + o.modalonly = true; + + o = s.option(form.Value, 'check_timeout', _('Check Timeout (s)'), + _('Maximum wait time in seconds for each individual check probe for this link.')); + o.datatype = 'uinteger'; + o.default = '3'; + o.rmempty = false; + o.modalonly = true; + + o = s.option(form.Value, 'recovery_delay', _('Recovery Delay'), + _('Number of consecutive successful checks required before marking this link as healthy (failback anti-flap).')); + o.datatype = 'uinteger'; + o.default = '3'; + o.rmempty = false; + o.modalonly = true; + + o = s.option(form.Value, 'failover_delay', _('Failover Delay'), + _('Number of consecutive failed checks required before marking this link as faulted (failover anti-flap).')); + o.datatype = 'uinteger'; + o.default = '2'; + o.rmempty = false; + o.modalonly = true; + + return m.render(); + } +}); diff --git a/luci-app-linkback/po/zh-cn b/luci-app-linkback/po/zh-cn new file mode 120000 index 000000000..8d69574dd --- /dev/null +++ b/luci-app-linkback/po/zh-cn @@ -0,0 +1 @@ +zh_Hans \ No newline at end of file diff --git a/luci-app-linkback/po/zh_Hans/linkback.po b/luci-app-linkback/po/zh_Hans/linkback.po new file mode 100644 index 000000000..fbd82d5e9 --- /dev/null +++ b/luci-app-linkback/po/zh_Hans/linkback.po @@ -0,0 +1,322 @@ +msgid "" +msgstr "Content-Type: text/plain; charset=UTF-8" + +msgid "LinkBack 链路守护" +msgstr "网关切换" + +msgid "Overview" +msgstr "概览" + +msgid "Settings" +msgstr "设置" + +msgid "Log" +msgstr "日志" + +msgid "Real-time health state, priority mapping, and service control for Multi-WAN default routing metrics." +msgstr "用于 Multi-WAN 默认路由 Metric 的实时健康状态、优先级映射及服务控制。" + +msgid "Service Status" +msgstr "服务状态" + +msgid "Current Status" +msgstr "当前状态" + +msgid "Service Control" +msgstr "服务控制" + +msgid "Restart" +msgstr "重启" + +msgid "Start" +msgstr "启动" + +msgid "Stop" +msgstr "停止" + +msgid "Link Status" +msgstr "链路状态" + +msgid "Loading real-time link status..." +msgstr "正在加载实时链路状态..." + +msgid "Running" +msgstr "运行中" + +msgid "Stopped" +msgstr "已停止" + +msgid "LinkBack daemon is not running or no links are configured. Please check Settings page." +msgstr "网关切换守护进程未运行或未配置任何链路。请检查设置页面。" + +msgid "主选链路 / Active" +msgstr "主选网关 / 活跃中" + +msgid "次选链路 / Standby" +msgstr "备选网关 / 待命" + +msgid "备选链路 / Faulted" +msgstr "故障网关 / 已断开" + +msgid "Priority" +msgstr "优先级" + +msgid "Metric" +msgstr "路由跃点 (Metric)" + +msgid "Gateway" +msgstr "网关地址" + +msgid "Score" +msgstr "得分" + +msgid "Failed" +msgstr "失败" + +msgid "Executing service action: %s ..." +msgstr "正在执行服务操作: %s ..." + +msgid "Service action completed successfully." +msgstr "服务操作执行成功。" + +msgid "Failed to execute service action." +msgstr "服务操作执行失败。" + +msgid "RPC error: %s" +msgstr "RPC 错误: %s" + +msgid "Configure Multi-WAN failover service, health check parameters, and monitored link interfaces." +msgstr "配置多 WAN 故障切换服务、健康度检查参数及被监控的网关接口。" + +msgid "Global Settings" +msgstr "全局设置" + +msgid "Enable Service" +msgstr "启用服务" + +msgid "Master switch to enable or disable the LinkBack failover daemon." +msgstr "启用或禁用网关切换服务的全局总开关。" + +msgid "Check Interval (s)" +msgstr "检测间隔 (秒)" + +msgid "Time in seconds between each health check cycle." +msgstr "每个健康度检测周期之间的时间间隔。" + +msgid "Check Timeout (s)" +msgstr "检测超时 (秒)" + +msgid "Maximum wait time in seconds for each individual check probe." +msgstr "每个检测探针的最大等待超时时间。" + +msgid "Recovery Delay" +msgstr "恢复判定延迟" + +msgid "Number of consecutive successful checks required before marking a faulted link as healthy again (failback anti-flap)." +msgstr "故障网关恢复健康所需连续检测成功的次数 (防抖动回切)。" + +msgid "Failover Delay" +msgstr "故障判定延迟" + +msgid "Number of consecutive failed checks required before marking a healthy link as faulted (failover anti-flap)." +msgstr "健康网关判定为故障所需连续检测失败的次数 (防抖动切换)。" + +msgid "Monitored WAN Interfaces" +msgstr "监控网关接口" + +msgid "Add and prioritize your WAN interfaces. Lower priority number means higher preference (e.g., 1 = primary, 2 = backup)." +msgstr "添加并配置您的广域网网关接口优先级。数值越小代表优先级越高 (例如:1 = 主网关,2 = 备用网关)。" + +msgid "Interface" +msgstr "网络接口" + +msgid "Select a logical WAN interface from Network settings." +msgstr "从系统网络配置中选择一个逻辑 WAN 接口。" + +msgid "Enabled" +msgstr "已启用" + +msgid "Base Metric" +msgstr "默认跃点" + +msgid "Default route metric when this link is healthy (e.g., wan=10, wan2=20)." +msgstr "当该接口健康时应用的默认路由 Metric 跃点数值 (例如:wan=10, wan2=20)。" + +msgid "Ping Targets" +msgstr "Ping 检测目标" + +msgid "Space-separated list of IPs to ping (e.g., 223.5.5.5 8.8.8.8)." +msgstr "通过空格分隔的 Ping 目标 IP 地址列表 (例如:223.5.5.5 8.8.8.8)。" + +msgid "Ping Weight" +msgstr "Ping 权重" + +msgid "DNS Server" +msgstr "DNS 服务器" + +msgid "DNS server IP for UDP query probe (e.g., 119.29.29.29)." +msgstr "用于 UDP 解析探测的 DNS 服务器 IP (例如:119.29.29.29)。" + +msgid "DNS Domain" +msgstr "DNS 解析域名" + +msgid "Domain name to resolve for DNS probe (e.g., www.baidu.com)." +msgstr "用于 DNS 探针解析的测试目标域名 (例如:www.baidu.com)。" + +msgid "DNS Weight" +msgstr "DNS 权重" + +msgid "TCP Target" +msgstr "TCP 检测目标" + +msgid "Target IP for TCP handshake probe." +msgstr "用于 TCP 三次握手探测的目标主机 IP 地址。" + +msgid "TCP Port" +msgstr "TCP 检测端口" + +msgid "Target port for TCP handshake probe." +msgstr "用于 TCP 探测的测试目标端口号。" + +msgid "TCP Weight" +msgstr "TCP 权重" + +msgid "Health Threshold" +msgstr "健康门槛" + +msgid "Combined weight score required to mark this link healthy (e.g., if threshold is 2, any 2 successful checks suffice)." +msgstr "判定该接口健康所需的各指标合并通过总分值 (例如:门槛为 2,任意两项检测成功即可)。" + +msgid "Loading logs..." +msgstr "正在加载运行日志..." + +msgid "Real-time routing adjustments and health check state transitions from the linkbackd daemon." +msgstr "来自后台 linkbackd 守护程序的实时路由调整和网关健康状态转换详情。" + +msgid "System Logs" +msgstr "系统日志" + +msgid "No logs available." +msgstr "暂无可用运行日志。" + +msgid "Enable Ping Probe" +msgstr "启用 Ping 检测" + +msgid "Enable DNS Probe" +msgstr "启用 DNS 检测" + +msgid "Enable TCP Probe" +msgstr "启用 TCP 检测" + +msgid "Select a logical WAN interface." +msgstr "选择逻辑 WAN 接口。" + +msgid "Routing priority (lower = higher preference)." +msgstr "路由优先级(数值越小优先级越高)。" + +msgid "Default route metric when healthy." +msgstr "接口健康时的默认路由跃点 (Metric) 数值。" + +msgid "Combined weight score required to mark this link healthy." +msgstr "判定该接口健康所需的各检测指标成功权重分之和。" + +msgid "Collecting..." +msgstr "正在收集数据..." + +msgid "Running State" +msgstr "运行状态" + +msgid "Check Type" +msgstr "检测类型" + +msgid "Time in seconds between each health check cycle for this link." +msgstr "该链路每次健康度检测周期之间的时间间隔 (秒)。" + +msgid "Maximum wait time in seconds for each individual check probe for this link." +msgstr "该链路每个检测探针的最大等待超时时间 (秒)。" + +msgid "Number of consecutive successful checks required before marking this link as healthy (failback anti-flap)." +msgstr "判定该链路恢复健康所需连续检测成功的次数 (防抖动回切)。" + +msgid "Number of consecutive failed checks required before marking this link as faulted (failover anti-flap)." +msgstr "判定该链路发生故障所需连续检测失败的次数 (防抖动切换)。" + +msgid "Add Monitored Interface" +msgstr "添加监控接口" + +msgid "Edit Monitored Interface" +msgstr "编辑监控接口" + +msgid "Cannot enable service: No monitored WAN interfaces are configured." +msgstr "无法启用服务: 未配置任何监控的 WAN 接口。" + +msgid "Cannot enable service: At least one interface must have a configured check type (Ping, DNS, or TCP)." +msgstr "无法启用服务: 至少需要为一个接口配置有效的检测类型 (Ping、DNS 或 TCP)。" + +msgid "-- Not Configured --" +msgstr "-- 未配置 --" + +msgid "Cannot enable service: At least 2 monitored WAN interfaces must be configured for failover switcher." +msgstr "无法启用服务: 链路备份切换至少需要配置 2 个监控的 WAN 接口。" + +msgid "Cannot enable service: Interface \"%s\" has no health check configured." +msgstr "无法启用服务: 接口「%s」未配置健康检测策略。" + +msgid "Cannot enable service: Interfaces \"%s\" and \"%s\" have the same priority %s." +msgstr "无法启用服务: 接口「%s」和「%s」的路由优先级均为 %s,不允许重复。" + +msgid "Service has been auto-disabled because the configuration is no longer valid: " +msgstr "由于配置不再合法,服务已被自动禁用: " + +msgid "Ping Probe" +msgstr "Ping 探测" + +msgid "DNS Probe" +msgstr "DNS 探测" + +msgid "TCP Probe" +msgstr "TCP 探测" + +msgid "%s (configured)" +msgstr "%s (已配置)" + +msgid "This interface has already been configured." +msgstr "该接口已被配置,请选择其他接口。" + +msgid "Priority must not be empty." +msgstr "优先级不能为空。" + +msgid "Priority %s conflicts with interface \"%s\". Priorities must be unique." +msgstr "优先级 %s 与接口 \"%s\" 冲突。优先级必须是唯一的。" + +msgid "Metric must not be empty." +msgstr "默认跃点不能为空。" + +msgid "Metric %s conflicts with interface \"%s\". Metrics must be unique." +msgstr "跃点数 %s 与接口 \"%s\" 冲突。跃点数必须是唯一的。" + +msgid "Link Name" +msgstr "链路名称" + +msgid "Status" +msgstr "状态" + +msgid "Routing Attributes" +msgstr "路由属性" + +msgid "Latency Details" +msgstr "时延详情" + +msgid "Active" +msgstr "活跃" + +msgid "Standby" +msgstr "备选" + +msgid "Faulted" +msgstr "故障" + +msgid "Comma-separated list of IPs to ping (e.g., 223.5.5.5,8.8.8.8)." +msgstr "通过逗号分隔的 Ping 目标 IP 地址列表 (例如:223.5.5.5,8.8.8.8)。" + + diff --git a/luci-app-linkback/root/usr/share/luci/menu.d/luci-app-linkback.json b/luci-app-linkback/root/usr/share/luci/menu.d/luci-app-linkback.json new file mode 100644 index 000000000..1e3ff8615 --- /dev/null +++ b/luci-app-linkback/root/usr/share/luci/menu.d/luci-app-linkback.json @@ -0,0 +1,37 @@ +{ + "admin/services/linkback": { + "title": "LinkBack 链路守护", + "order": 90, + "action": { + "type": "firstchild" + }, + "depends": { + "acl": [ "luci-app-linkback" ], + "uci": { "linkback": true } + } + }, + "admin/services/linkback/overview": { + "title": "Overview", + "order": 10, + "action": { + "type": "view", + "path": "linkback/overview" + } + }, + "admin/services/linkback/settings": { + "title": "Settings", + "order": 20, + "action": { + "type": "view", + "path": "linkback/settings" + } + }, + "admin/services/linkback/log": { + "title": "Log", + "order": 30, + "action": { + "type": "view", + "path": "linkback/log" + } + } +} diff --git a/luci-app-linkback/root/usr/share/rpcd/acl.d/luci-app-linkback.json b/luci-app-linkback/root/usr/share/rpcd/acl.d/luci-app-linkback.json new file mode 100644 index 000000000..c12bc9d77 --- /dev/null +++ b/luci-app-linkback/root/usr/share/rpcd/acl.d/luci-app-linkback.json @@ -0,0 +1,19 @@ +{ + "luci-app-linkback": { + "description": "ACL for LinkBack Multi-WAN Failover application", + "read": { + "uci": [ "linkback", "network" ], + "ubus": { + "luci.linkback": [ "get_status", "get_log" ], + "network.interface": [ "dump" ], + "network.device": [ "status" ] + } + }, + "write": { + "uci": [ "linkback", "network" ], + "ubus": { + "luci.linkback": [ "manage_service" ] + } + } + } +} diff --git a/luci-app-linkback/root/usr/share/rpcd/ucode/luci.linkback b/luci-app-linkback/root/usr/share/rpcd/ucode/luci.linkback new file mode 100644 index 000000000..4c744a548 --- /dev/null +++ b/luci-app-linkback/root/usr/share/rpcd/ucode/luci.linkback @@ -0,0 +1,64 @@ +'use strict'; + +import { readfile } from 'fs'; +import { popen } from 'fs'; + +const STATUS_FILE = '/var/run/linkback.json'; + +const methods = { + get_status: { + call: function() { + let content = readfile(STATUS_FILE); + let status = null; + + if (content) { + try { + status = json(content); + } catch (err) { + // Handle JSON parse error gracefully + } + } + + if (!status) { + status = { + enabled: false, + check_interval: 5, + active_link: "none", + links: [] + }; + } + + return status; + } + }, + + get_log: { + call: function() { + // Extract last 100 lines of linkbackd logs from syslog + let p = popen('logread -e linkbackd | tail -n 100', 'r'); + let log_content = ''; + if (p) { + log_content = p.read('all'); + p.close(); + } + return { log: log_content || 'No logs available.' }; + } + }, + + manage_service: { + args: { action: 'string' }, + call: function(request) { + let action = request.args?.action; + if (action !== 'start' && action !== 'stop' && action !== 'restart') { + return { success: false, error: 'Invalid action' }; + } + + let cmd = `/etc/init.d/linkback ${action} >/dev/null 2>&1`; + let rc = system(cmd); + + return { success: (rc === 0) }; + } + } +}; + +return { 'luci.linkback': methods }; diff --git a/luci-app-oui/Makefile b/luci-app-oui/Makefile index 949b2fe24..466e42820 100644 --- a/luci-app-oui/Makefile +++ b/luci-app-oui/Makefile @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0-only include $(TOPDIR)/rules.mk -PKG_VERSION:=1.0.6 -PKG_RELEASE:=1 +PKG_VERSION:=1.0.7 +PKG_RELEASE:=2 PKG_LICENSE:=GPL-2.0-only AND CC0-1.0 AND MIT AND LicenseRef-Public-Domain AND LicenseRef-fnOS-Trademark LUCI_MAINTAINER:=coolsnowwolf diff --git a/luci-app-oui/htdocs/luci-static/resources/oui/oui.js b/luci-app-oui/htdocs/luci-static/resources/oui/oui.js index 33db74e2a..4be403b79 100644 --- a/luci-app-oui/htdocs/luci-static/resources/oui/oui.js +++ b/luci-app-oui/htdocs/luci-static/resources/oui/oui.js @@ -75,7 +75,7 @@ fallback(); node.insertBefore(icon, node.firstChild); if (fnos === true) { - icon.title = 'fnOS 飞牛OS'; + icon.title = 'fnOS / FygoOS'; icon.onerror = fallback; icon.src = base + 'fnos.svg'; return; diff --git a/luci-app-oui/tools/test_oui.js b/luci-app-oui/tools/test_oui.js index 636db26f2..8ab2ba12b 100644 --- a/luci-app-oui/tools/test_oui.js +++ b/luci-app-oui/tools/test_oui.js @@ -43,11 +43,11 @@ function setup(fail = false) { assert.equal(unsafe.children[0].title,'Unknown vendor'); const fnos=t.node(); t.oui.decorate(fnos,'BA:71:BE:00:00:01',true); - assert.equal(fnos.children[0].title,'fnOS 飞牛OS'); + assert.equal(fnos.children[0].title,'fnOS / FygoOS'); assert(fnos.children[0].src.endsWith('/fnos.svg')); const overridden=t.node(); t.oui.decorate(overridden,'00:11:22:00:00:00',true); - assert.equal(overridden.children[0].title,'fnOS 飞牛OS'); + assert.equal(overridden.children[0].title,'fnOS / FygoOS'); fnos.children[0].onerror(); assert(fnos.children[0].src.endsWith('/computer.svg')); t=setup(true); @@ -71,7 +71,7 @@ function setup(fail = false) { enabled = true; const host = view.renderHostname('', '00:11:22:00:00:00'); assert.equal(host.children[0].text, ''); - assert.equal(scripts[0].src, '/luci-static/resources/oui/oui.js?v=7'); + assert.equal(scripts[0].src, '/luci-static/resources/oui/oui.js?v=8'); view.renderHostname('host2', '00:11:22:00:00:01'); assert.equal(scripts.length, 1); console.log('OUI runtime and optional integration checks passed'); diff --git a/luci-app-ssserver-next/Makefile b/luci-app-ssserver-next/Makefile new file mode 100644 index 000000000..36843bace --- /dev/null +++ b/luci-app-ssserver-next/Makefile @@ -0,0 +1,24 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=luci-app-ssserver-next +PKG_VERSION:=1.0.0 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Dante +PKG_LICENSE:=Apache-2.0 + +LUCI_TITLE:=LuCI support for Shadowsocks-rust Server (Next) +LUCI_DEPENDS:=+shadowsocks-rust-ssserver-next +luci-base +ucode +ucode-mod-fs +ucode-mod-ubus + +define Package/luci-app-ssserver/postinst +#!/bin/sh +[ -n "$${IPKG_INSTROOT}" ] || { + chmod +x /etc/init.d/ssserver + /etc/init.d/rpcd restart +} +exit 0 +endef + +include $(TOPDIR)/feeds/luci/luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-app-ssserver-next/htdocs/luci-static/resources/view/ssserver/config.js b/luci-app-ssserver-next/htdocs/luci-static/resources/view/ssserver/config.js new file mode 100644 index 000000000..129dae744 --- /dev/null +++ b/luci-app-ssserver-next/htdocs/luci-static/resources/view/ssserver/config.js @@ -0,0 +1,106 @@ +'use strict'; +'require view'; +'require form'; +'require rpc'; + +var callGetCiphers = rpc.declare({ + object: 'luci.ssserver', + method: 'get_ciphers', + expect: {} +}); + +var callGetTFOStatus = rpc.declare({ + object: 'luci.ssserver', + method: 'get_tfo_status', + expect: {} +}); + +var callGetLanIP = rpc.declare({ + object: 'luci.ssserver', + method: 'get_lan_ip', + expect: {} +}); + +return view.extend({ + load: function() { + return Promise.all([ + callGetCiphers(), + callGetTFOStatus(), + callGetLanIP() + ]); + }, + + render: function(data) { + var m, s, o; + var ciphers = data[0].ciphers || []; + var tfo_val = data[1].value || 0; + var lan_ip = data[2].ip || '192.168.1.1'; + + m = new form.Map('ssserver', _('Shadowsocks Server Title') + ' - ' + _('Settings'), + _('A fast and secure tunnel proxy that helps you securely access your local network. ' + + 'This version uses shadowsocks-rust.')); + + s = m.section(form.TypedSection, 'ssserver', _('Settings')); + s.anonymous = true; + s.addremove = false; + + o = s.option(form.Flag, 'enabled', _('Enable')); + o.rmempty = false; + + o = s.option(form.Value, 'server', _('Server Address'), + _('The address the server will bind to. Use 0.0.0.0 for all interfaces.')); + o.datatype = 'ipaddr'; + o.placeholder = '0.0.0.0'; + + o = s.option(form.Value, 'server_port', _('Server Port'), + _('The port the server will listen on.')); + o.datatype = 'port'; + o.placeholder = '8388'; + + o = s.option(form.Value, 'password', _('Password')); + o.password = true; + + o = s.option(form.ListValue, 'method', _('Encryption Method')); + for (var i = 0; i < ciphers.length; i++) { + o.value(ciphers[i]); + } + if (ciphers.indexOf('chacha20-ietf-poly1305') === -1 && ciphers.length === 0) { + o.value('chacha20-ietf-poly1305'); + o.value('aes-256-gcm'); + o.value('aes-128-gcm'); + } + + o = s.option(form.Value, 'timeout', _('ssserver timeout'), _('Connection timeout in seconds.')); + o.datatype = 'uinteger'; + o.placeholder = '300'; + + o = s.option(form.ListValue, 'mode', _('Network Mode')); + o.value('tcp_and_udp', _('TCP and UDP')); + o.value('tcp_only', _('TCP only')); + o.value('udp_only', _('UDP only')); + o.default = 'tcp_and_udp'; + + o = s.option(form.Value, 'dns_resolver', _('DNS Resolver'), + _('DNS server for the shadowsocks server to resolve addresses.')); + o.datatype = 'ipaddr'; + o.placeholder = lan_ip; + o.default = lan_ip; + + o = s.option(form.Flag, 'open_firewall', _('Open Firewall'), + _('Automatically open the server port in the firewall (WAN).')); + + var tfo_status_msg = ''; + if (tfo_val === 0) { + tfo_status_msg = ' (' + _('Not supported or disabled in kernel') + ')'; + } else if (tfo_val === 1) { + tfo_status_msg = ' (' + _('Enabled for client only') + ')'; + } else if (tfo_val === 2 || tfo_val === 3) { + tfo_status_msg = ' (' + _('Enabled and supported') + ')'; + } + + o = s.option(form.Flag, 'fast_open', _('TCP Fast Open'), + _('Enable TCP Fast Open (requires kernel support).') + tfo_status_msg); + + return m.render(); + } +}); diff --git a/luci-app-ssserver-next/htdocs/luci-static/resources/view/ssserver/log.js b/luci-app-ssserver-next/htdocs/luci-static/resources/view/ssserver/log.js new file mode 100644 index 000000000..9090b316b --- /dev/null +++ b/luci-app-ssserver-next/htdocs/luci-static/resources/view/ssserver/log.js @@ -0,0 +1,47 @@ +'use strict'; +'require view'; +'require rpc'; +'require poll'; + +var callGetLog = rpc.declare({ + object: 'luci.ssserver', + method: 'get_log', + expect: {} +}); + +return view.extend({ + handleSaveApply: null, + handleSave: null, + handleReset: null, + + render: function() { + var log_view = E('textarea', { + id: 'ssserver_log_content', + style: 'width:100%; height:500px; background:#f4f4f4; color:#333; padding:10px; border:1px solid #ccc; border-radius:3px; font-family:monospace; font-size:12px; overflow-y:auto; white-space:pre-wrap; word-break:break-all; margin-top:10px;', + readonly: 'readonly' + }, _('Loading logs...')); + + poll.add(function() { + return callGetLog().then(function(res) { + var area = document.getElementById('ssserver_log_content'); + if (area) { + if (res && res.log) { + area.value = res.log; + area.scrollTop = area.scrollHeight; + } else { + area.value = _('No log entries found.'); + } + } + }); + }, 5); + + return E('div', { 'class': 'cbi-map' }, [ + E('h2', {}, _('Shadowsocks Server Title') + ' - ' + _('Log')), + E('div', { 'class': 'cbi-map-descr' }, _('Logs are updated every 5 seconds.')), + E('fieldset', { 'class': 'cbi-section' }, [ + E('legend', {}, _('Log')), + E('div', { 'class': 'cbi-section-node' }, log_view) + ]) + ]); + } +}); diff --git a/luci-app-ssserver-next/htdocs/luci-static/resources/view/ssserver/overview.js b/luci-app-ssserver-next/htdocs/luci-static/resources/view/ssserver/overview.js new file mode 100644 index 000000000..dabfcc129 --- /dev/null +++ b/luci-app-ssserver-next/htdocs/luci-static/resources/view/ssserver/overview.js @@ -0,0 +1,189 @@ +'use strict'; +'require view'; +'require rpc'; +'require poll'; +'require ui'; +'require uci'; + +const callSsserverStatus = rpc.declare({ + object: 'luci.ssserver', + method: 'get_status' +}); + +const callServiceAction = rpc.declare({ + object: 'luci.ssserver', + method: 'service_action', + params: [ 'action' ] +}); + +const callSsserverLanIp = rpc.declare({ + object: 'luci.ssserver', + method: 'get_lan_ip' +}); + +function renderState(status) { + let text = _('Stopped'); + let color = 'red'; + + if (status.running) { + text = _('Running'); + if (status.pid) { + text += ' [PID: ' + status.pid + ']'; + } + color = 'green'; + } + + return { text, color }; +} + +return view.extend({ + handleSaveApply: null, + handleSave: null, + handleReset: null, + + load: function() { + return Promise.all([ + callSsserverStatus(), + uci.load('ssserver'), + callSsserverLanIp().catch(function() { return { ip: '' }; }) + ]); + }, + + render: function(data) { + const status = data && data[0] ? data[0] : {}; + const stateInfo = renderState(status); + const lanIpInfo = data && data[2] ? data[2] : { ip: '' }; + const lanIp = lanIpInfo.ip || '8.8.8.8'; + + // Read configurations from UCI + const ssserverConfig = uci.get('ssserver', 'main') || {}; + const server = ssserverConfig.server || '0.0.0.0'; + const port = ssserverConfig.server_port || '8388'; + const method = ssserverConfig.method || 'chacha20-ietf-poly1305'; + const timeout = ssserverConfig.timeout || '300'; + + let modeText = _('TCP and UDP'); + if (ssserverConfig.mode === 'tcp_only') modeText = _('TCP only'); + if (ssserverConfig.mode === 'udp_only') modeText = _('UDP only'); + + const dns = ssserverConfig.dns_resolver || lanIp; + const tfo = (ssserverConfig.fast_open === '1') ? _('Enabled') : _('Disabled'); + const firewall = (ssserverConfig.open_firewall === '1') ? _('Enabled') : _('Disabled'); + + const container = E('div', { 'class': 'cbi-map' }, [ + E('h2', {}, _('Shadowsocks Server Title') + ' - ' + _('Overview')), + E('div', { 'class': 'cbi-map-descr' }, _('Overview of ssserver running status and actual runtime configurations.')) + ]); + + // Service Status Section (Aligned with lucky style) + const statusSection = E('fieldset', { 'class': 'cbi-section' }, [ + E('legend', {}, _('Service Status')), + E('div', { 'class': 'cbi-section-node' }, [ + E('table', { 'class': 'table cbi-section-table' }, [ + E('tr', { 'class': 'tr' }, [ + E('td', { 'class': 'td left', 'width': '33%' }, _('Current Status')), + E('td', { 'class': 'td left' }, [ + E('span', { + id: 'ssserver-status-text', + 'style': 'font-weight:bold; color:' + stateInfo.color + '; margin-right:15px;' + }, stateInfo.text), + E('button', { + id: 'ssserver-restart-btn', + 'class': 'btn cbi-button cbi-button-apply', + 'style': 'display:' + (status.running ? 'inline-block' : 'none') + ';', + click: ui.createHandlerFn(this, function(ev) { + if (!ev || !ev.currentTarget) return; + const btn = ev.currentTarget; + btn.disabled = true; + + ui.addNotification(null, E('p', _('Restarting Shadowsocks Server, please wait...')), 'info'); + + return callServiceAction('restart').then(function(res) { + btn.disabled = false; + if (res && res.success) { + ui.addNotification(null, E('p', _('Service restarted successfully.')), 'info'); + } else { + ui.addNotification(null, E('p', _('Failed to restart service.')), 'error'); + } + }).catch(function(err) { + btn.disabled = false; + ui.addNotification(null, E('p', _('An error occurred: ') + err.message), 'error'); + }); + }) + }, _('Restart')) + ]) + ]) + ]) + ]) + ]); + + container.appendChild(statusSection); + + // Runtime Configuration Section (Aligned with lucky style) + const configSection = E('fieldset', { 'class': 'cbi-section' }, [ + E('legend', {}, _('Runtime Configurations')), + E('div', { 'class': 'cbi-section-node' }, [ + E('table', { 'class': 'table cbi-section-table' }, [ + E('tr', { 'class': 'tr' }, [ + E('td', { 'class': 'td left', 'width': '33%' }, _('Server Address')), + E('td', { 'class': 'td left' }, E('code', {}, server)) + ]), + E('tr', { 'class': 'tr' }, [ + E('td', { 'class': 'td left' }, _('Server Port')), + E('td', { 'class': 'td left' }, E('code', {}, port)) + ]), + E('tr', { 'class': 'tr' }, [ + E('td', { 'class': 'td left' }, _('Encryption Method')), + E('td', { 'class': 'td left' }, E('code', {}, method)) + ]), + E('tr', { 'class': 'tr' }, [ + E('td', { 'class': 'td left' }, _('Network Mode')), + E('td', { 'class': 'td left' }, modeText) + ]), + E('tr', { 'class': 'tr' }, [ + E('td', { 'class': 'td left' }, _('ssserver timeout')), + E('td', { 'class': 'td left' }, timeout + ' ' + _('seconds')) + ]), + E('tr', { 'class': 'tr' }, [ + E('td', { 'class': 'td left' }, _('DNS Resolver')), + E('td', { 'class': 'td left' }, E('code', {}, dns)) + ]), + E('tr', { 'class': 'tr' }, [ + E('td', { 'class': 'td left' }, _('TCP Fast Open')), + E('td', { 'class': 'td left' }, tfo) + ]), + E('tr', { 'class': 'tr' }, [ + E('td', { 'class': 'td left' }, _('Open Firewall')), + E('td', { 'class': 'td left' }, firewall) + ]) + ]) + ]) + ]); + + container.appendChild(configSection); + + // Add live status polling + poll.add(function() { + return callSsserverStatus().then(function(status) { + const textNode = document.getElementById('ssserver-status-text'); + const restartBtn = document.getElementById('ssserver-restart-btn'); + + if (textNode && restartBtn) { + const stateInfo = renderState(status || {}); + + textNode.textContent = stateInfo.text; + textNode.style.color = stateInfo.color; + + // Toggle button visibility based on runtime state + if (status.running) { + restartBtn.style.display = 'inline-block'; + } else { + restartBtn.style.display = 'none'; + } + } + }); + }, 5); + + return container; + } +}); diff --git a/luci-app-ssserver-next/po/zh-cn b/luci-app-ssserver-next/po/zh-cn new file mode 120000 index 000000000..8d69574dd --- /dev/null +++ b/luci-app-ssserver-next/po/zh-cn @@ -0,0 +1 @@ +zh_Hans \ No newline at end of file diff --git a/luci-app-ssserver-next/po/zh_Hans/ssserver.po b/luci-app-ssserver-next/po/zh_Hans/ssserver.po new file mode 100644 index 000000000..6bc7cb553 --- /dev/null +++ b/luci-app-ssserver-next/po/zh_Hans/ssserver.po @@ -0,0 +1,146 @@ +msgid "" +msgstr "Content-Type: text/plain; charset=UTF-8" + +msgid "Shadowsocks Server" +msgstr "Shadowsocks服务端" + +msgid "Overview" +msgstr "概览" + +msgid "Service Status" +msgstr "服务状态" + +msgid "Current Status" +msgstr "当前状态" + +msgid "Running" +msgstr "运行中" + +msgid "Stopped" +msgstr "已停止" + +msgid "Restart" +msgstr "重启" + +msgid "Unknown" +msgstr "未知" + +msgid "A fast and secure tunnel proxy that helps you securely access your local network. This version uses shadowsocks-rust." +msgstr "一个快速、安全的隧道代理,可以帮助您安全地访问局域网。此版本使用 shadowsocks-rust。" + +msgid "Settings" +msgstr "设置" + +msgid "Log" +msgstr "日志" + +msgid "Enable" +msgstr "启用" + +msgid "Server Address" +msgstr "服务器地址" + +msgid "The address the server will bind to. Use 0.0.0.0 for all interfaces." +msgstr "服务器绑定的地址。使用 0.0.0.0 以监听所有接口。" + +msgid "Server Port" +msgstr "服务器端口" + +msgid "The port the server will listen on." +msgstr "服务器监听的端口。" + +msgid "Password" +msgstr "密码" + +msgid "Encryption Method" +msgstr "加密方式" + +msgid "ssserver timeout" +msgstr "超时时间" + +msgid "Connection timeout in seconds." +msgstr "连接超时时间(秒)。" + +msgid "Network Mode" +msgstr "网络模式" + +msgid "TCP and UDP" +msgstr "TCP 和 UDP" + +msgid "TCP only" +msgstr "仅 TCP" + +msgid "UDP only" +msgstr "仅 UDP" + +msgid "TCP Fast Open" +msgstr "TCP 快速打开" + +msgid "Enable TCP Fast Open (requires kernel support)." +msgstr "启用 TCP 快速打开(需要内核支持)。" + +msgid "Not supported or disabled in kernel" +msgstr "内核不支持或已禁用" + +msgid "Enabled for client only" +msgstr "仅对客户端开启" + +msgid "Enabled and supported" +msgstr "已开启并支持" + +msgid "DNS Resolver" +msgstr "DNS 解析服务器" + +msgid "DNS server for the shadowsocks server to resolve addresses." +msgstr "Shadowsocks 服务端用于解析地址的 DNS 服务器。" + +msgid "Open Firewall" +msgstr "自动开放防火墙" + +msgid "Automatically open the server port in the firewall (WAN)." +msgstr "自动在防火墙 (WAN) 中开放服务器端口。" + +msgid "Shadowsocks Server Log" +msgstr "Shadowsocks服务端日志" + +msgid "Logs are updated every 5 seconds." +msgstr "日志每 5 秒更新一次。" + +msgid "No log entries found." +msgstr "未找到日志条目。" + +msgid "Default" +msgstr "默认" + +msgid "Enabled" +msgstr "已启用" + +msgid "Disabled" +msgstr "已禁用" + +msgid "Overview of ssserver running status and actual runtime configurations." +msgstr "Shadowsocks服务端运行状态及当前运行配置概览。" + +msgid "Restarting Shadowsocks Server, please wait..." +msgstr "正在重启Shadowsocks服务端,请稍候..." + +msgid "Service restarted successfully." +msgstr "服务重启成功。" + +msgid "Failed to restart service." +msgstr "服务重启失败。" + +msgid "An error occurred: " +msgstr "发生错误:" + +msgid "Runtime Configurations" +msgstr "运行配置" + +msgid "seconds" +msgstr "秒" + +msgid "Loading logs..." +msgstr "正在加载日志..." + +msgid "Shadowsocks Server Title" +msgstr "Shadowsocks 服务端" diff --git a/luci-app-ssserver-next/root/etc/config/ssserver b/luci-app-ssserver-next/root/etc/config/ssserver new file mode 100644 index 000000000..cb167f298 --- /dev/null +++ b/luci-app-ssserver-next/root/etc/config/ssserver @@ -0,0 +1,11 @@ + +config ssserver 'main' + option enabled '0' + option server '0.0.0.0' + option server_port '8388' + option password 'password' + option method 'chacha20-ietf-poly1305' + option timeout '300' + option mode 'tcp_and_udp' + option fast_open '0' + option open_firewall '1' diff --git a/luci-app-ssserver-next/root/etc/init.d/ssserver b/luci-app-ssserver-next/root/etc/init.d/ssserver new file mode 100755 index 000000000..5482d2697 --- /dev/null +++ b/luci-app-ssserver-next/root/etc/init.d/ssserver @@ -0,0 +1,104 @@ +#!/bin/sh /etc/rc.common + +USE_PROCD=1 +START=95 + +CONF_FILE="/var/etc/ssserver.json" + +ss_server_generate_json() { + local server server_port password method timeout fast_open dns_resolver lan_ip mode + config_get server "$1" server "0.0.0.0" + config_get server_port "$1" server_port "8388" + config_get password "$1" password "password" + config_get method "$1" method "chacha20-ietf-poly1305" + config_get timeout "$1" timeout "300" + config_get mode "$1" mode "tcp_and_udp" + config_get_bool fast_open "$1" fast_open 0 + config_get dns_resolver "$1" dns_resolver + + # If DNS is empty, try to get LAN IP + if [ -z "$dns_resolver" ]; then + lan_ip=$(ubus call network.interface.lan status | jsonfilter -e '@["ipv4-address"][0].address') + dns_resolver="${lan_ip:-8.8.8.8}" + fi + + mkdir -p /var/etc + + cat > "$CONF_FILE" <&1'); + if (p) { + let output = p.read('all'); + p.close(); + let start = index(output, '--encrypt-method'); + if (start >= 0) { + let sub = substr(output, start); + let res = match(sub, /possible values: (([^\]\r\n]|[\r\n])+)/); + if (res) { + let list = split(res[1], /,\s*/); + for (let c in list) { + let val = rtrim(ltrim(c)); + // Clean up possible newlines and extra spaces + val = replace(val, /\s+/g, ""); + if (val) push(ciphers, val); + } + } + } + } + // Fallback if parsing fails or returns nothing + if (length(ciphers) == 0) { + ciphers = [ + 'chacha20-ietf-poly1305', + 'aes-256-gcm', + 'aes-128-gcm', + '2022-blake3-aes-128-gcm', + '2022-blake3-aes-256-gcm', + '2022-blake3-chacha20-poly1305' + ]; + } + return { ciphers: ciphers }; + } + }, + + get_tfo_status: { + call: function() { + let val = rtrim(fs.readfile('/proc/sys/net/ipv4/tcp_fastopen') || '0'); + return { value: +val }; + } + }, + + get_lan_ip: { + call: function() { + let u = connect(); + let ip = ''; + if (u) { + let status = u.call('network.interface.lan', 'status'); + if (status && type(status['ipv4-address']) === 'array' && length(status['ipv4-address']) > 0) { + ip = status['ipv4-address'][0].address; + } + u.disconnect(); + } + return { ip: ip }; + } + }, + + get_status: { + call: function() { + let u = connect(); + let running = false; + let pid = null; + if (u) { + let res = u.call('service', 'list', { name: 'ssserver' }); + if (res && res.ssserver && res.ssserver.instances) { + let inst = res.ssserver.instances.instance1; + if (inst && inst.running) { + running = true; + pid = inst.pid; + } + } + u.disconnect(); + } + return { running: running, pid: pid }; + } + }, + + service_action: { + args: { action: '' }, + call: function(req) { + let action = req.args?.action ?? ''; + if (action != 'start' && action != 'stop' && action != 'restart' && action != 'reload') + return { success: false, error: 'invalid action' }; + let rc = system('/etc/init.d/ssserver ' + action + ' >/dev/null 2>&1'); + return { success: (rc === 0), applied: (rc === 0) }; + } + } +}; + +return { 'luci.ssserver': methods }; diff --git a/luci-base/po/templates/base.pot b/luci-base/po/templates/base.pot index 9266a9e7d..857b78637 100644 --- a/luci-base/po/templates/base.pot +++ b/luci-base/po/templates/base.pot @@ -13700,3 +13700,6 @@ msgstr "" msgid "Online Hosts" msgstr "" + +msgid "Connection count" +msgstr "" diff --git a/luci-base/po/zh_Hans/base.po b/luci-base/po/zh_Hans/base.po index 587b4e8b2..1f67e8658 100644 --- a/luci-base/po/zh_Hans/base.po +++ b/luci-base/po/zh_Hans/base.po @@ -14167,3 +14167,6 @@ msgstr "离线" msgid "Online Hosts" msgstr "在线主机" + +msgid "Connection count" +msgstr "连接数" diff --git a/luci-base/po/zh_Hant/base.po b/luci-base/po/zh_Hant/base.po index 5d7f7c2d8..1f2c21119 100644 --- a/luci-base/po/zh_Hant/base.po +++ b/luci-base/po/zh_Hant/base.po @@ -14022,3 +14022,6 @@ msgstr "離線" msgid "Online Hosts" msgstr "在線主機" + +msgid "Connection count" +msgstr "連線數" diff --git a/luci-mod-status/Makefile b/luci-mod-status/Makefile index 9a1f49fc3..662df042d 100644 --- a/luci-mod-status/Makefile +++ b/luci-mod-status/Makefile @@ -7,9 +7,9 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=LuCI Status Pages -LUCI_DEPENDS:=+luci-base +libiwinfo +rpcd-mod-iwinfo +ucode +ucode-mod-fs +ucode-mod-ubus +luci-app-oui +LUCI_DEPENDS:=+luci-base +luci-app-oui +libiwinfo +rpcd-mod-iwinfo +rpcd-mod-rrdns +ucode +ucode-mod-fs +ucode-mod-ubus +ucode-mod-socket -PKG_RELEASE:=8 +PKG_RELEASE:=9 PKG_BUILD_DEPENDS:=iwinfo PKG_LICENSE:=Apache-2.0 diff --git a/luci-mod-status/htdocs/luci-static/resources/view/status/include/30_network.js b/luci-mod-status/htdocs/luci-static/resources/view/status/include/30_network.js index b5f84a4fd..aeaf98ef9 100644 --- a/luci-mod-status/htdocs/luci-static/resources/view/status/include/30_network.js +++ b/luci-mod-status/htdocs/luci-static/resources/view/status/include/30_network.js @@ -165,8 +165,8 @@ return baseclass.extend({ const fields = [ { label: _('Active Connections'), value: ct_max ? ct_count : null }, { label: _('Online Users'), value: onlineusers ? onlineusers.onlineusers : null }, - { label: _('Total download bandwidth'), value: this.bandwidthBar(download, capacity) }, - { label: _('Total upload bandwidth'), value: this.bandwidthBar(upload, capacity) } + { label: _('Total upload bandwidth'), value: this.bandwidthBar(upload, capacity) }, + { label: _('Total download bandwidth'), value: this.bandwidthBar(download, capacity) } ]; const ctstatus = E('table', { 'class': 'table' }); diff --git a/luci-mod-status/htdocs/luci-static/resources/view/status/include/40_dhcp.js b/luci-mod-status/htdocs/luci-static/resources/view/status/include/40_dhcp.js index 36c6608c1..487488e3e 100644 --- a/luci-mod-status/htdocs/luci-static/resources/view/status/include/40_dhcp.js +++ b/luci-mod-status/htdocs/luci-static/resources/view/status/include/40_dhcp.js @@ -44,7 +44,7 @@ return baseclass.extend({ if (!this.ouiLoader) { this.ouiLoader = Promise.all([L.resolveDefault(uci.load('oui')), new Promise(function(resolve) { const script = document.createElement('script'); - script.src = L.resource('oui/oui.js') + '?v=7'; + script.src = L.resource('oui/oui.js') + '?v=8'; script.onload = function() { resolve(window.luciOUI); }; script.onerror = function() { resolve(null); }; document.head.appendChild(script); @@ -88,7 +88,13 @@ return baseclass.extend({ return this.rateValue(this.clientAddresses(lease, hints), data, direction); }, - rateValue(addresses, data, direction, mac) { + rateValue(addresses, data, direction, mac, online) { + if (direction == 'connections') { + if (online === false) + return [0, '0']; + const value = data?.connections?.[mac?.toUpperCase()]; + return value != null ? [Number(value), String(value)] : [-1, '-']; + } if (direction == 'total') { const value = data?.totals?.[mac?.toUpperCase()]; return value != null ? [Number(value), '%1024.2mB'.format(value)] : [-1, '-']; @@ -103,13 +109,14 @@ return baseclass.extend({ return addresses.length ? [ total, '%1024.1mB/s'.format(total) ] : [ -1, '-' ]; }, - rateCell(lease, hints, direction) { + rateCell(lease, hints, direction, online) { const addresses = this.clientAddresses(lease, hints); - const value = this.rateValue(addresses, this.rateData, direction, lease.macaddr); + const value = this.rateValue(addresses, this.rateData, direction, lease.macaddr, online); return [ value[0], E('span', { 'class': 'luci-client-rate', 'data-addresses': JSON.stringify(addresses), 'data-direction': direction, + 'data-online': online === false ? '0' : '1', 'data-mac': lease.macaddr || '' }, value[1]) ]; }, @@ -197,7 +204,7 @@ return baseclass.extend({ this.rateData = data; // Query again: the normal overview refresh may have replaced the rows. document.querySelectorAll('.luci-client-rate').forEach(cell => { - const value = this.rateValue(JSON.parse(cell.dataset.addresses), data, cell.dataset.direction, cell.dataset.mac); + const value = this.rateValue(JSON.parse(cell.dataset.addresses), data, cell.dataset.direction, cell.dataset.mac, cell.dataset.online !== '0'); cell.textContent = value[1]; cell.closest('td')?.setAttribute('data-value', value[0]); }); @@ -374,8 +381,9 @@ return baseclass.extend({ }, renderLeases(dhcp_leases, host_hints, macaddr, web, arp, history) { + const arpClients = this.arpLeases(arp); const leases = [...(Array.isArray(dhcp_leases.dhcp_leases) ? dhcp_leases.dhcp_leases : []), - ...this.arpLeases(arp), + ...arpClients, ...(Array.isArray(history?.dhcp_leases) ? history.dhcp_leases : []).map(lease => ({ ...lease, _historical: true }))]; const leases6 = [...(Array.isArray(dhcp_leases.dhcp6_leases) ? dhcp_leases.dhcp6_leases : []), ...(Array.isArray(history?.dhcp6_leases) ? history.dhcp6_leases : []).map(lease => ({ ...lease, _historical: true }))]; @@ -403,9 +411,8 @@ return baseclass.extend({ }; const clients = this.mergeLeases(leases, leases6, host_hints); - const onlineMACs = new Set(String(arp || '').trim().split(/\n/).map(line => line.trim().split(/\s+/)) - .filter(fields => fields.length == 6 && fields[5] == 'br-lan') - .map(fields => fields[3].toUpperCase())); + // Failed neighbours can retain their MAC in /proc/net/arp with flags 0x0. + const onlineMACs = new Set(arpClients.map(client => client.macaddr)); const table = E('table', { 'id': 'status_leases', 'class': 'table leases' }, [ E('tr', { 'class': 'tr table-titles' }, [ E('th', { 'class': 'th' }, _('Online')), @@ -416,6 +423,7 @@ return baseclass.extend({ E('th', { 'class': 'th' }, _('Upload')), E('th', { 'class': 'th' }, _('Download')), E('th', { 'class': 'th', 'data-total-traffic': '1' }, _('Total traffic')), + E('th', { 'class': 'th' }, _('Connection count')), isReadonlyView ? E([]) : E('th', { 'class': 'th cbi-section-actions center' }, _('Static Lease')) ]) ]); @@ -423,9 +431,7 @@ return baseclass.extend({ this.initLeaseTable(table); cbi_update_table(table, clients.map(client => { const hint = machints.find(h => h[0].toUpperCase() == client.macaddr); - let host = client.hostname || hint?.[1]; - if (hint && client.hostname && client.hostname != hint[1]) - host = '%s (%s)'.format(client.hostname, hint[1]); + const host = client.hostname || hint?.[1]; const vendor = macaddr?.[client.macaddr?.toLowerCase()]?.vendor; const online = onlineMACs.has(client.macaddr); const status = online ? _('Online') : _('Offline'); @@ -444,7 +450,8 @@ return baseclass.extend({ vendor ? `${client.macaddr} (${vendor})` : client.macaddr || '-', this.rateCell(client, host_hints, 'upload'), this.rateCell(client, host_hints, 'download'), - this.rateCell(client, host_hints, 'total') + this.rateCell(client, host_hints, 'total'), + this.rateCell(client, host_hints, 'connections', online) ]; if (!isReadonlyView) columns.push(this.leaseActions(client)); diff --git a/luci-mod-status/root/usr/libexec/luci-client-history b/luci-mod-status/root/usr/libexec/luci-client-history index 814329890..de4ebff65 100755 --- a/luci-mod-status/root/usr/libexec/luci-client-history +++ b/luci-mod-status/root/usr/libexec/luci-client-history @@ -3,7 +3,8 @@ 'use strict'; import { readfile, writefile, rename, chmod } from 'fs'; import { connect } from 'ubus'; -import { arp_leases, update_history } from 'luci.client_history'; +import { netbios_names } from 'luci.client_names'; +import { arp_leases, update_history, reverse_names } from 'luci.client_history'; const path = '/tmp/luci-client-history.json'; const boot_id = trim(readfile('/proc/sys/kernel/random/boot_id') || ''); @@ -13,11 +14,24 @@ let previous = {}; try { previous = json(readfile(path) || '{}'); } catch (e) {} const bus = connect(); let current = bus ? bus.call('luci-rpc', 'getDHCPLeases', {}) : null; +current ||= {}; +const active = arp_leases(readfile('/proc/net/arp')); +const reverse_dns = reverse_names(previous, current, active, boot_id, + int(split(readfile('/proc/uptime'), ' ')[0]), function(addrs) { + let names = bus ? (bus.call('network.rrdns', 'lookup', { addrs, timeout: 1000, limit: 8 }) || {}) : {}; + return { ...names, ...netbios_names(filter(addrs, ip => !names[ip])) }; + }); if (bus) bus.disconnect(); -current ||= {}; -current.dhcp_leases = [ ...(current.dhcp_leases || []), ...arp_leases(readfile('/proc/net/arp')) ]; -const next = sprintf('%J', update_history(previous, current, boot_id)); +// Recheck ownership after the asynchronous DNS query. +const owners = {}; +for (let lease in arp_leases(readfile('/proc/net/arp'))) + owners[lease.ipaddr] = lease.macaddr; +current.dhcp_leases = [ ...(current.dhcp_leases || []), + ...filter(active, lease => owners[lease.ipaddr] == lease.macaddr) ]; +const result = update_history(previous, current, boot_id); +result.reverse_dns = reverse_dns; +const next = sprintf('%J', result); if (next != readfile(path)) { if (writefile(path + '.new', next) != length(next)) exit(1); diff --git a/luci-mod-status/root/usr/share/ucode/luci/client_history.uc b/luci-mod-status/root/usr/share/ucode/luci/client_history.uc index e9b3c25fb..9d9ee6d4d 100644 --- a/luci-mod-status/root/usr/share/ucode/luci/client_history.uc +++ b/luci-mod-status/root/usr/share/ucode/luci/client_history.uc @@ -47,3 +47,43 @@ export function update_history(previous, current, boot_id) { } return result; }; + +// Cache both successful and unsuccessful PTR lookups. Bind results to MAC + IP +// so an address handed to another client cannot inherit the former name. +export function reverse_names(previous, current, active, boot_id, now, lookup) { + let old = type(previous) == 'object' && previous.boot_id == boot_id && + type(previous.reverse_dns) == 'object' ? previous.reverse_dns : {}; + let cache = {}, named = {}, pending = []; + for (let family in ['dhcp_leases', 'dhcp6_leases']) + for (let lease in current[family] || []) + if (type(lease.hostname) == 'string' && length(lease.hostname) && + lease.hostname != '*' && lease.hostname != lease.ipaddr && lease.macaddr) + named[uc(lease.macaddr)] = true; + for (let lease in active) { + if (named[lease.macaddr]) + continue; + let key = lease.macaddr + '@' + lease.ipaddr; + let entry = type(old[key]) == 'object' ? old[key] : {}; + cache[key] = entry; + if ((!entry.next || entry.next <= now) && length(pending) < 32) { + push(pending, lease.ipaddr); + entry.next = now + 300; + } + } + let answers = length(pending) ? lookup(pending) : {}; + for (let lease in active) { + let entry = cache[lease.macaddr + '@' + lease.ipaddr]; + if (!entry) + continue; + let name = answers?.[lease.ipaddr]; + if (type(name) == 'string') { + name = replace(name, /\.$/, ''); + if (length(name) <= 253 && match(name, /^[a-z0-9_][a-z0-9_.-]*$/i) && + !match(name, /^[0-9.]+$/)) + entry.hostname = name; + } + if (entry.hostname) + lease.hostname = entry.hostname; + } + return cache; +}; diff --git a/luci-mod-status/root/usr/share/ucode/luci/client_names.uc b/luci-mod-status/root/usr/share/ucode/luci/client_names.uc new file mode 100644 index 000000000..046033790 --- /dev/null +++ b/luci-mod-status/root/usr/share/ucode/luci/client_names.uc @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: Apache-2.0 +// RFC 1002 NBSTAT: unicast queries only, to known LAN clients. +import { create, poll, AF_INET, SOCK_DGRAM, POLLIN, MSG_DONTWAIT } from 'socket'; + +function byte(data, offset) { return ord(substr(data, offset, 1)); }; +function word(data, offset) { return byte(data, offset) * 256 + byte(data, offset + 1); }; +function skip_name(data, offset) { + while (offset < length(data)) { + let size = byte(data, offset++); + if (!size) return offset; + if ((size & 0xc0) == 0xc0) + return offset < length(data) ? offset + 1 : -1; + if (size > 63 || offset + size > length(data)) return -1; + offset += size; + } + return -1; +}; + +export function nbstat_name(data, id) { + if (type(data) != 'string' || length(data) < 12 || word(data, 0) != id || + (word(data, 2) & 0xfa0f) != 0x8000 || word(data, 6) != 1) + return null; + let offset = 12; + for (let i = 0; i < word(data, 4); i++) { + offset = skip_name(data, offset); + if (offset < 0 || offset + 4 > length(data)) return null; + offset += 4; + } + offset = skip_name(data, offset); + if (offset < 0 || offset + 11 > length(data) || word(data, offset) != 0x21 || + word(data, offset + 2) != 1) return null; + let size = word(data, offset + 8); + offset += 10; + if (size < 1 || offset + size > length(data)) return null; + let count = byte(data, offset++), server = null; + if (1 + count * 18 > size) return null; + for (let i = 0; i < count; i++, offset += 18) { + let suffix = byte(data, offset + 15), flags = word(data, offset + 16); + let name = trim(substr(data, offset, 15)); + if ((flags & 0x8000) || !match(name, /^[a-z0-9_][a-z0-9_.-]*$/i)) continue; + if (suffix == 0) return name; + if (suffix == 0x20) server = name; + } + return server; +}; + +export function netbios_names(addresses) { + let jobs = [], result = {}; + for (let ip in addresses) { + if (length(jobs) >= 32) break; + let sock = create(AF_INET, SOCK_DGRAM); + if (!sock) continue; + let id = (int(time()) + length(jobs)) & 65535; + let query = chr(id >> 8) + chr(id & 255) + '\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00' + + '\x20CKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x00\x00\x21\x00\x01'; + if (!sock.connect({ family: AF_INET, address: ip, port: 137 }) || sock.send(query) != length(query)) { + sock.close(); + continue; + } + push(jobs, [sock, POLLIN, ip, id]); + } + // Batch all clients; never wait one second per address. + for (let round = 0; round < 4 && length(jobs); round++) { + let events = poll(250, ...jobs) || []; + for (let event in events) { + if (!event[1]) continue; + let name = nbstat_name(event[0].recv(4096, MSG_DONTWAIT), event[3]); + if (name) result[event[2]] = name; + event[0].close(); + jobs = filter(jobs, job => job[2] != event[2]); + } + } + for (let job in jobs) job[0].close(); + return result; +}; diff --git a/luci-mod-status/tests/README.md b/luci-mod-status/tests/README.md index e7b01b98e..925b49477 100644 --- a/luci-mod-status/tests/README.md +++ b/luci-mod-status/tests/README.md @@ -17,3 +17,17 @@ Run `ucode client-history.uc` on a target with the installed restart, IP reassignment, changing IPv6 addresses and boot-ID reset without rebooting the device. Run the existing frontend tests with `node libs/rpcd-mod-luci/tests/traffic-ui.js` from the LuCI repository. + +For unnamed clients in the resolved LAN ARP table, the collector attempts DNS +PTR lookup, then unicast NetBIOS NBSTAT (UDP 137) when DNS has no answer. +Positive and negative results are cached for five minutes, keyed by MAC and IP. +Each pass considers at most 32 due addresses; DNS and NetBIOS each have a +one-second batch wait budget. Names are retained with the boot-local history; +DHCP names take precedence. Devices without PTR or NetBIOS service keep their +existing label. No subnet-wide or broadcast scan is performed. + +Run `ucode client-names.uc` with the installed `luci.client_history`, +`luci.client_names` and `ucode-mod-socket` modules. It checks positive/negative +caching, retry timing, address reuse, DHCP priority, boot reset and malformed +NBSTAT responses. For a live check, compare `netbios_names([ip])` with a known +NetBIOS responder; an unanswered query is not evidence of an offline client. diff --git a/luci-mod-status/tests/client-names.uc b/luci-mod-status/tests/client-names.uc new file mode 100644 index 000000000..09d8c35a4 --- /dev/null +++ b/luci-mod-status/tests/client-names.uc @@ -0,0 +1,35 @@ +import { reverse_names } from 'luci.client_history'; +import { nbstat_name, netbios_names } from 'luci.client_names'; +function check(v, message) { if (!v) die(message + '\n'); }; +let calls = 0; +const mac = '00:0C:29:D2:60:68', ip = '192.168.0.104'; +function active() { return [{macaddr:mac,ipaddr:ip}]; }; +let leases = active(); +let cache = reverse_names({}, {}, leases, 'boot', 10, function(ips) { + calls++; return {[ip]:'lean-esx.lan.'}; +}); +check(leases[0].hostname == 'lean-esx.lan', 'PTR name normalized'); +let previous = {boot_id:'boot',reverse_dns:cache}; +leases = active(); +reverse_names(previous, {}, leases, 'boot', 20, function() { die('cache missed'); }); +check(leases[0].hostname == 'lean-esx.lan', 'cached hostname restored'); +reverse_names(previous, {}, active(), 'boot', 310, function() { calls++; return {}; }); +check(calls == 2, 'refresh after five minutes'); +leases = [{macaddr:'00:11:22:33:44:55',ipaddr:ip}]; +let miss = reverse_names(previous, {}, leases, 'boot', 20, function() {calls++; return {};}); +check(!leases[0].hostname && calls == 3, 'address reuse does not inherit name'); +reverse_names({boot_id:'boot',reverse_dns:miss}, {}, leases, 'boot', 21, function() {die('negative cache missed');}); +reverse_names(previous, {dhcp_leases:[{macaddr:mac,hostname:'dhcp-name'}]}, active(), 'boot', 999, function() {die('queried named DHCP client');}); +reverse_names(previous, {}, active(), 'reboot', 1, function() {calls++;return {};}); +check(calls == 4, 'boot resets cache'); +// RFC 1002 response: skip group name and prefer the workstation name. +const records = 'WORKGROUP \x00' + chr(0x80) + '\x00' + 'LEAN-ESX \x20\x00\x00' + 'LEAN-ESX \x00\x00\x00'; +const packet = '\x12\x34' + chr(0x84) + '\x00\x00\x00\x00\x01\x00\x00\x00\x00' + + '\x20CKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x00' + + '\x00\x21\x00\x01\x00\x00\x00\x00\x00\x37\x03' + records; +check(nbstat_name(packet,0x1234) == 'LEAN-ESX', 'NBSTAT hostname'); +check(!nbstat_name(packet,0x5678), 'transaction mismatch'); +for (let i=0;i +PKG_LICENSE:=MIT +PKG_LICENSE_FILES:=LICENSE + +PKG_BUILD_DIR:=$(BUILD_DIR)/shadowsocks-v$(PKG_VERSION).$(SS_ARCH) + +include $(INCLUDE_DIR)/package.mk + +define Package/shadowsocks-rust-next/Default + SECTION:=net + CATEGORY:=Network + SUBMENU:=Web Servers/Proxies + TITLE:=shadowsocks-rust (Next) + URL:=https://github.com/shadowsocks/shadowsocks-rust + DEPENDS:=@(i386||x86_64||arm||aarch64||mipsel||mips) +endef + +define Package/shadowsocks-rust-ssserver-next + $(call Package/shadowsocks-rust-next/Default) + TITLE+= (ssserver) + PROVIDES:=shadowsocks-rust-ssserver + CONFLICTS:=shadowsocks-rust-ssserver +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) + tar -C $(PKG_BUILD_DIR) -xf $(DL_DIR)/$(PKG_SOURCE) +endef + +define Build/Configure +endef + +define Build/Compile +endef + +define Package/shadowsocks-rust-ssserver-next/install + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/ssserver $(1)/usr/bin/ +endef + +define Package/shadowsocks-rust-sslocal-next + $(call Package/shadowsocks-rust-next/Default) + TITLE+= (sslocal) + PROVIDES:=shadowsocks-rust-sslocal + CONFLICTS:=shadowsocks-rust-sslocal +endef + +define Package/shadowsocks-rust-sslocal-next/install + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/sslocal $(1)/usr/bin/ +endef + +$(eval $(call BuildPackage,shadowsocks-rust-ssserver-next)) +$(eval $(call BuildPackage,shadowsocks-rust-sslocal-next)) diff --git a/shadowsocks-rust-next/test.sh b/shadowsocks-rust-next/test.sh new file mode 100755 index 000000000..3d272b564 --- /dev/null +++ b/shadowsocks-rust-next/test.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +ssserver --version | grep "$PKG_VERSION" diff --git a/shadowsocks-rust-next/update.sh b/shadowsocks-rust-next/update.sh new file mode 100755 index 000000000..838e237cf --- /dev/null +++ b/shadowsocks-rust-next/update.sh @@ -0,0 +1,69 @@ +#!/bin/bash + +# 自动更新 OpenWrt shadowsocks-rust-next 包的版本和 Hash +# 依赖: curl, grep, sed, sha256sum (或 shasum) + +set -e + +PKG_DIR=$(cd "$(dirname "$0")"; pwd) +MAKEFILE="$PKG_DIR/Makefile" + +if [ ! -f "$MAKEFILE" ]; then + echo "错误: 找不到 Makefile 文件 ($MAKEFILE)" + exit 1 +fi + +# 1. 获取当前本地版本 +CURRENT_VERSION=$(grep 'PKG_VERSION:=' "$MAKEFILE" | cut -d'=' -f2 | tr -d ' ') +echo "当前本地版本: $CURRENT_VERSION" + +# 2. 获取 GitHub 上的最新版本号 +LATEST_VERSION=$(curl -s https://api.github.com/repos/shadowsocks/shadowsocks-rust/releases/latest | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/' | sed 's/^v//') + +if [ -z "$LATEST_VERSION" ]; then + echo "错误: 无法从 GitHub 获取最新版本号。" + exit 1 +fi + +echo "GitHub 最新版本: $LATEST_VERSION" + +# 3. 比较版本 +if [ "$CURRENT_VERSION" == "$LATEST_VERSION" ]; then + echo "版本已经是最新,无需更新。" + exit 0 +fi + +echo "发现新版本! 正在准备更新..." + +# 4. 下载新版本的源码包并计算 Hash +# shadowsocks-rust 的源码 URL 格式: https://codeload.github.com/shadowsocks/shadowsocks-rust/tar.gz/v$LATEST_VERSION +SOURCE_URL="https://codeload.github.com/shadowsocks/shadowsocks-rust/tar.gz/v$LATEST_VERSION" +echo "正在从 $SOURCE_URL 下载并计算 Hash..." + +# 探测可用的哈希计算工具 +if command -v sha256sum >/dev/null 2>&1; then + NEW_HASH=$(curl -sL "$SOURCE_URL" | sha256sum | cut -d' ' -f1) +elif command -v shasum >/dev/null 2>&1; then + NEW_HASH=$(curl -sL "$SOURCE_URL" | shasum -a 256 | cut -d' ' -f1) +else + echo "错误: 系统中未找到 sha256sum 或 shasum 命令。" + exit 1 +fi + +if [ -z "$NEW_HASH" ] || [ ${#NEW_HASH} -ne 64 ]; then + echo "错误: 计算得到的 Hash 值无效: $NEW_HASH" + exit 1 +fi + +echo "新 Hash 值: $NEW_HASH" + +# 5. 更新 Makefile +if [[ "$OSTYPE" == "darwin"* ]]; then + sed -i '' "s/PKG_VERSION:=.*/PKG_VERSION:=$LATEST_VERSION/" "$MAKEFILE" + sed -i '' "s/PKG_HASH:=.*/PKG_HASH:=$NEW_HASH/" "$MAKEFILE" +else + sed -i "s/PKG_VERSION:=.*/PKG_VERSION:=$LATEST_VERSION/" "$MAKEFILE" + sed -i "s/PKG_HASH:=.*/PKG_HASH:=$NEW_HASH/" "$MAKEFILE" +fi + +echo "Makefile 更新成功: $CURRENT_VERSION -> $LATEST_VERSION" diff --git a/tailscale-next/Makefile b/tailscale-next/Makefile new file mode 100644 index 000000000..18a656275 --- /dev/null +++ b/tailscale-next/Makefile @@ -0,0 +1,97 @@ +# +# Copyright (C) 2021 CZ.NIC, z. s. p. o. (https://www.nic.cz/) +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=tailscale-next +PKG_VERSION:=1.102.4 +PKG_RELEASE:=1 + +# Architecture mapping for pre-built binaries +ifeq ($(ARCH),x86_64) + TS_ARCH:=amd64 +endif +ifeq ($(ARCH),aarch64) + TS_ARCH:=arm64 +endif +ifeq ($(ARCH),arm64) + TS_ARCH:=arm64 +endif +ifeq ($(ARCH),armv8) + TS_ARCH:=arm64 +endif +ifeq ($(ARCH),arm) + TS_ARCH:=arm +endif +ifeq ($(ARCH),armv7) + TS_ARCH:=arm +endif +ifeq ($(ARCH),i386) + TS_ARCH:=386 +endif +ifeq ($(ARCH),mips) + TS_ARCH:=mips +endif +ifeq ($(ARCH),mipsel) + TS_ARCH:=mipsle +endif +ifeq ($(ARCH),riscv64) + TS_ARCH:=riscv64 +endif + +PKG_SOURCE:=tailscale_$(PKG_VERSION)_$(TS_ARCH).tgz +PKG_SOURCE_URL:=https://pkgs.tailscale.com/stable/ +PKG_HASH:=skip + +PKG_MAINTAINER:=Dante +PKG_LICENSE:=BSD-3-Clause +PKG_LICENSE_FILES:=LICENSE +PKG_CPE_ID:=cpe:/a:tailscale:tailscale + +PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION) + +include $(INCLUDE_DIR)/package.mk + +define Package/tailscale-next + SECTION:=net + CATEGORY:=Network + SUBMENU:=VPN + TITLE:=Zero config VPN (Next) - Pre-built Binary + URL:=https://tailscale.com + DEPENDS:=@(x86_64||aarch64||arm||i386||mips||mipsel||riscv64) +ca-bundle +kmod-tun +iptables + PROVIDES:=tailscale tailscaled + CONFLICTS:=tailscale tailscaled +endef + +define Package/tailscale-next/description + It creates a secure network between your servers, computers, + and cloud instances. Even when separated by firewalls or subnets. + This package contains official pre-built static binaries. +endef + +define Package/tailscale-next/conffiles +/etc/config/tailscale +/etc/tailscale/ +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) + tar -xzf $(DL_DIR)/$(PKG_SOURCE) -C $(PKG_BUILD_DIR) --strip-components=1 +endef + +define Build/Compile +endef + +define Package/tailscale-next/install + $(INSTALL_DIR) $(1)/usr/sbin $(1)/etc/init.d $(1)/etc/config + $(INSTALL_BIN) $(PKG_BUILD_DIR)/tailscaled $(1)/usr/sbin/tailscaled + $(INSTALL_BIN) $(PKG_BUILD_DIR)/tailscale $(1)/usr/sbin/tailscale + $(INSTALL_BIN) ./files/tailscale.init $(1)/etc/init.d/tailscale + $(INSTALL_DATA) ./files/tailscale.conf $(1)/etc/config/tailscale +endef + +$(eval $(call BuildPackage,tailscale-next)) diff --git a/tailscale-next/README.md b/tailscale-next/README.md new file mode 100644 index 000000000..e53dfb77e --- /dev/null +++ b/tailscale-next/README.md @@ -0,0 +1,23 @@ +# Tailscale +This readme should help you with tailscale client setup. + +> [!NOTE] +> By default this package will use nftables. If you wish to use iptables, the config file `/etc/config/tailscale` can be modfied, changing the line `fw_mode 'nftables'` to `fw_mode 'iptables'`. You can then run `/etc/init.d/tailscale restart` to restart tailscale using your chosen method + +## First setup + +First, enable and run daemon + +``` +/etc/init.d/tailscale enable +/etc/init.d/tailscale start +``` + +Then you should use tailscale utility to get a login link for your device. + +Run command and finish device registration with the given URL. +``` +tailscale up +``` + +See the [OpenWrt wiki](https://openwrt.org/docs/guide-user/services/vpn/tailscale/start) for more detailed setup instructions diff --git a/tailscale-next/files/tailscale.conf b/tailscale-next/files/tailscale.conf new file mode 100644 index 000000000..958e7f0ec --- /dev/null +++ b/tailscale-next/files/tailscale.conf @@ -0,0 +1,8 @@ +config settings 'settings' + option service_enabled '0' + option log_stderr '1' + option log_stdout '1' + option port '41641' + option state_file '/etc/tailscale/tailscaled.state' + # default to using nftables - change below to 'iptables' if still using iptables + option fw_mode 'nftables' \ No newline at end of file diff --git a/tailscale-next/files/tailscale.init b/tailscale-next/files/tailscale.init new file mode 100755 index 000000000..64bb0fbcb --- /dev/null +++ b/tailscale-next/files/tailscale.init @@ -0,0 +1,68 @@ +#!/bin/sh /etc/rc.common + +# Copyright 2020 Google LLC. +# Copyright (C) 2021 CZ.NIC z.s.p.o. (https://www.nic.cz/) +# SPDX-License-Identifier: Apache-2.0 + +USE_PROCD=1 +START=80 + +export TS_NO_LOGS_NO_SUPPORT=true + +start_service() { + local service_enabled + local state_file + local port + local std_out + + config_load tailscale + config_get_bool service_enabled "settings" service_enabled 0 + [ "$service_enabled" -eq 1 ] || return 0 + + config_get_bool std_out "settings" log_stdout 1 + config_get port "settings" port 41641 + config_get state_file "settings" state_file /etc/tailscale/tailscaled.state + local fw_mode="auto" + if [ -x /usr/sbin/nft ] && command -v fw4 >/dev/null 2>&1; then + fw_mode="nftables" + elif [ -x /usr/sbin/iptables ]; then + fw_mode="iptables" + fi + + /usr/sbin/tailscaled --cleanup + + procd_open_instance + procd_set_param command /bin/sh -c 'exec /usr/sbin/tailscaled "$@" 2>&1' -- + + # Set backend firewall mode automatically based on active OpenWrt firewall + procd_set_param env TS_DEBUG_FIREWALL_MODE="$fw_mode" + + # Disable logging to log.tailscale.com + procd_append_param env TS_NO_LOGS_NO_SUPPORT=true + + # Set the port to listen on for incoming VPN packets. + # Remote nodes will automatically be informed about the new port number, + # but you might want to configure this in order to set external firewall + # settings. + procd_append_param command --port "$port" + procd_append_param command --state "$state_file" + + procd_set_param respawn + procd_set_param stdout "$std_out" + procd_set_param stderr 0 + + procd_close_instance +} + +stop_service() { + /usr/sbin/tailscaled --cleanup + killall -9 tailscaled 2>/dev/null || true +} + +reload_service() { + restart +} + +service_triggers() { + procd_add_reload_trigger "tailscale" +} diff --git a/torrserver/Makefile b/torrserver/Makefile index 9b059d564..0192cf3fa 100644 --- a/torrserver/Makefile +++ b/torrserver/Makefile @@ -8,12 +8,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:=torrserver -PKG_VERSION:=MatriX.144.5 -PKG_RELEASE:=24 +PKG_VERSION:=142 +PKG_RELEASE:=25 PKG_SOURCE_PROTO:=git PKG_SOURCE_URL:=https://github.com/YouROK/TorrServer.git -PKG_SOURCE_VERSION:=4fdc051d858693c62c56307ec6ef7c93febaa35b +PKG_SOURCE_VERSION:=f0585eb7dfc92e0e5fdcb17a7e7eead212201e7d PKG_MIRROR_HASH:=skip PKG_MAINTAINER:=Konstantine Shevlakov diff --git a/wwand/Makefile b/wwand/Makefile index b975e8fac..a36cc5088 100644 --- a/wwand/Makefile +++ b/wwand/Makefile @@ -50,11 +50,11 @@ include $(TOPDIR)/rules.mk PKG_NAME:=wwand PKG_VERSION:=1.6.6_p28 -PKG_RELEASE:=37 +PKG_RELEASE:=38 PKG_SOURCE_PROTO:=git PKG_SOURCE_URL:=https://github.com/ddimension/wwand.git -PKG_SOURCE_VERSION:=f2e7ad0cfdd2cd614a0b1773bab4f7035c2f928b +PKG_SOURCE_VERSION:=df322691e8567b60cf2c46fe2352c3ae3160f093 PKG_MIRROR_HASH:=skip PKG_LICENSE:=GPL-2.0-only