fedora-csb-system-manager
1#!/usr/bin/env bash
2# Display DNS zone entries generated from Nix configuration
3
4set -euo pipefail
5
6# Color codes for output
7BOLD='\033[1m'
8DIM='\033[2m'
9GREEN='\033[0;32m'
10BLUE='\033[0;34m'
11YELLOW='\033[0;33m'
12CYAN='\033[0;36m'
13MAGENTA='\033[0;35m'
14RED='\033[0;31m'
15RESET='\033[0m'
16
17# Parse arguments
18VERBOSE=0
19HOST="${1:-demeter}"
20
21if [[ "${1:-}" == "--verbose" ]] || [[ "${2:-}" == "--verbose" ]]; then
22 VERBOSE=1
23 HOST="${2:-${1:-demeter}}"
24 if [[ "$HOST" == "--verbose" ]]; then
25 HOST="demeter"
26 fi
27fi
28
29# Define zones
30ZONES=(
31 "sbr.pm"
32 "home"
33 "vpn"
34 "192.168.1.in-addr.arpa"
35 "10.100.0.in-addr.arpa"
36)
37
38# Function to colorize DNS record type
39colorize_type() {
40 local type="$1"
41 case "$type" in
42 SOA) echo -e "${MAGENTA}${type}${RESET}" ;;
43 NS) echo -e "${CYAN}${type}${RESET}" ;;
44 A) echo -e "${GREEN}${type}${RESET}" ;;
45 AAAA) echo -e "${GREEN}${type}${RESET}" ;;
46 CNAME) echo -e "${YELLOW}${type}${RESET}" ;;
47 MX) echo -e "${BLUE}${type}${RESET}" ;;
48 TXT) echo -e "${DIM}${type}${RESET}" ;;
49 PTR) echo -e "${CYAN}${type}${RESET}" ;;
50 *) echo -e "${type}" ;;
51 esac
52}
53
54# Function to parse and display zone in compact format
55show_zone_compact() {
56 local zone_name="$1"
57 local zone_content="$2"
58
59 echo -e "${BOLD}${BLUE}━━━ ${zone_name} ━━━${RESET}"
60
61 # Count records by type
62 local soa_count
63 local ns_count
64 local a_count
65 local cname_count
66 local ptr_count
67 soa_count=$(echo "$zone_content" | grep -c " IN SOA " || true)
68 ns_count=$(echo "$zone_content" | grep -c " IN NS " || true)
69 a_count=$(echo "$zone_content" | grep -c " IN A " || true)
70 cname_count=$(echo "$zone_content" | grep -c " IN CNAME " || true)
71 ptr_count=$(echo "$zone_content" | grep -c " IN PTR " || true)
72
73 # Show summary
74 echo -e "${DIM}Records: SOA:${soa_count} NS:${ns_count} A:${a_count} CNAME:${cname_count} PTR:${ptr_count}${RESET}"
75 echo
76
77 # Parse and display records in organized format
78 local record_type=""
79 local prev_type=""
80
81 while IFS= read -r line; do
82 # Skip empty lines and TTL
83 [[ -z "$line" || "$line" =~ ^\$TTL ]] && continue
84
85 # Parse record type
86 if [[ "$line" =~ IN\ (SOA|NS|A|AAAA|CNAME|MX|TXT|PTR) ]]; then
87 record_type="${BASH_REMATCH[1]}"
88
89 # Add spacing between different record types
90 if [[ -n "$prev_type" && "$prev_type" != "$record_type" ]]; then
91 echo
92 fi
93 prev_type="$record_type"
94
95 # Format the line based on type
96 if [[ "$record_type" == "SOA" ]]; then
97 # SOA records - just show they exist
98 echo -e " $(colorize_type SOA) ${DIM}${line}${RESET}"
99 continue
100 elif [[ "$record_type" == "NS" ]]; then
101 # NS records
102 local name
103 local target
104 name=$(echo "$line" | awk '{print $1}')
105 target=$(echo "$line" | awk '{print $NF}')
106 printf " %-30s $(colorize_type NS) → %s\n" "$name" "$target"
107 elif [[ "$record_type" == "A" ]]; then
108 # A records - show name and IP
109 local name
110 local ip
111 local ttl
112 name=$(echo "$line" | awk '{print $1}')
113 ip=$(echo "$line" | awk '{print $NF}')
114 ttl=""
115
116 # Check if there's a TTL
117 if [[ "$line" =~ [0-9]+\ IN\ A ]]; then
118 ttl=$(echo "$line" | awk '{print $2}')
119 printf " %-30s $(colorize_type A) %s ${DIM}(TTL: %s)${RESET}\n" "$name" "$ip" "$ttl"
120 else
121 printf " %-30s $(colorize_type A) %s\n" "$name" "$ip"
122 fi
123 elif [[ "$record_type" == "PTR" ]]; then
124 # PTR records - reverse lookup
125 local name
126 local target
127 name=$(echo "$line" | awk '{print $1}')
128 target=$(echo "$line" | awk '{print $NF}')
129 printf " %-30s $(colorize_type PTR) → %s\n" "$name" "$target"
130 elif [[ "$record_type" == "CNAME" ]]; then
131 # CNAME records
132 local name
133 local target
134 name=$(echo "$line" | awk '{print $1}')
135 target=$(echo "$line" | awk '{print $NF}')
136 printf " %-30s $(colorize_type CNAME) → %s\n" "$name" "$target"
137 fi
138 fi
139 done <<< "$zone_content"
140
141 echo
142}
143
144# Function to show full zone
145show_zone_verbose() {
146 local zone_name="$1"
147 local zone_content="$2"
148
149 echo -e "${BOLD}${GREEN}═══ Zone: ${zone_name} ═══${RESET}"
150 echo
151 echo "$zone_content" | while IFS= read -r line; do
152 if [[ "$line" =~ IN\ SOA ]]; then
153 echo -e "${MAGENTA}${line}${RESET}"
154 elif [[ "$line" =~ IN\ NS ]]; then
155 echo -e "${CYAN}${line}${RESET}"
156 elif [[ "$line" =~ IN\ A ]]; then
157 echo -e "${GREEN}${line}${RESET}"
158 elif [[ "$line" =~ IN\ CNAME ]]; then
159 echo -e "${YELLOW}${line}${RESET}"
160 elif [[ "$line" =~ IN\ PTR ]]; then
161 echo -e "${CYAN}${line}${RESET}"
162 elif [[ "$line" =~ IN\ (SRV|MX|TXT) ]]; then
163 echo -e "${BLUE}${line}${RESET}"
164 elif [[ "$line" =~ ^\$TTL ]]; then
165 echo -e "${DIM}${line}${RESET}"
166 else
167 echo "$line"
168 fi
169 done
170 echo
171}
172
173# Header
174echo -e "${BOLD}${CYAN}DNS Zones for ${HOST}${RESET}"
175echo -e "${DIM}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
176echo
177
178# Process each zone
179total_zones=0
180failed_zones=0
181
182for zone_name in "${ZONES[@]}"; do
183 # Get the zone file content directly
184 zone_content=$(nix eval --raw ".#nixosConfigurations.${HOST}.config.services.bind.zones.\"${zone_name}\".file" --apply 'path: builtins.readFile path' 2>&1 | grep -v "^warning:" | grep -v "^Using saved setting" | grep -v "^building " || true)
185
186 if [[ -n "$zone_content" ]] && [[ "$zone_content" != *"error"* ]]; then
187 total_zones=$((total_zones + 1))
188
189 if [[ $VERBOSE -eq 1 ]]; then
190 show_zone_verbose "$zone_name" "$zone_content"
191 else
192 show_zone_compact "$zone_name" "$zone_content"
193 fi
194 else
195 failed_zones=$((failed_zones + 1))
196 echo -e "${YELLOW}⚠ Could not generate zone ${zone_name}${RESET}"
197 echo
198 fi
199done
200
201# Summary
202echo -e "${DIM}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
203echo -e "${BOLD}Summary:${RESET} Generated ${GREEN}${total_zones}${RESET} zones successfully"
204[[ $failed_zones -gt 0 ]] && echo -e " Failed to generate ${RED}${failed_zones}${RESET} zones"
205echo
206
207# Usage info
208if [[ $VERBOSE -eq 0 ]]; then
209 echo -e "${DIM}Tip: Use --verbose flag to see full zone files${RESET}"
210fi
211echo -e "${DIM}Usage: $0 [--verbose] [hostname]${RESET}"