/etc/resolv.conf redux

Brian Inglis Brian.Inglis@SystematicSW.ab.ca
Wed Mar 26 18:03:44 GMT 2025


On 2025-03-26 11:37, Jim Garrison via Cygwin wrote:
> Referring to Referring to Brian Inglis's response in
> https://cygwin.com/pipermail/cygwin/2024-February/255425.html
> 
>> I added a Cygwin postinstall script:
>>
>>     /etc/postinstall/0p_l_etc_resolv_conf.dash
>>
>> to create resolv.conf from `ipconfig /all` DNS servers, an internal list of 
>> open public DNS servers, and search domains, update:
>>
>>     /var/run/resolvconf/resolv.conf
>>
>> when changed, and `ln -frsvt /etc/`, also run from a Scheduled Task on System 
>> Restart.
> 
> The script seems to have disappeared in more recent iterations, and seems to 
> have been explicitly removed.
> 
>    $ ls -1 /etc/postinstall/0p*
>    /etc/postinstall/0p_000_autorebase.dash
>    /etc/postinstall/0p_update-info-dir.dash
> 
> Was that a deliberate change?  Not complaining here, just asking, so I know to 
> recreate resolv.conf if/when my delegated IPv6 prefix changes.

Never distributed - custom DIY AWK hack plus 0p_l_... local - attached.
Also includes a bunch of ISP, Canadian, alternate DNS and DoH services, and 
alternate local private subnets, as things change, sometimes without notice.

-- 
Take care. Thanks, Brian Inglis              Calgary, Alberta, Canada

La perfection est atteinte                   Perfection is achieved
non pas lorsqu'il n'y a plus rien à ajouter  not when there is no more to add
mais lorsqu'il n'y a plus rien à retrancher  but when there is no more to cut
                                 -- Antoine de Saint-Exupéry
-------------- next part --------------
#!/bin/dash
# 0p_l_etc_resolv_conf.dash - update /etc/resolv.conf if changed

r=resolv
cr=/usr/local/bin/cyg-$r.awk
run=/var/run/${r}conf
rrc=$run/$r.conf
SYSCONFDIR=${SYSCONFDIR:-/etc}
conf=$SYSCONFDIR/$r.conf

/bin/mkdir -pv		-- $run/		&& \
ip=$(/usr/bin/which	-- ipconfig)		&& \
tmp=$(/bin/mktemp -t	-- .XXXXXXXX.)		&& \
$ip /all | $cr	 > $tmp				&& \
[ -s $tmp ]					&& \
[ -w $rrc ]	|| : > $rrc
if ! /usr/bin/cmp -s	-- $tmp $rrc; then
    /bin/cp -fv		-- $tmp $rrc
    /bin/ln -frsTv	-- $rrc $conf
fi

/bin/rm -f		-- $tmp
-------------- next part --------------
#!/usr/bin/awk -f
# cyg-resolv.awk - create Cygwin resolv.conf from Windows ipconfig /all output

BEGIN {
# ISP domains
    CISP	= "# ISP Shaw/Rogers"
    isp_domains	= "shaw[^.]*[.]|sjrb[.]"
    isp		= "shaw.ca."
# suffixes
    SUF	= "cg.shawcable.net. shawcable.net. shaw.ca. sjrb.ca. SystematicSW.ab.ca. ca. org. net. edu. uk. com."
# public name servers Quad 9, Cloudflare, Cisco OpenDNS, Google Public DNS, Comodo Secure DNS
# Quad9 dns.quad9.net Malware Blocking, DNSSEC Validation
# Quad9 dns11.quad9.net Secured w/ECS: Malware blocking, DNSSEC Validation, ECS enabled
# Quad9 dns10.quad9.net Unsecured: No Malware blocking, no DNSSEC validation
# Quad9 dns12.quad9.net Secured w/ECS: No Malware blocking, No DNSSEC Validation, ECS enabled
# CloudFlare security.cloudflare-dns.com Malware Blocking
# CloudFlare one.one.one.one 1dot1dot1dot1.cloudflare-dns.com No Malware or Adult Content Blocking
# CloudFlare family.cloudflare-dns.com Malware and Adult Content Blocking
# Cisco OpenDNS dns.opendns.com. -> resolver2.opendns.com. resolver1.opendns.com. Secured w/ECS: Malware blocking, DNSSEC Validation, ECS enabled
# Cisco OpenDNS familyshield.opendns.com. Secured w/ECS: Malware and Adult Content blocking, DNSSEC Validation, ECS enabled
# Cisco OpenDNS sandbox.opendns.com. Secured w/ECS: No Malware blocking, DNSSEC Validation, ECS enabled
# Google Public DNS dns.google. -> google-public-dns-b.google.com. google-public-dns-a.google.com.
# Google Public DNS dns64.dns.google. NAT64 DNS64
    NS	= "dns.quad9.net. dns11.quad9.net. dns10.quad9.net. dns12.quad9.net. " \
	  "security.cloudflare-dns.com. family.cloudflare-dns.com. 1dot1dot1dot1.cloudflare-dns.com. "  \
	  "dns.opendns.com. familyshield.opendns.com. sandbox.opendns.com. "  \
	  "ns2.recursive.dnsbycomodo.com. ns1.recursive.dnsbycomodo.com. "   \
	  "dns.google. dns64.dns.google. " \
	  ""
# CleanBrowsing
#	    "security-filter-dns.cleanbrowsing.org. "			\
#	    "adult-filter-dns.cleanbrowsing.org. "			\
#	    "family-filter-dns.cleanbrowsing.org. "			\
# CIRA Canadian Shield Protected+malware+phishing
#	    "CAshieldProtected"						\
# resolv.conf comments
    CFHD = "# /etc/resolv.conf"
    CFHD = CFHD " - Internet Domain Name System resolver configuration file"
    CDS  = "# domain suffix"
    CSSL = "# suffix search list"
# hosts command
    hosts = "/usr/bin/getent ahosts"
# IP v4
    # digit patterns: [0-9], [1-9], [6-9], [0-4], [0-5], [0[0]]0-255, .[0[0]]0-255, .[0]16-31
    z9		= "[0-9]"
    o9		= "[1-9]"
    s9		= "[6-9]"
    z4		= "[0-4]"
    z5		= "[0-5]"
    p0_255	= "(0{0,2}" z9 "|0{0,1}" o9 z9 "|1" z9 z9 "|2(" z4 z9 "|5" z5 "))"
    d0_255	= "(." p0_255 ")"
    d16_31	= ".0?(1" s9 "|2" z9 "|3[01])"
    ipv4	= "^" p0_255 d0_255 "{3}$"
# private subnets
    # 10.0.0.0-.255.255.255
    p10		= "^10" d0_255 "{3}$"
    # 169.254.0.0-.255.255 Zeroconf Link-Local (IPv4LL) Automatic Private IP Addressing (APIPA) 
    p169	= "^169.254" d0_255 "{2}$"
    # 172.16.0.0-.31.255.255
    p172	= "^172" d16_31 d0_255 "{2}$"
    # 192.168.0.0-.255.255
    p192	= "^192.168" d0_255 "{2}$"
# IP v6
    # hex, id
    px		= "[0-9A-Fa-f]"
    gx		= px "{0,4}"
    cx		= ":" gx
    id		= "[0-9A-Za-z]"
    ipv6	= "^" gx "(" cx "){1,7}" "(%" id "+)?$"
# private subnets
    # fc00::/7	fc-fe + ff bit 7 local
    pfc00	= "^[Ff][C-Fc-f]" px "{2}:"
# seen to avoid duplication
    used["127.0.0.1"] = "127.0.0.1"
}


function nextaddr( addr, name, ns, nameserveraddr, nameserverhostname	,private,n) {
    if (DEBUG) print addr, name, ns > DEBUG

    # private subnets
    if (!(addr in used || addr ~ p10 || addr ~ p169 || addr ~ p172 || addr ~ p192 || addr ~ pfc00)) {
	n = ++ns

	if (addr)   { nameserveraddr[n]	= addr }

	if (name)   { nameserverhostname[n] = name }

	if (DEBUG) print addr, name, ns > DEBUG

	used[addr] = addr
    }

    return ns
}


function addrs( NS, nameserveraddr, ns	,c) {
# $ getent ahosts $NS
# 1.0.0.1         STREAM      one.one.one.one
# 1.0.0.1         DGRAM       one.one.one.one
# 1.1.1.1         STREAM
# 1.1.1.1         DGRAM
# 149.112.112.112 0      dns.quad9.net
# 9.9.9.9         0
# 208.67.220.220  0      resolver2.opendns.com
# 208.67.222.222  0      resolver1.opendns.com
# 8.8.4.4         0      google-public-dns-b.google.com
# 8.8.8.8         0      google-public-dns-a.google.com
# 149.112.122.20  0      CAshieldProtected      
# 149.112.121.20  0
    c = hosts " " NS

    while ((c | getline) > 0) {
	    ns = nextaddr( $1, $3, ns, nameserveraddr, nameserverhostname)
    }

    close( c )

    return ns
}


/\r/				{ sub( /\r/, "", $NF) }	# trim \r


# collect DNS domain suffixes
/D[Nn][Ss]\sSuffix[^:]*:\s\S/	{
    last = $NF
    if (last ~ /\./ && last !~ /\.$/)	last = last ".";	# add root dot

    if (!(last in domain)) {
	domain[last] = last
	domains = domains " " last
    }

    while (last ~ /\..+\..+/) {	# strip labels if more than two for domain
	sub(/^[^.]+./, "", last)
	if (last ~ /\./ && last !~ /\.$/)	last = last "."; # add root dot

	if (!(last in domain)) {
	    domain[last] = last
	    domains = domains " " last
	}
    }
}


# collect DNS search suffixes
/Search\sList[^:]*:\s\S/	{
    for (d in domain) {
	if (!(d in search))	search[d] = d

	if (d ~ isp_domains) {
	    last = isp

	    if (!(last in search)) {
		search[last] = last
		domains = domains " " last
	    }
	}
    }

    last = $NF
    if (last ~ /\./ && last !~ /\.$/)	last = last ".";	# add root dot

    if (!(last in search)) {
	search[last] = last
	domains = domains " " last
    }

    while (last ~ /\..+\..+/) {	# strip labels if more than two for domain
	sub(/^[^.]+./, "", last)
	if (last ~ /\./ && last !~ /\.$/)	last = last "."; # add root dot

	if (!(last in search)) {
	    search[last] = last
	    domains = domains " " last
	}
    }

    ns = split( SUF, sa)

    for (s = 1; s <= ns; ++s) {
	last = sa[s]
	if (last ~ /\./ && last !~ /\.$/)	last = last "."; # add root dot

	if (!(last in search)) {
	    search[last] = last
	    domains = domains " " last
	}
    }
}


# collect DNS server IP addresses
/DNS\sServers[^:]*:\s\S/		{ dns = 1 }	# start - enable


dns && ($NF ~ ipv4 || $NF ~ ipv6)	{		# collect IP addrs
    ns = nextaddr( $NF, last, ns, nameserveraddr, nameserverhostname)
    last = ""
}


dns && $NF !~ ipv6 && $NF !~ ipv4	{ dns = 0 }	# non-IP disable


# output unique resolv.conf entries
END {
    print CFHD
    print CISP

    ns = addrs( NS, nameserveraddr, ns)

    for (n = 0; n <= ns; ++n)	{
	if (n in nameserverhostname && nameserverhostname[n]) {
	    print "#", nameserverhostname[n]
	}

	if (n in nameserveraddr && nameserveraddr[n]) {
	    print "nameserver", nameserveraddr[n]
	}
    }

    if (!domains)   domains = SUF

    last = 0

    for (d in domain)	{ ++last }

    d = gensub(/\s.*$/, "", 1, domains)

    if (!last)    domain[d] = d

    print CDS
    for (d in domain)	{ print "domain", d; ++last; }

    print CSSL
    if (domains)	print "search", domains
}



More information about the Cygwin mailing list