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.