Bringing E-Mail Server In-House - Part 1:
Introduction and DNS

Stupid laws drafted/created by stupid people. This article is the first (possibly of several) detailing the steps I have taken to take control of my e-mail services.

The Issues

Security, Privacy, Terrorists, Activists, blah, blah, blah

Blah, blah, blah? Yeah, or in other words hearing "blah de blah" whenever someone talks about "the issues". What are the issues? Those words that make the majority of people tune out.

But people on both sides with an argument/view don't tune out.

If You Have Nothing To Hide

Some will say that in order to prosecute pedophiles the "authorities" need to know who you communicate with, the content of that communication, how often you communicate with so-and-so, whether you know the price of milk, the last time you bought baked beans, your fingerprints, whether your diet matches the amount of toilet paper you use, and anything juicy that can be used to blackmail you. This is commonly called the "if you have nothing to hide" argument.

Privacy

Privacy is generally the other side of the argument, but when you're up against people who think that GCHQ need videos of your colonoscopies so you can be identified by sticking a camera up your arse it is a bit hard to come up with a "would you...?" argument.

Privacy at its simplest is about being in control versus being controlled. I believe all my social media is set to public, at least as far as tweets/posts are concerned.

Direct Messages on twitter are used by companies to receive identifiable information to help with customer support, so I don't want "this proves I'm me" to be made available to others (such as News of the World) through cracking, backdoors, or bribable "authorities".

Now, someone who records and publishes every sexual encounter they have probably doesn't have a problem with someone getting hold of naked pictures of them, and they may use social media so much they "Check In" when visiting sexual health clinics. They may even go so far as to monitor all their health stats and publish their heart rate for every second of the day. They may have said at some point on social media that they have nothing to hide.

Lie detectors aren't reliable/trustworthy, but the "authorities" would be so grateful to be able to analyse every social media post ever made and compare it to any heart rate changes at the time the comment was being composed. Throw in a perspiration sensor and respiration sensor (technology is probably not there yet, although an O2 sat sensor probably exists that can act in a similar way) and that is probably the equivalent of supplying a polygraph for everything you've ever posted.

Anyway, privacy and security go hand in hand with control. If you have no control over your privacy, you have no control over your security. If you have no control over your security, you have to trust those that do have control not to lose control. In this context, by "lose control" I mean to no longer have full control, in a similar way to having your domain name hijacked because your registrar gave control to someone who had some of your personally identifiable information to hand.

Control

Control. The more people that have control over your data storage, security systems, and communications, the less control you have.

If you travel somewhere, you may think you have control over getting there, but you (and others travelling) have delegated control of traffic flow to those that control the traffic lights. When the traffic lights break down (and they are at a junction where traffic flow problems are not caused by the lights functioning properly) you can get annoyed at the party responsible for managing them. If it is a power cut, you (and the people you were originally annoyed with) can get annoyed at the power company.

If some idiot cut through a cable somewhere, everyone can blame them. If they were given plans that were inaccurate, they get the blame (although whether the person looking at the plans should have double-checked the accuracy might lead to an argument over blame). Even then, the power company might be slow to respond so they might still be blamed, and the lights could have been converted to LED and given backup power so those that manage the lights could still be attributed some blame.

The point being that the less control you have, the more things that can go wrong. You could blame your GPS for taking you the direction you took, you can blame fate for making you late, and if you previously argued with someone travelling with you that the direction you were going was going to be the most efficient they can blame you. The more things that can go wrong, the more likely something going wrong is not a simple "this went wrong" but a cascading event of failures.

If you asked your registrar to renew your domain name, and they failed to do so, your domain (for UK domains) might get suspended and e-mails to that domain stop working (and e-mails sent from that domain get ignored if certain validation checks are used).

On the flip side, the more control you have, the more likely it is that you are to blame for a fault (or data breach). If you delegate security of your data to a third-party you can probably blame them, but that is assuming you didn't cause the issue as there are typically "does not cover stupidity" clauses in contracts.

This is the point I'm trying to make: If you have as much control as possible, and do everything correctly, in all likelihood you are not only not to blame for an issue but you can determine who is to blame. Since this article is about bringing e-mail in-house, the most common thing I expect to encounter is "you should have received the e-mail". When you control everything, you can log everything. You can actually prove that not only are you not to blame, but the mail log can provide evidence that, for example, their mail server made no attempt to connect to your mail server, or that their SPF/DKIM/etc. keys and/or policies resulted in the mail being rejected.

And here is the main issue with taking control of your e-mail. To do e-mail correctly you need to not only make sure you do everything correctly, but that when something like DMARC comes along you adapt.

DMARC

Some mailing list managers would still be using gopher (or similar) going by their complaints about having to adapt to DMARC. Some of them blacklisted all messages from Yahoo customers because they didn't want to adapt. Then along came AOL, and they still refused to adapt. Outlook and Comcast adopted DMARC and suddenly the major mailing list software developers decided to adapt.

Suddenly mailing list software was compatible with DMARC and the reason the mailing list managers were to be fully blamed for not working properly was because they refused to change how they did things (the equivalent to a bank sticking with SSL 2.0 and not caring about users/customers even after being made aware of issues).

To add a further DMARC point, I have been controlling my e-mail (albeit not in-house) for several years as well as my DNS servers (although I have since added some slave DNS servers that I do not have full control over).

When I was analysing an issue, I noticed a lot of _dmarc DNS lookups. At that time there was nothing I could find through Google about DMARC. As it was Google (some Googlemail/Gmail hostname, don't have the logs to be more exact) asking for _dmarc.mydomain.example.com, as well as asking for the SPF and DKIM records (and A/AAAA records) I knew it was something to do with e-mail. I assumed it must be a new mail security/policy thing, and every so often I would look up DMARC and watched it evolve to the point that it got a specification and was added to postfix.

I cannot say when I implemented DMARC, but I do know that my first DMARC report was received on 16th September 2012. My memory problems (and apparent lack of logging everything I did when I made the change) means I do not know if the date of that first report is when I implemented DMARC or if it was when I changed my DMARC policies so that I started to say "please send me reports!" I haven't analysed the reports as of yet, but it is something that I may do in the future.

Something may come along and you might think "I really need something like that" so you look at it, and give it a try to see if it does what you need. The more control you have over your e-mail, the less hurdles there will be in trialling something.

The Plan

As with everything, a plan is needed. I'm going to use an ordered list here and use the UTF-8 tick mark (✓) and cross marks (✗) to indicate progress.

  1. Move away from Gmail. ✗
    1. Decide upon a domain for my new e-mail address(es). ✓
    2. Start changing my registered e-mail address with those that e-mail me. ✓
    3. Receive 0 e-mails that are not spam for a 12 month period. ✗
  2. Move away from my VPS for e-mail. ✗
    1. Set-up home server as mail server. ✗
    2. Set-up my VPS as a forwarding mail server. ✗
    3. Do stuff. ✗

Set-up Home Server as a Mail Server

Whilst writing this I came across the first issue I am going to have - pdnsd (what I use as a DNS caching server at home) does not recognise DNS type SPF or TYPE99.

The problem I'm going to have is obvious to me - an SPF lookup failure results in my mail server saying the equivalent to "sorry, try again later".

The reason I am strict on SPF (and other) checks is because some spammers are actually using the fact some mail admins are lenient on DNS setup issues and let spam through.

If you have an invalid SPF (or SPF/TXT) record, there is more likelihood a spammer will spoof your domain because there is more chance of the spam not being rejected. Ergo, the first thing I need to do before even thinking about postfix is looking for a suitable DNS caching server.

DNS Caching Server

A DNS caching server is used on my LAN to reduce the delay in DNS lookups made by connected machines/devices. For example, DNS lookups of CDNs are only made once when there is no cached entry or the entry is stale, and as a result lag when connecting to sites is reduced.

As I intend to trial DNSSEC once Hurricane Electric's DNS service supports it (I use HE for slave DNS server(s)), I need a DNS caching server that can handle:

  1. SPF records
  2. DNSSEC records
  3. DNSCurve/DNSCrypt
  4. IPv6

The obvious thing I need to do is look for a DNSSEC capable caching proxy. In theory, if it supports DNSSEC then it should do the other stuff I need it to. A quick Google and a bit of time looking at a Wikipedia comparison page and the choice appears to be between BIND version > 9.x or PowerDNS version > 3.0. Whilst looking at this, I am unsure whether I will use one of those or NSD for the DNS on my server when I start looking at DNSSEC.

The PowerDNS Recurser does not support DNSSEC validation. It looks like there might be a PowerDNS Validator that will handle that. Do I really want to use BIND though?

So, what I want is a DNS caching, DNSSEC-validating, AAAA and SPF supporting, recursive server that is free. I am fine with multiple servers doing their own thing as djbdns/dbndns currently do on my VPS (djbdns, axfrdns, etc).

My decision seems to be that I will use Unbound for the caching server, and NSD for the authoritative servers.

The next issue, of course, is the fact that I do not want my ISP snooping on my DNS lookups (or messing with DNS resolution). For me to implement DNSSEC validation on my in-house caching server, I need to implement DNSSEC validation on my VPS caching nameserver.

Unfortunately, my IPv6 ULA addressing for DNS servers (allowing a lot of server changes before reusing a DNS server IP address) only applies to my public authoritative DNS servers. The reason is one of need - a fixed IP address for LAN resolution that never changes means no issues on machines/devices that don't get the DNS resolver IP addresses via DHCPv6.

Installing Unbound

Before I think about installing a new DNS caching server, I need to know how I'm currently doing things. This means knowing what IPs pdnsd is listening on, what IPs my home server uses to resolve addresses (internally), and what IPs pdnsd uses to talk to my VPS:

sudo netstat -antup | grep pdnsd
tcp6       0      0 :::53                   :::*                    LISTEN      3334/pdnsd  
udp6       0      0 :::53                   :::*                                3334/pdnsd

cat /etc/resolv.conf
nameserver fdd7:5938:e2e6:1::b:53
nameserver 2001:470:20::2
nameserver 74.82.42.42

sudo pdnsd-ctl status | grep -A 6 "Server 1"
Server 1:
------
        label: dns2.watfordjc.bit
        ip: fcf4:90db:f24c:72ca:df4d:b9ee:be0b:c37d
        server assumed available: yes
        ip: 2001:470:1f09:38d::fcf4:53
        server assumed available: yes

The first issue will be that pdnsd is listening on all IPs (iptables restricts access). The second issue is the upstream IP addresses are also deliberately fixed so that a lot of thinking is needed to modify them as they aren't part of my future-proofed addressing scheme. This is already covered though, because pdnsd uses Hurricane Electric DNS as Server 2 and Google DNS for Server 3 (backup DNS resolvers) so I should be able to prevent any downtime when changing things on my VPS. More on this issue later though.

That fdd7 ULA IP is the one I have given to pdnsd. If I install Unbound and bind it to the next reserved DNS Caching Server IP (fdd7:5938:e2e6:1::c:53) I should avoid the situation where pdnsd and Unbound are racing to get the IP and port first. After thorough testing and everything is working perfectly I can update the DHCPv6 DNS server(s). Time then to add that IP address to my IPv6 scripts.

sudo nano /etc/init.d/ipv6-addresses

start() {
...
        /bin/ip -6 addr add fdd7:5938:e2e6:1::c:53/128 dev eth0
...
}

stop() {
...
        /bin/ip -6 addr del fdd7:5938:e2e6:1::c:53/128 dev eth0
...
}

sudo /etc/init.d/ipv6-addresses start
sudo ifconfig | grep :c: 
          inet6 addr: fdd7:5938:e2e6:1::c:53/128 Scope:Global


sudo nano /etc/network/ip6tables.bak

...
-A in-new -d fdd7:5938:e2e6:1::c:53 -p tcp -m tcp --dport 53 -j permitted-dns
-A in-new -d fdd7:5938:e2e6:1::c:53 -p udp -m udp --dport 53 -j permitted-dns
...

sudo /etc/init.d/ipv6tables start
sudo ip6tables -L -n -v | grep :c: 
    0     0 permitted-dns  tcp      *      *       ::/0                 fdd7:5938:e2e6:1::c:53/128  tcp dpt:53
    0     0 permitted-dns  udp      *      *       ::/0                 fdd7:5938:e2e6:1::c:53/128  udp dpt:53

With all that done there should be zero issues on boot, so all that is left in this section is to install Unbound.

sudo apt-get update
sudo apt-get install unbound 
[....] Starting recursive DNS server: unbound
[1412893302] unbound[9845:0] error: bind: address already in use
[1412893302] unbound[9845:0] fatal error: could not open ports
 failed!

And, of course, to tell unbound what IP address it should use.

sudo nano /etc/unbound/unbound.conf

...
server:
...
    interface: fdd7:5938:e2e6:1::c:53
    verbosity: 5

sudo service unbound start 
[....] Starting recursive DNS server: unbound
[1412893760] unbound[10097:0] debug: creating udp6 socket fdd7:5938:e2e6:1::c:53 53
[1412893760] unbound[10097:0] error: bind: address already in use
[1412893760] unbound[10097:0] fatal error: could not open ports
 failed!

Of course it failed. pdnsd is listening to port 53 on all IP addresses. Time to see if I can tame it.

sudo nano /usr/local/etc/pdnsd.conf

...
global {
//      server_ip = any;

}
...

sudo service pdnsd stop
sudo service pdnsd start

sudo netstat -antpu | grep pdnsd
tcp6       0      0 fdd7:5938:e2e6:1::b::53 :::*                    LISTEN      10375/pdnsd 
udp6       0      0 fdd7:5938:e2e6:1::b::53 :::*                                10375/pdnsd

sudo service unbound start 
[....] Starting recursive DNS server: unbound
[1412894267] unbound[10496:0] debug: creating udp6 socket fdd7:5938:e2e6:1::c:53 53
[1412894267] unbound[10496:0] debug: creating tcp6 socket fdd7:5938:e2e6:1::c:53 53
[1412894267] unbound[10496:0] debug: creating tcp6 socket ::1 8953
[1412894267] unbound[10496:0] debug: creating tcp4 socket 127.0.0.1 8953
[1412894267] unbound[10496:0] debug: switching log to syslog
. ok

And, finally, tell unbound not to refuse requests from anywhere, since we have a firewall doing that.

sudo nano /etc/unbound/unbound.conf

...
server:
...
    access-control: ::/0 allow

And now a simple test that we have a recursive DNSSEC-validating DNS caching server:

dig +dnssec . SOA  @fdd7:5938:e2e6:1::c:53

; <<>> DiG 9.8.4-rpz2+rl005.12-P1 <<>> +dnssec . SOA @fdd7:5938:e2e6:1::c:53
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 30255
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 14, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;.                              IN      SOA

;; ANSWER SECTION:
.                       86400   IN      SOA     a.root-servers.net. nstld.verisign-grs.com. 2014100901 1800 900 604800 86400
.                       86400   IN      RRSIG   SOA 8 0 86400 20141016170000 20141009160000 22603 . kW1Mqa8zcEEzYKfLSk6QNAVPuFBlUxdeLJ9G37rAREHun2JK5jBMwJ8e VFMU5dw40XfPwk+SJyc7OX/5Io7mdtsLqZ9rkJM9ssRXFg64TOjfMBIW 4wzDoE8pGWIDiTrgaFELPTnVc/6wm8VVsJI1j8QMA70V2UIo5WeI7flv 6hg=

;; AUTHORITY SECTION:
.                       518400  IN      NS      b.root-servers.net.
.                       518400  IN      NS      g.root-servers.net.
.                       518400  IN      NS      m.root-servers.net.
.                       518400  IN      NS      i.root-servers.net.
.                       518400  IN      NS      e.root-servers.net.
.                       518400  IN      NS      c.root-servers.net.
.                       518400  IN      NS      d.root-servers.net.
.                       518400  IN      NS      h.root-servers.net.
.                       518400  IN      NS      a.root-servers.net.
.                       518400  IN      NS      l.root-servers.net.
.                       518400  IN      NS      k.root-servers.net.
.                       518400  IN      NS      f.root-servers.net.
.                       518400  IN      NS      j.root-servers.net.
.                       518400  IN      RRSIG   NS 8 0 518400 20141016170000 20141009160000 22603 . AC1jT7DO1xtuCZZJppHrahLOuHSMlHeOM7N24y0xgdc3nKfPk5NDY+dY RHRogwRlnMYm5m3cHAAzSxB59roNc8zLk3pEyFY1xP+k3vsP5sqIS7o/ CpS19uhETLh/78eGjYBTN4zGLXr1IkM1/4zJ3UtRrYVP+TcReNKB3dTe AYA=

;; Query time: 261 msec
;; SERVER: fdd7:5938:e2e6:1::c:53#53(fdd7:5938:e2e6:1::c:53)
;; WHEN: Thu Oct  9 23:27:29 2014
;; MSG SIZE  rcvd: 612

We have an ad bit set under flags in the response, and the query response time was 261 milliseconds. If we wait a minute or two and repeat the same query, we should see the response has been cached...

dig +dnssec . SOA  @fdd7:5938:e2e6:1::c:53

; <<>> DiG 9.8.4-rpz2+rl005.12-P1 <<>> +dnssec . SOA @fdd7:5938:e2e6:1::c:53
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 5981
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 14, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;.                              IN      SOA

;; ANSWER SECTION:
.                       86185   IN      SOA     a.root-servers.net. nstld.verisign-grs.com. 2014100901 1800 900 604800 86400
.                       86185   IN      RRSIG   SOA 8 0 86400 20141016170000 20141009160000 22603 . kW1Mqa8zcEEzYKfLSk6QNAVPuFBlUxdeLJ9G37rAREHun2JK5jBMwJ8e VFMU5dw40XfPwk+SJyc7OX/5Io7mdtsLqZ9rkJM9ssRXFg64TOjfMBIW 4wzDoE8pGWIDiTrgaFELPTnVc/6wm8VVsJI1j8QMA70V2UIo5WeI7flv 6hg=

;; AUTHORITY SECTION:
.                       518185  IN      NS      b.root-servers.net.
.                       518185  IN      NS      g.root-servers.net.
.                       518185  IN      NS      m.root-servers.net.
.                       518185  IN      NS      i.root-servers.net.
.                       518185  IN      NS      e.root-servers.net.
.                       518185  IN      NS      c.root-servers.net.
.                       518185  IN      NS      d.root-servers.net.
.                       518185  IN      NS      h.root-servers.net.
.                       518185  IN      NS      a.root-servers.net.
.                       518185  IN      NS      l.root-servers.net.
.                       518185  IN      NS      k.root-servers.net.
.                       518185  IN      NS      f.root-servers.net.
.                       518185  IN      NS      j.root-servers.net.
.                       518185  IN      RRSIG   NS 8 0 518400 20141016170000 20141009160000 22603 . AC1jT7DO1xtuCZZJppHrahLOuHSMlHeOM7N24y0xgdc3nKfPk5NDY+dY RHRogwRlnMYm5m3cHAAzSxB59roNc8zLk3pEyFY1xP+k3vsP5sqIS7o/ CpS19uhETLh/78eGjYBTN4zGLXr1IkM1/4zJ3UtRrYVP+TcReNKB3dTe AYA=

;; Query time: 0 msec
;; SERVER: fdd7:5938:e2e6:1::c:53#53(fdd7:5938:e2e6:1::c:53)
;; WHEN: Thu Oct  9 23:31:04 2014
;; MSG SIZE  rcvd: 612

There we go, we have the first stage complete. Of course we're nowhere near installing postfix yet because we still need to do a lot more DNS stuff, including trusting (and asking) our upstream VPS server for our responses, and doing everything so far done on Ubuntu (my home server is Debian, so it shouldn't be that different). Other things I need to do include installing NSD for LAN authoritative DNS, DNSCurve/DNSCrypt stuff, and testing everything works both locally and on the VPS before switching over from pdnsd and dnscache.

There is also the issue of root zones. I need to ensure I can carry on utilising NameCoin and OpenNIC, and get DNSSEC working for them if enabled. With the number of new TLDs being added to the ICANN root, I also need to make sure that new ones cause no problems - at the moment I have a script on my VPS that pulls the TLDs from ICANN and OpenNIC when I manually run it, and "." is not trusted to anyone, which may be impossible with DNSSEC but as I said, it needs investigating.

I will end this article here because of the length, so this will be a multi-part series of articles. I have not actually done any work with DNSSEC before, and this article actually includes my first ever DNS query/response with the DO bit set.

I did not originally intend to cover a lot of things because I thought it was going to be as simple as copying the configuration on my VPS and making some adjustments. Obviously, for me to do everything I want to do, this is going to be a lot more involved than that. Because of that, it is unlikely that this guide (if anyone ever calls it that) will be fully relevant to someone else's setup, nor a "how to" for bringing your own e-mail in-house. As anyone with experience troubleshooting issues will know, however, a page with text that is Googleable and slightly relevant is probably relevant even if it contains a lot of irrelevant stuff in a foreign language.

I shall close on why Unbound was really needed.

dig -tspf thejc.me.uk

; <<>> DiG 9.8.4-rpz2+rl005.12-P1 <<>> -tspf thejc.me.uk
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOTIMP, id: 33460
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;thejc.me.uk.                   IN      SPF

;; Query time: 0 msec
;; SERVER: fdd7:5938:e2e6:1::b:53#53(fdd7:5938:e2e6:1::b:53)
;; WHEN: Thu Oct  9 23:54:45 2014
;; MSG SIZE  rcvd: 29


dig -tspf thejc.me.uk @fdd7:5938:e2e6:1::c:53

; <<>> DiG 9.8.4-rpz2+rl005.12-P1 <<>> -tspf thejc.me.uk @fdd7:5938:e2e6:1::c:53
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 9041
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 3, ADDITIONAL: 4

;; QUESTION SECTION:
;thejc.me.uk.                   IN      SPF

;; ANSWER SECTION:
thejc.me.uk.            7200    IN      SPF     "v=spf1 +a:mail.thejc.me.uk +a:mail3.thejc.me.uk -all"

;; AUTHORITY SECTION:
thejc.me.uk.            60      IN      NS      ns5.thejc.me.uk.
thejc.me.uk.            60      IN      NS      ns7.thejc.me.uk.
thejc.me.uk.            3600    IN      NS      ns5.he.net.

;; ADDITIONAL SECTION:
ns5.thejc.me.uk.        60      IN      A       149.255.99.49
ns5.thejc.me.uk.        60      IN      AAAA    2001:470:1f09:38d::3
ns7.thejc.me.uk.        60      IN      A       149.255.99.50
ns7.thejc.me.uk.        60      IN      AAAA    2001:470:1f09:38d::4

;; Query time: 925 msec
;; SERVER: fdd7:5938:e2e6:1::c:53#53(fdd7:5938:e2e6:1::c:53)
;; WHEN: Thu Oct  9 23:55:23 2014
;; MSG SIZE  rcvd: 242