diff --git a/luci-app-passwall/Makefile b/luci-app-passwall/Makefile index f807b5681..be1051427 100644 --- a/luci-app-passwall/Makefile +++ b/luci-app-passwall/Makefile @@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-passwall PKG_VERSION:=26.9.16 -PKG_RELEASE:=281 +PKG_RELEASE:=282 PKG_PO_VERSION:=$(PKG_VERSION) PKG_CONFIG_DEPENDS:= \ diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/1_sing-box.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/1_sing-box.lua index 769e125d9..fe6fd30eb 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/1_sing-box.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/1_sing-box.lua @@ -564,9 +564,12 @@ o.default = "" o.rows = 5 o.wrap = "off" o:depends({ tls_certificate = true }) +o.cfgvalue = function(self, section) + return (m:get(section, "tls_certificate_pem") or ""):gsub("\\n", "\n") +end o.validate = function(self, value) - value = api.trim(value):gsub("\r\n", "\n"):gsub("[ \t]*\n[ \t]*", "\n"):gsub("\n+", "\n") - return value + value = api.trim(value):gsub("\r\n", "\n"):gsub("\r", "\n"):gsub("[ \t]*\n[ \t]*", "\n"):gsub("\n+", "\n") + return value:gsub("\n", "\\n") end o = s:option(Value, "cipherSuites", translate("Cipher Suites"), '***' .. " " .. translate("Configures the list of supported cipher suites, separated by :")) @@ -585,9 +588,12 @@ o.default = "" o.rows = 5 o.wrap = "off" o:depends({ ech = true }) +o.cfgvalue = function(self, section) + return (m:get(section, "ech_config") or ""):gsub("\\n", "\n") +end o.validate = function(self, value) - value = api.trim(value):gsub("\r\n", "\n"):gsub("[ \t]*\n[ \t]*", "\n"):gsub("\n+", "\n") - return value + value = api.trim(value):gsub("\r\n", "\n"):gsub("\r", "\n"):gsub("[ \t]*\n[ \t]*", "\n"):gsub("\n+", "\n") + return value:gsub("\n", "\\n") end o = s:option(Value, "ech_query_server_name", translate("ECH Query Domain"), translate("Overrides the domain name used for ECH HTTPS record queries.")) diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/2_xray.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/2_xray.lua index 52d5df673..c4a564a87 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/2_xray.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/2_xray.lua @@ -453,9 +453,12 @@ o.default = "" o.rows = 5 o.wrap = "off" o:depends({ tls_certificate = true }) +o.cfgvalue = function(self, section) + return (m:get(section, "tls_certificate_pem") or ""):gsub("\\n", "\n") +end o.validate = function(self, value) - value = api.trim(value):gsub("\r\n", "\n"):gsub("[ \t]*\n[ \t]*", "\n"):gsub("\n+", "\n") - return value + value = api.trim(value):gsub("\r\n", "\n"):gsub("\r", "\n"):gsub("[ \t]*\n[ \t]*", "\n"):gsub("\n+", "\n") + return value:gsub("\n", "\\n") end o = s:option(Flag, "ech", translate("ECH")) diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/1_sing-box.lua b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/1_sing-box.lua index 59a843d47..65e69f993 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/1_sing-box.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/1_sing-box.lua @@ -253,12 +253,19 @@ o.default = 0 o.validate = function(self, value, t) if value then local reality = s.fields["reality"] and s.fields["reality"]:formvalue(t) or nil + local use_pem = s.fields["tls_use_pem"] and s.fields["tls_use_pem"]:formvalue(t) or nil if reality and reality == "1" then return value end - if value == "1" then + if value == "1" and use_pem ~= "1" then local ca = s.fields["tls_certificateFile"] and s.fields["tls_certificateFile"]:formvalue(t) or "" local key = s.fields["tls_keyFile"] and s.fields["tls_keyFile"]:formvalue(t) or "" if ca == "" or key == "" then - return nil, translate("Certificate or Private key path can not be empty!") + return nil, translate("Certificate and Private key path can not be empty!") + end + elseif value == "1" and use_pem == "1" then + local ca = s.fields["tls_certificate"] and s.fields["tls_certificate"]:formvalue(t) or "" + local key = s.fields["tls_key"] and s.fields["tls_key"]:formvalue(t) or "" + if ca == "" or key == "" then + return nil, translate("Certificate and Private key PEM can not be empty!") end end return value @@ -311,14 +318,21 @@ o:depends({ protocol = "hysteria" }) -- [[ TLS部分 ]] -- -o = s:option(FileUpload, "tls_certificateFile", translate("Path to the certificate file"), translate("as:") .. "/etc/ssl/fullchain.crt") -o.default = m:get(s.section, "tls_certificateFile") or "/etc/config/ssl/" .. arg[1] .. ".crt" -if o and o:formvalue(arg[1]) then o.default = o:formvalue(arg[1]) end +o = s:option(Flag, "tls_use_pem", translate("Use PEM"), translate("Use certificate and private key PEM content.")) o:depends({ tls = true, reality = false }) o:depends({ protocol = "naive" }) o:depends({ protocol = "hysteria" }) o:depends({ protocol = "tuic" }) o:depends({ protocol = "hysteria2" }) + +o = s:option(FileUpload, "tls_certificateFile", translate("Path to the certificate file"), translate("as:") .. "/etc/ssl/fullchain.crt") +o.default = m:get(s.section, "tls_certificateFile") or "/etc/config/ssl/" .. arg[1] .. ".crt" +if o and o:formvalue(arg[1]) then o.default = o:formvalue(arg[1]) end +o:depends({ tls = true, reality = false, tls_use_pem = false }) +o:depends({ protocol = "naive", tls_use_pem = false }) +o:depends({ protocol = "hysteria", tls_use_pem = false }) +o:depends({ protocol = "tuic", tls_use_pem = false }) +o:depends({ protocol = "hysteria2", tls_use_pem = false }) o.validate = function(self, value, t) if value and value ~= "" then if not api.fs.access(value) then @@ -333,11 +347,11 @@ end o = s:option(FileUpload, "tls_keyFile", translate("Path to the private key file"), translate("as:") .. "/etc/ssl/private.key") o.default = m:get(s.section, "tls_keyFile") or "/etc/config/ssl/" .. arg[1] .. ".key" if o and o:formvalue(arg[1]) then o.default = o:formvalue(arg[1]) end -o:depends({ tls = true, reality = false }) -o:depends({ protocol = "naive" }) -o:depends({ protocol = "hysteria" }) -o:depends({ protocol = "tuic" }) -o:depends({ protocol = "hysteria2" }) +o:depends({ tls = true, reality = false, tls_use_pem = false }) +o:depends({ protocol = "naive", tls_use_pem = false }) +o:depends({ protocol = "hysteria", tls_use_pem = false }) +o:depends({ protocol = "tuic", tls_use_pem = false }) +o:depends({ protocol = "hysteria2", tls_use_pem = false }) o.validate = function(self, value, t) if value and value ~= "" then if not api.fs.access(value) then @@ -349,6 +363,32 @@ o.validate = function(self, value, t) return nil end +o = s:option(TextValue, "tls_certificate", "TLS Certificate (PEM)", translate("Full certificate (chain), PEM format.")) +o.default = "" +o.rows = 5 +o.wrap = "off" +o:depends({ tls_use_pem = true }) +o.cfgvalue = function(self, section) + return (m:get(section, "tls_certificate") or ""):gsub("\\n", "\n") +end +o.validate = function(self, value) + value = api.trim(value):gsub("\r\n", "\n"):gsub("\r", "\n"):gsub("[ \t]*\n[ \t]*", "\n"):gsub("\n+", "\n") + return value:gsub("\n", "\\n") +end + +o = s:option(TextValue, "tls_key", "TLS Private Key (PEM)", translate("Private key in PEM format.")) +o.default = "" +o.rows = 5 +o.wrap = "off" +o:depends({ tls_use_pem = true }) +o.cfgvalue = function(self, section) + return (m:get(section, "tls_key") or ""):gsub("\\n", "\n") +end +o.validate = function(self, value) + value = api.trim(value):gsub("\r\n", "\n"):gsub("\r", "\n"):gsub("[ \t]*\n[ \t]*", "\n"):gsub("\n+", "\n") + return value:gsub("\n", "\\n") +end + o = s:option(Flag, "ech", translate("ECH")) o.default = "0" o:depends({ tls = true, flow = "", reality = false }) @@ -362,13 +402,12 @@ o.default = "" o.rows = 5 o.wrap = "off" o:depends({ ech = true }) +o.cfgvalue = function(self, section) + return (m:get(section, "ech_key") or ""):gsub("\\n", "\n") +end o.validate = function(self, value) - value = value:gsub("^%s+", ""):gsub("%s+$","\n"):gsub("\r\n","\n"):gsub("[ \t]*\n[ \t]*", "\n") - value = value:gsub("^%s*\n", "") - if value:sub(-1) == "\n" then - value = value:sub(1, -2) - end - return value + value = api.trim(value):gsub("\r\n", "\n"):gsub("\r", "\n"):gsub("[ \t]*\n[ \t]*", "\n"):gsub("\n+", "\n") + return value:gsub("\n", "\\n") end o = s:option(ListValue, "transport", translate("Transport")) diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/2_xray.lua b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/2_xray.lua index 017814211..b126f0211 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/2_xray.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/2_xray.lua @@ -193,12 +193,19 @@ o.default = 0 o.validate = function(self, value, t) if value then local reality = s.fields["reality"] and s.fields["reality"]:formvalue(t) or nil + local use_pem = s.fields["tls_use_pem"] and s.fields["tls_use_pem"]:formvalue(t) or nil if reality and reality == "1" then return value end - if value == "1" then + if value == "1" and use_pem ~= "1" then local ca = s.fields["tls_certificateFile"] and s.fields["tls_certificateFile"]:formvalue(t) or "" local key = s.fields["tls_keyFile"] and s.fields["tls_keyFile"]:formvalue(t) or "" if ca == "" or key == "" then - return nil, translate("Certificate or Private key path can not be empty!") + return nil, translate("Certificate and Private key path can not be empty!") + end + elseif value == "1" and use_pem == "1" then + local ca = s.fields["tls_certificate"] and s.fields["tls_certificate"]:formvalue(t) or "" + local key = s.fields["tls_key"] and s.fields["tls_key"]:formvalue(t) or "" + if ca == "" or key == "" then + return nil, translate("Certificate and Private key PEM can not be empty!") end end return value @@ -263,11 +270,15 @@ end -- [[ TLS部分 ]] -- +o = s:option(Flag, "tls_use_pem", translate("Use PEM"), translate("Use certificate and private key PEM content.")) +o:depends({ tls = true, reality = false }) +o:depends({ protocol = "hysteria2" }) + o = s:option(FileUpload, "tls_certificateFile", translate("Path to the certificate file"), translate("as:") .. "/etc/ssl/fullchain.crt") o.default = m:get(s.section, "tls_certificateFile") or "/etc/config/ssl/" .. s.section .. ".crt" if o and o:formvalue(s.section) then o.default = o:formvalue(s.section) end -o:depends({ tls = true, reality = false }) -o:depends({ protocol = "hysteria2"}) +o:depends({ tls = true, reality = false, tls_use_pem = false }) +o:depends({ protocol = "hysteria2", tls_use_pem = false }) o.validate = function(self, value, t) if value and value ~= "" then if not api.fs.access(value) then @@ -282,8 +293,8 @@ end o = s:option(FileUpload, "tls_keyFile", translate("Path to the private key file"), translate("as:") .. "/etc/ssl/private.key") o.default = m:get(s.section, "tls_keyFile") or "/etc/config/ssl/" .. s.section .. ".key" if o and o:formvalue(s.section) then o.default = o:formvalue(s.section) end -o:depends({ tls = true, reality = false }) -o:depends({ protocol = "hysteria2"}) +o:depends({ tls = true, reality = false, tls_use_pem = false }) +o:depends({ protocol = "hysteria2", tls_use_pem = false }) o.validate = function(self, value, t) if value and value ~= "" then if not api.fs.access(value) then @@ -295,6 +306,32 @@ o.validate = function(self, value, t) return nil end +o = s:option(TextValue, "tls_certificate", "TLS Certificate (PEM)", translate("Full certificate (chain), PEM format.")) +o.default = "" +o.rows = 5 +o.wrap = "off" +o:depends({ tls_use_pem = true }) +o.cfgvalue = function(self, section) + return (m:get(section, "tls_certificate") or ""):gsub("\\n", "\n") +end +o.validate = function(self, value) + value = api.trim(value):gsub("\r\n", "\n"):gsub("\r", "\n"):gsub("[ \t]*\n[ \t]*", "\n"):gsub("\n+", "\n") + return value:gsub("\n", "\\n") +end + +o = s:option(TextValue, "tls_key", "TLS Private Key (PEM)", translate("Private key in PEM format.")) +o.default = "" +o.rows = 5 +o.wrap = "off" +o:depends({ tls_use_pem = true }) +o.cfgvalue = function(self, section) + return (m:get(section, "tls_key") or ""):gsub("\\n", "\n") +end +o.validate = function(self, value) + value = api.trim(value):gsub("\r\n", "\n"):gsub("\r", "\n"):gsub("[ \t]*\n[ \t]*", "\n"):gsub("\n+", "\n") + return value:gsub("\n", "\\n") +end + o = s:option(Flag, "ech", translate("ECH")) o.default = "0" o:depends({ tls = true, reality = false }) diff --git a/luci-app-passwall/luasrc/passwall/util_sing-box.lua b/luci-app-passwall/luasrc/passwall/util_sing-box.lua index b795ed42f..de86ddcb9 100644 --- a/luci-app-passwall/luasrc/passwall/util_sing-box.lua +++ b/luci-app-passwall/luasrc/passwall/util_sing-box.lua @@ -248,7 +248,7 @@ function gen_outbound(flag, node, tag, proxy_table) --max_version = "1.3", fragment = fragment, record_fragment = record_fragment, - certificate = (node.tls_certificate == "1" and node.tls_certificate_pem ~= "") and api.split(node.tls_certificate_pem, "\n") or nil, + certificate = (node.tls_certificate == "1" and node.tls_certificate_pem ~= "") and api.split(node.tls_certificate_pem:gsub("\\n", "\n"), "\n") or nil, cipher_suites = (node.cipherSuites and node.cipherSuites ~= "") and api.split(node.cipherSuites, ":") or nil, ech = (node.ech == "1") and (function() local function get_ech_domain(s) --兼容xray "域名+DNS" 格式ech @@ -273,7 +273,7 @@ function gen_outbound(flag, node, tag, proxy_table) ech.query_server_name = qname ech_domain[qname] = true elseif config then - ech.config = { config } + ech.config = api.split(config:gsub("\\n", "\n"), "\n") elseif node.tls_serverName and node.tls_serverName ~= "" then ech_domain[node.tls_serverName] = true end @@ -709,8 +709,10 @@ function gen_config_server(node) local tls = { enabled = true, - certificate_path = node.tls_certificateFile, - key_path = node.tls_keyFile, + certificate_path = (node.tls_use_pem ~= "1") and node.tls_certificateFile or nil, + key_path = (node.tls_use_pem ~= "1") and node.tls_keyFile or nil, + certificate = (node.tls_use_pem == "1" and node.tls_certificate) and api.split(node.tls_certificate:gsub("\\n", "\n"), "\n") or nil, + key = (node.tls_use_pem == "1" and node.tls_key) and api.split(node.tls_key:gsub("\\n", "\n"), "\n") or nil, alpn = (node.alpn and node.alpn ~= "default") and (function() local alpn = {} string.gsub(node.alpn, '[^,]+', function(w) @@ -724,6 +726,8 @@ function gen_config_server(node) if node.tls == "1" and node.reality == "1" then tls.certificate_path = nil tls.key_path = nil + tls.certificate = nil + tls.key = nil tls.server_name = node.reality_handshake_server tls.reality = { enabled = true, diff --git a/luci-app-passwall/luasrc/passwall/util_xray.lua b/luci-app-passwall/luasrc/passwall/util_xray.lua index fb78f8523..0c1c94e44 100644 --- a/luci-app-passwall/luasrc/passwall/util_xray.lua +++ b/luci-app-passwall/luasrc/passwall/util_xray.lua @@ -181,7 +181,7 @@ function gen_outbound(flag, node, tag, proxy_table) verifyPeerCertByName = node.tls_CertByName or "", echConfigList = (node.ech == "1") and node.ech_config or nil, certificates = (node.tls_certificate == "1" and node.tls_certificate_pem ~= "") and { - certificate = api.split(node.tls_certificate_pem, "\n"), + certificate = api.split(node.tls_certificate_pem:gsub("\\n", "\n"), "\n"), usage = "verify" } or nil, cipherSuites = node.cipherSuites or nil @@ -697,8 +697,10 @@ function gen_config_server(node) disableSystemRoot = false, certificates = { { - certificateFile = node.tls_certificateFile, - keyFile = node.tls_keyFile + certificateFile = (node.tls_use_pem ~= "1") and node.tls_certificateFile or nil, + keyFile = (node.tls_use_pem ~= "1") and node.tls_keyFile or nil, + certificate = (node.tls_use_pem == "1" and node.tls_certificate) and api.split(node.tls_certificate:gsub("\\n", "\n"), "\n") or nil, + key = (node.tls_use_pem == "1" and node.tls_key) and api.split(node.tls_key:gsub("\\n", "\n"), "\n") or nil } }, echServerKeys = (node.ech == "1") and node.ech_key or nil diff --git a/luci-app-passwall/po/zh-cn/passwall.po b/luci-app-passwall/po/zh-cn/passwall.po index 8228c4c5d..a4bd6593b 100644 --- a/luci-app-passwall/po/zh-cn/passwall.po +++ b/luci-app-passwall/po/zh-cn/passwall.po @@ -1655,8 +1655,17 @@ msgstr "ECH 密钥路径" msgid "Can't find this file!" msgstr "找不到这个文件!" -msgid "Certificate or Private key path can not be empty!" -msgstr "证书或私钥文件路径不能为空!" +msgid "Certificate and Private key path can not be empty!" +msgstr "证书和私钥文件路径不能为空!" + +msgid "Certificate and Private key PEM can not be empty!" +msgstr "证书和私钥 PEM 不能为空!" + +msgid "Use PEM" +msgstr "使用 PEM" + +msgid "Use certificate and private key PEM content." +msgstr "使用证书和私钥的 PEM 内容。" msgid "Server-Side" msgstr "服务器端" @@ -1850,6 +1859,12 @@ msgstr "TLS 证书(PEM)" msgid "Full certificate (chain), PEM format." msgstr "完整证书(链),PEM 格式。" +msgid "TLS Private Key (PEM)" +msgstr "TLS 私钥(PEM)" + +msgid "Private key in PEM format." +msgstr "PEM 格式的私钥。" + msgid "ECH Config" msgstr "ECH 配置" diff --git a/netifd/Makefile b/netifd/Makefile deleted file mode 100644 index d21bb7866..000000000 --- a/netifd/Makefile +++ /dev/null @@ -1,53 +0,0 @@ -include $(TOPDIR)/rules.mk - -PKG_NAME:=netifd -PKG_RELEASE:=5 - -PKG_SOURCE_PROTO:=git -PKG_SOURCE_URL=$(PROJECT_GIT)/project/netifd.git -PKG_SOURCE_DATE:=2026-02-26 -PKG_SOURCE_VERSION:=cbb83a1857407a28a63dc09412a1f209195914ef -PKG_MIRROR_HASH:=skip -PKG_MAINTAINER:=Felix Fietkau - -PKG_LICENSE:=GPL-2.0 -PKG_LICENSE_FILES:= - -PKG_BUILD_FLAGS:=lto - -include $(INCLUDE_DIR)/package.mk -include $(INCLUDE_DIR)/cmake.mk - -define Package/netifd - SECTION:=base - CATEGORY:=Base system - DEPENDS:=+libuci +libnl-tiny +libubus +ubus +ubusd +jshn +libubox +libudebug \ - +ucode +ucode-mod-fs +ucode-mod-ubus +ucode-mod-uloop +ucode-mod-uci - TITLE:=OpenWrt Network Interface Configuration Daemon -endef - -define Package/netifd/conffiles -/etc/udhcpc.user -/etc/udhcpc.user.d/ -endef - -TARGET_CFLAGS += \ - -I$(STAGING_DIR)/usr/include/libnl-tiny \ - -I$(STAGING_DIR)/usr/include - -CMAKE_OPTIONS += \ - -DLIBNL_LIBS=-lnl-tiny \ - -DDEBUG=1 - -define Package/netifd/install - $(INSTALL_DIR) $(1)/sbin - $(INSTALL_BIN) $(PKG_BUILD_DIR)/netifd $(1)/sbin/ - $(CP) ./files/* $(1)/ - $(INSTALL_DIR) $(1)/etc/udhcpc.user.d/ - $(CP) \ - $(PKG_BUILD_DIR)/scripts/utils.sh \ - $(PKG_BUILD_DIR)/scripts/netifd-proto.sh \ - $(1)/lib/netifd/ -endef - -$(eval $(call BuildPackage,netifd)) diff --git a/netifd/files/etc/hotplug.d/iface/00-netstate b/netifd/files/etc/hotplug.d/iface/00-netstate deleted file mode 100644 index 71ccb0191..000000000 --- a/netifd/files/etc/hotplug.d/iface/00-netstate +++ /dev/null @@ -1,6 +0,0 @@ -[ ifup = "$ACTION" ] && { - uci_toggle_state network "$INTERFACE" up 1 - [ -n "$DEVICE" ] && { - uci_toggle_state network "$INTERFACE" ifname "$DEVICE" - } -} diff --git a/netifd/files/etc/init.d/network b/netifd/files/etc/init.d/network deleted file mode 100755 index b8b2a219b..000000000 --- a/netifd/files/etc/init.d/network +++ /dev/null @@ -1,143 +0,0 @@ -#!/bin/sh /etc/rc.common - -START=20 -STOP=90 - -USE_PROCD=1 - -init_switch() { - setup_switch() { return 0; } - - include /lib/network - setup_switch -} - -start_service() { - init_switch - - procd_open_instance - procd_set_param command /sbin/netifd - procd_set_param respawn - procd_set_param watch network.interface - [ -e /proc/sys/kernel/core_pattern ] && { - procd_set_param limits core="unlimited" - } - procd_close_instance -} - -reload_service() { - local rv=0 - - init_switch - ubus call network reload || rv=1 - return $rv -} - -stop_service() { - [ -x /sbin/wifi ] && /sbin/wifi down - ifdown -a - sleep 1 -} - -validate_atm_bridge_section() -{ - uci_validate_section network "atm-bridge" "${1}" \ - 'unit:uinteger:0' \ - 'vci:range(32, 65535):35' \ - 'vpi:range(0, 255):8' \ - 'atmdev:uinteger:0' \ - 'encaps:or("llc", "vc"):llc' \ - 'payload:or("bridged", "routed"):bridged' -} - -validate_route_section() -{ - uci_validate_section network route "${1}" \ - 'interface:string' \ - 'target:cidr4' \ - 'netmask:netmask4' \ - 'gateway:ip4addr' \ - 'metric:uinteger' \ - 'mtu:uinteger' \ - 'table:or(range(0,65535),string)' -} - -validate_route6_section() -{ - uci_validate_section network route6 "${1}" \ - 'interface:string' \ - 'target:cidr6' \ - 'gateway:ip6addr' \ - 'metric:uinteger' \ - 'mtu:uinteger' \ - 'table:or(range(0,65535),string)' -} - -validate_rule_section() -{ - uci_validate_section network rule "${1}" \ - 'in:string' \ - 'out:string' \ - 'src:cidr4' \ - 'dest:cidr4' \ - 'tos:range(0,31)' \ - 'mark:string' \ - 'invert:bool' \ - 'lookup:or(range(0,65535),string)' \ - 'goto:range(0,65535)' \ - 'action:or("prohibit", "unreachable", "blackhole", "throw")' -} - -validate_rule6_section() -{ - uci_validate_section network rule6 "${1}" \ - 'in:string' \ - 'out:string' \ - 'src:cidr6' \ - 'dest:cidr6' \ - 'tos:range(0,31)' \ - 'mark:string' \ - 'invert:bool' \ - 'lookup:or(range(0,65535),string)' \ - 'goto:range(0,65535)' \ - 'action:or("prohibit", "unreachable", "blackhole", "throw")' -} - -validate_switch_section() -{ - uci_validate_section network switch "${1}" \ - 'name:string' \ - 'enable:bool' \ - 'enable_vlan:bool' \ - 'reset:bool' \ - 'ar8xxx_mib_poll_interval:uinteger' \ - 'ar8xxx_mib_type:range(0,1)' -} - -validate_switch_vlan() -{ - uci_validate_section network switch_vlan "${1}" \ - 'device:string' \ - 'vlan:uinteger' \ - 'ports:list(ports)' -} - -service_triggers() -{ - procd_add_reload_trigger network wireless - - procd_open_validate - validate_atm_bridge_section - validate_route_section - [ -e /proc/sys/net/ipv6 ] && validate_route6_section - validate_rule_section - [ -e /proc/sys/net/ipv6 ] && validate_rule6_section - validate_switch_section - validate_switch_vlan - procd_close_validate -} - -shutdown() { - ifdown -a - sleep 1 -} diff --git a/netifd/files/etc/init.d/packet_steering b/netifd/files/etc/init.d/packet_steering deleted file mode 100755 index 5266a931a..000000000 --- a/netifd/files/etc/init.d/packet_steering +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/sh /etc/rc.common - -START=25 -USE_PROCD=1 - -start_service() { - reload_service -} - -service_triggers() { - procd_add_reload_trigger "network" - procd_add_reload_trigger "firewall" - procd_add_raw_trigger "interface.*" 1000 /etc/init.d/packet_steering reload -} - -reload_service() { - packet_steering="$(uci -q get "network.@globals[0].packet_steering")" - steering_flows="$(uci -q get "network.@globals[0].steering_flows")" - [ "${steering_flows:-0}" -gt 0 ] && opts="-l $steering_flows" - if [ -e "/usr/libexec/platform/packet-steering.sh" ]; then - /usr/libexec/platform/packet-steering.sh "$packet_steering" - else - /usr/libexec/network/packet-steering.uc $opts "$packet_steering" - fi -} diff --git a/netifd/files/etc/uci-defaults/14_migrate-dhcp-release b/netifd/files/etc/uci-defaults/14_migrate-dhcp-release deleted file mode 100644 index f1b384eec..000000000 --- a/netifd/files/etc/uci-defaults/14_migrate-dhcp-release +++ /dev/null @@ -1,23 +0,0 @@ -. /lib/functions.sh - -migrate_release() { - local config="$1" - local proto - local release - - config_get proto "$config" proto - config_get release "$config" release - - [ "$proto" = "dhcp" ] && [ -n "$release" ] && { - norelease="$((!$release))" - uci_set network "$config" norelease "$norelease" - uci_remove network "$config" release - } - -} - -config_load network -config_foreach migrate_release interface -uci commit network - -exit 0 diff --git a/netifd/files/etc/udhcpc.user b/netifd/files/etc/udhcpc.user deleted file mode 100644 index 78e2ba5f1..000000000 --- a/netifd/files/etc/udhcpc.user +++ /dev/null @@ -1 +0,0 @@ -# This script is sourced by udhcpc's dhcp.script at every DHCP event. diff --git a/netifd/files/lib/netifd/dhcp.script b/netifd/files/lib/netifd/dhcp.script deleted file mode 100755 index db8deac9e..000000000 --- a/netifd/files/lib/netifd/dhcp.script +++ /dev/null @@ -1,120 +0,0 @@ -#!/bin/sh -[ -z "$1" ] && echo "Error: should be run by udhcpc" && exit 1 - -. /lib/functions.sh -. /lib/netifd/netifd-proto.sh - -set_classless_routes() { - local max=128 - while [ -n "$1" -a -n "$2" -a $max -gt 0 ]; do - proto_add_ipv4_route "${1%%/*}" "${1##*/}" "$2" "$ip" - max=$(($max-1)) - shift 2 - done -} - -setup_interface () { - proto_init_update "*" 1 - proto_add_ipv4_address "$ip" "${subnet:-255.255.255.0}" - # TODO: apply $broadcast - - local ip_net IP PREFIX NETWORK NETMASK BROADCAST - ipcalc "$ip/$mask" && ip_net="$NETWORK" - - local i - for i in $router; do - local gw_net - ipcalc "$i/$mask" && gw_net="$NETWORK" - - [ "$ip_net" != "$gw_net" ] && proto_add_ipv4_route "$i" 32 "" "$ip" - proto_add_ipv4_route 0.0.0.0 0 "$i" "$ip" - - local r - for r in $CUSTOMROUTES; do - proto_add_ipv4_route "${r%%/*}" "${r##*/}" "$i" "$ip" - done - done - - # CIDR STATIC ROUTES (rfc3442) - [ -n "$staticroutes" ] && set_classless_routes $staticroutes - [ -n "$msstaticroutes" ] && set_classless_routes $msstaticroutes - - for i in $dns; do - proto_add_dns_server "$i" - done - for i in $domain; do - proto_add_dns_search "$i" - done - - # TODO: Deprecate timesvr in favor of timesrv - if [ -n "$timesvr" -a -z "$timesrv" ]; then - timesrv="$timesvr" - echo "Environment variable 'timesvr' will be deprecated; use 'timesrv' instead." - fi - - proto_add_data - [ -n "$ZONE" ] && json_add_string zone "$ZONE" - [ -n "$ntpsrv" ] && json_add_string ntpserver "$ntpsrv" - [ -n "$timesrv" ] && json_add_string timeserver "$timesrv" - [ -n "$hostname" ] && json_add_string hostname "$hostname" - [ -n "$message" ] && json_add_string message "$message" - [ -n "$timezone" ] && json_add_int timezone "$timezone" - [ -n "$lease" ] && json_add_int leasetime "$lease" - [ -n "$serverid" ] && json_add_string dhcpserver "$serverid" - proto_close_data - - proto_send_update "$INTERFACE" - - - if [ "$IFACE6RD" != 0 -a -n "$ip6rd" ]; then - local v4mask="${ip6rd%% *}" - ip6rd="${ip6rd#* }" - local ip6rdprefixlen="${ip6rd%% *}" - ip6rd="${ip6rd#* }" - local ip6rdprefix="${ip6rd%% *}" - ip6rd="${ip6rd#* }" - local ip6rdbr="${ip6rd%% *}" - - [ -n "$ZONE" ] || ZONE=$(fw3 -q network $INTERFACE 2>/dev/null) - [ -z "$IFACE6RD" -o "$IFACE6RD" = 1 ] && IFACE6RD=${INTERFACE}_6 - - json_init - json_add_string name "$IFACE6RD" - json_add_string ifname "@$INTERFACE" - json_add_string proto "6rd" - json_add_string peeraddr "$ip6rdbr" - json_add_int ip4prefixlen "$v4mask" - json_add_string ip6prefix "$ip6rdprefix" - json_add_int ip6prefixlen "$ip6rdprefixlen" - json_add_string tunlink "$INTERFACE" - [ -n "$IFACE6RD_DELEGATE" ] && json_add_boolean delegate "$IFACE6RD_DELEGATE" - [ -n "$ZONE6RD" ] || ZONE6RD=$ZONE - [ -n "$ZONE6RD" ] && json_add_string zone "$ZONE6RD" - [ -n "$MTU6RD" ] && json_add_string mtu "$MTU6RD" - json_close_object - - ubus call network add_dynamic "$(json_dump)" - fi -} - -deconfig_interface() { - proto_init_update "*" 0 - proto_send_update "$INTERFACE" -} - -case "$1" in - deconfig) - deconfig_interface - ;; - renew|bound) - setup_interface - ;; -esac - -# user rules -[ -f /etc/udhcpc.user ] && . /etc/udhcpc.user "$@" -for f in /etc/udhcpc.user.d/*; do - [ -f "$f" ] && (. "$f" "$@") -done - -exit 0 diff --git a/netifd/files/lib/netifd/main.uc b/netifd/files/lib/netifd/main.uc deleted file mode 100644 index 69677bb15..000000000 --- a/netifd/files/lib/netifd/main.uc +++ /dev/null @@ -1,79 +0,0 @@ -import * as uci from "uci"; -import * as uloop from "uloop"; -import * as ubus from "ubus"; -import { access, dirname } from "fs"; - -function ex_handler(e) -{ - netifd.log(netifd.L_WARNING, `Exception: ${e}\n${e.stacktrace[0].context}\n`); -} - -uloop.guard(ex_handler); -ubus.guard(ex_handler); - -let wireless; - -function uci_ctx() -{ - let savedir = netifd.dummy_mode ? "./tmp" : null; - let ctx = uci.cursor(netifd.config_path, savedir, null, { - strict: false - }); - return ctx; -} - -function config_init() -{ - let ctx = uci_ctx(); - - if (wireless) - wireless.config_init(ctx); -} - -function config_start() -{ - if (wireless) - wireless.config_start(); -} - -function check_interfaces() -{ - if (wireless) - wireless.check_interfaces(); -} - -function hotplug(name, add) -{ - if (wireless) - wireless.hotplug(name, add); -} - -function ex_wrap(cb) -{ - let fn = cb; - return (...args) => { - try { - return fn(...args); - } catch (e) { - netifd.log(netifd.L_WARNING, `${e}\n${e.stacktrace[0].context}`); - } - }; -} - -netifd.cb = { - hotplug: ex_wrap(hotplug), - config_init: ex_wrap(config_init), - config_start: ex_wrap(config_start), - check_interfaces: ex_wrap(check_interfaces), -}; - -const wireless_module = dirname(sourcepath()) + "/wireless.uc"; -if (access(wireless_module, "r")) { - try { - wireless = loadfile(wireless_module)(); - } catch (e) { - netifd.log(netifd.L_WARNING, `Error loading wireless module: ${e}\n${e.stacktrace[0].context}\n`); - } -} else { - netifd.log(netifd.L_WARNING, `Wireless module not found\n`); -} diff --git a/netifd/files/lib/netifd/proto/dhcp.sh b/netifd/files/lib/netifd/proto/dhcp.sh deleted file mode 100755 index 5948183ef..000000000 --- a/netifd/files/lib/netifd/proto/dhcp.sh +++ /dev/null @@ -1,140 +0,0 @@ -#!/bin/sh - -[ -x /sbin/udhcpc ] || exit 0 - -. /lib/functions.sh -. /lib/functions/network.sh -. ../netifd-proto.sh -. /lib/config/uci.sh -init_proto "$@" - -proto_dhcp_init_config() { - renew_handler=1 - - proto_config_add_string 'ipaddr:ipaddr' - proto_config_add_string 'hostname:hostname' - proto_config_add_string clientid - proto_config_add_string sendclientid - proto_config_add_string vendorid - proto_config_add_boolean 'broadcast:bool' - proto_config_add_boolean 'norelease:bool' - proto_config_add_string 'reqopts:list(string)' - proto_config_add_boolean 'defaultreqopts:bool' - proto_config_add_string iface6rd - proto_config_add_array 'sendopts:list(string)' - proto_config_add_boolean delegate - proto_config_add_string zone6rd - proto_config_add_string zone - proto_config_add_string mtu6rd - proto_config_add_string customroutes - proto_config_add_boolean classlessroute -} - -proto_dhcp_add_sendopts() { - [ -n "$1" ] && append "$3" "-x $1" -} - -proto_dhcp_get_default_clientid() { - [ -z "$1" ] && return - - local iface="$1" - local duid - local iaid - - duid="$(uci_get network @globals[0] dhcp_default_duid)" - [ -n "$duid" ] && { - duid="$(hexdump_2hex "$duid")" - [ -z "$duid" ] && logger -p warn -t dhcp "$iface: ignoring invalid dhcp_default_duid value" - } - [ -z "$duid" ] && return - network_generate_iface_iaid iaid "$iface" - printf "ff%s%s" "$iaid" "$duid" -} - -proto_dhcp_setup() { - local config="$1" - local iface="$2" - - local ipaddr hostname clientid sendclientid vendorid broadcast norelease reqopts defaultreqopts iface6rd sendopts delegate zone6rd zone mtu6rd customroutes classlessroute - json_get_vars ipaddr hostname clientid sendclientid vendorid broadcast norelease reqopts defaultreqopts iface6rd delegate zone6rd zone mtu6rd customroutes classlessroute - - local opt dhcpopts - for opt in $reqopts; do - append dhcpopts "-O $opt" - done - - json_for_each_item proto_dhcp_add_sendopts sendopts dhcpopts - - [ -z "$hostname" ] && hostname="$(cat /proc/sys/kernel/hostname)" - [ "$hostname" = "*" ] && hostname= - - [ "$defaultreqopts" = 0 ] && defaultreqopts="-o" || defaultreqopts= - [ "$broadcast" = 1 ] && broadcast="-B" || broadcast= - [ "$norelease" = 1 ] && norelease="" || norelease="-R" - case "$sendclientid" in - global) - clientid="$(proto_dhcp_get_default_clientid "$iface")" - ;; - hardware) - clientid='' - ;; - none) - clientid='-C' - ;; - auto|\ - *) - [ -n "$clientid" ] && { - clientid="$(hexdump_2hex "$clientid")" - [ -z "$clientid" ] && { - logger -p warn -t dhcp "$iface: ignoring invalid clientid value" - } - } - [ -z "$clientid" ] && clientid="$(proto_dhcp_get_default_clientid "$iface")" - ;; - esac - [ -n "${clientid##-C}" ] && clientid="-x 0x3d:$clientid" - [ -n "$vendorid" ] && append dhcpopts "-x 0x3c:$(echo -n "$vendorid" | hexdump -ve '1/1 "%02x"')" - [ -n "$iface6rd" ] && proto_export "IFACE6RD=$iface6rd" - [ "$iface6rd" != 0 -a -f /lib/netifd/proto/6rd.sh ] && append dhcpopts "-O 212" - [ -n "$zone6rd" ] && proto_export "ZONE6RD=$zone6rd" - [ -n "$zone" ] && proto_export "ZONE=$zone" - [ -n "$mtu6rd" ] && proto_export "MTU6RD=$mtu6rd" - [ -n "$customroutes" ] && proto_export "CUSTOMROUTES=$customroutes" - [ "$delegate" = "0" ] && proto_export "IFACE6RD_DELEGATE=0" - # Request classless route option (see RFC 3442) by default - [ "$classlessroute" = "0" ] || append dhcpopts "-O 121" - - # Avoid sending duplicate Option 60 values - local emptyvendorid - case "$dhcpopts" in - *"-x 0"[xX]*"3"[cC]":"* |\ - *"-x 60:"* |\ - *"-x vendor:"*) - emptyvendorid=1 - ;; - esac - - proto_export "INTERFACE=$config" - proto_run_command "$config" udhcpc \ - -p /var/run/udhcpc-$iface.pid \ - -s /lib/netifd/dhcp.script \ - -f -t 0 -i "$iface" \ - ${ipaddr:+-r ${ipaddr/\/*/}} \ - ${hostname:+-x "hostname:$hostname"} \ - ${emptyvendorid:+-V ""} \ - $clientid $defaultreqopts $broadcast $norelease $dhcpopts -} - -proto_dhcp_renew() { - local interface="$1" - # SIGUSR1 forces udhcpc to renew its lease - local sigusr1="$(kill -l SIGUSR1)" - [ -n "$sigusr1" ] && proto_kill_command "$interface" $sigusr1 -} - -proto_dhcp_teardown() { - local interface="$1" - proto_kill_command "$interface" -} - -add_protocol dhcp diff --git a/netifd/files/lib/netifd/utils.uc b/netifd/files/lib/netifd/utils.uc deleted file mode 100644 index 84db69d2f..000000000 --- a/netifd/files/lib/netifd/utils.uc +++ /dev/null @@ -1,131 +0,0 @@ -'use strict'; - -import { glob, basename, realpath, chdir, mkstemp } from "fs"; - -export const TYPE_ARRAY = 1; -export const TYPE_STRING = 3; -export const TYPE_INT = 5; -export const TYPE_BOOL = 7; - -export function parse_bool(val) -{ - switch (val) { - case "1": - case "true": - return true; - case "0": - case "false": - return false; - } -}; - -export function parse_array(val) -{ - if (type(val) != "array") - val = split(val, /\s+/); - return val; -}; - -function __type_parsers() -{ - let ret = []; - - ret[TYPE_ARRAY] = parse_array; - ret[TYPE_STRING] = function(val) { - return val; - }; - ret[TYPE_INT] = function(val) { - return +val; - }; - ret[TYPE_BOOL] = parse_bool; - - return ret; -} -export const type_parser = __type_parsers(); - -export function handler_load(path, cb) -{ - for (let script in glob(path + "/*.sh")) { - script = basename(script); - - let f = mkstemp(); - let prev_dir = realpath("."); - chdir(path); - system(`./${script} "" "dump" >&${f.fileno()}`); - chdir(prev_dir); - f.seek(); - while (!f.error()) { - let data = trim(f.read("line")); - try { - data = json(data); - } catch (e) { - continue; - } - - if (type(data) != "object") - continue; - - cb(script, data); - } - f.close(); - } -}; - -export function handler_attributes(data, extra, validate) -{ - let ret = { ...extra }; - for (let cur in data) { - let name_data = split(cur[0], ":", 2); - let name = name_data[0]; - ret[name] = cur[1]; - if (validate && name_data[1]) - validate[name] = name_data[1]; - } - return ret; -}; - -export function parse_attribute_list(data, spec) -{ - let ret = {}; - - for (let name, type_id in spec) { - if (!(name in data)) - continue; - - let val = data[name]; - let parser = type_parser[type_id]; - if (parser) - val = parser(val); - ret[name] = val; - } - - return ret; -}; - -export function is_equal(val1, val2) { - let t1 = type(val1); - - if (t1 != type(val2)) - return false; - - if (t1 == "array") { - if (length(val1) != length(val2)) - return false; - - for (let i = 0; i < length(val1); i++) - if (!is_equal(val1[i], val2[i])) - return false; - - return true; - } else if (t1 == "object") { - for (let key in val1) - if (!is_equal(val1[key], val2[key])) - return false; - for (let key in val2) - if (val1[key] == null) - return false; - return true; - } else { - return val1 == val2; - } -}; diff --git a/netifd/files/lib/network/config.sh b/netifd/files/lib/network/config.sh deleted file mode 100755 index 4cd28e4ce..000000000 --- a/netifd/files/lib/network/config.sh +++ /dev/null @@ -1,76 +0,0 @@ -#!/bin/sh -# Copyright (C) 2011 OpenWrt.org - -. /usr/share/libubox/jshn.sh - -find_config() { - local device="$1" - local ifdev ifl3dev ifobj - for ifobj in $(ubus list network.interface.\*); do - interface="${ifobj##network.interface.}" - ( - json_load "$(ifstatus $interface)" - json_get_var ifdev device - json_get_var ifl3dev l3_device - if [ "$device" = "$ifdev" ] || [ "$device" = "$ifl3dev" ]; then - echo "$interface" - exit 0 - else - exit 1 - fi - ) && return - done -} - -unbridge() { - return -} - -ubus_call() { - json_init - local _data="$(ubus -S call "$1" "$2")" - [ -z "$_data" ] && return 1 - json_load "$_data" - return 0 -} - - -fixup_interface() { - local config="$1" - local ifname type device l3dev - - config_get type "$config" type - config_get ifname "$config" ifname - [ "bridge" = "$type" ] && ifname="br-$config" - ubus_call "network.interface.$config" status || return 0 - json_get_var l3dev l3_device - [ -n "$l3dev" ] && ifname="$l3dev" - json_init - config_set "$config" ifname "$ifname" -} - -scan_interfaces() { - config_load network - config_foreach fixup_interface interface -} - -prepare_interface_bridge() { - local config="$1" - - [ -n "$config" ] || return 0 - ubus call network.interface."$config" prepare -} - -setup_interface() { - local iface="$1" - local config="$2" - - [ -n "$config" ] || return 0 - ubus call network.interface."$config" add_device "{ \"name\": \"$iface\" }" -} - -do_sysctl() { - [ -n "$2" ] && \ - sysctl -n -e -w "$1=$2" >/dev/null || \ - sysctl -n -e "$1" -} diff --git a/netifd/files/sbin/devstatus b/netifd/files/sbin/devstatus deleted file mode 100755 index 3c35b26a4..000000000 --- a/netifd/files/sbin/devstatus +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh -. /usr/share/libubox/jshn.sh -DEVICE="$1" - -[ -n "$DEVICE" ] || { - echo "Usage: $0 " - exit 1 -} - -json_init -json_add_string name "$DEVICE" -ubus call network.device status "$(json_dump)" diff --git a/netifd/files/sbin/ifdown b/netifd/files/sbin/ifdown deleted file mode 120000 index a0e5c176a..000000000 --- a/netifd/files/sbin/ifdown +++ /dev/null @@ -1 +0,0 @@ -ifup \ No newline at end of file diff --git a/netifd/files/sbin/ifstatus b/netifd/files/sbin/ifstatus deleted file mode 100755 index 8a951e6e1..000000000 --- a/netifd/files/sbin/ifstatus +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh -INTERFACE="$1" - -[ -n "$INTERFACE" ] || { - echo "Usage: $0 " - exit 1 -} - -ubus -S list "network.interface.$INTERFACE" >/dev/null || { - echo "Interface $INTERFACE not found" - exit 1 -} -ubus call network.interface status "{ \"interface\" : \"$INTERFACE\" }" diff --git a/netifd/files/sbin/ifup b/netifd/files/sbin/ifup deleted file mode 100755 index fbf2fd80c..000000000 --- a/netifd/files/sbin/ifup +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/sh - -ifup_all= - -if_call() { - local interface="$1" - for mode in $modes; do - ubus call network.interface $mode "{ \"interface\" : \"$interface\" }" - done -} - -case "$0" in - *ifdown) modes=down;; - *ifup) - modes="down up" - ;; - *) echo "Invalid command: $0";; -esac - -while :; do - case "$1" in - -a) - ifup_all=1 - shift - ;; - *) - break - ;; - esac -done - -[ "$modes" = "down up" ] && ubus call network reload -if [ -n "$ifup_all" ]; then - for interface in $(ubus -S list 'network.interface.*'); do - if_call "${interface##network.interface.}" - done - exit -else - ubus -S list "network.interface.$1" > /dev/null || { - echo "Interface $1 not found" - exit - } - if_call "$1" -fi diff --git a/netifd/files/usr/libexec/network/packet-steering.uc b/netifd/files/usr/libexec/network/packet-steering.uc deleted file mode 100755 index 34df46d18..000000000 --- a/netifd/files/usr/libexec/network/packet-steering.uc +++ /dev/null @@ -1,279 +0,0 @@ -#!/usr/bin/env ucode -'use strict'; -import { glob, basename, dirname, readlink, readfile, realpath, writefile, error, open } from "fs"; - -let napi_weight = 1.0; -let cpu_thread_weight = 0.75; -let rx_weight = 0.75; -let eth_bias = 2.0; -let debug = 0, do_nothing = 0; -let disable; -let cpus; -let all_cpus; -let local_flows = 0; - -while (length(ARGV) > 0) { - let arg = shift(ARGV); - switch (arg) { - case "-d": - debug++; - break; - case "-n": - do_nothing++; - break; - case '0': - disable = true; - break; - case '2': - all_cpus = true; - break; - case '-l': - local_flows = +shift(ARGV); - break; - } -} - -function task_name(pid) -{ - let stat = open(`/proc/${pid}/status`, "r"); - if (!stat) - return; - let line = stat.read("line"); - stat.close(); - return trim(split(line, "\t", 2)[1]); -} - -function set_task_cpu(pid, cpu) { - if (disable) - cpu = join(",", map(cpus, (cpu) => cpu.id)); - let name = task_name(pid); - if (!name) - return; - if (debug || do_nothing) - warn(`taskset -p -c ${cpu} ${name}\n`); - if (!do_nothing) - system(`taskset -p -c ${cpu} ${pid}`); -} - -function cpu_mask(cpu) -{ - let mask; - if (cpu < 0) - mask = (1 << length(cpus)) - 1; - else - mask = (1 << int(cpu)); - return sprintf("%x", mask); -} - -function set_netdev_cpu(dev, cpu, rx_queue) { - rx_queue ??= "rx-*"; - let queues = glob(`/sys/class/net/${dev}/queues/${rx_queue}/rps_cpus`); - let val = cpu_mask(cpu); - if (disable) - val = 0; - for (let queue in queues) { - if (debug || do_nothing) - warn(`echo ${val} > ${queue}\n`); - if (!do_nothing) - writefile(queue, `${val}`); - } - queues = glob(`/sys/class/net/${dev}/queues/${rx_queue}/rps_flow_cnt`); - for (let queue in queues) { - if (debug || do_nothing) - warn(`echo ${local_flows} > ${queue}\n`); - if (!do_nothing) - writefile(queue, `${local_flows}`); - } -} - -function task_device_match(name, device) -{ - let napi_match = match(name, /napi\/([^-]*)-\d+/); - if (!napi_match) - napi_match = match(name, /mt76-tx (phy\d+)/); - if (napi_match && - (index(device.phy, napi_match[1]) >= 0 || - index(device.netdev, napi_match[1]) >= 0)) - return true; - - if (device.driver == "mtk_soc_eth" && match(name, /napi\/mtk_eth-/)) - return true; - - return false; -} - -cpus = map(glob("/sys/bus/cpu/devices/*"), (path) => { - return { - id: int(match(path, /.*cpu(\d+)/)[1]), - core: int(trim(readfile(`${path}/topology/core_id`))), - load: 0.0, - }; -}); - -cpus = slice(cpus, 0, 64); -if (length(cpus) < 2) - exit(0); - -function cpu_add_weight(cpu_id, weight) -{ - let cpu = cpus[cpu_id]; - cpu.load += weight; - for (let sibling in cpus) { - if (sibling == cpu || sibling.core != cpu.core) - continue; - sibling.load += weight * cpu_thread_weight; - } -} - -function get_next_cpu(weight, prev_cpu) -{ - if (disable) - return 0; - - let sort_cpus = sort(slice(cpus), (a, b) => a.load - b.load); - let idx = 0; - - if (prev_cpu != null && sort_cpus[idx].id == prev_cpu) - idx++; - - let cpu = sort_cpus[idx].id; - cpu_add_weight(cpu, weight); - return cpu; -} - -let phys_devs = {}; -let netdev_phys = {}; -let netdevs = map(glob("/sys/class/net/*"), (dev) => basename(dev)); - -for (let dev in netdevs) { - let pdev_path = realpath(`/sys/class/net/${dev}/device`); - if (!pdev_path) - continue; - - if (length(glob(`/sys/class/net/${dev}/lower_*`)) > 0) - continue; - - let pdev = phys_devs[pdev_path]; - if (!pdev) { - pdev = phys_devs[pdev_path] = { - path: pdev_path, - driver: basename(readlink(`${pdev_path}/driver`)), - netdev: [], - phy: [], - tasks: [], - rx_tasks: [], - rx_queues: map(glob(`/sys/class/net/${dev}/queues/rx-*/rps_cpus`), - (v) => basename(dirname(v))), - }; - } - - let phyidx = trim(readfile(`/sys/class/net/${dev}/phy80211/index`)); - if (phyidx != null) { - let phy = `phy${phyidx}`; - if (index(pdev.phy, phy) < 0) - push(pdev.phy, phy); - } - - push(pdev.netdev, dev); - netdev_phys[dev] = pdev; -} - -for (let path in glob("/proc/*/exe")) { - readlink(path); - if (error() != "No such file or directory") - continue; - - let pid = basename(dirname(path)); - let name = task_name(pid); - for (let devname in phys_devs) { - let dev = phys_devs[devname]; - if (!task_device_match(name, dev)) - continue; - - push(dev.tasks, pid); - - let napi_match = match(name, /napi\/([^-]*)-(\d+)/); - if (napi_match && napi_match[2] > 0) - push(dev.rx_tasks, pid); - break; - } -} - -function assign_dev_queues_cpu(dev) { - let num = length(dev.rx_queues); - if (num < length(dev.rx_tasks)) - num = length(dev.rx_tasks); - - for (let i = 0; i < num; i++) { - let cpu; - - let task = dev.rx_tasks[i]; - if (num >= length(cpus)) - cpu = i % length(cpus); - else if (task) - cpu = get_next_cpu(napi_weight); - else - cpu = -1; - set_task_cpu(task, cpu); - - let rxq = dev.rx_queues[i]; - if (!rxq) - continue; - - if (num >= length(cpus)) - cpu = (i + 1) % length(cpus); - else if (all_cpus) - cpu = -1; - else - cpu = get_next_cpu(napi_weight, cpu); - for (let netdev in dev.netdev) - set_netdev_cpu(netdev, cpu, rxq); - } -} - -function assign_dev_cpu(dev) { - if (length(dev.rx_queues) > 1 && - length(dev.rx_tasks) > 1) - return assign_dev_queues_cpu(dev); - - if (length(dev.tasks) > 0) { - let cpu = dev.napi_cpu = get_next_cpu(napi_weight); - for (let task in dev.tasks) - set_task_cpu(task, cpu); - } - - if (length(dev.netdev) > 0) { - let cpu; - if (all_cpus) - cpu = -1; - else - cpu = get_next_cpu(rx_weight, dev.napi_cpu); - for (let netdev in dev.netdev) - set_netdev_cpu(netdev, cpu); - } -} - -// Assign ethernet devices first -for (let devname in phys_devs) { - let dev = phys_devs[devname]; - if (!length(dev.phy)) - assign_dev_cpu(dev); -} - -// Add bias to avoid assigning other tasks to CPUs with ethernet NAPI -for (let devname in phys_devs) { - let dev = phys_devs[devname]; - if (!length(dev.tasks) || dev.napi_cpu == null) - continue; - cpu_add_weight(dev.napi_cpu, eth_bias); -} - -// Assign WLAN devices -for (let devname in phys_devs) { - let dev = phys_devs[devname]; - if (length(dev.phy) > 0) - assign_dev_cpu(dev); -} - -if (debug > 1) - warn(sprintf("devices: %.J\ncpus: %.J\n", phys_devs, cpus)); diff --git a/netifd/files/usr/share/udhcpc/default.script b/netifd/files/usr/share/udhcpc/default.script deleted file mode 100755 index 0a9eb0180..000000000 --- a/netifd/files/usr/share/udhcpc/default.script +++ /dev/null @@ -1,57 +0,0 @@ -#!/bin/sh -[ -z "$1" ] && echo "Error: should be run by udhcpc" && exit 1 - -set_classless_routes() { - local max=128 - local type - while [ -n "$1" -a -n "$2" -a $max -gt 0 ]; do - [ ${1##*/} -eq 32 ] && type=host || type=net - echo "udhcpc: adding route for $type $1 via $2" - route add -$type "$1" gw "$2" dev "$interface" - max=$(($max-1)) - shift 2 - done -} - -setup_interface() { - echo "udhcpc: ip addr add $ip/${subnet:-255.255.255.0} broadcast ${broadcast:-+} dev $interface" - ip addr add $ip/${subnet:-255.255.255.0} broadcast ${broadcast:-+} dev $interface - - [ -n "$router" ] && [ "$router" != "0.0.0.0" ] && [ "$router" != "255.255.255.255" ] && { - echo "udhcpc: setting default routers: $router" - - local valid_gw="" - for i in $router ; do - route add default gw $i dev $interface - valid_gw="${valid_gw:+$valid_gw|}$i" - done - - eval $(route -n | awk ' - /^0.0.0.0\W{9}('$valid_gw')\W/ {next} - /^0.0.0.0/ {print "route del -net "$1" gw "$2";"} - ') - } - - # CIDR STATIC ROUTES (rfc3442) - [ -n "$staticroutes" ] && set_classless_routes $staticroutes - [ -n "$msstaticroutes" ] && set_classless_routes $msstaticroutes -} - - -applied= -case "$1" in - deconfig) - ip -4 addr flush dev "$interface" - ;; - renew) - setup_interface update - ;; - bound) - setup_interface ifup - ;; -esac - -# user rules -[ -f /etc/udhcpc.user ] && . /etc/udhcpc.user - -exit 0 diff --git a/netifd/patches/default-ipv4-netmask-fallback-24.patch b/netifd/patches/default-ipv4-netmask-fallback-24.patch deleted file mode 100644 index 677fcbdbc..000000000 --- a/netifd/patches/default-ipv4-netmask-fallback-24.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/proto.c -+++ b/proto.c -@@ -426,6 +426,8 @@ proto_apply_static_ip_settings(struct interface *iface, struct blob_attr *attr) - error = "INVALID_NETMASK"; - goto error; - } -+ } else if (iface && !strncmp(iface->name, "lan", 3)) { -+ netmask = 24; - } - - if ((cur = tb[OPT_BROADCAST])) { diff --git a/ttyd/Makefile b/ttyd/Makefile new file mode 100644 index 000000000..62d2500f0 --- /dev/null +++ b/ttyd/Makefile @@ -0,0 +1,52 @@ +# +# Copyright (C) 2016 Shuanglei Tao +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=ttyd +PKG_VERSION:=1.7.7 +PKG_RELEASE:=1 + +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz +PKG_SOURCE_URL:=https://codeload.github.com/tsl0922/ttyd/tar.gz/$(PKG_VERSION)? +PKG_HASH:=skip + +PKG_MAINTAINER:=Shuanglei Tao +PKG_LICENSE:=MIT +PKG_LICENSE_FILES:=LICENSE +PKG_CPE_ID:=cpe:/a:ttyd_project:ttyd + +include $(INCLUDE_DIR)/package.mk +include $(INCLUDE_DIR)/cmake.mk + +define Package/ttyd + SECTION:=utils + CATEGORY:=Utilities + TITLE:=Command-line tool for sharing terminal over the web + DEPENDS:=+libcap +libopenssl +libjson-c +libuv +zlib +libwebsockets-full + URL:=https://github.com/tsl0922/ttyd + SUBMENU:=Terminal +endef + +define Package/ttyd/description +ttyd is a command-line tool for sharing terminal over the web. +endef + +define Package/ttyd/conffiles +/etc/config/ttyd +endef + +define Package/ttyd/install + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/ttyd $(1)/usr/bin/ + $(INSTALL_DIR) $(1)/etc/config/ + $(INSTALL_CONF) ./files/ttyd.config $(1)/etc/config/ttyd + $(INSTALL_DIR) $(1)/etc/init.d/ + $(INSTALL_BIN) ./files/ttyd.init $(1)/etc/init.d/ttyd +endef + +$(eval $(call BuildPackage,ttyd)) diff --git a/ttyd/files/ttyd.config b/ttyd/files/ttyd.config new file mode 100644 index 000000000..cc6c71f49 --- /dev/null +++ b/ttyd/files/ttyd.config @@ -0,0 +1,4 @@ + +config ttyd + option command '/bin/login' + diff --git a/ttyd/files/ttyd.init b/ttyd/files/ttyd.init new file mode 100644 index 000000000..7e24aeab2 --- /dev/null +++ b/ttyd/files/ttyd.init @@ -0,0 +1,102 @@ +#!/bin/sh /etc/rc.common + +START=99 +STOP=50 +USE_PROCD=1 + +NAME=ttyd +PROG=/usr/bin/$NAME + +validate_section_ttyd() +{ + uci_load_validate ttyd ttyd "$1" "$2" \ + 'enable:bool:1' \ + 'port:port' \ + 'interface:string' \ + 'credential:string' \ + 'uid:uinteger' \ + 'gid:uinteger' \ + 'signal:uinteger' \ + 'url_arg:bool' \ + 'readonly:bool:0' \ + 'client_option:list(string)' \ + 'terminal_type:string' \ + 'check_origin:bool' \ + 'max_clients:uinteger' \ + 'once:bool' \ + 'index:string' \ + 'ipv6:bool' \ + 'ssl:bool' \ + 'ssl_cert:file' \ + 'ssl_key:file' \ + 'ssl_ca:file' \ + 'debug:uinteger' \ + 'command:string' +} + +ttyd_instance() +{ + [ "$2" = 0 ] || { + echo "validation failed" + return 1 + } + + [ "$enable" = 0 ] && return 1 + [ -z "$command" ] && return 1 + + [ "${interface::1}" = @ ] && { + interface=$( + . /lib/functions/network.sh + network_get_device device "${interface:1}" + echo -n "$device" + ) + } + + [ "$url_arg" = 0 ] && url_arg="" + [ "$readonly" = 0 ] && readonly="-W" + [ "$check_origin" = 0 ] && check_origin="" + [ "$once" = 0 ] && once="" + [ "$ipv6" = 0 ] && ipv6="" + [ "$ssl" = 0 ] && ssl="" + + procd_open_instance + procd_set_param command "$PROG" \ + ${port:+-p $port} \ + ${interface:+-i $interface} \ + ${credential:+-c $credential} \ + ${uid:+-u $uid} \ + ${gid:+-g $gid} \ + ${signal:+-s $signal} \ + ${url_arg:+-a} \ + ${readonly:-} \ + ${terminal_type:+-T $terminal_type} \ + ${check_origin:+-O} \ + ${max_clients:+-m $max_clients} \ + ${once:+-o} \ + ${index:+-I $index} \ + ${ipv6:+-6} \ + ${ssl:+-S} \ + ${ssl_cert:+-C $ssl_cert} \ + ${ssl_key:+-K $ssl_key} \ + ${ssl_ca:+-A $ssl_ca} \ + ${debug:+-d $debug} + config_list_foreach "$1" client_option "procd_append_param command -t" + procd_append_param command $command + procd_set_param stdout 1 + procd_set_param stderr 1 + procd_close_instance +} + +start_service() { + config_load "$NAME" + config_foreach validate_section_ttyd ttyd ttyd_instance +} + +shutdown() { + # close all open connections + killall "$NAME" +} + +service_triggers() { + procd_add_reload_trigger "$NAME" +} diff --git a/ttyd/patches/100-log-to-syslog.patch b/ttyd/patches/100-log-to-syslog.patch new file mode 100644 index 000000000..838f9d62d --- /dev/null +++ b/ttyd/patches/100-log-to-syslog.patch @@ -0,0 +1,20 @@ +--- a/src/server.c ++++ b/src/server.c +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + + #include "utils.h" + +@@ -520,7 +521,8 @@ int main(int argc, char **argv) { + return -1; + } + +- lws_set_log_level(debug_level, NULL); ++ openlog("ttyd", LOG_NDELAY | LOG_PID, LOG_DAEMON); ++ lws_set_log_level(debug_level, lwsl_emit_syslog); + + char server_hdr[128] = ""; + sprintf(server_hdr, "ttyd/%s (libwebsockets/%s)", TTYD_VERSION, LWS_LIBRARY_VERSION);