🌴 Sync 2026-09-19 18:46:44

This commit is contained in:
github-actions[bot] committed 2026-09-19 18:46:44 +08:00
1 parent 375023b135
commit 9e354d0c3e
30 files changed
+322 -1252

No files matched your search

+1 -1
View File
@@ -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:= \
@@ -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"), '<a href="https://go.dev/src/crypto/tls/cipher_suites.go#L44" target="_blank">***</a>' .. " " .. 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."))
@@ -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"))
@@ -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"))
@@ -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 })
@@ -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,
@@ -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
+17 -2
View File
@@ -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 配置"
-53
View File
@@ -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 <nbd@nbd.name>
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))
@@ -1,6 +0,0 @@
[ ifup = "$ACTION" ] && {
uci_toggle_state network "$INTERFACE" up 1
[ -n "$DEVICE" ] && {
uci_toggle_state network "$INTERFACE" ifname "$DEVICE"
}
}
-143
View File
@@ -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
}
-25
View File
@@ -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
}
@@ -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
-1
View File
@@ -1 +0,0 @@
# This script is sourced by udhcpc's dhcp.script at every DHCP event.
-120
View File
@@ -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
-79
View File
@@ -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`);
}
-140
View File
@@ -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
-131
View File
@@ -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;
}
};
-76
View File
@@ -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"
}
-12
View File
@@ -1,12 +0,0 @@
#!/bin/sh
. /usr/share/libubox/jshn.sh
DEVICE="$1"
[ -n "$DEVICE" ] || {
echo "Usage: $0 <device>"
exit 1
}
json_init
json_add_string name "$DEVICE"
ubus call network.device status "$(json_dump)"
-1
View File
@@ -1 +0,0 @@
ifup
-13
View File
@@ -1,13 +0,0 @@
#!/bin/sh
INTERFACE="$1"
[ -n "$INTERFACE" ] || {
echo "Usage: $0 <interface>"
exit 1
}
ubus -S list "network.interface.$INTERFACE" >/dev/null || {
echo "Interface $INTERFACE not found"
exit 1
}
ubus call network.interface status "{ \"interface\" : \"$INTERFACE\" }"
-44
View File
@@ -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
@@ -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));
@@ -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
@@ -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])) {
+52
View File
@@ -0,0 +1,52 @@
#
# Copyright (C) 2016 Shuanglei Tao <tsl0922@gmail.com>
#
# 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 <tsl0922@gmail.com>
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))
+4
View File
@@ -0,0 +1,4 @@
config ttyd
option command '/bin/login'
+102
View File
@@ -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"
}
+20
View File
@@ -0,0 +1,20 @@
--- a/src/server.c
+++ b/src/server.c
@@ -10,6 +10,7 @@
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
+#include <syslog.h>
#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);