diff --git a/main.go b/main.go index 1fc600f..81af77c 100644 --- a/main.go +++ b/main.go @@ -545,6 +545,10 @@ type ifaceCounters struct { TxBytes uint64 } +func isIgnoredInterface(iface string) bool { + return iface == "" || iface == "lo" +} + func getCurrentStats() StatsDTO { statsMu.RLock() defer statsMu.RUnlock() @@ -580,6 +584,9 @@ func NewIfaceTotalsManager() *IfaceTotalsManager { // It is resilient to kernel counter resets (e.g. host reboot): if the kernel counter // goes backwards, it treats the new value as "delta since reset". func (tm *IfaceTotalsManager) ApplyKernel(iface string, kRx, kTx uint64) (totalRx, totalTx uint64) { + if isIgnoredInterface(iface) { + return 0, 0 + } tm.mu.Lock() defer tm.mu.Unlock() @@ -638,6 +645,9 @@ func (tm *IfaceTotalsManager) ResetAllToKernel(netMap map[string]ifaceCounters) tm.m = make(map[string]*IfaceTotals, len(netMap)) out := make([]IfaceTotals, 0, len(netMap)) for iface, ctrs := range netMap { + if isIgnoredInterface(iface) { + continue + } st := &IfaceTotals{ Iface: iface, TotalRxBytes: 0, @@ -657,6 +667,9 @@ func (tm *IfaceTotalsManager) Load(rows []IfaceTotals) { tm.mu.Lock() defer tm.mu.Unlock() for _, r := range rows { + if isIgnoredInterface(r.Iface) { + continue + } cp := r // copy tm.m[r.Iface] = &cp } @@ -667,6 +680,9 @@ func (tm *IfaceTotalsManager) Snapshot() []IfaceTotals { defer tm.mu.Unlock() out := make([]IfaceTotals, 0, len(tm.m)) for _, v := range tm.m { + if v == nil || isIgnoredInterface(v.Iface) { + continue + } out = append(out, *v) } return out @@ -732,6 +748,9 @@ func startStatsCollector() { dt := now.Sub(prevTime).Seconds() if netMap != nil { for name, ctrs := range netMap { + if isIgnoredInterface(name) { + continue + } st := InterfaceStats{ Name: name, } @@ -937,6 +956,9 @@ func readNetDev() (map[string]ifaceCounters, error) { continue } iface := strings.TrimSpace(parts[0]) + if isIgnoredInterface(iface) { + continue + } fields := strings.Fields(parts[1]) if len(fields) < 9 { continue @@ -1205,7 +1227,8 @@ func (s *Store) EnsureIfaceTotalsTable(ctx context.Context) error { func (s *Store) LoadIfaceTotals(ctx context.Context) ([]IfaceTotals, error) { rows, err := s.db.QueryContext(ctx, ` SELECT iface, total_rx_bytes, total_tx_bytes, last_kernel_rx_bytes, last_kernel_tx_bytes, updated_at, reset_at - FROM ssh_iface_totals`) + FROM ssh_iface_totals + WHERE iface <> 'lo'`) if err != nil { return nil, err } @@ -1234,6 +1257,9 @@ func (s *Store) UpsertIfaceTotals(ctx context.Context, rows []IfaceTotals) error } // Simple loop (small N: number of interfaces). Keeps CPU/DB overhead minimal. for _, r := range rows { + if isIgnoredInterface(r.Iface) { + continue + } resetAt := r.ResetAt if resetAt.IsZero() { resetAt = time.Now() diff --git a/update.sh b/update.sh index 5e4eb74..49bb1be 100644 --- a/update.sh +++ b/update.sh @@ -316,7 +316,51 @@ PYEOF fi } +dnstt_redirect_is_enabled() { + # Updates must not resurrect this service when an admin intentionally + # disabled/removed it because it can break ip6tables on some machines. + local unit="sshpanel-dnstt-redirect.service" + + if systemctl is-enabled --quiet "$unit" 2>/dev/null; then + return 0 + fi + + return 1 +} + +write_sshpanel_systemd_override() { + local include_dnstt_redirect="${1:-false}" + + mkdir -p /etc/systemd/system/sshpanel.service.d + { + echo "[Unit]" + if [[ "$include_dnstt_redirect" == "true" ]]; then + echo "Wants=sshpanel-dnstt-redirect.service" + echo "After=local-fs.target sshpanel-dnstt-redirect.service" + else + echo "After=local-fs.target" + fi + echo + echo "[Service]" + echo "Environment=PANEL_LOG_FILE=${INSTALL_DIR}/logs/panel.log" + echo "Environment=PANEL_LOG_MAX_BYTES=${PANEL_LOG_MAX_BYTES}" + echo "ExecStartPre=" + echo "ExecStartPre=/usr/bin/mkdir -p ${INSTALL_DIR}/logs" + echo "ExecStartPre=/bin/sh -c '/usr/bin/mountpoint -q ${INSTALL_DIR}/logs || /usr/bin/mount -t tmpfs -o size=${LOG_TMPFS_SIZE},mode=0755 tmpfs ${INSTALL_DIR}/logs || true'" + echo "ExecStartPre=/bin/sh -c '/usr/bin/touch ${INSTALL_DIR}/logs/panel.log && /usr/bin/chmod 0644 ${INSTALL_DIR}/logs/panel.log || true'" + echo "StandardOutput=append:${INSTALL_DIR}/logs/panel.log" + echo "StandardError=append:${INSTALL_DIR}/logs/panel.log" + } > /etc/systemd/system/sshpanel.service.d/override.conf +} + ensure_dnstt_redirect() { + if ! dnstt_redirect_is_enabled; then + warn " sshpanel-dnstt-redirect is disabled or removed; update will not recreate or enable it." + write_sshpanel_systemd_override false + systemctl daemon-reload + return 0 + fi + info " Ensuring DNSTT DNS redirect service exists..." cat > /usr/local/sbin/sshpanel-dnstt-redirect.sh <<'EOS' #!/bin/bash @@ -374,22 +418,7 @@ RemainAfterExit=yes WantedBy=multi-user.target EOF2 - mkdir -p /etc/systemd/system/sshpanel.service.d - cat > /etc/systemd/system/sshpanel.service.d/override.conf <= CURRENT_DATE - $1::int + AND iface <> 'lo' ORDER BY usage_date DESC, iface ASC`, days-1) if err != nil { return out, err @@ -188,6 +195,7 @@ func (s *Store) LoadIfaceUsage(ctx context.Context, days, months int) (VnstatDTO SELECT iface, to_char(month_start, 'YYYY-MM') AS period, rx_bytes, tx_bytes FROM ssh_iface_monthly_usage WHERE month_start >= (date_trunc('month', CURRENT_DATE)::date - ($1::int * INTERVAL '1 month')) + AND iface <> 'lo' ORDER BY month_start DESC, iface ASC`, months-1) if err != nil { return out, err @@ -230,6 +238,9 @@ func (s *Store) ReplaceIfaceTotals(ctx context.Context, rows []IfaceTotals) erro return err } for _, r := range rows { + if isIgnoredInterface(r.Iface) { + continue + } resetAt := r.ResetAt if resetAt.IsZero() { resetAt = time.Now()