#!/usr/bin/env bash # # wg-convert-config — rewrite a WireGuard config's DNS= line as an equivalent # PostUp command, for containers where openresolv/resolvconf can't run. # # usage: wg-convert-config [out.conf] # wg-convert-config - # write to stdout # # With no output path, writes ./ctr. set -euo pipefail prog=${0##*/} usage() { cat >&2 < [out.conf] Moves DNS= out of [Interface] and appends an equivalent PostUp that writes /etc/resolv.conf directly. Handles comma-separated addresses (v4 and v6) and treats non-IP values as search domains. Use - as out.conf for stdout. Defaults to ./ctr. EOF exit "${1:-2}" } case ${1:-} in -h | --help) usage 0 ;; "" | -*) usage ;; esac (($# <= 2)) || usage src=$1 dst=${2:-ctr${src##*/}} [[ -r $src ]] || { printf '%s: cannot read %s\n' "$prog" "$src" >&2; exit 1; } if [[ $dst != - && -e $dst && $src -ef $dst ]]; then printf '%s: refusing to overwrite the source file\n' "$prog" >&2 exit 1 fi convert() { awk ' BEGIN { q = "\047" } function flushpend( i) { for (i = 1; i <= npend; i++) print pend[i] npend = 0 } function emit( i, out) { if (!nns && !nsd) return out = "PostUp = printf " q "%s\\n" q for (i = 1; i <= nns; i++) out = out " " q "nameserver " ns[i] q if (nsd) { out = out " " q "search" for (i = 1; i <= nsd; i++) out = out " " sd[i] out = out q } print out " > /etc/resolv.conf" if (nns > 3) printf("%s: %d nameservers emitted; glibc reads only the first 3\n", prog, nns) > "/dev/stderr" nns = 0; nsd = 0 } # Section header: close out the [Interface] block before leaving it. /^[[:space:]]*\[/ { if (iface) emit() flushpend() iface = (tolower($0) ~ /^[[:space:]]*\[interface\][[:space:]]*$/) print next } # DNS = a, b, c (keys are case-insensitive, # starts a comment) iface && tolower($0) ~ /^[[:space:]]*dns[[:space:]]*=/ { s = $0 sub(/#.*/, "", s) sub(/^[^=]*=/, "", s) gsub(/,/, " ", s) n = split(s, a, /[[:space:]]+/) for (i = 1; i <= n; i++) { if (a[i] == "") continue if (a[i] ~ /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/ || (a[i] ~ /:/ && a[i] ~ /^[0-9a-fA-F:.%]+$/)) ns[++nns] = a[i] else sd[++nsd] = a[i] } next } # Hold blank lines so the PostUp lands above them, not under [Peer]. iface && /^[[:space:]]*$/ { pend[++npend] = $0; next } { flushpend(); print } END { if (iface) emit(); flushpend() } ' prog="$prog" "$src" } if [[ $dst == - ]]; then convert else tmp=$(mktemp -- "$dst.XXXXXX") trap 'rm -f -- "$tmp"' EXIT convert > "$tmp" chmod --reference="$src" -- "$tmp" 2>/dev/null || chmod 600 -- "$tmp" mv -- "$tmp" "$dst" trap - EXIT printf '%s: wrote %s\n' "$prog" "$dst" >&2 fi