2 # update-virtualhosts Virtual hosts updater
3 # (C) 2019 Nirgal Vourgère <nirgal@debian.org>
7 VERBOSE=1 # 0=only_warnings 1=notice 2=debug
18 echo "Usage: $0 [options] basedir..."
19 echo " -h|--help Display that help"
20 echo " --verbose-lvl=level Define verbosity level. Defaults to $VERBOSE."
21 echo " 0: Only warnings"
22 echo " 1: Include notices"
24 echo " Fell free to ignore STDERR"
25 echo " -q|--quiet Identical to --verbose-lvl=0"
26 echo " -d|--debug Identical to --verbose-lvl=2"
50 echo "Unknown option $_OPT" >&2
61 NORMAL=`tput sgr0 2>/dev/null`
62 RED=`tput setaf 1 2>/dev/null`
63 GREEN=`tput setaf 2 2>/dev/null`
99 # ======================================================================
101 # Parse $INPUT that reads like
102 # www1.lan < example.com www.example.com
103 # 192.168.0.11 < example.net www.example.net
104 # fdce:266b:c77a::b < example.net www.example.net
105 # and fill these 6 vars:
106 redirections4_src=() # ( "example.com www.example.com" "example.net www.example.net" )
107 redirections4_dst=() # ( "192.168.0.10" "192.168.0.11" )
108 redirections4_dstname=() # ( "www1.lan" "192.168.0.11" )
109 redirections6_src=() # ( "example.com www.example.com" "example.net www.example.net" )
110 redirections6_dst=() # ( "fdce:266b:c77a::a" "fdce:266b:c77a::b" )
111 redirections6_dstname=() # ( "www1.lan" "fdce:266b:c77a::b" )
112 redirectionsn_src=() # ( "example.com www.example.com" )
113 redirectionsn_dst=() # ( "www1.lan" )
115 if test -r "$basedir/config"
117 log_info "Reading $basedir/config"
118 source "$basedir/config"
120 log_error "Cannot read $basedir/config. Skiping."
125 log_error "Variable INPUT is empty. Skiping $basedir."
130 if [[ "$line" =~ ^([^\>]*)[[:space:]]*\>[[:space:]]*(.*)$ ]]
132 sources="${BASH_REMATCH[1]}"
133 destination=${BASH_REMATCH[2]}
134 if [[ "$destination" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]
136 log_info "Virtual host(s) $sources redirect(s) to ipv4 $destination, no ipv6."
137 redirections4_src+=("$sources")
138 redirections4_dst+=($destination)
139 redirections4_dstname+=($destination)
140 elif [[ "$destination" =~ ^[0-9a-f:]*:[0-9a-f:]* ]]
142 log_info "Virtual host(s) $sources redirect(s) to ipv6 $destination, no ipv4."
143 redirections6_src+=("$sources")
144 redirections6_dst+=("$destination")
145 redirections6_dstname+=("$destination")
147 msg="Virtual host(s) $sources redirect(s) to host $destination: "
148 redirectionsn_src+=("$sources")
149 redirectionsn_dst+=("$destination")
150 ipv4=$(getent ahostsv4 "$destination" | cut -d ' ' -f 1 | sort -u)
151 ipv6=$(getent ahostsv6 "$destination" | cut -d ' ' -f 1 | sort -u)
152 if (( $(echo "$ipv4" | wc -l) > 1 ))
154 log_error "ERROR: $destination has several ipv4 addresses. This is not supported. ipv4 disabled for this domain."
157 if (( $(echo "$ipv6" | wc -l) > 1 ))
159 log_error "ERROR: $destination has several ipv6 addresses. This is not supported. ipv6 disabled for this domain."
165 redirections4_src+=("$sources")
166 redirections4_dst+=($ipv4)
167 redirections4_dstname+=($destination)
174 redirections6_src+=("$sources")
175 redirections6_dst+=($ipv6)
176 redirections6_dstname+=($destination)
181 if [[ -z "$ipv4" && -z "$ipv6" && ! -d "$basedir/hostname" ]]
183 log_error "ERROR: $destination has no ipv4 nor ipv6."
187 log_error "ERROR: syntax error while parsing $line"
191 #log_debug "============================================================="
193 #for (( i=0; i<${#redirections4_dst[@]}; i++ ))
195 # log_debug "${redirections4_dst[$i]}"
196 # sources=${redirections4_src[$i]}
197 # for s in ${sources[*]}
203 # ======================================================================
204 # Step 2: write the file
205 if [[ -n "$OUTPUT" ]]
207 log_debug "Backup'ing $OUTPUT"
208 mv "$OUTPUT" "$OUTPUT.bak"
209 log_info "Writing to $OUTPUT."
213 log_debug "============================================================="
215 output "############################################################################"
216 output "# DO NOT EDIT THAT FILE"
217 output "# Notice: That file was generated using:"
218 output "# $COMMANDLINE"
219 output "# See $basedir/config"
220 output "############################################################################"
222 if [[ -f "$basedir/prolog" ]]
224 fragment=$(cat "$basedir/prolog")
228 if [[ -d "$basedir/ipv4" ]]
230 for fragmentdir in $( find "$basedir/ipv4" -mindepth 1 -maxdepth 1 -type d | sort )
232 log_debug "Processing $fragmentdir"
233 if test -f "$fragmentdir/prolog"
235 fragment=$(cat "$fragmentdir/prolog")
238 for (( i=0; i<${#redirections4_dst[@]}; i++ ))
240 destination="${redirections4_dst[$i]}"
241 dstname="${redirections4_dstname[$i]}"
242 log_debug "Processing $fragmentdir for destination $destination"
243 if test -f "$fragmentdir/destination"
245 fragment=$(cat "$fragmentdir/destination")
246 fragment="${fragment//[$]destination/$destination}"
247 fragment="${fragment//[$]dstname/$dstname}"
250 sources=${redirections4_src[$i]}
251 for source in ${sources[*]}
253 if test -f "$fragmentdir/line_$source"
255 fragment=$(cat "$fragmentdir/line_$source")
256 fragment="${fragment//[$]destination/$destination}"
257 fragment="${fragment//[$]dstname/$dstname}"
258 fragment="${fragment//[$]source/$source}"
260 elif test -f "$fragmentdir/line"
262 fragment=$(cat "$fragmentdir/line")
263 fragment="${fragment//[$]destination/$destination}"
264 fragment="${fragment//[$]dstname/$dstname}"
265 fragment="${fragment//[$]source/$source}"
273 if [[ -d "$basedir/ipv6" ]]
275 for fragmentdir in $( find "$basedir/ipv6" -mindepth 1 -maxdepth 1 -type d | sort )
277 log_debug "processing $fragmentdir"
278 if test -f "$fragmentdir/prolog"
280 fragment=$(cat "$fragmentdir/prolog")
283 for (( i=0; i<${#redirections6_dst[@]}; i++ ))
285 destination="${redirections6_dst[$i]}"
286 dstname="${redirections6_dstname[$i]}"
287 log_debug "processing $fragmentdir for destination $destination"
288 if test -f "$fragmentdir/destination"
290 fragment=$(cat "$fragmentdir/destination")
291 fragment="${fragment//[$]destination/$destination}"
292 fragment="${fragment//[$]dstname/$dstname}"
295 sources=${redirections6_src[$i]}
296 for source in ${sources[*]}
298 if test -f "$fragmentdir/line_$source"
300 fragment=$(cat "$fragmentdir/line_$source")
301 fragment="${fragment//[$]destination/$destination}"
302 fragment="${fragment//[$]dstname/$dstname}"
303 fragment="${fragment//[$]source/$source}"
305 elif test -f "$fragmentdir/line"
307 fragment=$(cat "$fragmentdir/line")
308 fragment="${fragment//[$]destination/$destination}"
309 fragment="${fragment//[$]dstname/$dstname}"
310 fragment="${fragment//[$]source/$source}"
318 if [[ -d "$basedir/hostname" ]]
320 for fragmentdir in $( find "$basedir/hostname" -mindepth 1 -maxdepth 1 -type d | sort )
322 log_debug "processing $fragmentdir"
323 if test -f "$fragmentdir/prolog"
325 fragment=$(cat "$fragmentdir/prolog")
328 for (( i=0; i<${#redirectionsn_dst[@]}; i++ ))
330 destination="${redirectionsn_dst[$i]}"
331 log_debug "processing $fragmentdir for destination $destination"
332 if test -f "$fragmentdir/destination"
334 fragment=$(cat "$fragmentdir/destination")
335 fragment="${fragment//[$]destination/$destination}"
338 sources=${redirectionsn_src[$i]}
339 for source in ${sources[*]}
341 if test -f "$fragmentdir/line_$source"
343 fragment=$(cat "$fragmentdir/line_$source")
344 fragment="${fragment//[$]destination/$destination}"
345 fragment="${fragment//[$]source/$source}"
347 elif test -f "$fragmentdir/line"
349 fragment=$(cat "$fragmentdir/line")
350 fragment="${fragment//[$]destination/$destination}"
351 fragment="${fragment//[$]source/$source}"
359 # ======================================================================
360 # Step 3: run the hook
363 read -p "$HOOK ? (y/n): " -n 1 confirm
365 if [[ "$confirm" = "y" ]]
367 log_info "Running hook: $HOOK"
370 log_debug "Skipping hook: $HOOK"
375 for dir in "${DIRS[@]}"
377 # Reset some vars that are supposed to be in $dir/condig
378 # We don't want to keep the value from previous dir
385 # vim: set ts=4 noet: