From de7e69dbe3865f0d70238203d453f0f84f059ddf Mon Sep 17 00:00:00 2001 From: bgme <i@bgme.me> Date: Mon, 21 Apr 2025 13:54:00 +0800 Subject: [PATCH] Squashed 'luci-app-einat/' content from commit 82838e7 git-subtree-dir: luci-app-einat git-subtree-split: 82838e76d43b3b947c4bd5ddac26d5be02d5fb94 --- .prepare.sh | 19 ++ LICENSE | 21 ++ Makefile | 23 +++ README.md | 40 ++++ htdocs/luci-static/resources/view/einat.js | 183 ++++++++++++++++++ po/templates/einat.pot | 133 +++++++++++++ po/zh_Hans/einat.po | 142 ++++++++++++++ po/zh_Hant/einat.po | 142 ++++++++++++++ .../usr/share/luci/menu.d/luci-app-einat.json | 13 ++ root/usr/share/rpcd/acl.d/luci-app-einat.json | 21 ++ root/usr/share/rpcd/ucode/luci.einat | 38 ++++ 11 files changed, 775 insertions(+) create mode 100755 .prepare.sh create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 README.md create mode 100644 htdocs/luci-static/resources/view/einat.js create mode 100644 po/templates/einat.pot create mode 100644 po/zh_Hans/einat.po create mode 100644 po/zh_Hant/einat.po create mode 100644 root/usr/share/luci/menu.d/luci-app-einat.json create mode 100644 root/usr/share/rpcd/acl.d/luci-app-einat.json create mode 100644 root/usr/share/rpcd/ucode/luci.einat diff --git a/.prepare.sh b/.prepare.sh new file mode 100755 index 0000000..ee81496 --- /dev/null +++ b/.prepare.sh @@ -0,0 +1,19 @@ +PKG_NAME="$1" +CURDIR="$2" +PKG_BUILD_DIR="$3" + +if [ -d "$CURDIR/.git" ]; then + config="$CURDIR/.git/config" +else + config="$(sed "s|^gitdir:\s*|$CURDIR/|;s|$|/config|" "$CURDIR/.git")" +fi +[ -n "$(sed -En '/^\[remote /{h;:top;n;/^\[/b;s,(https?://gitcode\.(com|net)),\1,;T top;H;x;s|\n\s*|: |;p;}' "$config")" ] && { + for d in luasrc ucode htdocs root src; do + rm -rf "$PKG_BUILD_DIR"/$d + done + mkdir -p "$PKG_BUILD_DIR"/htdocs/luci-static/resources/view + touch "$PKG_BUILD_DIR"/htdocs/luci-static/resources/view/$PKG_NAME.js + mkdir -p "$PKG_BUILD_DIR"/root/usr/share/luci/menu.d + touch "$PKG_BUILD_DIR"/root/usr/share/luci/menu.d/$PKG_NAME.json +} +exit 0 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..8c55001 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Anya Lin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..957fbbd --- /dev/null +++ b/Makefile @@ -0,0 +1,23 @@ +# SPDX-License-Identifier: MIT +# +# Copyright (C) 2024-2025 Anya Lin <https://github.com/muink> + +include $(TOPDIR)/rules.mk + +LUCI_NAME:=luci-app-einat + +LUCI_TITLE:=LuCI Support for einat +LUCI_PKGARCH:=all +LUCI_DEPENDS:=+einat-ebpf + +LUCI_DESCRIPTION:=eBPF-based Endpoint-Independent NAT + +PKG_MAINTAINER:=Anya Lin <hukk1996@gmail.com> +PKG_LICENSE:=MIT +PKG_LICENSE_FILES:=LICENSE + +PKG_UNPACK=$(CURDIR)/.prepare.sh $(PKG_NAME) $(CURDIR) $(PKG_BUILD_DIR) + +include $(TOPDIR)/feeds/luci/luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/README.md b/README.md new file mode 100644 index 0000000..97ca837 --- /dev/null +++ b/README.md @@ -0,0 +1,40 @@ +# luci-app-einat + +> [einat-ebpf][] project is an eBPF application implements an "Endpoint-Independent Mapping" and "Endpoint-Independent Filtering" NAT(network address translation) on TC egress and ingress hooks. + +## Depends + +1. [openwrt-einat-ebpf][] + +## Releases +You can find the prebuilt-ipks [here](https://fantastic-packages.github.io/packages/) + +## Build + +```shell +# Take the x86_64 platform as an example +tar xjf openwrt-sdk-23.05.3-x86-64_gcc-12.3.0_musl.Linux-x86_64.tar.xz +# Go to the SDK root dir +cd OpenWrt-sdk-*-x86_64_* +# First run to generate a .config file +make menuconfig +./scripts/feeds update -a +./scripts/feeds install -a +# Get Makefile +git clone --depth 1 --branch master --single-branch --no-checkout https://github.com/muink/luci-app-einat.git package/luci-app-einat +pushd package/luci-app-einat +umask 022 +git checkout +popd +# Select the package LuCI -> Applications -> luci-app-einat +make menuconfig +# Start compiling +make package/luci-app-einat/compile V=99 +``` + +[einat-ebpf]: https://github.com/EHfive/einat-ebpf +[openwrt-einat-ebpf]: https://github.com/muink/openwrt-einat-ebpf + +## License + +This project is licensed under the MIT license diff --git a/htdocs/luci-static/resources/view/einat.js b/htdocs/luci-static/resources/view/einat.js new file mode 100644 index 0000000..ff92063 --- /dev/null +++ b/htdocs/luci-static/resources/view/einat.js @@ -0,0 +1,183 @@ +'use strict'; +'require form'; +'require fs'; +'require uci'; +'require ui'; +'require rpc'; +'require poll'; +'require view'; +'require network'; +'require tools.widgets as widgets'; + +const conf = 'einat'; +const instance = 'einat'; + +const callServiceList = rpc.declare({ + object: 'service', + method: 'list', + params: ['name'], + expect: { '': {} } +}); + +const callRcInit = rpc.declare({ + object: 'rc', + method: 'init', + params: ['name', 'action'] +}); + +const callGetFeatures = rpc.declare({ + object: 'luci.einat', + method: 'get_features', + expect: { '': {} } +}); + +function getServiceStatus() { + return L.resolveDefault(callServiceList(conf), {}) + .then((res) => { + let isrunning = false; + try { + isrunning = res[conf]['instances'][instance]['running']; + } catch (e) { } + return isrunning; + }); +} + +function handleAction(action, ev) { + return callRcInit("einat", action).then((ret) => { + if (ret) + throw _('Command failed'); + + return true; + }).catch((e) => { + ui.addNotification(null, E('p', _('Failed to execute "/etc/init.d/%s %s" action: %s').format("einat", action, e))); + }); +} + +return view.extend({ + load() { + return Promise.all([ + getServiceStatus(), + L.resolveDefault(fs.stat('/usr/bin/einat'), null), + callGetFeatures(), + uci.load('einat') + ]); + }, + + poll_status(nodes, stat) { + const isRunning = stat[0]; + let view = nodes.querySelector('#service_status'); + + if (isRunning) { + view.innerHTML = "<span style=\"color:green;font-weight:bold\">" + instance + " - " + _("SERVER RUNNING") + "</span>"; + } else { + view.innerHTML = "<span style=\"color:red;font-weight:bold\">" + instance + " - " + _("SERVER NOT RUNNING") + "</span>"; + } + return; + }, + + render(res) { + const isRunning = res[0]; + const has_einat = res[1] ? res[1].path : null; + const features = res[2]; + + let m, s, o; + + m = new form.Map('einat', _('einat-ebpf'), _('eBPF-based Endpoint-Independent NAT')); + + s = m.section(form.NamedSection, '_status'); + s.anonymous = true; + s.render = function(section_id) { + return E('div', { class: 'cbi-section' }, [ + E('div', { id: 'service_status' }, _('Collecting data ...')) + ]); + }; + + s = m.section(form.NamedSection, 'config', instance); + s.anonymous = true; + + o = s.option(form.Button, '_reload', _('Reload')); + o.inputtitle = _('Reload'); + o.inputstyle = 'apply'; + o.onclick = function() { + return handleAction('reload'); + }; + + o = s.option(form.Flag, 'enabled', _('Enable')); + o.default = o.disabled; + o.rmempty = false; + if (! has_einat) { + o.description = _('To enable you need install <b>einat-ebpf</b> first'); + o.readonly = true; + } + + o = s.option(form.ListValue, 'bpf_log_level', _('BPF tracing log level')); + o.default = '0'; + o.value('0', 'disable - ' + _('Disable')); + o.value('1', 'error - ' + _('Error')); + o.value('2', 'warn - ' + _('Warn')); + o.value('3', 'info - ' + _('Info')); + o.value('4', 'debug - ' + _('Debug')); + o.value('5', 'trace - ' + _('Trace')); + + o = s.option(form.ListValue, 'bpf_loader', _('BPF loading backend')); + o.value('', _('Default')); + if (features.features.includes('aya')) + o.value('aya', _('aya')); + if (features.features.includes('libbpf')) + o.value('libbpf', _('libbpf')); + + o = s.option(form.Flag, 'nat44', _('NAT44')); + o.default = o.disabled; + o.rmempty = false; + + //o = s.option(form.Flag, 'nat66', _('NAT66')); + //o.default = o.disabled; + //o.rmempty = false; + + o = s.option(widgets.DeviceSelect, 'ifname', _('External interface')); + o.multiple = false; + o.noaliases = true; + o.nobridges = true; + o.nocreate = true; + + o = s.option(form.Value, 'ports', _('External TCP/UDP port ranges'), + _('Please avoid conflicts with external ports used by other applications')); + o.datatype = 'portrange'; + o.placeholder = '20000-29999'; + o.rmempty = true; + + o = s.option(widgets.NetworkSelect, 'internal_ifaces', _('Internal interfaces'), + _('Perform source NAT for these internal networks only.')); + o.multiple = true; + o.nocreate = true; + + o = s.option(form.DynamicList, 'internal_subnets', _('Internal subnets'), + _('Perform source NAT for these internal networks only.')); + o.datatype = 'cidr'; + o.placeholder = '192.168.0.0/16'; + + o = s.option(form.Flag, 'hairpin_enabled', _('Enable hairpin'), + _('May conflict with other policy routing-based applications')); + o.default = o.disabled; + o.rmempty = false; + + o = s.option(widgets.DeviceSelect, 'hairpinif', _('Hairpin internal interfaces')); + o.multiple = true; + o.noaliases = true; + o.nobridges = false; + o.nocreate = true; + o.depends('hairpin_enabled', '1'); + o.rmempty = true; + o.retain = true; + + return m.render() + .then(L.bind(function(m, nodes) { + poll.add(L.bind(function() { + return Promise.all([ + getServiceStatus() + ]).then(L.bind(this.poll_status, this, nodes)); + }, this), 3); + return nodes; + }, this, m)); + } +}); diff --git a/po/templates/einat.pot b/po/templates/einat.pot new file mode 100644 index 0000000..3677805 --- /dev/null +++ b/po/templates/einat.pot @@ -0,0 +1,133 @@ +msgid "" +msgstr "Content-Type: text/plain; charset=UTF-8" + +#: htdocs/luci-static/resources/view/einat.js:114 +msgid "BPF loading backend" +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:105 +msgid "BPF tracing log level" +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:83 +msgid "Collecting data ..." +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:42 +msgid "Command failed" +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:111 +msgid "Debug" +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:115 +msgid "Default" +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:107 +msgid "Disable" +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:97 +msgid "Enable" +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:149 +msgid "Enable hairpin" +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:108 +msgid "Error" +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:133 +msgid "External TCP/UDP port ranges" +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:127 +msgid "External interface" +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:46 +msgid "Failed to execute \"/etc/init.d/%s %s\" action: %s" +msgstr "" + +#: root/usr/share/rpcd/acl.d/luci-app-einat.json:3 +msgid "Grant access to LuCI app einat" +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:154 +msgid "Hairpin internal interfaces" +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:110 +msgid "Info" +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:139 +msgid "Internal interfaces" +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:144 +msgid "Internal subnets" +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:150 +msgid "May conflict with other policy routing-based applications" +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:119 +msgid "NAT44" +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:140 +#: htdocs/luci-static/resources/view/einat.js:145 +msgid "Perform source NAT for these internal networks only." +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:134 +msgid "Please avoid conflicts with external ports used by other applications" +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:90 +#: htdocs/luci-static/resources/view/einat.js:91 +msgid "Reload" +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:66 +msgid "SERVER NOT RUNNING" +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:64 +msgid "SERVER RUNNING" +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:101 +msgid "To enable you need install <b>einat-ebpf</b> first" +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:112 +msgid "Trace" +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:109 +msgid "Warn" +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:116 +msgid "aya" +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:77 +msgid "eBPF-based Endpoint-Independent NAT" +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:77 +#: root/usr/share/luci/menu.d/luci-app-einat.json:3 +msgid "einat-ebpf" +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:117 +msgid "libbpf" +msgstr "" diff --git a/po/zh_Hans/einat.po b/po/zh_Hans/einat.po new file mode 100644 index 0000000..caa52f5 --- /dev/null +++ b/po/zh_Hans/einat.po @@ -0,0 +1,142 @@ +msgid "" +msgstr "" +"PO-Revision-Date: 2024-05-10 12:23+0000\n" +"Last-Translator: Anya Lin <muink@users.noreply.github.com>\n" +"Language-Team: Chinese (Simplified) <https://hosted.weblate.org/projects/" +"openwrt/luciapplicationseinat/zh_Hans/>\n" +"Language: zh_Hans\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Weblate 4.18-dev\n" + +#: htdocs/luci-static/resources/view/einat.js:114 +msgid "BPF loading backend" +msgstr "BPF 加载后端" + +#: htdocs/luci-static/resources/view/einat.js:105 +msgid "BPF tracing log level" +msgstr "BPF 追踪日志等级" + +#: htdocs/luci-static/resources/view/einat.js:83 +msgid "Collecting data ..." +msgstr "正在收集数据..." + +#: htdocs/luci-static/resources/view/einat.js:42 +msgid "Command failed" +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:111 +msgid "Debug" +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:115 +msgid "Default" +msgstr "默认" + +#: htdocs/luci-static/resources/view/einat.js:107 +msgid "Disable" +msgstr "禁用" + +#: htdocs/luci-static/resources/view/einat.js:97 +msgid "Enable" +msgstr "启用" + +#: htdocs/luci-static/resources/view/einat.js:149 +msgid "Enable hairpin" +msgstr "启用 Hairpin" + +#: htdocs/luci-static/resources/view/einat.js:108 +msgid "Error" +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:133 +msgid "External TCP/UDP port ranges" +msgstr "外部 TCP/UDP 端口范围" + +#: htdocs/luci-static/resources/view/einat.js:127 +msgid "External interface" +msgstr "外部接口" + +#: htdocs/luci-static/resources/view/einat.js:46 +msgid "Failed to execute \"/etc/init.d/%s %s\" action: %s" +msgstr "" + +#: root/usr/share/rpcd/acl.d/luci-app-einat.json:3 +msgid "Grant access to LuCI app einat" +msgstr "授予访问 LuCI 应用 einat 的权限" + +#: htdocs/luci-static/resources/view/einat.js:154 +msgid "Hairpin internal interfaces" +msgstr "Hairpin 内部接口" + +#: htdocs/luci-static/resources/view/einat.js:110 +msgid "Info" +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:139 +msgid "Internal interfaces" +msgstr "内部接口" + +#: htdocs/luci-static/resources/view/einat.js:144 +msgid "Internal subnets" +msgstr "内部子网" + +#: htdocs/luci-static/resources/view/einat.js:150 +msgid "May conflict with other policy routing-based applications" +msgstr "可能与其他基于策略路由的应用程序发生冲突" + +#: htdocs/luci-static/resources/view/einat.js:119 +msgid "NAT44" +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:140 +#: htdocs/luci-static/resources/view/einat.js:145 +msgid "Perform source NAT for these internal networks only." +msgstr "仅对这些内部网络执行 SNAT。" + +#: htdocs/luci-static/resources/view/einat.js:134 +msgid "Please avoid conflicts with external ports used by other applications" +msgstr "请避免与其他应用使用的外部端口冲突" + +#: htdocs/luci-static/resources/view/einat.js:90 +#: htdocs/luci-static/resources/view/einat.js:91 +msgid "Reload" +msgstr "重新载入" + +#: htdocs/luci-static/resources/view/einat.js:66 +msgid "SERVER NOT RUNNING" +msgstr "服务器未运行" + +#: htdocs/luci-static/resources/view/einat.js:64 +msgid "SERVER RUNNING" +msgstr "服务器运行中" + +#: htdocs/luci-static/resources/view/einat.js:101 +msgid "To enable you need install <b>einat-ebpf</b> first" +msgstr "要启用您需要先安装 <b>einat-ebpf</b>" + +#: htdocs/luci-static/resources/view/einat.js:112 +msgid "Trace" +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:109 +msgid "Warn" +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:116 +msgid "aya" +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:77 +msgid "eBPF-based Endpoint-Independent NAT" +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:77 +#: root/usr/share/luci/menu.d/luci-app-einat.json:3 +msgid "einat-ebpf" +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:117 +msgid "libbpf" +msgstr "" diff --git a/po/zh_Hant/einat.po b/po/zh_Hant/einat.po new file mode 100644 index 0000000..f972830 --- /dev/null +++ b/po/zh_Hant/einat.po @@ -0,0 +1,142 @@ +msgid "" +msgstr "" +"PO-Revision-Date: 2024-05-10 12:23+0000\n" +"Last-Translator: Anya Lin <muink@users.noreply.github.com>\n" +"Language-Team: Chinese (Traditional) <https://hosted.weblate.org/projects/" +"openwrt/luciapplicationseinat/zh_Hant/>\n" +"Language: zh_Hant\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Weblate 4.18-dev\n" + +#: htdocs/luci-static/resources/view/einat.js:114 +msgid "BPF loading backend" +msgstr "BPF 載入後端" + +#: htdocs/luci-static/resources/view/einat.js:105 +msgid "BPF tracing log level" +msgstr "BPF 追蹤日誌級別" + +#: htdocs/luci-static/resources/view/einat.js:83 +msgid "Collecting data ..." +msgstr "正在收集數據..." + +#: htdocs/luci-static/resources/view/einat.js:42 +msgid "Command failed" +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:111 +msgid "Debug" +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:115 +msgid "Default" +msgstr "預設" + +#: htdocs/luci-static/resources/view/einat.js:107 +msgid "Disable" +msgstr "禁用" + +#: htdocs/luci-static/resources/view/einat.js:97 +msgid "Enable" +msgstr "啟用" + +#: htdocs/luci-static/resources/view/einat.js:149 +msgid "Enable hairpin" +msgstr "啟用 Hairpin" + +#: htdocs/luci-static/resources/view/einat.js:108 +msgid "Error" +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:133 +msgid "External TCP/UDP port ranges" +msgstr "外部 TCP/UDP 埠範圍" + +#: htdocs/luci-static/resources/view/einat.js:127 +msgid "External interface" +msgstr "外部介面" + +#: htdocs/luci-static/resources/view/einat.js:46 +msgid "Failed to execute \"/etc/init.d/%s %s\" action: %s" +msgstr "" + +#: root/usr/share/rpcd/acl.d/luci-app-einat.json:3 +msgid "Grant access to LuCI app einat" +msgstr "授予訪問 LuCI 應用 einat 的權限" + +#: htdocs/luci-static/resources/view/einat.js:154 +msgid "Hairpin internal interfaces" +msgstr "Hairpin 內部介面" + +#: htdocs/luci-static/resources/view/einat.js:110 +msgid "Info" +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:139 +msgid "Internal interfaces" +msgstr "內部介面" + +#: htdocs/luci-static/resources/view/einat.js:144 +msgid "Internal subnets" +msgstr "內部子網" + +#: htdocs/luci-static/resources/view/einat.js:150 +msgid "May conflict with other policy routing-based applications" +msgstr "可能與其他基於策略路由的應用程式發生衝突" + +#: htdocs/luci-static/resources/view/einat.js:119 +msgid "NAT44" +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:140 +#: htdocs/luci-static/resources/view/einat.js:145 +msgid "Perform source NAT for these internal networks only." +msgstr "僅對這些內部網路執行 SNAT。" + +#: htdocs/luci-static/resources/view/einat.js:134 +msgid "Please avoid conflicts with external ports used by other applications" +msgstr "請避免與其他應用程式使用的外部連接埠衝突" + +#: htdocs/luci-static/resources/view/einat.js:90 +#: htdocs/luci-static/resources/view/einat.js:91 +msgid "Reload" +msgstr "重新載入" + +#: htdocs/luci-static/resources/view/einat.js:66 +msgid "SERVER NOT RUNNING" +msgstr "伺服器未運行" + +#: htdocs/luci-static/resources/view/einat.js:64 +msgid "SERVER RUNNING" +msgstr "伺服器運行中" + +#: htdocs/luci-static/resources/view/einat.js:101 +msgid "To enable you need install <b>einat-ebpf</b> first" +msgstr "要啟用您需要先安裝 <b>einat-ebpf</b>" + +#: htdocs/luci-static/resources/view/einat.js:112 +msgid "Trace" +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:109 +msgid "Warn" +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:116 +msgid "aya" +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:77 +msgid "eBPF-based Endpoint-Independent NAT" +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:77 +#: root/usr/share/luci/menu.d/luci-app-einat.json:3 +msgid "einat-ebpf" +msgstr "" + +#: htdocs/luci-static/resources/view/einat.js:117 +msgid "libbpf" +msgstr "" diff --git a/root/usr/share/luci/menu.d/luci-app-einat.json b/root/usr/share/luci/menu.d/luci-app-einat.json new file mode 100644 index 0000000..a0ea134 --- /dev/null +++ b/root/usr/share/luci/menu.d/luci-app-einat.json @@ -0,0 +1,13 @@ +{ + "admin/network/einat": { + "title": "einat-ebpf", + "order": 60, + "action": { + "type": "view", + "path": "einat" + }, + "depends": { + "acl": [ "luci-app-einat" ] + } + } +} diff --git a/root/usr/share/rpcd/acl.d/luci-app-einat.json b/root/usr/share/rpcd/acl.d/luci-app-einat.json new file mode 100644 index 0000000..a3cab4a --- /dev/null +++ b/root/usr/share/rpcd/acl.d/luci-app-einat.json @@ -0,0 +1,21 @@ +{ + "luci-app-einat": { + "description": "Grant access to LuCI app einat", + "read": { + "file": { + "/etc/init.d/einat reload": [ "exec" ] + }, + "ubus": { + "service": [ "list" ], + "luci.einat": [ "*" ] + }, + "uci": ["einat"] + }, + "write": { + "ubus": { + "rc": [ "init" ] + }, + "uci": ["einat"] + } + } +} diff --git a/root/usr/share/rpcd/ucode/luci.einat b/root/usr/share/rpcd/ucode/luci.einat new file mode 100644 index 0000000..7128563 --- /dev/null +++ b/root/usr/share/rpcd/ucode/luci.einat @@ -0,0 +1,38 @@ +#!/usr/bin/ucode + +'use strict'; + +import { access, popen } from 'fs'; + +const methods = { + get_features: { + call: function() { + let features = { + version: null, + features: [], + build_features: [] + }; + + const fd = popen('/usr/bin/einat -v'); + if (fd) { + for (let line = fd.read('line'); length(line); line = fd.read('line')) { + let ver = match(trim(line), /version: (\S+)/); + if (ver) + features.version = ver[1]; + let feats = match(trim(line), /features: (\S+)/); + if (feats) + features.features = split(feats[1], ','); + let build_feats = match(trim(line), /build_features: (\S+)/); + if (build_feats) + features.build_features = split(build_feats[1], ','); + } + + fd.close(); + } + + return features; + } + } +}; + +return { 'luci.einat': methods };