Geo DNS in BIND with ECS support
You will be able in 3 minutes:
- Setup your own GEO DNS server with BIND.
- Primary and a Secondary (in old terms: Mater and a Slave).
- Keep own master records and fetch Geodata acting as s slave.
- ECS compatible so your users will be able to dig your DNS via 8.8.8.8 (etc) and get the right GEO-aware answers.
- You will be able to setup separate zone files for different counties.
Fully explained automated shell script following. You can copy-paste it to root terminal to get the goal.
We're using Debian 9 but fell free to use any other Debian or CentOS.
Just substitute apt-get install with yum install for Red Hat based OS.
Just substitute apt-get install with yum install for Red Hat based OS.
Installing BIND
Now installing the most recent BIND version:
cat <<'EOF' > /etc/apt/preferences.d/jessie-backports-bind.pref Package: bind9* bind9utils bind9-host libbind9* Pin: release a=stretch-backports Pin-Priority: 777 EOF cat <<'EOF' > /etc/apt/sources.list.d/stretch-backports.list deb http://http.debian.net/debian stretch-backports main EOF apt-get update apt-get -y -t stretch-backports install bind9 bind9-host libbind9*
Downloading GEO data with ECS
Following example will download MaxMind geographical database and convert it to BIND-like format.
Also the code is producing ECS enabled output.
Also the code is producing ECS enabled output.
cd / cat <<'EOF' > /GeoIP-ecs.sh_ #!/bin/bash [ -f GeoIPCountryCSV.zip ] || wget -T 5 -t 1 http://geolite.maxmind.com/download/geoip/database/GeoIPCountryCSV.zip echo -n "Creating CBE (Country,Begin,End) CSV file..." unzip -p GeoIPCountryCSV.zip GeoIPCountryWhois.csv | gawk -F \" '{print $10","$6","$8}' > cbe.csv echo -ne "DONE\nGenerating BIND GeoIP.acl file..." (for c in $(gawk -F , '{print $1}' cbe.csv | sort -u) do echo "acl \"$c\" { " grep "^$c," cbe.csv | gawk -F , 'function s(b,e,l,m,n) {l = int(log(e-b+1)/log(2)); m = 2^32-2^l; n = and(m,e); if (n == and(m,b)) printf "\t%u.%u.%u.%u/%u;\n",b/2^24%256,b/2^16%256,b/2^8%256,b%256,32-l; else {s(b,n-1); s(n,e)}} s($2,$3)' grep "^$c," cbe.csv | gawk -F , 'function s(b,e,l,m,n) {l = int(log(e-b+1)/log(2)); m = 2^32-2^l; n = and(m,e); if (n == and(m,b)) printf "\tecs %u.%u.%u.%u/%u;\n",b/2^24%256,b/2^16%256,b/2^8%256,b%256,32-l; else {s(b,n-1); s(n,e)}} s($2,$3)' echo -e "};\n" done) > GeoIP-ecs.acl rm -f cbe.csv echo "DONE" exit 0 EOF cd - chmod 755 /GeoIP-ecs.sh_ /GeoIP-ecs.sh_
Turning ON GEO and ECS BIND options
We're creating separate options file for our configuration and includes it in main configuration.
cd / cat <<'EOF' > /etc/bind/named.conf.local.geodns.options #following directives inside options {.. #geoip-directory "/usr/share/GeoIP/"; geoip-use-ecs yes; allow-transfer {trusted;}; allow-query {any;}; notify yes; EOF cd - cp -ia /etc/bind/named.conf.options /etc/bind/named.conf.options.orig sed -i 's/^};/\n\ninclude "\/etc\/bind\/named.conf.local.geodns.options"; \n};/g' /etc/bind/named.conf.options
Excluding default zones
RFC require that every DNS instance will provides default zones, but they don't wrapped with 'view' statements.
#/etc/bind/named.conf.default-zones:2: when using 'view' statements, all zones must be in views cp -ia /etc/bind/named.conf /etc/bind/named.conf.orig sed -i 's/^include "\/etc\/bind\/named.conf.default-zones";/#include "\/etc\/bind\/named.conf.default-zones";/g' /etc/bind/named.conf
Adding ECS and GEO configuration
"trusted" ACL will be defined later in this article.
#==> named.conf <== cd / cat <<'EOF' > /etc/bind/named.conf.local.geodns.conf #include "/GeoIP.acl"; include "/GeoIP-ecs.acl"; acl "trusted" { localhost; 8.8.8.8; }; EOF cd - echo 'include "/etc/bind/named.conf.local.geodns.conf";' >> /etc/bind/named.conf
Adding BIND logging (optional)
Logging very useful to debug GEO instance.
#==> named.conf <== cd / cat <<'EOF' > /etc/bind/named.conf.local.geodns.conf.logging logging { channel default_file { file "/var/log/named/default.log" versions 3 size 5m; severity dynamic; print-time yes; }; channel general_file { file "/var/log/named/general.log" versions 3 size 5m; severity dynamic; print-time yes; }; channel database_file { file "/var/log/named/database.log" versions 3 size 5m; severity dynamic; print-time yes; }; channel security_file { file "/var/log/named/security.log" versions 3 size 5m; severity dynamic; print-time yes; }; channel config_file { file "/var/log/named/config.log" versions 3 size 5m; severity dynamic; print-time yes; }; channel resolver_file { file "/var/log/named/resolver.log" versions 3 size 5m; severity dynamic; print-time yes; }; channel xfer-in_file { file "/var/log/named/xfer-in.log" versions 3 size 5m; severity dynamic; print-time yes; }; channel xfer-out_file { file "/var/log/named/xfer-out.log" versions 3 size 5m; severity dynamic; print-time yes; }; channel notify_file { file "/var/log/named/notify.log" versions 3 size 5m; severity dynamic; print-time yes; }; channel client_file { file "/var/log/named/client.log" versions 3 size 5m; severity dynamic; print-time yes; }; channel unmatched_file { file "/var/log/named/unmatched.log" versions 3 size 5m; severity dynamic; print-time yes; }; channel queries_file { file "/var/log/named/queries.log" versions 3 size 5m; severity dynamic; print-time yes; }; channel network_file { file "/var/log/named/network.log" versions 3 size 5m; severity dynamic; print-time yes; }; channel update_file { file "/var/log/named/update.log" versions 3 size 5m; severity dynamic; print-time yes; }; channel dispatch_file { file "/var/log/named/dispatch.log" versions 3 size 5m; severity dynamic; print-time yes; }; channel dnssec_file { file "/var/log/named/dnssec.log" versions 3 size 5m; severity dynamic; print-time yes; }; channel lame-servers_file { file "/var/log/named/lame-servers.log" versions 3 size 5m; severity dynamic; print-time yes; }; category default { default_file; }; category general { general_file; }; category database { database_file; }; category security { security_file; }; category config { config_file; }; category resolver { resolver_file; }; category xfer-in { xfer-in_file; }; category xfer-out { xfer-out_file; }; category notify { notify_file; }; category client { client_file; }; category unmatched { unmatched_file; }; category queries { queries_file; }; category network { network_file; }; category update { update_file; }; category dispatch { dispatch_file; }; category dnssec { dnssec_file; }; category lame-servers { lame-servers_file; }; }; EOF cd - echo 'include "/etc/bind/named.conf.local.geodns.conf.logging";' >> /etc/bind/named.conf mkdir /var/log/named ; chmod 775 /var/log/named ; chown root:bind /var/log/named
Adding example GEO zones configuration
Note of match-clients directive and the /GeoIP-ecs.acl file content.
You can add your own IP ranges to file.
You can add your own IP ranges to file.
#==> named.conf <== mkdir /etc/bind/zones ; chmod 755 /etc/bind/zones ; chown bind:bind /etc/bind/zones ; mkdir /etc/bind/zones/master ; chmod 755 /etc/bind/zones/master ; chown bind:bind /etc/bind/zones/master ; mkdir /etc/bind/zones/slave ; chmod 755 /etc/bind/zones/slave ; chown bind:bind /etc/bind/zones/slave ; cd / cat <<'EOF' > /etc/bind/named.conf.local.geodns.conf.zones view "Europa" { //match-clients { BE; DE; NL; GB; PL; SL;}; match-clients { RU; BE; DE; NL; GB; PL; SL;}; recursion no; zone "example.com" IN { type master; file "/etc/bind/zones/master/example.com.zone.eu"; }; }; view "RU-UA-BY" { //match-clients { RU; UA; BY; KZ;}; match-clients { UA; BY; KZ;}; recursion no; zone "example.com" IN { type master; file "/etc/bind/zones/master/example.com.zone.ua"; }; }; view "NotMatched" { match-clients { any; }; recursion no; zone "example.com" IN { type master; file "/etc/bind/zones/master/example.com.zone"; }; }; EOF cd - echo 'include "/etc/bind/named.conf.local.geodns.conf.zones";' >> /etc/bind/named.conf
And the GEO zones itself
#==> example.com.zone <== cd / cat <<'EOF' > /etc/bind/zones/master/example.com.zone $ORIGIN example.com. $TTL 60 @ IN SOA ns1.example.com. hostmaster.example.com. 1511161583 300 350 400 2 @ NS ns1.example.com. @ NS ns2.example.com. ns1 A 151.80.149.182 ns2 A 145.239.95.188 @ A 192.168.4.1 EOF cd - #==> example.com.zone.eu <== cd / cat <<'EOF' > /etc/bind/zones/master/example.com.zone.eu $ORIGIN example.com. $TTL 60 @ IN SOA ns1.example.com. hostmaster.example.com. 1511161583 300 350 400 2 @ NS ns1.example.com. @ NS ns2.example.com. ns1 A 151.80.149.182 ns2 A 145.239.95.188 @ A 192.168.4.2 EOF cd - #==> example.com.zone.ua <== cd / cat <<'EOF' > /etc/bind/zones/master/example.com.zone.ua $ORIGIN example.com. $TTL 60 @ IN SOA ns1.example.com. hostmaster.example.com. 1511161583 300 350 400 2 @ NS ns1.example.com. @ NS ns2.example.com. ns1 A 151.80.149.182 ns2 A 145.239.95.188 @ A 192.168.4.3 EOF cd -
All done
Now you're all set. Just reload BIND and test it.
Now try to add your own network to GEO file
We need it also after /GeoIP-ecs.acl file changed.
Edit /GeoIP-ecs.acl with: vi or nano.
Find line staring with: acl "UA" {
add following:
Edit /GeoIP-ecs.acl with: vi or nano.
Find line staring with: acl "UA" {
add following:
vi /GeoIP-ecs.acl ... acl "UA" { 127.0.0.3/32; ...
Restarting BIND
/etc/init.d/bind9 restart
Testing GEO DNS from localhost
Note of -b 127.0.0.3, we get the view "RU-UA-BY" { .. match-clients { UA; BY; KZ;}; match
from the /etc/bind/zones/master/example.com.zone.ua file.
And the view "NotMatched" { .. match-clients { any; }; match
from the /etc/bind/zones/master/example.com.zonefile in the other case.
from the /etc/bind/zones/master/example.com.zone.ua file.
And the view "NotMatched" { .. match-clients { any; }; match
from the /etc/bind/zones/master/example.com.zonefile in the other case.
dig -b 127.0.0.3 example.com @localhost dig -b 127.0.0.1 example.com @localhost
Request us to setup your GEO DNS
Go to main website page to find contacts.