diff --git a/dsvpn/Makefile b/dsvpn/Makefile index d6ebcf9c..3c4da476 100644 --- a/dsvpn/Makefile +++ b/dsvpn/Makefile @@ -14,7 +14,7 @@ PKG_SOURCE_URL:=https://github.com/Ysurac/dsvpn.git PKG_SOURCE_VERSION:=aae011339bba733d3fa4ffe8b5dd95dab2efb4ab PKG_NAME:=dsvpn PKG_VERSION:=0.1.5 -PKG_RELEASE:=1 +PKG_RELEASE:=2 PKG_LICENSE:=MIT PKG_LICENSE_FILES:=LICENSE diff --git a/dsvpn/files/init b/dsvpn/files/init index fe860314..b077fd3c 100755 --- a/dsvpn/files/init +++ b/dsvpn/files/init @@ -41,6 +41,8 @@ version_over_5_4() { start_instance() { local enable key host port dev + local key_dir="/var/run/${PROG_NAME}" + local key_file="${key_dir}/${1}.key" validate_section "${1}" || { _err "validation failed" @@ -55,7 +57,12 @@ start_instance() { [ -z "${port}" ] && port="auto" [ -n "${dev}" ] || return 1 - echo "${key}" > /tmp/${PROG_NAME}-${1}.key + mkdir -p "$key_dir" + chmod 0700 "$key_dir" + ( umask 077; printf '%s\n' "$key" > "$key_file" ) || { + _err "can't create key file" + return 1 + } key="" if [ "$(uci -q get network.omrvpn)" != "" ] && [ "$(uci -q get network.omrvpn)" != "$dev" ]; then @@ -75,7 +82,7 @@ start_instance() { procd_open_instance procd_set_param command ${PROG} ${mode} \ - /tmp/${PROG_NAME}-${1}.key \ + "$key_file" \ $host \ $port \ $dev \ @@ -87,7 +94,7 @@ start_instance() { procd_set_param respawn 0 30 5 procd_set_param nice 10 - procd_set_param file /tmp/${PROG_NAME}-${1}.key + procd_set_param file "$key_file" procd_set_param stdout 1 procd_set_param stderr 1 diff --git a/glorytun-udp/Makefile b/glorytun-udp/Makefile index a5e590fa..aa8e7421 100644 --- a/glorytun-udp/Makefile +++ b/glorytun-udp/Makefile @@ -13,7 +13,7 @@ PKG_SOURCE_URL:=https://github.com/ysurac/glorytun.git PKG_SOURCE_VERSION:=203c5f2223d7d5146d659b51159b2f02c2480d15 PKG_NAME:=glorytun-udp PKG_VERSION:=0.3.4 -PKG_RELEASE:=1 +PKG_RELEASE:=2 PKG_LICENSE:=BSD-2-Clause PKG_LICENSE_FILES:=LICENSE diff --git a/glorytun-udp/init b/glorytun-udp/init index 066b1933..fe1055af 100755 --- a/glorytun-udp/init +++ b/glorytun-udp/init @@ -32,6 +32,8 @@ validate_section() { start_instance() { local enable key host port listener proto mtuauto chacha dev mode + local key_dir="/var/run/${PROG_NAME}" + local key_file="${key_dir}/${1}.key" validate_section "${1}" || { _err "validation failed" @@ -46,7 +48,12 @@ start_instance() { [ -n "${dev}" ] || return 1 [ -n "${mode}" ] || return 1 - echo "${key}" > /tmp/${PROG_NAME}-${1}.key + mkdir -p "$key_dir" + chmod 0700 "$key_dir" + ( umask 077; printf '%s\n' "$key" > "$key_file" ) || { + _err "can't create key file" + return 1 + } key="" if [ "$(uci -q get network.omrvpn)" != "" ]; then @@ -68,14 +75,14 @@ start_instance() { procd_set_param command ${PROG} \ ${bind} \ ${dev:+dev "$dev"} \ - keyfile /tmp/${PROG_NAME}-${1}.key \ + keyfile "$key_file" \ persist [ "${chacha}" = "1" ] && procd_append_param command chacha procd_set_param respawn 0 30 0 procd_set_param nice 10 - procd_set_param file /tmp/${PROG_NAME}-${1}.key + procd_set_param file "$key_file" procd_set_param stdout 1 procd_set_param stderr 1 diff --git a/glorytun/Makefile b/glorytun/Makefile index 8e699f69..874e421d 100755 --- a/glorytun/Makefile +++ b/glorytun/Makefile @@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=glorytun -PKG_RELEASE:=2 +PKG_RELEASE:=3 PKG_SOURCE_PROTO:=git PKG_SOURCE_VERSION:=95fa5ead2154adb546bcdb454c56c876e9f60bb5 PKG_SOURCE:=glorytun-$(PKG_VERSION).tar.gz diff --git a/glorytun/init b/glorytun/init index 56274c14..baf190e2 100755 --- a/glorytun/init +++ b/glorytun/init @@ -82,6 +82,8 @@ optimize_cpu_cores() { start_instance() { local enable key host port dev mptcp proto chacha20 mode multiqueue cpu_affinity timeout localip remoteip + local key_dir="/var/run/${PROG_NAME}" + local key_file="${key_dir}/${1}.key" validate_section "${1}" || { _err "validation failed" @@ -102,8 +104,10 @@ start_instance() { [ -n "${dev}" ] || return 1 [ -n "${host}" ] || return 1 - echo "${key}" > /tmp/${PROG_NAME}-${1}.key - [ -f "/tmp/${PROG_NAME}-${1}.key" ] || { + mkdir -p "$key_dir" + chmod 0700 "$key_dir" + ( umask 077; printf '%s\n' "$key" > "$key_file" ) + [ -f "$key_file" ] || { _err "can't create key file" return 1 } @@ -119,7 +123,7 @@ start_instance() { procd_open_instance procd_set_param command ${PROG} \ - keyfile /tmp/${PROG_NAME}-${1}.key \ + keyfile "$key_file" \ ${port:+port "$port"} \ ${host:+host "$host"} \ ${dev:+dev "$dev"} @@ -137,7 +141,7 @@ start_instance() { procd_set_param respawn 0 30 0 procd_set_param nice 10 - procd_set_param file /tmp/${PROG_NAME}-${1}.key + procd_set_param file "$key_file" procd_set_param stdout 1 procd_set_param stderr 1 diff --git a/luci-app-iperf/luasrc/controller/iperf.lua b/luci-app-iperf/luasrc/controller/iperf.lua index 68e270ea..41b962e4 100644 --- a/luci-app-iperf/luasrc/controller/iperf.lua +++ b/luci-app-iperf/luasrc/controller/iperf.lua @@ -13,34 +13,58 @@ end function run_test(server,proto,mode,updown,omit,parallel,transmit,bitrate) luci.http.prepare_content("text/plain") local iperf + server = tostring(server or "") + if not server:match("^[%w_%-]+$") then + luci.http.write_json({ error = "Invalid server" }) + return + end local addr = uci:get("iperf",server,"host") local ports = uci:get("iperf",server,"ports") local user = uci:get("iperf",server,"user") or "" local password = uci:get("iperf",server,"password") or "" local key = uci:get("iperf",server,"key") or "" - local options = "" + if not addr or not ports then + luci.http.write_json({ error = "Invalid server" }) + return + end + parallel = tostring(parallel or "1"):match("^%d+$") or "1" + omit = tostring(omit or "0"):match("^%d+$") or "0" + transmit = tostring(transmit or "10"):match("^%d+$") or "10" + bitrate = tostring(bitrate or "1M") + if not bitrate:match("^[0-9]+[KMG]?$") then + bitrate = "1M" + end + local options = {} if user ~= "" and password ~= "" and key ~= "" then - luci.sys.call("echo " .. key .. " | base64 -d > /tmp/iperf.pem") - options = options .. " --username " .. user .. " --rsa-public-key-path /tmp/iperf.pem" + luci.sys.call("printf %s " .. ut.shellquote(key) .. " | base64 -d > /tmp/iperf.pem") + options[#options + 1] = "--username " .. ut.shellquote(user) + options[#options + 1] = "--rsa-public-key-path /tmp/iperf.pem" end if mode == "udp" then - options = options .. " -u -b " .. bitrate + options[#options + 1] = "-u -b " .. ut.shellquote(bitrate) end - if direction == "receive" then - options = options .. " -R" + if updown == "download" or updown == "receive" then + options[#options + 1] = "-R" end local ipv = "4" if proto == "ipv6" then - local ipv = "6" + ipv = "6" end local t={} for pt in ports:gmatch("([^,%s]+)") do - table.insert(t,pt) + if pt:match("^%d+$") then + table.insert(t,pt) + end + end + if #t == 0 then + luci.http.write_json({ error = "Invalid server port" }) + return end local port = t[ math.random( #t ) ] + options = table.concat(options, " ") if password ~= "" then - iperf = io.popen("omr-iperf %s -P %s -%s -O %s -t %s -J -Z %s" % {server,parallel,ipv,omit,transmit,options}) + iperf = io.popen("omr-iperf %s -P %s -%s -O %s -t %s -J -Z %s" % {ut.shellquote(server),parallel,ipv,omit,transmit,options}) else iperf = io.popen("iperf3 -c %s -P %s -%s -p %s -O %s -t %s -J -Z %s" % {ut.shellquote(addr),parallel,ipv,port,omit,transmit,options}) end @@ -53,4 +77,4 @@ function run_test(server,proto,mode,updown,omit,parallel,transmit,bitrate) end end return -end \ No newline at end of file +end diff --git a/luci-app-packet-capture/po/ru/packet-capture.po b/luci-app-packet-capture/po/ru/packet-capture.po new file mode 100644 index 00000000..12a3d00f --- /dev/null +++ b/luci-app-packet-capture/po/ru/packet-capture.po @@ -0,0 +1,97 @@ +msgid "" +msgstr "" +"PO-Revision-Date: 2024-01-01 00:00+0000\n" +"Last-Translator: \n" +"Language-Team: Russian\n" +"Language: ru\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" + +#: luci-app-packet-capture/htdocs/luci-static/resources/view/packet_capture/tcpdump.js:177 +msgid "Capture packets with tcpdump." +msgstr "Захват пакетов с помощью tcpdump." + +#: luci-app-packet-capture/htdocs/luci-static/resources/view/packet_capture/tcpdump.js:247 +msgid "Close" +msgstr "Закрыть" + +#: luci-app-packet-capture/htdocs/luci-static/resources/view/packet_capture/tcpdump.js:201 +msgid "Convert host addresses to names." +msgstr "Преобразовывать адреса хостов в имена." + +#: luci-app-packet-capture/htdocs/luci-static/resources/view/packet_capture/tcpdump.js:277 +msgid "Download" +msgstr "Скачать" + +#: luci-app-packet-capture/htdocs/luci-static/resources/view/packet_capture/tcpdump.js:275 +msgid "Download capture file" +msgstr "Скачать файл захвата" + +#: luci-app-packet-capture/htdocs/luci-static/resources/view/packet_capture/tcpdump.js:193 +msgid "Duration" +msgstr "Длительность" + +#: luci-app-packet-capture/htdocs/luci-static/resources/view/packet_capture/tcpdump.js:193 +msgid "Duration of packet capturing in seconds." +msgstr "Длительность захвата пакетов в секундах." + +#: luci-app-packet-capture/htdocs/luci-static/resources/view/packet_capture/tcpdump.js:189 +msgid "Filter" +msgstr "Фильтр" + +#: luci-app-packet-capture/root/usr/share/rpcd/acl.d/luci-app-packet-capture.json:3 +msgid "Grant access to tcpdump ubus object" +msgstr "Предоставить доступ к объекту ubus tcpdump" + +#: luci-app-packet-capture/htdocs/luci-static/resources/view/packet_capture/tcpdump.js:181 +msgid "Interface" +msgstr "Интерфейс" + +#: luci-app-packet-capture/htdocs/luci-static/resources/view/packet_capture/tcpdump.js:197 +msgid "Number of packets to be captured." +msgstr "Количество пакетов для захвата." + +#: luci-app-packet-capture/root/usr/share/luci/menu.d/luci-app-packet-capture.json:3 +msgid "Packet Capture" +msgstr "Захват пакетов" + +#: luci-app-packet-capture/htdocs/luci-static/resources/view/packet_capture/tcpdump.js:177 +msgid "Packet Capture - Tcpdump" +msgstr "Захват пакетов — Tcpdump" + +#: luci-app-packet-capture/htdocs/luci-static/resources/view/packet_capture/tcpdump.js:197 +msgid "Packets" +msgstr "Пакеты" + +#: luci-app-packet-capture/htdocs/luci-static/resources/view/packet_capture/tcpdump.js:203 +msgid "Print the link-level header on each dump line." +msgstr "Печатать заголовок канального уровня в каждой строке дампа." + +#: luci-app-packet-capture/htdocs/luci-static/resources/view/packet_capture/tcpdump.js:201 +msgid "Resolve domains" +msgstr "Разрешать домены" + +#: luci-app-packet-capture/htdocs/luci-static/resources/view/packet_capture/tcpdump.js:205 +msgid "Save capture to pcap file." +msgstr "Сохранить захват в файл pcap." + +#: luci-app-packet-capture/htdocs/luci-static/resources/view/packet_capture/tcpdump.js:205 +msgid "Save to file" +msgstr "Сохранить в файл" + +#: luci-app-packet-capture/htdocs/luci-static/resources/view/packet_capture/tcpdump.js:207 +msgid "Start tcpdump" +msgstr "Запустить tcpdump" + +#: luci-app-packet-capture/htdocs/luci-static/resources/view/packet_capture/tcpdump.js:263 +msgid "Stop tcpdump" +msgstr "Остановить tcpdump" + +#: luci-app-packet-capture/htdocs/luci-static/resources/view/packet_capture/tcpdump.js:189 +msgid "Tcpdump filter like protocol, port etc." +msgstr "Фильтр tcpdump: протокол, порт и т.д." + +#: luci-app-packet-capture/htdocs/luci-static/resources/view/packet_capture/tcpdump.js:203 +msgid "Verbose output" +msgstr "Подробный вывод" diff --git a/luci-app-packet-capture/root/usr/libexec/packet_capture b/luci-app-packet-capture/root/usr/libexec/packet_capture index e1ecf23f..42e4a390 100755 --- a/luci-app-packet-capture/root/usr/libexec/packet_capture +++ b/luci-app-packet-capture/root/usr/libexec/packet_capture @@ -11,17 +11,68 @@ end local args = "-n" local duration = "" +local workdir = "/var/run/packet_capture" +local filterfile = workdir .. "/tcpdump_filter" +local pcapbase = workdir .. "/capture.pcap" +local outputfile = "/tmp/capture.pcap" + +local function validate_args(value) + if type(value) ~= "string" or value == "" then + return false + end + local tokens = {} + for token in value:gmatch("%S+") do + tokens[#tokens + 1] = token + end + local i = 1 + while i <= #tokens do + local token = tokens[i] + if token == "-n" or token == "-e" then + i = i + 1 + elseif token == "-i" then + if not tokens[i + 1] or not tokens[i + 1]:match("^[%w_.:-]+$") then return false end + i = i + 2 + elseif token == "-c" then + if not tokens[i + 1] or not tokens[i + 1]:match("^%d+$") then return false end + i = i + 2 + elseif token == "-W" then + if tokens[i + 1] ~= "2" then return false end + i = i + 2 + elseif token == "-C" then + if not tokens[i + 1] or not tokens[i + 1]:match("^%d+$") then return false end + i = i + 2 + elseif token == "-w" then + if tokens[i + 1] ~= pcapbase then return false end + i = i + 2 + elseif token == "-z" then + if tokens[i + 1] ~= "/usr/libexec/packet_capture_stop" then return false end + i = i + 2 + elseif token == "-F" then + if tokens[i + 1] ~= filterfile then return false end + i = i + 2 + else + return false + end + end + return true +end if arg[1] ~= nil then args = arg[1] - if arg[2] ~= "" then + if not validate_args(args) then + error("Invalid tcpdump arguments") + end + if arg[2] ~= nil and arg[2] ~= "" then duration = arg[2] + if not duration:match("^%d+$") then + error("Invalid duration") + end end end -local filter = fs.stat("/tmp/tcpdump_filter") +local filter = fs.stat(filterfile) if filter then - args = args .. " -F /tmp/tcpdump_filter" + args = args .. " -F " .. filterfile end local ubus_objects = { @@ -48,14 +99,14 @@ for line in pipe:lines() do conn:notify(ubus_objects.tcpdump.__ubusobj, "tcpdump.data", params) end -local pcap = fs.stat("/tmp/capture.pcap0") +local pcap = fs.stat(pcapbase .. "0") if pcap then - fs.move("/tmp/capture.pcap0","/tmp/capture.pcap") - fs.remove("/tmp/capture.pcap1") + fs.move(pcapbase .. "0", outputfile) + fs.remove(pcapbase .. "1") end if filter then - fs.remove("/tmp/tcpdump_filter") + fs.remove(filterfile) end conn:close() diff --git a/luci-app-packet-capture/root/usr/libexec/packet_capture_start b/luci-app-packet-capture/root/usr/libexec/packet_capture_start index acdf8915..8694532a 100755 --- a/luci-app-packet-capture/root/usr/libexec/packet_capture_start +++ b/luci-app-packet-capture/root/usr/libexec/packet_capture_start @@ -3,12 +3,18 @@ . /usr/share/libubox/jshn.sh PIDFILE="/var/run/packet_capture.pid" +WORKDIR="/var/run/packet_capture" +FILTERFILE="$WORKDIR/tcpdump_filter" +PCAPFILE="$WORKDIR/capture.pcap" -if [ -f "$PIDFILE"];then +if [ -f "$PIDFILE" ]; then echo "error: Packet capture is running" exit 1 fi +mkdir -p "$WORKDIR" +chmod 0700 "$WORKDIR" + json_load "$1" json_get_var interface interface json_get_var filter filter @@ -20,13 +26,19 @@ json_get_var file file args="-n" -if [ "$domains" == "1" ];then +if [ "$domains" = "1" ];then args="" fi if [ -n "$interface" ];then + case "$interface" in + *[!A-Za-z0-9_.:-]*) + echo "error: Incorrect format of an interface" + exit 1 + ;; + esac ip a show "$interface" > /dev/null 2>&1 - if [ "$?" == "1" ]; then + if [ "$?" -ne 0 ]; then echo "error: Incorrect format of an interface" exit 1 fi @@ -35,7 +47,7 @@ if [ -n "$interface" ];then fi if [ -n "$packets" ];then - echo "$packets" | egrep '^[0-9]*$' + echo "$packets" | egrep '^[0-9]+$' >/dev/null if [ "$?" -eq 0 ];then args="$args -c $packets" else @@ -44,13 +56,21 @@ if [ -n "$packets" ];then fi fi -if [ "$verbose" == "1" ];then +if [ -n "$duration" ];then + echo "$duration" | egrep '^[0-9]+$' >/dev/null + if [ "$?" -ne 0 ];then + echo "error: Incorrect duration argument" + exit 1 + fi +fi + +if [ "$verbose" = "1" ];then args="$args -e" fi -if [ "$file" == "1" ];then +if [ "$file" = "1" ];then mem=$(awk '/MemTotal/ {print $2}' /proc/meminfo) - args="$args -W 2 -C $((mem/(1024 * 10))) -w /tmp/capture.pcap -z /usr/libexec/packet_capture_stop" + args="$args -W 2 -C $((mem/(1024 * 10))) -w $PCAPFILE -z /usr/libexec/packet_capture_stop" fi if [ -n "$filter" ];then @@ -59,7 +79,7 @@ if [ -n "$filter" ];then echo "error: Incorrect filter argument" exit 1 fi - echo "$filter" > /tmp/tcpdump_filter + ( umask 077; printf '%s\n' "$filter" > "$FILTERFILE" ) fi (/usr/libexec/packet_capture "$args" "$duration")& diff --git a/luci-theme-aurora/.dev/src/media/patches/admin-modem-qmodem.css b/luci-theme-aurora/.dev/src/media/patches/admin-modem-qmodem.css new file mode 100644 index 00000000..4c91f732 --- /dev/null +++ b/luci-theme-aurora/.dev/src/media/patches/admin-modem-qmodem.css @@ -0,0 +1,147 @@ +/* + PATCH: admin-modem-qmodem (luci-app-qmodem) + Unified per-application patch — loaded on all admin/modem/qmodem/* pages. + Prefix-matched by header.ut: admin-modem-qmodem(-overview|-sms|…). +*/ +@reference "../main.css"; + +[data-page^="admin-modem-qmodem"] { + .copyright-section { + @apply text-text-muted! text-center! bg-surface-sunken border-hairline border-1; + } + + fieldset.cbi-section > legend { + @apply border-hairline text-text float-left mb-4 w-full border-b px-0 pb-3 leading-tight; + } + + fieldset.cbi-section { + @apply flow-root; + } + + fieldset.cbi-section > :not(legend) { + @apply clear-both; + } + + .cbi-section-table-titles.named { + @apply before:bg-surface-sunken before:rounded-tl-2xl before:border-b! before:border-hairline!; + + + } +} + +[data-page^="admin-modem-qmodem-sms-conversation"] { + #sms-messages-area { + @apply border-hairline! border-1 bg-surface-sunken! text-text!; + } + + .sms-message-bubble { + @apply border-hairline! border-1 bg-surface-overlay! text-text!; + } + + .sms-message-content { + @apply text-text!; + } + + .sms-message-meta { + @apply text-text-muted!; + } +} + +[data-page="admin-modem-qmodem-config_advanced"] { + /* NOTE: targets
  • directly (not li > a) because qmodem's tab markup + has no inside tabs — so this won't auto-update with the shared + _segmented.css conventions. */ + .cbi-tabmenu { + & li { + @apply text-text-muted hover:text-text hover:bg-hover-faint cursor-pointer rounded-4xl px-4 py-2 text-center text-sm font-medium whitespace-nowrap transition-colors duration-150; + + &.cbi-tab { + @apply bg-text text-surface font-semibold shadow-sm; + } + } + } +} + +[data-page="admin-modem-qmodem-sms"] { + .td > div { + @apply text-text-muted! mt-1.5! text-xs! leading-relaxed!; + } + + .td > span[style*="margin-left"] { + @apply text-text ml-2!; + } + + .sms-conversations { + @apply mt-5 mb-0; + + & > .cbi-section { + @apply m-0! border-0! bg-transparent! p-0! shadow-none!; + } + + & fieldset.cbi-section { + @apply mb-0; + } + + & .table.cbi-section-table { + @apply mb-0 overflow-hidden; + } + } + + .cbi-section-table-row.tr { + @apply text-text transition-colors duration-150; + + & > .td, + & > td { + @apply text-text; + } + + & > .td:nth-child(2), + & > td:nth-child(2) { + @apply text-text-muted; + } + + &:hover { + @apply bg-hover-faint! text-text!; + + & > .td, + & > td { + @apply text-text! bg-transparent!; + } + } + } + + .sms-unread-conversation { + @apply bg-brand-subtle! font-semibold; + } + + .sms-unread-badge { + @apply bg-danger! text-on-brand! ml-2! rounded-full! px-2! py-0.5! text-xs! font-semibold!; + } +} + +[data-page="admin-modem-qmodem-sms_sim"] { + .cbi-section-table-row.tr { + @apply text-text transition-colors duration-150; + + & > .td, + & > td { + @apply text-text; + } + + &:hover { + @apply bg-hover-faint!; + + & > .td, + & > td { + @apply text-text! bg-transparent!; + } + } + } +} + +[data-page="admin-modem-qmodem-settings"] { + + .cbi-section-table-descr.named { + @apply before:bg-surface-sunken before:content-['']!; + } +} diff --git a/luci-theme-aurora/Makefile b/luci-theme-aurora/Makefile index f0cdd910..c064b238 100644 --- a/luci-theme-aurora/Makefile +++ b/luci-theme-aurora/Makefile @@ -9,7 +9,7 @@ LUCI_TITLE:=Aurora Theme (A modern browser theme built with Vite and Tailwind CS LUCI_DEPENDS:=+luci-base PKG_VERSION:=1.1.2 -PKG_RELEASE:=53 +PKG_RELEASE:=54 PKG_LICENSE:=Apache-2.0 LUCI_MINIFY_CSS:=