Ignore LO , dont re-enable the iptables redirect if disabled
This commit is contained in:
28
main.go
28
main.go
@@ -545,6 +545,10 @@ type ifaceCounters struct {
|
|||||||
TxBytes uint64
|
TxBytes uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isIgnoredInterface(iface string) bool {
|
||||||
|
return iface == "" || iface == "lo"
|
||||||
|
}
|
||||||
|
|
||||||
func getCurrentStats() StatsDTO {
|
func getCurrentStats() StatsDTO {
|
||||||
statsMu.RLock()
|
statsMu.RLock()
|
||||||
defer statsMu.RUnlock()
|
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
|
// 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".
|
// goes backwards, it treats the new value as "delta since reset".
|
||||||
func (tm *IfaceTotalsManager) ApplyKernel(iface string, kRx, kTx uint64) (totalRx, totalTx uint64) {
|
func (tm *IfaceTotalsManager) ApplyKernel(iface string, kRx, kTx uint64) (totalRx, totalTx uint64) {
|
||||||
|
if isIgnoredInterface(iface) {
|
||||||
|
return 0, 0
|
||||||
|
}
|
||||||
tm.mu.Lock()
|
tm.mu.Lock()
|
||||||
defer tm.mu.Unlock()
|
defer tm.mu.Unlock()
|
||||||
|
|
||||||
@@ -638,6 +645,9 @@ func (tm *IfaceTotalsManager) ResetAllToKernel(netMap map[string]ifaceCounters)
|
|||||||
tm.m = make(map[string]*IfaceTotals, len(netMap))
|
tm.m = make(map[string]*IfaceTotals, len(netMap))
|
||||||
out := make([]IfaceTotals, 0, len(netMap))
|
out := make([]IfaceTotals, 0, len(netMap))
|
||||||
for iface, ctrs := range netMap {
|
for iface, ctrs := range netMap {
|
||||||
|
if isIgnoredInterface(iface) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
st := &IfaceTotals{
|
st := &IfaceTotals{
|
||||||
Iface: iface,
|
Iface: iface,
|
||||||
TotalRxBytes: 0,
|
TotalRxBytes: 0,
|
||||||
@@ -657,6 +667,9 @@ func (tm *IfaceTotalsManager) Load(rows []IfaceTotals) {
|
|||||||
tm.mu.Lock()
|
tm.mu.Lock()
|
||||||
defer tm.mu.Unlock()
|
defer tm.mu.Unlock()
|
||||||
for _, r := range rows {
|
for _, r := range rows {
|
||||||
|
if isIgnoredInterface(r.Iface) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
cp := r // copy
|
cp := r // copy
|
||||||
tm.m[r.Iface] = &cp
|
tm.m[r.Iface] = &cp
|
||||||
}
|
}
|
||||||
@@ -667,6 +680,9 @@ func (tm *IfaceTotalsManager) Snapshot() []IfaceTotals {
|
|||||||
defer tm.mu.Unlock()
|
defer tm.mu.Unlock()
|
||||||
out := make([]IfaceTotals, 0, len(tm.m))
|
out := make([]IfaceTotals, 0, len(tm.m))
|
||||||
for _, v := range tm.m {
|
for _, v := range tm.m {
|
||||||
|
if v == nil || isIgnoredInterface(v.Iface) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
out = append(out, *v)
|
out = append(out, *v)
|
||||||
}
|
}
|
||||||
return out
|
return out
|
||||||
@@ -732,6 +748,9 @@ func startStatsCollector() {
|
|||||||
dt := now.Sub(prevTime).Seconds()
|
dt := now.Sub(prevTime).Seconds()
|
||||||
if netMap != nil {
|
if netMap != nil {
|
||||||
for name, ctrs := range netMap {
|
for name, ctrs := range netMap {
|
||||||
|
if isIgnoredInterface(name) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
st := InterfaceStats{
|
st := InterfaceStats{
|
||||||
Name: name,
|
Name: name,
|
||||||
}
|
}
|
||||||
@@ -937,6 +956,9 @@ func readNetDev() (map[string]ifaceCounters, error) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
iface := strings.TrimSpace(parts[0])
|
iface := strings.TrimSpace(parts[0])
|
||||||
|
if isIgnoredInterface(iface) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
fields := strings.Fields(parts[1])
|
fields := strings.Fields(parts[1])
|
||||||
if len(fields) < 9 {
|
if len(fields) < 9 {
|
||||||
continue
|
continue
|
||||||
@@ -1205,7 +1227,8 @@ func (s *Store) EnsureIfaceTotalsTable(ctx context.Context) error {
|
|||||||
func (s *Store) LoadIfaceTotals(ctx context.Context) ([]IfaceTotals, error) {
|
func (s *Store) LoadIfaceTotals(ctx context.Context) ([]IfaceTotals, error) {
|
||||||
rows, err := s.db.QueryContext(ctx, `
|
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
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
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.
|
// Simple loop (small N: number of interfaces). Keeps CPU/DB overhead minimal.
|
||||||
for _, r := range rows {
|
for _, r := range rows {
|
||||||
|
if isIgnoredInterface(r.Iface) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
resetAt := r.ResetAt
|
resetAt := r.ResetAt
|
||||||
if resetAt.IsZero() {
|
if resetAt.IsZero() {
|
||||||
resetAt = time.Now()
|
resetAt = time.Now()
|
||||||
|
|||||||
69
update.sh
69
update.sh
@@ -316,7 +316,51 @@ PYEOF
|
|||||||
fi
|
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() {
|
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..."
|
info " Ensuring DNSTT DNS redirect service exists..."
|
||||||
cat > /usr/local/sbin/sshpanel-dnstt-redirect.sh <<'EOS'
|
cat > /usr/local/sbin/sshpanel-dnstt-redirect.sh <<'EOS'
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
@@ -374,22 +418,7 @@ RemainAfterExit=yes
|
|||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
EOF2
|
EOF2
|
||||||
|
|
||||||
mkdir -p /etc/systemd/system/sshpanel.service.d
|
write_sshpanel_systemd_override true
|
||||||
cat > /etc/systemd/system/sshpanel.service.d/override.conf <<EOF2
|
|
||||||
[Unit]
|
|
||||||
Wants=sshpanel-dnstt-redirect.service
|
|
||||||
After=local-fs.target sshpanel-dnstt-redirect.service
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Environment=PANEL_LOG_FILE=${INSTALL_DIR}/logs/panel.log
|
|
||||||
Environment=PANEL_LOG_MAX_BYTES=${PANEL_LOG_MAX_BYTES}
|
|
||||||
ExecStartPre=
|
|
||||||
ExecStartPre=/usr/bin/mkdir -p ${INSTALL_DIR}/logs
|
|
||||||
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'
|
|
||||||
ExecStartPre=/bin/sh -c '/usr/bin/touch ${INSTALL_DIR}/logs/panel.log && /usr/bin/chmod 0644 ${INSTALL_DIR}/logs/panel.log || true'
|
|
||||||
StandardOutput=append:${INSTALL_DIR}/logs/panel.log
|
|
||||||
StandardError=append:${INSTALL_DIR}/logs/panel.log
|
|
||||||
EOF2
|
|
||||||
|
|
||||||
systemctl daemon-reload
|
systemctl daemon-reload
|
||||||
systemctl enable --now sshpanel-dnstt-redirect.service || warn "DNSTT redirect service failed. Check: journalctl -u sshpanel-dnstt-redirect -e"
|
systemctl enable --now sshpanel-dnstt-redirect.service || warn "DNSTT redirect service failed. Check: journalctl -u sshpanel-dnstt-redirect -e"
|
||||||
@@ -400,6 +429,11 @@ restart_service() {
|
|||||||
ensure_dnstt_redirect
|
ensure_dnstt_redirect
|
||||||
|
|
||||||
if $RESTART_NEEDED; then
|
if $RESTART_NEEDED; then
|
||||||
|
info " Starting $SERVICE_NAME after update..."
|
||||||
|
else
|
||||||
|
warn " $SERVICE_NAME was not running before update; starting it now."
|
||||||
|
fi
|
||||||
|
|
||||||
systemctl start "$SERVICE_NAME"
|
systemctl start "$SERVICE_NAME"
|
||||||
sleep 2
|
sleep 2
|
||||||
if systemctl is-active --quiet "$SERVICE_NAME"; then
|
if systemctl is-active --quiet "$SERVICE_NAME"; then
|
||||||
@@ -413,9 +447,6 @@ restart_service() {
|
|||||||
fi
|
fi
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
else
|
|
||||||
warn " Service was not running. Start it with: systemctl start $SERVICE_NAME"
|
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Pre-flight
|
# Pre-flight
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ var ifaceUsagePending = struct {
|
|||||||
}{m: make(map[string]ifaceCounters)}
|
}{m: make(map[string]ifaceCounters)}
|
||||||
|
|
||||||
func addPendingIfaceUsage(iface string, rxBytes, txBytes uint64) {
|
func addPendingIfaceUsage(iface string, rxBytes, txBytes uint64) {
|
||||||
if iface == "" || (rxBytes == 0 && txBytes == 0) {
|
if isIgnoredInterface(iface) || (rxBytes == 0 && txBytes == 0) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ifaceUsagePending.mu.Lock()
|
ifaceUsagePending.mu.Lock()
|
||||||
@@ -42,6 +42,9 @@ func flushPendingIfaceUsage(at time.Time) []IfaceUsageDelta {
|
|||||||
}
|
}
|
||||||
deltas := make([]IfaceUsageDelta, 0, len(ifaceUsagePending.m))
|
deltas := make([]IfaceUsageDelta, 0, len(ifaceUsagePending.m))
|
||||||
for iface, ctrs := range ifaceUsagePending.m {
|
for iface, ctrs := range ifaceUsagePending.m {
|
||||||
|
if isIgnoredInterface(iface) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
deltas = append(deltas, IfaceUsageDelta{Iface: iface, RxBytes: ctrs.RxBytes, TxBytes: ctrs.TxBytes, At: at})
|
deltas = append(deltas, IfaceUsageDelta{Iface: iface, RxBytes: ctrs.RxBytes, TxBytes: ctrs.TxBytes, At: at})
|
||||||
}
|
}
|
||||||
ifaceUsagePending.m = make(map[string]ifaceCounters)
|
ifaceUsagePending.m = make(map[string]ifaceCounters)
|
||||||
@@ -52,6 +55,9 @@ func restorePendingIfaceUsage(deltas []IfaceUsageDelta) {
|
|||||||
ifaceUsagePending.mu.Lock()
|
ifaceUsagePending.mu.Lock()
|
||||||
defer ifaceUsagePending.mu.Unlock()
|
defer ifaceUsagePending.mu.Unlock()
|
||||||
for _, d := range deltas {
|
for _, d := range deltas {
|
||||||
|
if isIgnoredInterface(d.Iface) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
p := ifaceUsagePending.m[d.Iface]
|
p := ifaceUsagePending.m[d.Iface]
|
||||||
p.RxBytes += d.RxBytes
|
p.RxBytes += d.RxBytes
|
||||||
p.TxBytes += d.TxBytes
|
p.TxBytes += d.TxBytes
|
||||||
@@ -117,7 +123,7 @@ func (s *Store) UpsertIfaceUsageDeltas(ctx context.Context, deltas []IfaceUsageD
|
|||||||
defer tx.Rollback()
|
defer tx.Rollback()
|
||||||
|
|
||||||
for _, d := range deltas {
|
for _, d := range deltas {
|
||||||
if d.Iface == "" || (d.RxBytes == 0 && d.TxBytes == 0) {
|
if isIgnoredInterface(d.Iface) || (d.RxBytes == 0 && d.TxBytes == 0) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
at := d.At
|
at := d.At
|
||||||
@@ -167,6 +173,7 @@ func (s *Store) LoadIfaceUsage(ctx context.Context, days, months int) (VnstatDTO
|
|||||||
SELECT iface, usage_date::text, rx_bytes, tx_bytes
|
SELECT iface, usage_date::text, rx_bytes, tx_bytes
|
||||||
FROM ssh_iface_daily_usage
|
FROM ssh_iface_daily_usage
|
||||||
WHERE usage_date >= CURRENT_DATE - $1::int
|
WHERE usage_date >= CURRENT_DATE - $1::int
|
||||||
|
AND iface <> 'lo'
|
||||||
ORDER BY usage_date DESC, iface ASC`, days-1)
|
ORDER BY usage_date DESC, iface ASC`, days-1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return out, err
|
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
|
SELECT iface, to_char(month_start, 'YYYY-MM') AS period, rx_bytes, tx_bytes
|
||||||
FROM ssh_iface_monthly_usage
|
FROM ssh_iface_monthly_usage
|
||||||
WHERE month_start >= (date_trunc('month', CURRENT_DATE)::date - ($1::int * INTERVAL '1 month'))
|
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)
|
ORDER BY month_start DESC, iface ASC`, months-1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return out, err
|
return out, err
|
||||||
@@ -230,6 +238,9 @@ func (s *Store) ReplaceIfaceTotals(ctx context.Context, rows []IfaceTotals) erro
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, r := range rows {
|
for _, r := range rows {
|
||||||
|
if isIgnoredInterface(r.Iface) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
resetAt := r.ResetAt
|
resetAt := r.ResetAt
|
||||||
if resetAt.IsZero() {
|
if resetAt.IsZero() {
|
||||||
resetAt = time.Now()
|
resetAt = time.Now()
|
||||||
|
|||||||
Reference in New Issue
Block a user