Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DNSSEC setup for dnsseed #85

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
299 changes: 299 additions & 0 deletions README-dnssec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,299 @@
# DNSSEC setup for dnsseed

##### Table of Contents
[Requirements](#Requirements)
[Software needed](#Software)
[Setup](#Setup)
[Testing](#Testing)
[Example](#Example)
[Improvements](#Improvements)
[Links](#Links)


<a name="Requirements"/>

## Recommendation
* run only this service on the host (security precaution)
Emzy marked this conversation as resolved.
Show resolved Hide resolved

<a name="Software"/>

## Software needed

* Debian GNU/Linux 10
* tor
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can drop Tor, because seeds were only able to announce Tor v2 addresses.

* bind9
* dig (debian package bind9-dnsutils)
* nsupdate (debian package bind9-dnsutils)
* bitcoin-seeder
* ufw
* bash
Emzy marked this conversation as resolved.
Show resolved Hide resolved

```
apt update
apt install bind9 bind9-dnsutils bind9utils ufw tor
```

<a name="Setup"/>

## Setup

### ufw
Configure and enable firewall
```
ufw allow 22/tcp
ufw allow 53/udp
ufw allow 53/tcp
ufw enable
ufw status
```

### Configuring Bind9
Replace `example.com` with your domain.

* add or change in /etc/bind/named.conf.options
```
querylog no;
allow-transfer { none; };
dnssec-enable yes;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

```

* add to /etc/bind/named.conf.local
```
zone "dnsseed.example.com" {
type master;
file "/var/lib/bind/db.dnsseed.example.com";
key-directory "/var/lib/bind";
allow-update {localhost;};
auto-dnssec maintain;
inline-signing yes;
};
```

* Generate new file /var/lib/bind/db.example.com
```
$ORIGIN .
$TTL 3600 ; 1 hour
dnsseed.example.com. IN SOA dnsseed-host.example.com. contact-email.example.com. (
2000000001 ; serial
3600 ; refresh (1 hour)
600 ; retry (10 minutes)
86400 ; expire (1 day)
600 ; minimum (10 minutes)
)
NS dnsseed-host.example.com.
dummy A 127.0.0.1
```

* Check config
```
named-checkconf
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This complains /etc/bind/named.conf.local:14: option 'auto-dnssec' is deprecated

named-checkzone dnsseed.example.com /var/lib/bind/db.dnsseed.example.com
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the expected result of this?

$ named-checkzone seed.bitcoin.sprovoost.nl /var/lib/bind/db.seed.bitcoin.sprovoost.nl 
/var/lib/bind/db.seed.bitcoin.sprovoost.nl:3: ignoring out-of-zone data (dnsseed.example.com)
/var/lib/bind/db.seed.bitcoin.sprovoost.nl:11: ignoring out-of-zone data (dummy)
zone seed.bitcoin.sprovoost.nl/IN: has 0 SOA records
zone seed.bitcoin.sprovoost.nl/IN: has no NS records
zone seed.bitcoin.sprovoost.nl/IN: not loaded due to errors.

Copy link
Contributor

@Sjors Sjors Aug 21, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

^ I got rid of the remaining dnsseed.example.com

But that leaves:

/var/lib/bind/db.seed.bitcoin.sprovoost.nl:11: ignoring out-of-zone data (dummy)
zone seed.bitcoin.sprovoost.nl/IN: NS 'seed.bitcoin.sprovoost.nl' has no address records (A or AAAA)
zone seed.bitcoin.sprovoost.nl/IN: not loaded due to errors.

```

* Restart Bind9
`service bind9 restart`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to succeed, though startup will have the same errors/warnings as above.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I may have accidentally deleted this service, but this still works: sudo systemctl restart named


* Generate DNSSEC keys
```
cd /var/lib/bind
dnssec-keygen -r /dev/urandom -a ECDSAP256SHA256 dnsseed.example.com`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

` at the end?

Also:

dnssec-keygen: fatal: The -r option has been deprecated.
System random data is always used.

dnssec-keygen -r /dev/urandom -a ECDSAP256SHA256 -b 2048 -fKSK -n ZONE dnsseed.example.com
chown bind: Kdnsseed.example.com*.key
Emzy marked this conversation as resolved.
Show resolved Hide resolved
```

* Add keys to zone file
```
cd /var/lib/bind
for key in Kdnsseed.example.com*.key
do
echo "\$INCLUDE $key">> db.example.com
done
```

* Sign zone
```
dnssec-signzone -A -3 $(head -c 1000 /dev/random | sha1sum | cut -b 1-16) -N INCREMENT -o example.com -t db.example.com
Emzy marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean -o dnsseed.example.com -t db.dnsseed.example.com or really the root domain?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also my bind9 seems to insist that the signed output is in raw format, so adding -O raw

```

* Restart Bind9
`service bind9 restart`

* after the restart you will have a file /var/lib/bind/dsset-dnsseed.example.com.
This file contains the DS records that need to be entered in the parent dns zone or in your domain registrar’s control panel.


### Building bitcoin-seeder (should be non root)

* Install requirements
```
sudo apt-get install build-essential libboost-all-dev libssl-dev
```

* Download
```
git pull https://github.com/sipa/bitcoin-seeder.git
```

* Compile
```
make
```

* Start
```
./dnsseed -p5353 -h dnsseed.example.com -n dnsseed-host.example.com -m someting.example.com -o 127.0.0.1:9050
```

**TODO** systemd service

### Cron script to fetch dns records from bitcoin-seeder

* Download the file

[/etc/cron.hourly/dnsupdate](contrib/dnsupdate)

* Put it in /etc/cron.hourly/

* Change following line

`ZONE=dnsseed.example.com`

* Make it executable
`chmod +x /etc/cron.daily/dnsupdate`

<a name="Testing"/>

## Testing

* Checking if RRSIG record is present
```
dig A dnsseed.emzy.de @8.8.8.8 +noadditional +dnssec +multiline
dig AAAA dnsseed.emzy.de @8.8.8.8 +noadditional +dnssec +multiline
dig A x49.dnsseed.emzy.de. +dnssec @8.8.8.8 +dnssec +multiline
dig AAAA x49.dnsseed.emzy.de. +dnssec @8.8.8.8 +dnssec +multiline
```

* Check if all looks good on
https://dnsviz.net/d/dnsseed.emzy.de/dnssec/

* Check syslog that nsupdate is working
/var/log/syslog should have many `updating zone` entries and a `zone ... (signed)` entry every hour.
```
...named[99]: client @0x7fd78048c650 127.0.0.1#41161: updating zone 'dnsseed.emzy.de/IN': adding an RR at 'x40c.dnss
eed.emzy.de' A 134.209.232.105
...named[99]: client @0x7fd7800b8520 127.0.0.1#58337: updating zone 'dnsseed.example.com/IN': adding an RR at 'x448.dnsseed.example.com' AAAA 2600:1f16:625:e00:aefd:9cc7:d3:6e86
[...]
...named[99]: zone dnsseed.emzy.de/IN (signed): serial 2000002744 (unsigned 2000002740)
[...]
```

* * *
<a name="Example"/>

## Example (Debian 10)

### bitcoin-seeder

* Should look like this
```
user@dnsseed:~/bitcoin-seeder$ ./dnsseed -p5353 -h dnsseed.example.com -n dnsseed-host.example.com -m someting.example.com -o 127.0.0.1:9050
Supporting whitelisted filters: 0x1,0x5,0x9,0xd,0x49,0x400,0x404,0x408,0x40c,0x448
Using Tor proxy at 127.0.0.1:9050
Loading dnsseed.dat...done
Starting 4 DNS threads for dnsseed.example.com on dnsseed-host.example.com (port 5353).......done
Starting seeder...done
[20-09-18 13:02:55] 5733/36914 available (34970 tried in 1332s, 408 new, 1536 active), 55236 banned; 112 DNS requests, 44 db queries
```

### Bind9 full config files

* /etc/bind/named.conf.options
```
options {
directory "/var/cache/bind";

// If there is a firewall between you and nameservers you want
// to talk to, you may need to fix the firewall to allow multiple
// ports to talk. See http://www.kb.cert.org/vuls/id/800113

// If your ISP provided one or more IP addresses for stable
// nameservers, you probably want to use them as forwarders.
// Uncomment the following block, and insert the addresses replacing
// the all-0's placeholder.

// forwarders {
// 0.0.0.0;
// };

//========================================================================
// If BIND logs error messages about the root key being expired,
// you will need to update your keys. See https://www.isc.org/bind-keys
//========================================================================
dnssec-validation auto;

listen-on-v6 { any; };
// hide version number from clients for security reasons.
version "not currently available";

// disable recursion on authoritative DNS server.
recursion no;

// disable the query log
querylog no;

// disallow zone transfer
allow-transfer { none; };

dnssec-enable yes;
};
```

* /etc/bind/named.conf.local
```
//
// Do any local configuration here
//

// Consider adding the 1918 zones here, if they are not used in your
// organization
//include "/etc/bind/zones.rfc1918";

zone "dnsseed.emzy.de" {
type master;
file "/var/lib/bind/db.dnsseed.emzy.de";
key-directory "/var/lib/bind";
allow-update {localhost;};
auto-dnssec maintain;
inline-signing yes;
};
```

* /var/lib/bind/db.example.com
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean /var/lib/bind/db.dnsseed-host.example.com or does this have to one level up?

```
$ORIGIN .
$TTL 3600 ; 1 hour
dnsseed.example.com. IN SOA dnsseed-host.example.com. contact-email.example.com. (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I overlooked the -host bit here.

2000000001 ; serial
3600 ; refresh (1 hour)
600 ; retry (10 minutes)
86400 ; expire (1 day)
600 ; minimum (10 minutes)
)
NS dnsseed-host.example.com.
dummy A 127.0.0.1
dnsseed.example.com. IN DNSKEY 257 3 13 euXp/lPIx...xuSVYZ clx...xM==
dnsseed.example.com. IN DNSKEY 256 3 13 6CNJQx...xykHv XKx...xg==
```


<a name="Improvements"/>

## Possible improvements
* enable key only authentication on ssh
* use different SSH port (don't forget to add to ufw)
* non root cron job and key for the nsupdate authentication

<a name="Links"/>

## Links
* https://www.digitalocean.com/community/tutorials/how-to-setup-dnssec-on-an-authoritative-bind-dns-server--2
42 changes: 42 additions & 0 deletions contrib/dnsupdate
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#!/bin/bash
# This queries the bitcoin-seeder via dns on port 5353 and
# puts the result in the dns zone of a Bind9.
# bitcoin-seeder: https://github.com/sipa/bitcoin-seeder

Emzy marked this conversation as resolved.
Show resolved Hide resolved
set -euo pipefail

# Zone to request from bintcoin-seeder
ZONE=dnsseed.emzy.de
# Filters to fetch
FILTERS='x1 x5 x9 xd x49 x400 x404 x408 x40c x448'

# Fetch and update A and AAAA records @ of the zone
(
echo server localhost
echo zone ${ZONE}
echo update delete ${ZONE} a
echo update delete ${ZONE} aaaa
for proto in A AAAA ; do
dig +noall +answer -t ${proto} -p 15353 @52.37.101.214 ${ZONE} | \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The IP here is replaced with where the seeder is running at?

Same below.

Can you the port, IP and domain a variable that's passed in an argument? That's more consistent the seeder command and easier when you have multiple seeds running on the same machine (mainnet, testnet, etc).

awk '{ print "update add "$1" 3600 "$4" "$5"" }'

done
echo send
) | \
nsupdate -v

# Fetch and update A and AAAA records of all available FILTER domain names
for filter in ${FILTERS} ; do
(
echo server localhost
echo zone ${ZONE}
echo update delete ${filter}.${ZONE} a
echo update delete ${filter}.${ZONE} aaaa
for proto in A AAAA ; do
dig +noall +answer -t ${proto} -p 15353 @52.37.101.214 ${filter}.${ZONE} | \
awk '{ print "update add "$1" 3600 "$4" "$5"" }'
done
echo send
) | \
nsupdate -v
done