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 defaultrandom
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..