thanks to inspiration from Robert Woźny, i’ve just launched two separate AS112 sites in Poland. that would never be possible without great folks at ATMAN:

…and at EPIX:

what is AS112 all about?

as112

AS112 is world-wide project that sinkholes requests coming in from misbehaving or misconfigured DNS clients (which may be your home PC but also some enterprise-y workstation). they send queries looking for answers to questions like “what’s the name of 192.168.0.1?” and because that’s not contained as it should be on the local or company level, it goes all up to the root servers. the question itself may be valid, but as you can see, IP address comes from RFC 1918 space, and therefore - shouldn’t be even appearing in public internet space. either we close those queries at the local level, or they really don’t make much sense once you cross private<>public border. actually, malicious actor could be abusing such queries, responding them in a way that will open your network to attack.

but more importantly, those questions are waste of resources for root servers. redirecting them locally and answering takes the load off our precious critical infrastructure, and enables it to focus on real work. in the worst case, this may be also way to lower stress of DDoS volume targeting them.

so right now, when you start asking questions like the ones above, those queries will be redirected to closest instance (thanks to magic of anycast) of DNS server doing nothing else but answering those on behalf of root DNS servers. one of them is colocated in ATMAN network, the other - in EPIX. both run FreeBSD as system of choice, OpenFRR as BGP stack and BIND 9 as DNS name resolving daemon.

there’s no specific magic behind the configurations, so just in typical transparent manner, let me share how those services are configured for our polish deployment. if you’re looking for references, best practices for this service are documented in two RFCs as well as on AS112 project page.

FreeBSD configuration

to be part of project, your server needs to listen on couple of specific IPv4 and IPv6 addresses. on my AS112 instances, i decided to keep those IPs bound to physical interface vmx0 (well, it’s virtual, but still). alternate configuration is to bind them to lo0 interface. anyway, the general format of configuration if your normal interface is vmx0, will be as follows:

ifconfig_vmx0_alias0="inet 192.175.48.1 netmask 255.255.255.255"
ifconfig_vmx0_alias1="inet 192.175.48.6 netmask 255.255.255.255"
ifconfig_vmx0_alias2="inet 192.175.48.42 netmask 255.255.255.255"
ifconfig_vmx0_alias3="inet 192.31.196.1 netmask 255.255.255.255"
ifconfig_vmx0_alias4="inet6 2620:4f:8000::1 prefixlen 128"
ifconfig_vmx0_alias5="inet6 2620:4f:8000::6 prefixlen 128"
ifconfig_vmx0_alias6="inet6 2620:4f:8000::42 prefixlen 128"
ifconfig_vmx0_alias7="inet6 2001:4:112::1 prefixlen 128"

other relevant parts that will start our daemons from later part of the article is listed here for completness:

# OpenFRR

frr_enable="YES"
frr_daemons="bgpd"
frr_flags="-A 127.0.0.1"

# BIND 9
named_enable="YES"

BIND 9 configuration

first, we need to properly configure name server. you can use nsd, named or whatever authoritative server you’re familiar with. we’ll be using BIND 9 below.

BIND 9 configuration lives in named.conf file. for FreeBSD that we’re using it’s just a question of installing proper package, and then editing files in /usr/local/etc/namedb directory:

main configuration for BIND will be to listen on all assigned IP interfaces, and answer proper zones. we need to disable recursion and zone transfers and the rest is up to you: logging (or not) of queries, hardening some options a bit and obviously in BIND case - playing with version, hostname and server-id answers for CHAOS type of queries ;)

so the config:

[as112 /usr/local/etc/namedb]$ more named.conf
options {
// some not relevant options

// our listening IPs, part of anycasted service:
        listen-on       { 192.175.48.1;      // prisoner.iana.org
                          192.175.48.6;      // blackhole-1.iana.org
                          192.175.48.42;     // blackhole-2.iana.org
                          192.31.196.1; };   // blackhole.as112.arpa
// no, we won't be open DNS resolver ;)
	recursion              no;
        minimal-responses      yes;
        minimal-any            yes;
        allow-transfer         { none; };
        version                "1.0.0";
        hostname               "AS112";
        server-id              "DNS";
};

// zones we're answering queries to:

zone "10.in-addr.arpa" { type master; file "m/db.RFC-1918"; };

zone "16.172.in-addr.arpa" { type master; file "m/db.RFC-1918"; };
zone "17.172.in-addr.arpa" { type master; file "m/db.RFC-1918"; };
zone "18.172.in-addr.arpa" { type master; file "m/db.RFC-1918"; };
zone "19.172.in-addr.arpa" { type master; file "m/db.RFC-1918"; };
zone "20.172.in-addr.arpa" { type master; file "m/db.RFC-1918"; };
zone "21.172.in-addr.arpa" { type master; file "m/db.RFC-1918"; };
zone "22.172.in-addr.arpa" { type master; file "m/db.RFC-1918"; };
zone "23.172.in-addr.arpa" { type master; file "m/db.RFC-1918"; };
zone "24.172.in-addr.arpa" { type master; file "m/db.RFC-1918"; };
zone "25.172.in-addr.arpa" { type master; file "m/db.RFC-1918"; };
zone "26.172.in-addr.arpa" { type master; file "m/db.RFC-1918"; };
zone "27.172.in-addr.arpa" { type master; file "m/db.RFC-1918"; };
zone "28.172.in-addr.arpa" { type master; file "m/db.RFC-1918"; };
zone "29.172.in-addr.arpa" { type master; file "m/db.RFC-1918"; };
zone "30.172.in-addr.arpa" { type master; file "m/db.RFC-1918"; };
zone "31.172.in-addr.arpa" { type master; file "m/db.RFC-1918"; };

zone "168.192.in-addr.arpa" { type master; file "m/db.RFC-1918"; };

zone "254.169.in-addr.arpa" { type master; file "m/db.RFC-1918"; };

// our own local instance information as per AS112 best practice

zone "empty.as112.arpa" { type master; file "m/db.RFC-1918.empty"; };

zone "hostname.as112.net" { type master; file "m/db.hostname.as112.net"; };
zone "hostname.as112.arpa" { type master; file "m/db.hostname.as112.arpa"; };

the zone files have following contents. first, m/db.RFC-1918:

$TTL 1W
@ IN SOA prisoner.iana.org. hostmaster.root-servers.org. (
                         1 1W 1M 1W 1W );
     NS blackhole-1.iana.org.
     NS blackhole-2.iana.org.

m/db.hostname.as112.net which hosts data about this AS112 instance:

$TTL 1W
@ IN SOA as112.bromirski.net. info.bromirski.net. (
                         1 1W 1M 1W 1W );

     TXT "Your local name for the instance"
     TXT "City, Poland"
     TXT "See http://as112.net/ for more information."
     TXT "See https://lukasz.bromirski.net/post/as-112/ for more information."
     NS blackhole-1.iana.org.
     NS blackhole-2.iana.org.

m/db.hostname.as112.arpa is very similar, but provides info for arpa domain:

$TTL 1W
@ IN SOA as112.bromirski.net. info.bromirski.net. (
                         1 1W 1M 1W 1W );

     TXT "Your local name for the instance"
     TXT "City, Poland"
     TXT "See http://as112.net/ for more information."
     TXT "See https://lukasz.bromirski.net/post/as-112/ for more information."
     NS blackhole.as112.arpa.

last file is empty zone for as112.arpa domain, with contact details pointing to ICANN NOC - we store it above in the db.RFC-1918.empty file:

$TTL    1W
@ IN SOA blackhole.as112.arpa. noc.dns.icann.org. (
                                  1       ; serial number
                                  1W      ; refresh
                                  1M      ; retry
                                  1W      ; expire
                                  1W )    ; negative caching TTL

     NS     blackhole.as112.arpa.

BTW, if you want those records to be returned in exactly this order, add rrset-order { order fixed; }; to your named configuration. note, that this generally may not be best idea, as default random option gives good load-balancing on multiple records. in this specific case this may be however “nice touch”.

OpenFRR configuration

for OpenFRR we need to make sure of two things:

  • we can establish BGP sessions with your upstream ISP
  • we can advertise proper prefixes belonging to AS112 project

for that, we need two files - bgpd.conf and staticd.conf.

first, bgpd.conf for BGP configuration:

!
hostname as112.colo.bgpd
password very-hard-to-guess-password
enable password even-more-harder-password
log file /usr/local/etc/frr/bgpd.log ! if needed to debug
service advanced-vty
service password-encryption
!
!
!
router bgp 112
 bgp router-id A.B.C.D ! your router-ID
 no bgp default ipv4-unicast
 neighbor 169.254.1.1 remote-as 65055     ! upstream ISP IPv4 address
 neighbor 169.254.1.1 description ISP-1   ! description
 neighbor 169.254.1.1 ebgp-multihop 3     ! typically it's eBGP multihop
 neighbor 2001:db8::1 remote-as 65055     ! upstream ISP IPv6 address
 neighbor 2001:db8::1 description ISP-1   ! description
 neighbor 2001:db8::1 ebgp-multihop 3     ! typically it's eBGP multihop
 ! some other global neighbor options may be put here, like
 ! for example update-source specification or BFD fall-over
 !
 address-family ipv4 unicast
  ! IPv4 address-family specific configuration
  network 192.31.196.0/24      ! AS112 assigned IPv4 prefix
  network 192.175.48.0/24      ! AS112 assigned IPv4 prefix
  neighbor 169.254.1.1 activate
  neighbor 169.254.1.1 prefix-list AS112-IN in
  neighbor 169.254.1.1 route-map AS112-v4-OUT out
 exit-address-family
 !
 address-family ipv6 unicast
  ! IPv6 address-family specific configuration
  network 2001:4:112::/48      ! AS112 assigned IPv6 prefix
  network 2620:4f:8000::/48    ! AS112 assigned IPv6 prefix
  neighbor 2001:db8::1 activate
  neighbor 2001:db8::1 prefix-list AS112-IN in
  neighbor 2001:db8::1 route-map AS112-v6-OUT out
 exit-address-family
!
ip prefix-list AS112-v4 seq 5 permit 192.175.48.0/24
ip prefix-list AS112-v4 seq 10 permit 192.31.196.0/24
!
ipv6 prefix-list AS112-v6 seq 5 permit 2620:4f:8000::/48
ipv6 prefix-list AS112-v6 seq 10 permit 2001:4:112::/48
!
ip prefix-list AS112-IN seq 10 deny any
!
route-map AS112-v4-OUT permit 10
 ! this route-map makes sure outgoing prefixes have proper
 ! attributes set (origin) and it checks if we're not trying
 ! to advertise something extra to upstreams ;)
 set origin igp
 set community 112:112
 match ip address prefix-list AS112-v4
route-map AS112-v6-OUT permit 10
 ! this route-map makes sure outgoing prefixes have proper
 ! attributes set (origin) and it checks if we're not trying
 ! to advertise something extra to upstreams ;)
 set origin igp
 set community 112:112
 match ipv6 address prefix-list AS112-v6
!
line vty
!

and then staticd.conf. this file takes care of ‘static’ route configuration - when OpenFRR starts, proper static routes are added to host routing table. this is typically needed to makes sure BGP has route to establish BGP session. of course you may do this at FreeBSD rc.conf/rc.conf.local level if you prefer to. I prefer this approach, as when OpenFRR is shut down, those routing entries are removed as well. YMMV.

!
hostname as112.colo.staticd
password very-hard-to-guess-password
enable password even-more-harder-password
!
ip route 169.254.1.1/32 A.B.C.D        ! static route via your gateway to
                                       ! your IPv4 BGP peer
ipv6 route 2001:db8::1/128 2001:db8::X ! static route via your gateway to
                                       ! your IPv6 BGP peer
!

as it’s FreeBSD and not some brain-damaged, half-cooked, fundamentally broken systemd based Linux distribution, configuration for both named and OpenFRR will be in your local /etc/rc.conf.local file:

# BIND 9
named_enable="YES"

# OpenFRR
frr_enable="YES"
frr_flags="-A 127.0.0.1"
frr_daemons="bgpd staticd"

summary

what do you need to do, to use this service? nothing. your upstream ISP should direct your traffic to closest anycasted instance of AS112 project DNS service. will it be “ours”, Polish one? that depends from where you’re asking from, but chances are that if you’re in Poland - it will be one of ours. you can check that by using:

dig @prisoner.iana.org +short hostname.as112.net txt
"AS112 ATMAN colo"
"Warszawa, Poland"
"See http://as112.net/ for more information."
"See https://lukasz.bromirski.net/post/as-112/ for more information."

if you see “Poland” anywhere above, you’re probably being served by one of our local, country instances. as far as I can see, there’s another one served by good folks at Aplitt S.A..