Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions config/ns-support-tunnel.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
CONFIG_PACKAGE_ns-support-tunnel=y
51 changes: 51 additions & 0 deletions packages/ns-support-tunnel/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#
# Copyright (C) 2026 Nethesis S.r.l.
# SPDX-License-Identifier: GPL-3.0-only
#

include $(TOPDIR)/rules.mk

PKG_NAME:=ns-support-tunnel
PKG_VERSION:=0.0.1
PKG_RELEASE:=1

PKG_BUILD_DIR:=$(BUILD_DIR)/ns-support-tunnel-$(PKG_VERSION)

PKG_MAINTAINER:=Edoardo Spadoni <edoardo.spadoni@nethesis.it>
PKG_LICENSE:=GPL-3.0-only

include $(INCLUDE_DIR)/package.mk

define Package/ns-support-tunnel
SECTION:=base
CATEGORY:=NethSecurity
TITLE:=WebSocket-based remote support tunnel (coexists with don)
URL:=https://github.com/NethServer/nethsecurity/
DEPENDS:=+jq
endef

define Package/ns-support-tunnel/description
WebSocket-based remote support client using tunnel-client.
Coexists with the existing OpenVPN-based don support system.
endef

# No compilation needed - binary is pre-built
define Build/Compile
endef

define Package/ns-support-tunnel/install
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_DIR) $(1)/usr/libexec/rpcd
$(INSTALL_DIR) $(1)/usr/share/rpcd/acl.d
$(INSTALL_DIR) $(1)/etc/uci-defaults
$(INSTALL_DIR) $(1)/usr/share/my/users.d
$(INSTALL_DIR) $(1)/usr/share/my/diagnostics.d
$(INSTALL_BIN) ./files/support-tunnel $(1)/usr/sbin
$(INSTALL_BIN) ./files/tunnel-client $(1)/usr/sbin
$(INSTALL_BIN) ./files/ns.support-tunnel $(1)/usr/libexec/rpcd
$(INSTALL_DATA) ./files/ns.support-tunnel.json $(1)/usr/share/rpcd/acl.d
$(INSTALL_BIN) ./files/health $(1)/usr/share/my/diagnostics.d
$(INSTALL_CONF) ./files/20_ns_support_tunnel $(1)/etc/uci-defaults
endef

$(eval $(call BuildPackage,ns-support-tunnel))
10 changes: 10 additions & 0 deletions packages/ns-support-tunnel/files/20_ns_support_tunnel
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[ "$(uci -q get support-tunnel.config.url)" = "" ] || exit 0

uci -q import support-tunnel << EOI
config main 'config'
option url 'wss://support.nethesis.it/api/tunnel'
option system_key ''
option system_secret ''
option exclude_patterns ''
option tls_insecure '0'
EOI
152 changes: 152 additions & 0 deletions packages/ns-support-tunnel/files/health
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
#!/bin/sh

#
# Copyright (C) 2026 Nethesis S.r.l.
# SPDX-License-Identifier: GPL-3.0-only
#

#
# diagnostics.d plugin for NethSecurity health
#
# Checks core services, WAN connectivity, firewall, disk/overlay usage,
# and DNS resolution. Outputs JSON PluginResult.
#
# Exit codes: 0=ok, 1=warning, 2=critical
#

# Use /usr/bin/jsonfilter if jq is not available
JQ=$(command -v jq 2>/dev/null || echo "")

overall="ok"

worst() {
local a="$1" b="$2"
case "$a" in
critical) echo "critical" ;;
warning) [ "$b" = "critical" ] && echo "critical" || echo "warning" ;;
ok) echo "$b" ;;
*) echo "$b" ;;
esac
}

checks="["
first=true

add_check() {
local name="$1" status="$2" value="$3" details="$4"
[ "$first" = true ] && first=false || checks="$checks,"
if [ -n "$details" ]; then
checks="$checks{\"name\":\"$name\",\"status\":\"$status\",\"value\":\"$value\",\"details\":$details}"
else
checks="$checks{\"name\":\"$name\",\"status\":\"$status\",\"value\":\"$value\"}"
fi
overall=$(worst "$overall" "$status")
}

# 1. Core services
services="firewall dnsmasq dropbear"
svc_details="["
svc_first=true
svc_ok=0
svc_total=0
for svc in $services; do
svc_total=$((svc_total + 1))
if /etc/init.d/$svc enabled 2>/dev/null; then
state=$(/etc/init.d/$svc running 2>/dev/null && echo "running" || echo "stopped")
else
state="disabled"
fi
s="ok"
[ "$state" != "running" ] && s="critical"
[ "$state" = "disabled" ] && s="ok" # disabled is fine
[ "$state" = "running" ] && svc_ok=$((svc_ok + 1))
[ "$svc_first" = true ] && svc_first=false || svc_details="$svc_details,"
svc_details="$svc_details{\"name\":\"$svc\",\"state\":\"$state\"}"
done
svc_details="$svc_details]"
svc_status="ok"
[ "$svc_ok" -lt "$svc_total" ] && svc_status="warning"
add_check "core_services" "$svc_status" "$svc_ok/$svc_total running" "$svc_details"

# 2. WAN connectivity
wan_if=$(uci -q get network.wan.device || uci -q get network.wan.ifname)
wan_proto=$(uci -q get network.wan.proto)
wan_ip=""
if [ -n "$wan_if" ]; then
wan_ip=$(ip -4 addr show dev "$wan_if" 2>/dev/null | grep -oP 'inet \K[0-9.]+' | head -1)
fi

if [ -n "$wan_ip" ]; then
wan_status="ok"
wan_value="$wan_ip"
else
wan_status="warning"
wan_value="no IP"
fi
add_check "wan" "$wan_status" "$wan_value" "{\"interface\":\"$wan_if\",\"proto\":\"$wan_proto\",\"ip\":\"$wan_ip\"}"

# 3. DNS resolution
dns_result=$(nslookup nethesis.it 127.0.0.1 2>&1 | grep -c "Address.*[0-9]")
if [ "$dns_result" -gt 1 ]; then
add_check "dns" "ok" "resolving"
else
add_check "dns" "warning" "failing"
overall=$(worst "$overall" "warning")
fi

# 4. Overlay disk usage
overlay_used=$(df /overlay 2>/dev/null | awk 'NR==2{print $5}' | tr -d '%')
if [ -n "$overlay_used" ]; then
overlay_total=$(df /overlay 2>/dev/null | awk 'NR==2{print $2}')
overlay_avail=$(df /overlay 2>/dev/null | awk 'NR==2{print $4}')
if [ "$overlay_used" -gt 95 ]; then
disk_status="critical"
elif [ "$overlay_used" -gt 85 ]; then
disk_status="warning"
else
disk_status="ok"
fi
add_check "overlay_usage" "$disk_status" "${overlay_used}%" "{\"total_kb\":$overlay_total,\"available_kb\":$overlay_avail,\"used_pct\":$overlay_used}"
fi

# 5. Firewall status
fw_status=$(nft list tables 2>&1 | grep -c "table")
if [ "$fw_status" -gt 0 ]; then
# Count rules
rule_count=$(nft list ruleset 2>/dev/null | grep -c "^ ")
add_check "firewall" "ok" "$fw_status tables" "{\"tables\":$fw_status,\"rules\":$rule_count}"
else
add_check "firewall" "critical" "no tables loaded"
fi

# 6. Connected clients (DHCP leases)
lease_count=0
if [ -f /tmp/dhcp.leases ]; then
lease_count=$(wc -l < /tmp/dhcp.leases)
fi
add_check "dhcp_leases" "ok" "$lease_count"

# 7. Uptime
uptime_sec=$(cat /proc/uptime | awk '{printf "%d", $1}')
days=$((uptime_sec / 86400))
hours=$(( (uptime_sec % 86400) / 3600 ))
mins=$(( (uptime_sec % 3600) / 60 ))
add_check "uptime" "ok" "${days}d ${hours}h ${mins}m" "{\"days\":$days,\"hours\":$hours,\"minutes\":$mins,\"total_seconds\":$uptime_sec}"

checks="$checks]"

# Build summary
ok_count=$(echo "$checks" | grep -o '"status":"ok"' | wc -l)
warn_count=$(echo "$checks" | grep -o '"status":"warning"' | wc -l)
crit_count=$(echo "$checks" | grep -o '"status":"critical"' | wc -l)

cat << EOF
{"id":"health","name":"NethSecurity Health","status":"$overall","summary":"$ok_count ok, $warn_count warning, $crit_count critical","checks":$checks}
EOF

# Exit code
case "$overall" in
critical) exit 2 ;;
warning) exit 1 ;;
*) exit 0 ;;
esac
49 changes: 49 additions & 0 deletions packages/ns-support-tunnel/files/ns.support-tunnel
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#!/usr/bin/python3

#
# Copyright (C) 2026 Nethesis S.r.l.
# SPDX-License-Identifier: GPL-3.0-only
#

# Manage support-tunnel helpdesk session

import sys
import json
import subprocess
from nethsec import utils

def start():
try:
p = subprocess.run(["/usr/sbin/support-tunnel", "start", "-j"], check=True, capture_output=True, text=True)
return json.loads(p.stdout)
except:
return utils.generic_error("support_tunnel_start_failed")

def status():
try:
p = subprocess.run(["/usr/sbin/support-tunnel", "status", "-j"], check=True, capture_output=True, text=True)
return json.loads(p.stdout)
except:
return {"active": False}

def stop():
try:
p = subprocess.run(["/usr/sbin/support-tunnel", "stop", "-j"], check=True, capture_output=True, text=True)
return json.loads(p.stdout)
except:
return utils.generic_error("support_tunnel_stop_failed")

cmd = sys.argv[1]

if cmd == 'list':
print(json.dumps({"start": {}, "stop": {}, "status":{}}))
else:
action = sys.argv[2]
if action == "start":
ret = start()
elif action == "status":
ret = status()
elif action == "stop":
ret = stop()

print(json.dumps(ret))
13 changes: 13 additions & 0 deletions packages/ns-support-tunnel/files/ns.support-tunnel.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"support-tunnel-manager": {
"description": "support-tunnel session manager",
"write": {},
"read": {
"ubus": {
"ns.support-tunnel": [
"*"
]
}
}
}
}
Loading
Loading