#! /bin/sh # #ident "@(#)$Id: gtld-wildhosts.sh,v 1.5 2013/09/27 23:50:11 woods Exp $" # This script will try a random name for each gTLD to reveal whether # there's a wildcard for that zone, and then, prints the A RR value(s) # for the host pointed to by that wildcard record. # # Up to date versions of this script can be found here: # # ftp://ftp.weird.com/pub/local/gtld-wildhosts.sh # http://www.weird.com/~woods/projects/gtld-wildhosts.sh # # The addresses discovered by this script can be used with Unbound's # "private-addresses" option. # # BIND-9.7 (and newer) users can add these addresses to the # "deny-answer-addresses" list. # # NOTE: BIND-9 users can also turn on "root-delegation-only" (or use # the "delegation-only" option per zone) and with this feature enabled # the results of this script are not needed. Take care to understand # the difference between forcing TLDs to be "delegation-only" vs. just # filtering out addresses of known wildcard target hosts. # # Patches adding a similar feature to BIND-8 can be found here: # # ftp://ftp.weird.com/pub/local/bind-8.4.7-REL-Planix-1.diff # # An ACL definition would then be configured: # # # Deny A records with these target addresses. This prevents stupid # # wildcard A RRs in delegation-only zones from having any effect. # # # # Note that .MUSEUM is supposed to have a wildcard -- it's defined # # to work that way. # # # acl deny_address_record_acl { # 64.74.134.14; # .CD. # 66.113.70.101; # .CD. (target of their wildcard MX) # . . . # # 195.7.77.20; # .MUSEUM. # . . . # # 127.0.0.2; # .SO. (randomly comes and goes) # . . . # }; # # and then in the "options" section: # # options { # . . . # # Deny bogus A RRs (turn them into NXDOMAIN responses) # # # # WARNING: to see rejected records named must have its # # debugging level increased, e.g. by sending it a SIGUSR1. # # # deny_address_record { # deny_address_record_acl; # }; # # For a complete example see the named.conf file included in this: # # ftp://ftp.weird.com/pub/local/named-sample-conf.src.shar # # TODO: # # - handle IPv6 addresses too. # # - find targets wildcard top-level MX records like the one for .CD # # NOTE: the "ftp" command must be one supporting '-o -' and URL # formatted parameters # # NOTE: the "host" command must be one supporting the "--canonskip" # parameter; as well as "-t RTYPE", "-r", and "-Z" # get the canonical list of all gTLDs # # each entry must terminate in a "." # all_tlds=$(ftp -o - ftp://ftp.internic.net/domain/root.zone.gz | gunzip -c | awk '$1 != "." && $4 == "NS" {print $1}' | sort -u) # find the IP address of a root server we can talk to # # we'll get the NS records for each TLD directly from this server # root_ns=$(host --canonskip -t NS . | awk '$2 == "NS" {print $NF; exit 0;}') root_a=$(host --canonskip -t A $root_ns | awk '$2 == "A" {print $NF; exit 0;}') host -r --canonskip -t SOA . $root_a > /dev/null if [ $? -ne 0 ]; then echo "There seems to be something wrong with the root NS at $root_a" >&2 exit 1 fi for tld in $all_tlds; do nslist=$(host --canonskip -t NS $tld $root_a 2> /dev/null | awk '$2 == "NS" {print $NF;}') # we probably don't have to check them all, but since it is a # little difficult without additional parsing to tell whether # the reason for a query failure is an authoritative NXDOMAIN # or not, we'll check all auth nameservers stopping early only # if we actually do find a wildcard record... # for auth_ns in $nslist; do cname=$(host -r --canonskip -t CNAME "*.${tld}" $auth_ns 2> /dev/null | awk '$2 == "CNAME" {print $3}') case "${cname}" in # # if there's no CNAME for "*.gtld" then we ask an A RR # "") host -r -Z --canonskip -t A "*.${tld}" $auth_ns 2> /dev/null | awk '$4 == "A" {print $5 ";\t# .'$tld' TTL=" $2;}' ;; # # in the case of a gTLD having a CNAME for "*.gtld" # then we need to find the A RR for this CNAME the # parent domain of the CNAME target. # # note: don't use '-r' with '-P' on older versions # *.*) host -Z --canonskip -t A -P ${cname} 2> /dev/null | awk '$4 == "A" {print $NF ";\t# .'$tld' (CNAME='${cname}') TTL=" $2;}' ;; *) host -Z --canonskip -t A -P ${cname}. 2> /dev/null | awk '$4 == "A" {print $NF ";\t# .'$tld' (CNAME='${cname}') TTL=" $2;}' ;; esac if [ $? -eq 0 ]; then break; fi done done .