Skip to content
Merged
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
3 changes: 3 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ jobs:
- name: test_cli.sh
run: bash hosting-panels/common/tests/test_cli.sh

- name: test_hostname_filter.sh
run: bash hosting-panels/common/tests/test_hostname_filter.sh

- name: test_cyberpanel_db.sh
run: bash hosting-panels/common/tests/test_cyberpanel_db.sh

Expand Down
18 changes: 18 additions & 0 deletions hosting-panels/common/seconddns_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import configparser
import json
import os
import socket
import subprocess
import sys
import urllib.error
Expand Down Expand Up @@ -163,11 +164,28 @@ def panel_zones():
zones = [l.strip() for l in (out or "").splitlines() if l.strip()]
if out is None:
raise PanelError(f"could not read the zone list ({source}); refusing to continue")
# The server's own hostname zone belongs to the host, not the customer; the
# API refuses it, so every cPanel install left a failed op behind.
host = _server_hostname()
if host:
zones = [z for z in zones if z.lower().rstrip(".") != host]
# A panel with no zones is a legal state — a fresh server, or one that was
# emptied. Only a failed read is an error, and that is the branch above.
return zones


def _server_hostname():
"""This machine's fully qualified name, lowercased, or '' if unknown."""
name = os.environ.get("SECONDDNS_HOSTNAME") # tests
if name is None:
try:
name = socket.getfqdn()
except OSError:
return ""
name = (name or "").strip().lower().rstrip(".")
return name if "." in name else ""


def zones_from_file(path):
zones = [l.strip() for l in open(path) if l.strip() and not l.startswith("#")]
if not zones:
Expand Down
44 changes: 44 additions & 0 deletions hosting-panels/common/tests/test_hostname_filter.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#!/bin/bash
# The server's own hostname is not a customer zone: cPanel lists it, the API
# refuses it, and every install left a failed op behind.
# Run: bash hosting-panels/common/tests/test_hostname_filter.sh
set -u
HERE="$(cd "$(dirname "$0")" && pwd)"
PASS=0; FAIL=0
ok() { PASS=$((PASS+1)); echo " ok: $1"; }
fail() { FAIL=$((FAIL+1)); echo " FAIL: $1"; }

zones() { # $1 = hostname, $2 = panel zone list
env SECONDDNS_HOSTNAME="$1" SECONDDNS_PANEL_ZONES_CMD="printf '%s\n' $2" \
PYTHONPATH="$HERE/.." python3 -c "
from seconddns_common import panel_zones
print(' '.join(panel_zones()))
" 2>&1
}

echo "== the hostname zone is dropped"
out=$(zones "server1.seconddns.com" "a.example.com server1.seconddns.com b.example.com")
[ "$out" = "a.example.com b.example.com" ] && ok "hostname removed, order kept" || fail "got '$out'"

echo "== matching is case- and dot-insensitive"
out=$(zones "server1.seconddns.com" "SERVER1.SecondDNS.com a.example.com")
[ "$out" = "a.example.com" ] && ok "uppercase form removed" || fail "got '$out'"
out=$(zones "server1.seconddns.com" "server1.seconddns.com. a.example.com")
[ "$out" = "a.example.com" ] && ok "trailing dot removed" || fail "got '$out'"

echo "== only the exact name goes"
out=$(zones "server1.seconddns.com" "seconddns.com sub.server1.seconddns.com a.example.com")
[ "$out" = "seconddns.com sub.server1.seconddns.com a.example.com" ] \
&& ok "parent and child zones kept" || fail "got '$out'"

echo "== a bare hostname is not a zone name"
out=$(zones "localhost" "localhost a.example.com")
[ "$out" = "localhost a.example.com" ] && ok "no dot, nothing dropped" || fail "got '$out'"

echo "== an empty panel stays empty, not an error"
out=$(zones "server1.seconddns.com" "")
[ -z "$out" ] && ok "empty list survives the filter" || fail "got '$out'"

echo
echo "passed=$PASS failed=$FAIL"
[ "$FAIL" -eq 0 ]
33 changes: 0 additions & 33 deletions hosting-panels/cpanel/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -503,39 +503,6 @@ if [ -n "$API_NS" ]; then
fi
fi

# Initial sync
echo ""
if confirm "Sync existing cPanel accounts to secondary DNS now?"; then
echo "[*] Syncing accounts..."
added=0
failed=0

if [ -d /var/cpanel/users ]; then
for user_file in /var/cpanel/users/*; do
[ -f "$user_file" ] || continue
sdomain=$(grep "^DNS=" "$user_file" 2>/dev/null | cut -d= -f2)
[ -z "$sdomain" ] && continue

response=$(curl -sf --max-time 15 \
-X POST \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-H "User-Agent: SecondDNS-cPanel/1.0" \
-d "{\"name\":\"$sdomain\",\"masterIp\":\"$MASTER_IP\"}" \
"$API_URL/api/zones" 2>/dev/null)
if [ $? -eq 0 ]; then
echo " [+] $sdomain"
added=$((added+1))
else
failed=$((failed+1))
fi
done
else
echo "[!] /var/cpanel/users not found — skipping sync"
fi

echo "[+] Synced: $added domains, failed: $failed"
fi

echo ""
# reconcile already knows where each panel keeps its zone list; --add-missing
Expand Down