Improving your email reputation

Posted on Leave a commentPosted in CentOS 7, DNS, Email, Linux, RHEL 7, Security, System Administration

In the past I have looked at, adding Sender Policy Framework (SPF) which looks at the bounce address of an email, I have also looked at SenderID which looks at the FROM address part of the email header, and then there was Domain Keys Identified Mail (DKIM) which signs your emails to confirm that they were indeed sent from an authorised email server (which has a published public key via DNS).

Now the final piece in the email puzzle is DMARC.

What is DMARC?

Very briefly it stands for Domain Message Authorisation Reporting and Conformance.

What does it do?

Two things;

  • Via DNS you (the sender) publish under your domain record an instruction that states whether or not a receiving email server should trust your SPF, SenderID and DKIM.  All three are also published under your domain DNS zone.  You can say whether or not they should reject or quarantine emails that purport to come from your email server but don’t (or do nothing).
  • Receiving information in XML format about how your domain reputation is fairing from a given receiving email server, as and when your users send emails to third parties.

What does the DNS record look like?

It looks like the following;

_dmarc IN TXT "v=DMARC1; p=none; rua=mailto:postmaster@lab.tobyheywood.com"

OK, so if we break this down a little we have the following components;

  • “_dmarc” – This is the name of the TXT record, which recipient email servers will try to retrieve from your DNS when configured to use DMARC.
  • “IN” – Standard part of a BIND DNS record.  Means Internet, nothing more, nothing less.
  • “TXT” – This is the record type.  DMARC utilises the bog standard TXT record type as this was seen as the quickest method to adoption, rather than treading the lengthy path towards a new DNS record type.
  • Now we have the actual payload (note they are separated by semicolons);
    • “v=DMARC1”  this is the version of DMARC
    • “p=none” – We are effectively saying do nothing and we don’t want to confirm or deny that the emails are from us or that the SPF, SenderID or DKIM information should be trusted
    • “rua=postmaster@lab.tobyheywood.com” – Doesn’t need to be included but if you do include this part, then you can expect to receive emails from the 3rd party email servers who have received email(s) from your domain, confirming what they thought of it

Are there other options?

Yes, though I am only going to focus on a couple here;

The “p=” option has three values that you can use;

  • none – Effectively do nothing, this should be set initially whilst you get things set up. Once you have confirmed things look good, then you can start to be a bit more forceful in what you would like other email providers to do with messages which do not come from your email server.
  • “quarantine” – This is were they would potentially pass the email on for further screening or simply decide to put it into the spam/junk folder.
  • “reject” – This is you saying that if a 3rd party receives an email, supposedly from you, but that wasn’t sent from one of the list of approved email servers (SPF or SenderID) or if it doesn’t pass the DKIM test then it should be rejected and not even delivered.

You set your _dmarc record, now what?

We will assume that you DNS zone has replicated to all of your DNS servers and that you have correctly configured the you email server to sign your outbound emails with your DKIM private key.

At this point I would highly advise going to https:///www.mail-tester.com and send a test email (with a realistic subject and a paragraph or two of readable text) to the email address they provide.

Once mail-tester.com has received your test email, they will process the email headers to confirm whether or not SPF, SenderID, DKIM and DMARC are all correctly configured and working.

It is possible that if your DNS servers are not completely aligned and up-to-date, mail-tester.com may be unable to provide an accurate report.  If that happens give it 12 hours and repeat the test again.

 

Credit: Thanks to Mr Darkroom for making the featured image called Checkpoint available on Flickr.

DKIM + Courier-MTA on CentOS7

Posted on 8 CommentsPosted in CentOS 7, DNS, Email, Linux, RHEL 7, Security, SELinux, System Administration

Email.  One of those things which is critical to business and depending on what you read and who you speak to, you may be led to believe that it is dying out in favour of instant messaging technologies.  Well, as of right now, I can’t see it dying out any time soon, though it does come with a really annoying, frustrating, excruciating problem.  Junk mail!  Otherwise know as spam!  It has once again become a bit of a problem for me, especially when the likes of yahoo begin to imped the flow of emails leaving one of the servers I have worked on recently unable to send emails to recipients with Yahoo accounts.

Now, don’t get my wrong.  I don’t hold a grudge with any of the large email service providers for blocking spam which has sadly managed to be sent via a mail server I have some involvement with, but I do wish the world wasn’t such a bad place that we have to continuously fight on our email frontiers to protect our virtual/real name and brand.

So anyway.  On with the show

The server

  • CentOS 7
  • Patched to the nines
  • Courier MTA
  • Blocking of known spammers was enabled
  • Spamassassin was used as a secondary measure should the hard blocks fail
  • SPF is configured for all hosted domains
  • DKIM was not configured
  • DMAC was not configured
  • It *was not* an open relay
  • The time was not in sync, which  didn’t help later down the line

The problem

The server’s “reputation” had been tarnished as someone had managed to start sending spam via the server through a vulnerability which was found in one of the websites hosted on the server.

After reviewing the advice from Yahoo, I started my investigation on how to approach this topic.

A bit of googling, led me to this web site; https://www.strangeworld.com/blog/archives/128. Now for me, there were a few things missing in the instructions, though complete were it was most needed.  So recreating some of the  good work done on the strangeworld.com website and providing my own twist on things here;

DKIM & ZDKIMFILTER Pre-requisites

In order to install zdkimfilter you need to manually compile the code and install (a .spec file will be included in future releases which should mean you can just use rpmbuild to create the RPM package for you).  The machine I needed to install this onto did not have any compilers install for reasons of security, and so my list of pre-requisites was rather long and included more than I would have liked but needs must, and the compilers were removed afterwards.  But anyway, here is the list of commands issued to get everything where it needed to be;

sudo rpm -ivh http://www.elrepo.org/elrepo-release-7.0-2.el7.elrepo.noarch.rpm
sudo yum install gcc
sudo yum install openssl-libs openssl-devel
sudo yum install libopendkim opendkim
sudo yum install libtool libidn2 libidn2-devel
sudo yum install opendbx-devel opendbx-mysql opendbx-utils opendbx

Note.  The addition of the elrepo.org rpm is required as there are a couple of dependencies, which don’t appear to be available in the main CentOS yum repository.

Download, compile and install

Now, the original instructions I followed, (see reference material at bottom of this page), took me through the steps of manually compiling the code for and installing opendkim.  After I had installed it, I found that opendkim is available in the CentOS base yum repo and so I could have avoided that step.  You will be pleased to hear that I have not included those steps here (if you do need to know though, see this blog post – strangeworld.com).

Next up we need to obtain the tar ball containing the source code for zdkimfilter, which was downloaded from; http://www.tana.it/sw/zdkimfilter/.  At the time of writing the current version was v1.5.

Now we have that lets work through the process of compiling and installing it.

wget http://www.tana.it/sw/zdkimfilter/zdkimfilter-1.5.tar.gz
tar zxvf zdkimfilter-1.5.tar.gz 
cd zdkimfilter-1.5
./configure --prefix=/usr/local
make -j4
sudo make install

Configuration

Last on the list of installation steps is configuring zdkimfilter and making sure we have the correct directory structure, etc;

cp /etc/courier/filters/zdkimfilter.conf.dist /etc/courier/filters/zdkimfilter.conf
mkdir /etc/courier/filters/keys
chmod u=rwx,g=rw,o-rwx /etc/courier/filters/keys

Nothing more was needed at this time.

Generate some keys and update your DNS zones

At this point, we should have everything installed and configured that we need, and can now proceed with the steps for generating the necessary private keys which will be used to sign our emails as they leave your courier email server and also the public key that will be published in DNS.

A word of warning.  Not sure how important this is, but when looking at generating the keys using opendkim-genkey, I would advise that you choose your selector name carefully.  Initially I set this to be the same as the domain.  I then went to a couple of dkim testing websites and found that one of them didn’t like the “.” (dot) in the selector name.  At this point I changed my plan slightly (in case this was a more wide spread issue) and made sure there were no periods in the selector name.

cd /etc/courier/filters/keys/
opendkim-genkey -b 2048 -d tobyheywood.com -D /etc/courier/filters/keys -s tobyheywood -r --nosubdomains -v
ln -s tobyheywood.private tobyheywood.com
chown root.daemon tobyheywood.*
(Just making sure ownership is correct)
chmod u=rw,g=r,o-rwx tobyheywood.*
(this will change the permissions on the tobyheywood.private file which contains the private key, and the tobyheywood.txt file which contains the public key)

It’s also worth making sure the directory /etc/courier/filters/keys has the right permissions;

chmod u=rwx,g=rx,o-rwx /etc/courier/filters/keys

And also if you are running SELinux, then it is worth double checking the SELinux security context associated with these newly created files.  In my case, I didn’t have to do anything, but best to check.

Now you need to update your DNS zone file(s) with everything in the .txt file up to and including the last “)”.  You could include the rest if you wish, but it’s purely a comment.  Reload you zone and test.

Testing, testing, 1, 2, 3

I performed two types of test.  The first was to make sure the record was returned correctly when queried by third parties and that there were no issues with the DNS side of things.  The website I preferred was; https://www.mail-tester.com/spf-dkim-check as it was a nice and simple site and worked better than the unnamed first site I tried.

The second part of my test, was to send an email to a yahoo or gmail account to confirm that it was accepted and so that I could review the headers.  This turned out to be a very good move!  The headers of my first test emails showed there was no DKIM key present, which I thought was odd, but that was due to the umask and the keys directory didn’t have the execute bit set for group members.  I have corrected this in the above [rough] instructions.

Another attempt at sending an email showed there was a valid key but that the time on this server was ahead by some 6 minutes.  I then found that NTP hadn’t been enabled and so had to enable this in order to get the time aligned with other servers on the Internet.

My last test email, was a complete success.  The headers showed that everything was as it should be.  The DKIM signature had been accepted.

The next thing I need to read up on and implement for the domain in question is dmarc.  But more on that later.

Reference material

Courier MTA and DKIM

Image credit:  Thanks to Jake Rush for uploading the featured image GotCredit to flickr.com.

Back to basics – Setting up a TFTP server & PXE (PreBoot Environment)

Posted on Leave a commentPosted in CentOS 7, DHCP, DNS, Fedora, RHCE, RHEL 6, RHEL 7, System Administration

Right then.  So far (if you have been following along) we have done the following;

  • Created a local yum repository based on the installation media on the initial server in our sand boxed lab
  • Installed and setup DNS with Forward and Reverse zones
  • Installed and configured dhcpd for the lab network
  • Tested the DNS and dhcp services using a client machine
  • And network enabled our yum repository by exposing the directory using Apache

The final steps to enable an ISO free installation of CentOS 7 into a KVM virtual machine are;

  • Installing, configuring and testing Trivial FTP, adding additional configuration to DHCPd to enable PXE booting and testing that setup (this post)
  • The final piece will be to create our kickstart file from which will define the standard installation on CentOS 7 (maybe splitting out into server and client)

So, lets not waste any time and get our hands dirty and flex our fingers with a bit of typing…

Trivial FTP (tftp)

First things first, lets log on to the server and get the packages installed.  Thankfully they are part of the installation media and therefore part of the yum repository that was set up in the last post.

[toby@rhc-server ~]$ sudo yum install tftp*
Loaded plugins: fastestmirror
baselocal                                                                                                            | 3.6 kB  00:00:00     
Loading mirror speeds from cached hostfile
Resolving Dependencies
-- Running transaction check
--- Package tftp.x86_64 0:5.2-11.el7 will be installed
--- Package tftp-server.x86_64 0:5.2-11.el7 will be installed
-- Finished Dependency Resolution

Dependencies Resolved

============================================================================================================================================
 Package                            Arch                          Version                            Repository                        Size
============================================================================================================================================
Installing:
 tftp                               x86_64                        5.2-11.el7                         baselocal                         35 k
 tftp-server                        x86_64                        5.2-11.el7                         baselocal                         44 k

Transaction Summary
============================================================================================================================================
Install  2 Packages

Total download size: 79 k
Installed size: 112 k
Is this ok [y/d/N]: y
Downloading packages:
--------------------------------------------------------------------------------------------------------------------------------------------
Total                                                                                                       654 kB/s |  79 kB  00:00:00     
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
  Installing : tftp-server-5.2-11.el7.x86_64                                                                                            1/2 
  Installing : tftp-5.2-11.el7.x86_64                                                                                                   2/2 
  Verifying  : tftp-5.2-11.el7.x86_64                                                                                                   1/2 
  Verifying  : tftp-server-5.2-11.el7.x86_64                                                                                            2/2 

Installed:
  tftp.x86_64 0:5.2-11.el7                                          tftp-server.x86_64 0:5.2-11.el7                                         

Complete!

Note, I’ve installed both client and server RPMs on the server. For my tests from a client I will only install the client tftp package.

Next step is to prepare the folder structure where the files will be served from.  Don’t forget to make sure SELinux contexts, etc. are defined correctly otherwise things will not work as expected.

[root@rhc-server lib]# ll -aZ /var/lib/tftpboot
drwxr-xr-x. root root system_u:object_r:tftpdir_rw_t:s0 .
drwxr-xr-x. root root system_u:object_r:var_lib_t:s0    ..

Note that the SELinux type is “tftpdir_rw_t”, we will need to apply this same type to the folder created next.

[root@rhc-server ~]# mkdir /tftpboot
[root@rhc-server ~]# chcon --reference=/var/lib/tftpboot/ /tftpboot
[root@rhc-server ~]# ll -Z /
[.. snip ..]
drwxr-xr-x. root root system_u:object_r:tftpdir_rw_t:s0 tftpboot

I am slightly cheating with the above command as I am using the standard tftp directory SELinux security types and contexts as a reference. Why make things more difficult than they need to be.

And now lets configure the tftp daemon to use this new location by default.

So lets just check where we are;

  • tftp server and client installed? – check!
  • folder structure created, permissions set and SELinux attributes defined correctly – check!
  • tftp server configured? – Nope

Best fix the TFTP configuration side of things before going further;

[toby@rhc-server lib]$ cat /etc/xinetd.d/tftp
# default: off
# description: The tftp server serves files using the trivial file transfer \
#    protocol.  The tftp protocol is often used to boot diskless \
#    workstations, download configuration files to network-aware printers, \
#    and to start the installation process for some operating systems.
service tftp
{
socket_type        = dgram
protocol        = udp
wait            = yes
user            = root
server            = /usr/sbin/in.tftpd
server_args        = -s /tftpboot
disable            = no
per_source        = 11
cps            = 100 2
flags            = IPv4
}

OK, so the remaining task at this point before we start the service is to make sure the firewall is configured to allow connectivity to the tftp service via its LAN interface and also to make sure the hosts.allow file has an entry for the tftp service.  hosts.allow is used by the xinetd processes, and is required in addition to the firewall changes.

Lets get the hosts.allow file out of the way first;

[root@rhc-server ~]# cat /etc/hosts.allow 
#
# hosts.allow	This file contains access rules which are used to
#		allow or deny connections to network services that
#		either use the tcp_wrappers library or that have been
#		started through a tcp_wrappers-enabled xinetd.
#
#		See 'man 5 hosts_options' and 'man 5 hosts_access'
#		for information on rule syntax.
#		See 'man tcpd' for information on tcp_wrappers
#
in.tftp:	ALL

And now for the firewall;

[root@rhc-server ~]# firewall-cmd --zone public --add-service tftp
[root@rhc-server ~]# firewall-cmd --permanent --zone public --add-service tftp
success

It is worth mentioning that if you use the “–permanent” parameter on the command line, it will not be applied immediately.  Now we should be good to start the service and do some tests. We will create a test file to try and copy via tftp before performing the tests.

[root@rhc-server ~]# systemctl enable tftp.socket
ln -s '/usr/lib/systemd/system/tftp.socket' '/etc/systemd/system/sockets.target.wants/tftp.socket'
[root@rhc-server ~]# systemctl reload xinetd

Based on the above the service has started successfully and nothing appears to be out of the ordinary in the journal, so lets proceed with the testing, and here is my test file;

[root@rhc-server ~]# echo "Hello?  Is it me you're looking for?" > /tftpboot/this_is_a_test

[root@rhc-server ~]# ll -Z /tftpboot/
-rw-r--r--. root root unconfined_u:object_r:tftpdir_rw_t:s0 this_is_a_test

Call me paranoid, but I wanted to make sure the file had inherited the SELinux type of “tftpdir_rw_t”.  Which it did 🙂

Testing locally on server

[toby@rhc-server ~]$ tftp -4 localhost
tftp> get this_is_a_test
tftp> quit
[toby@rhc-server ~]$ ls
this_is_a_test
[toby@rhc-server ~]$ cat this_is_a_test 
Hello?  Is it me you're looking for?

Looking good so far! 🙂

Testing remotely from client

Before we can test lets determine if the tftp package is installed, in my case it wasn’t, so I installed it;

[toby@rhc-client ~]$ yum search tftp
Loaded plugins: fastestmirror, langpacks
Determining fastest mirrors
============================================================ N/S matched: tftp =============================================================
syslinux-tftpboot.x86_64 : SYSLINUX modules in /tftpboot, available for network booting
tftp.x86_64 : The client for the Trivial File Transfer Protocol (TFTP)
tftp-server.x86_64 : The server for the Trivial File Transfer Protocol (TFTP)

  Name and summary matches only, use "search all" for everything.
[toby@rhc-client ~]$ yum list tftp
Loaded plugins: fastestmirror, langpacks
Loading mirror speeds from cached hostfile
Available Packages
tftp.x86_64                                                     5.2-11.el7                                                     th_lab_server
[toby@rhc-client ~]$ sudo yum install tftp
[sudo] password for toby: 
Loaded plugins: fastestmirror, langpacks
th_lab_server                                                                                                        | 3.6 kB  00:00:00     
Loading mirror speeds from cached hostfile
Resolving Dependencies
--> Running transaction check
---> Package tftp.x86_64 0:5.2-11.el7 will be installed
--> Finished Dependency Resolution

Dependencies Resolved

============================================================================================================================================
 Package                      Arch                           Version                            Repository                             Size
============================================================================================================================================
Installing:
 tftp                         x86_64                         5.2-11.el7                         th_lab_server                          35 k

Transaction Summary
============================================================================================================================================
Install  1 Package

Total download size: 35 k
Installed size: 48 k
Is this ok [y/d/N]: y
Downloading packages:
warning: /var/cache/yum/x86_64/7/th_lab_server/packages/tftp-5.2-11.el7.x86_64.rpm: Header V3 RSA/SHA256 Signature, key ID f4a80eb5: NOKEY
Public key for tftp-5.2-11.el7.x86_64.rpm is not installed
tftp-5.2-11.el7.x86_64.rpm                                                                                           |  35 kB  00:00:00     
Retrieving key from file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
Importing GPG key 0xF4A80EB5:
 Userid     : "CentOS-7 Key (CentOS 7 Official Signing Key) <security@centos.org>"
 Fingerprint: 6341 ab27 53d7 8a78 a7c2 7bb1 24c6 a8a7 f4a8 0eb5
 Package    : centos-release-7-0.1406.el7.centos.2.3.x86_64 (@anaconda)
 From       : /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
Is this ok [y/N]: y
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
  Installing : tftp-5.2-11.el7.x86_64                                                                                                   1/1 
  Verifying  : tftp-5.2-11.el7.x86_64                                                                                                   1/1 

Installed:
  tftp.x86_64 0:5.2-11.el7                                                                                                                  

Complete!

And now the test from the client.

[toby@rhc-client ~]$ sudo firewall-cmd --zone public --add-service tftp
[sudo] password for toby: 
success
[toby@rhc-client ~]$ tftp rhc-server
tftp> get this_is_a_test
tftp> quit
[toby@rhc-client ~]$ ls
Desktop  Documents  Downloads  Music  Pictures  Public  Templates  test  this_is_a_test  Videos
[toby@rhc-client ~]$ cat this_is_a_test 
Hello?  Is it me you're looking for?
[toby@rhc-client ~]$ sudo firewall-cmd --zone public --remove-service tftp
success

Note. If you don’t temporarily enable the tftp port on the client, the test will fail. I got the follow error via tcpdump which highlighted that the firewall was blocking the request;

23:25:40.388650 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto UDP (17), length 54)
    192.168.20.50.36588 > 192.168.20.1.69: [udp sum ok]  26 RRQ "this_is_a_test" netascii
23:25:40.390312 IP (tos 0x0, ttl 64, id 31747, offset 0, flags [none], proto UDP (17), length 70)
    192.168.20.1.43788 > 192.168.20.50.36588: [bad udp cksum 0xa9c7 -> 0xddd1!] UDP, length 42
23:25:40.390721 IP (tos 0xc0, ttl 64, id 3881, offset 0, flags [none], proto ICMP (1), length 98)
    192.168.20.50 > 192.168.20.1: ICMP host 192.168.20.50 unreachable - admin prohibited, length 78
	IP (tos 0x0, ttl 64, id 31747, offset 0, flags [none], proto UDP (17), length 70)
    192.168.20.1.43788 > 192.168.20.50.36588: [udp sum ok] UDP, length 42

At this point we have now completed the necessary steps to ensure we have a working tftp service.

Setting up PXE

The second part of today’s post covers the steps needed to enable booting from the network to facilitate building machines without the hassle of creating USB bootable images or burning ISO images to CD or DVD.

Out task list for this section is;

  • Add the additional config to the DHCP scope
  • Ensure we have the pxelinux/syslinux installed and copied to the required location
  • Create a basic menu to provide end users with a installation options
  • Test

Configuring DHCP

So, lets start by reminding ourselves what the current dhcpd.conf file looks like;

[toby@rhc-server ~]$ sudo cat /etc/dhcp/dhcpd.conf
[sudo] password for toby: 
#
#  lab.tobyheywood.com dhcp daemon configuration file
#
#  2016-02-22 - Initial creation
#

# Define which IP to listen on.  NOTE. daemon can only listen to one
# IP at a time if defined.
local-address 192.168.20.1;

# option definitions common to all supported networks...
option domain-name "lab.tobyheywood.com";
option domain-name-servers ns.lab.tobyheywood.com;

default-lease-time 600;
max-lease-time 7200;

# Use this to enble / disable dynamic dns updates globally.
#ddns-update-style interim;

# This is the authoritative DHCP server.
authoritative;

# Use this to send dhcp log messages to a different log file (you also
# have to hack syslog.conf to complete the redirection).
log-facility local7;

# Interface which can be accessed from outside the sandbox
# **** NOT IN USE ****
subnet 192.168.122.0 netmask 255.255.255.0 {
}

# The lab network
subnet 192.168.20.0 netmask 255.255.255.128 {
  range 192.168.20.50 192.168.20.99;
  option routers rtr.lab.tobyheywood.com;
}

So in order to get PXE (Preboot eXecution Environment) to function we will need to add a few more lines to the configuration, as highlighted below.

[toby@rhc-server ~]$ sudo cat /etc/dhcp/dhcpd.conf
[sudo] password for toby: 
#
#  lab.tobyheywood.com dhcp daemon configuration file
#
#  2016-02-22 - Initial creation
#

# Define which IP to listen on.  NOTE. daemon can only listen to one
# IP at a time if defined.
local-address 192.168.20.1;

# option definitions common to all supported networks...
option domain-name "lab.tobyheywood.com";
option domain-name-servers ns.lab.tobyheywood.com;

default-lease-time 600;
max-lease-time 7200;

# Use this to enble / disable dynamic dns updates globally.
#ddns-update-style interim;

# This is the authoritative DHCP server.
authoritative;

# Use this to send dhcp log messages to a different log file (you also
# have to hack syslog.conf to complete the redirection).
log-facility local7;

# Interface which can be accessed from outside the sandbox
# **** NOT IN USE ****
subnet 192.168.122.0 netmask 255.255.255.0 {
}

# The lab network
subnet 192.168.20.0 netmask 255.255.255.128 {
  range 192.168.20.50 192.168.20.99;
  option routers rtr.lab.tobyheywood.com;
}

# Additional configuration for PXE booting
allow booting;
allow bootp;
option option-128 code 128 = string;
option option-129 code 129 = text;
next-server 192.168.20.1;
filename "/pxelinux.0";

Setting up the required syslinux files in /tftpboot

During the section above when testing the tftp service on the client, I saw that there may be a shortcut to getting things up and running.  Everything I have read says you need to manually copy the syslinux files into the /tftpboot directory, however, if you search the rpm database with yum for anything tftp related, I see that there is potentially an easier way.

[toby@rhc-server ~]$ yum list tftp
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
Installed Packages
tftp.x86_64                                     5.2-11.el7                                     @baselocal
[toby@rhc-server ~]$ yum search tftp
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
=========================================== N/S matched: tftp ===========================================
syslinux-tftpboot.x86_64 : SYSLINUX modules in /tftpboot, available for network booting
tftp.x86_64 : The client for the Trivial File Transfer Protocol (TFTP)
tftp-server.x86_64 : The server for the Trivial File Transfer Protocol (TFTP)

As you can see there appears to be a syslinux-tftpboot rpm.  So lets see what it gives us;

[toby@rhc-server ~]$ sudo yum install syslinux-tftpboot
[sudo] password for toby: 
Loaded plugins: fastestmirror
baselocal                                                                         | 3.6 kB  00:00:00     
Loading mirror speeds from cached hostfile
Resolving Dependencies
--> Running transaction check
---> Package syslinux-tftpboot.x86_64 0:4.05-8.el7 will be installed
--> Finished Dependency Resolution

Dependencies Resolved

=========================================================================================================
 Package                        Arch                Version                 Repository              Size
=========================================================================================================
Installing:
 syslinux-tftpboot              x86_64              4.05-8.el7              baselocal              425 k

Transaction Summary
=========================================================================================================
Install  1 Package

Total download size: 425 k
Installed size: 1.3 M
Is this ok [y/d/N]: y
Downloading packages:
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
  Installing : syslinux-tftpboot-4.05-8.el7.x86_64                                                   1/1 
  Verifying  : syslinux-tftpboot-4.05-8.el7.x86_64                                                   1/1 

Installed:
  syslinux-tftpboot.x86_64 0:4.05-8.el7                                                                  

Complete!
[toby@rhc-server ~]$ ls /tftpboot/
cat.c32        dmitest.c32   host.c32     ls.c32       pcitest.c32   rosh.c32        vesamenu.c32
chain.c32      elf.c32       ifcpu64.c32  lua.c32      pmload.c32    sanboot.c32     vpdtest.c32
cmd.c32        ethersel.c32  ifcpu.c32    mboot.c32    poweroff.com  sdi.c32         whichsys.c32
config.c32     gfxboot.c32   ifplop.c32   memdisk      pwd.c32       sysdump.c32     zzjson.c32
cpuid.c32      gpxecmd.c32   int18.com    memdump.com  pxechain.com  this_is_a_test
cpuidtest.c32  gpxelinux.0   kbdmap.c32   meminfo.c32  pxelinux.0    ver.com
disk.c32       hdt.c32       linux.c32    menu.c32     reboot.c32    vesainfo.c32

It looks like we have a winner!  Now we just need to make sure that the Preboot environment has a kernel or two to play with;

[root@rhc-server ~]# cp /software/centos7/images/pxeboot/* /tftpboot/centos7/
[root@rhc-server ~]# ls -Z /tftpboot/centos7/
-rw-r--r--. root root unconfined_u:object_r:tftpdir_t:s0 initrd.img
-r--r--r--. root root unconfined_u:object_r:tftpdir_t:s0 TRANS.TBL
-rw-r--r--. root root unconfined_u:object_r:tftpdir_t:s0 upgrade.img
-rwxr-xr-x. root root unconfined_u:object_r:tftpdir_t:s0 vmlinuz

OK, so lets now create the directory which will hold the PXE menus;

[toby@rhc-server ~]$ sudo mkdir /tftpboot/pxelinux.cfg
[sudo] password for toby: 
[toby@rhc-server ~]$ ls -Zd /tftpboot/pxelinux.cfg
drwxr-xr-x. root root unconfined_u:object_r:tftpdir_t:s0 /tftpboot/pxelinux.cfg

And now lets look at what is required to create the menus from which we will be able to select installation options.

[root@rhc-server centos7]# cat /tftpboot/pxelinux.cfg/default 
DEFAULT menu.c32
PROMPT 0
TIMEOUT 300
ONTIMEOUT localdisk
MENU TITLE PXE Network Boot

LABEL localdisk
    MENU LABEL ^Local Hard Drive
    MENU DEFAULT
    LOCALBOOT 0

LABEL Install_CentOS_7_2
    MENU LABEL CentOS 7.2
    KERNEL centos7/vmlinuz
    APPEND initrd=http://rhc-server.lab.tobyheywood.com/centos7/isolinux/initrd.img  inst.repo=http://rhc-server.lab.tobyheywood.com/centos7

At this point, all I wanted to do was prove that the pxe settings in dhcp were correct and that maybe, just maybe, I could build a vm across the network, first time.  No such luck! 🙁  Well, I guess 50% of the way there.

You can skip the next and jump to here if you don’t want to understand the pain I went through to get this operational.

I thought things were going well.  I created a blank VM, made sure to select that I was going to boot from the network to install the OS in Virtual Manager and turned the VM on.

pxeboot_initial_screen

So far so good!

pxeboot_menu

I’m now feel pretty happy with myself.  I select CentOS 7.0 and hit the enter key… and then am presented with the expected Welcome to CentOS 7 screen, from where I can kick off a manual installation.

pxeboot_centos7_initial_install_screen

So all, in all, things look good.  However there is more work to be done, as the next step is to create a kickstart file to define how the base install should look.

Reference Material

Trivial FTP (tftp)

PXE

Featured image taken by Ed Robinson who kindly uploaded it to Flickr.com.  I have made no changes to this image and left it in its original form for your viewing pleasure.  And to give the page a bit of colour 😉

DHCPD and the mysterious “host unknown”

Posted on Leave a commentPosted in CentOS 7, DHCP, DNS, Fedora, Linux, RHEL 7

For those of you following my “back to basics” series, in my last post setting up a dhcp server, I finished up with an error that flummoxed me initially.

Feb 22 22:13:36 rhc-server dhcpd[2682]: ns.lab.tobyheywood.com: host unknown.<br />
Feb 22 22:13:36 rhc-server dhcpd[2682]: rtr.lab.tobyheywood.com: host unknown.

I had tried;

  • pinging the supposedly unknown hosts
    • both locally on the server which has the named daemon on it
    • remotely from the client that had just been assigned an IP address from my newly installed dhcp server
  • used tools such as dig to confirm the zone looked fine
  • double checked the dhcpd.conf file
  • nothing stood out as being odd
  • So, as it was late, I went to bed with the determination that I would research and fix the issue before me!

So I started reading through the dhcpd.conf man page (an online version though no guarantee it’s the latest version, can be found here http://linux.die.net/man/5/dhcpd.conf).

After scanning through the first few sections, I began reading about the steps required to setup Dynamic DNS Updates (ddns) and spied the recommendations regarding securing the dynamic DNS configuration. And something suddenly occurred to me… I hadn’t created a reverse lookup zone!!!

To the bat cave!

Now before I begin, there are two things I should mention;

  1. It’s good to reboot
  2. After rebooting my virtual machines it fixed my issue, but I suspect something had not refreshed as both the DNS and DHCP servers were created in the same evening.  I had also made modifications to my NIC setup to reflect the fact that I now had a local DNS server.
  3. Bonus material, I shall continue with the reverse zone creation steps.

Just to double check that I am setting up my reverse zone, I also consulted the current documentation for Red Hat Enterprise Linux 7 (essential CentOS 7) https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/Networking_Guide/sec-BIND.html#sec-bind-zone.  I guess now is a good time to mention the fact that Red Hat does have some awesome documentation and you really should take the time to read all of it (which I have), as quite often not only do you find out the bits of information you were looking for but also you will find some interesting shortcuts and new ways of doing things.

Anyway…

Creating a reverse zone

So my reverse zone file looks like this

[root@rhc-server data]# cat lab.tobyheywood.com.rr.zone<br />
$ORIGIN 20.168.192.in-addr.arpa.<br />
$TTL 1d<br />
@    IN    SOA    ns.lab.tobyheywood.com.    hostmaster.lab.tobyheywood.com. (<br />
2016022400    ; Serial<br />
6h        ; Refresh<br />
1h        ; Retry<br />
2d        ; Expire<br />
1d )        ; Minimum TTL<br />
;<br />
@    IN    NS    ns.lab.tobyheywood.com.<br />
;<br />
1    IN    PTR    rhc-server.lab.tobyheywood.com.<br />

Annoyingly the formatting seems to ignore tabs and multiple spacing where I put the code snippets on my website but I can assure you it is all neatly indented to ensure easy reading.

And I also added the following into the /etc/named.conf file;

[root@rhc-server data]# cat /etc/named.conf<br />
options {<br />
listen-on port 53 { 192.168.20.1; };<br />
//listen-on-v6 port 53 { ::1; };<br />
directory     &quot;/var/named&quot;;<br />
dump-file     &quot;/var/named/data/cache_dump.db&quot;;<br />
statistics-file &quot;/var/named/data/named_stats.txt&quot;;<br />
memstatistics-file &quot;/var/named/data/named_mem_stats.txt&quot;;<br />
allow-query     { any; };</p>
<p>dnssec-enable yes;<br />
dnssec-validation yes;<br />
dnssec-lookaside auto;</p>
<p>/* Path to ISC DLV key */<br />
bindkeys-file &quot;/etc/named.iscdlv.key&quot;;</p>
<p>managed-keys-directory &quot;/var/named/dynamic&quot;;</p>
<p>pid-file &quot;/run/named/named.pid&quot;;<br />
session-keyfile &quot;/run/named/session.key&quot;;<br />
};</p>
<p>logging {<br />
channel default_debug {<br />
file &quot;data/named.run&quot;;<br />
severity dynamic;<br />
};<br />
};</p>
<p>zone &quot;.&quot; IN {<br />
type hint;<br />
file &quot;named.ca&quot;;<br />
};</p>
<p>zone &quot;lab.tobyheywood.com&quot; IN {<br />
type master;<br />
file &quot;data/lab.tobyheywood.com&quot;;<br />
allow-update { none; };<br />
};</p>
<p>zone &quot;20.168.192.in-addr.arpa&quot; IN {<br />
type master;<br />
file &quot;data/lab.tobyheywood.com.rr.zone&quot;;<br />
allow-update { none; };<br />
};</p>
<p>include &quot;/etc/named.rfc1912.zones&quot;;<br />
include &quot;/etc/named.root.key&quot;;<br />

Now I spotted that “recursion yes” had not be commented whilst I was adding the new zone “20.168.192.in-addr.arpa”.  This is unwanted as I do not want the server to be a caching DNS server, I’m only interested at this time in it providing my internal host details and nothing more.

[root@rhc-server data]# dig -x 192.168.20.1</p>
<p>; &lt;&lt;&gt;&gt; DiG 9.9.4-RedHat-9.9.4-14.el7 &lt;&lt;&gt;&gt; -x 192.168.20.1<br />
;; global options: +cmd<br />
;; Got answer:<br />
;; -&gt;&gt;HEADER&lt;&lt;- opcode: QUERY, status: NOERROR, id: 45831<br />
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 2</p>
<p>;; OPT PSEUDOSECTION:<br />
; EDNS: version: 0, flags:; udp: 4096<br />
;; QUESTION SECTION:<br />
;1.20.168.192.in-addr.arpa.    IN    PTR</p>
<p>;; ANSWER SECTION:<br />
1.20.168.192.in-addr.arpa. 86400 IN    PTR    rhc-server.lab.tobyheywood.com.</p>
<p>;; AUTHORITY SECTION:<br />
20.168.192.in-addr.arpa. 86400    IN    NS    ns.lab.tobyheywood.com.</p>
<p>;; ADDITIONAL SECTION:<br />
ns.lab.tobyheywood.com.    86400    IN    A    192.168.20.1</p>
<p>;; Query time: 0 msec<br />
;; SERVER: 192.168.20.1#53(192.168.20.1)<br />
;; WHEN: Wed Feb 24 23:20:47 GMT 2016<br />
;; MSG SIZE  rcvd: 131<br />

And there we have it, a reverse DNS zone has been born!  Yay!

Back to basics – Setting up a local (internal) DNS server

Posted on Leave a commentPosted in CentOS 7, DNS, Linux, RHEL 7, System Administration

Today’s “back to basics” post is all about setting up a local internal DNS server. Though there are a number of applications out there which will ease the process of setting up DNS and/or DHCP services, I am sticking with what would be used in the enterprise environment and also focusing on doing things manually.

Why manually?? Well, it has been a while since I’ve had to configure named from scratch and so it’s good to remind me how it all fits together. Plus, by knowing how the internals are working (as far as the configuration is concerned) it means if I run into problems, then I’m better placed to fix the issue sooner and with less searching.

So for DNS that would be (IMHO) BIND.  BIND has been around for a very long time and for those of you with an interest in it’s history, take a look at; BIND – Wikipedia.  In CentOS and RHEL you have two options the base BIND packages or an additional package which configures BIND to run in a chroot jail.

Because I am only setting this up for the purpose of a lab, I will not be making use of the chroot version (though in all honesty it doesn’t require much additional effort) and will stick
instead with the base package.  HOWEVER, IF you are going to use BIND on a server which has a public facing interface onto the big
, bad Internet, then without doubt, MAKE SURE YOU USE THE CHROOT package too.  There is no reason not to in my opinion!

Back to the lab installation

</p>
<p>[root@rhc-server ~]# yum install bind -y<br />
Loaded plugins: fastestmirror<br />
Loading mirror speeds from cached hostfile<br />
Resolving Dependencies<br />
--&gt; Running transaction check<br />
---&gt; Package bind.x86_64 32:9.9.4-14.el7 will be installed<br />
--&gt; Finished Dependency Resolution</p>
<p>Dependencies Resolved</p>
<p>============================================================================================================================================<br />
Package                     Arch                          Version                                   Repository                        Size<br />
============================================================================================================================================<br />
Installing:<br />
bind                        x86_64                        32:9.9.4-14.el7                           baselocal                        1.8 M</p>
<p>Transaction Summary<br />
============================================================================================================================================<br />
Install  1 Package</p>
<p>Total download size: 1.8 M<br />
Installed size: 4.3 M<br />
Downloading packages:<br />
Running transaction check<br />
Running transaction test<br />
Transaction test succeeded<br />
Running transaction<br />
Installing : 32:bind-9.9.4-14.el7.x86_64                                                                                              1/1<br />
Verifying  : 32:bind-9.9.4-14.el7.x86_64                                                                                              1/1</p>
<p>Installed:<br />
bind.x86_64 32:9.9.4-14.el7</p>
<p>Complete!</p>
<p>

OK, so now we have it installed we need to create a zone file which will contain all of our required internal DNS zone information.  Zone files are stored in the /var/named/data directory (or if using chroot version of bind /var/named/chroot/var/named/data).  As you can see currently there are no zone files in this location;

</p>
<p>[root@rhc-server data]# pwd<br />
/var/named/data<br />
[root@rhc-server data]# ls<br />
[root@rhc-server data]#</p>
<p>

For my internal DNS I’m going setting up a zone called “lab.tobyheywood.com” and the zone file looks more or less as follows;

</p>
<p>[root@rhc-server data]# cat lab.tobyheywood.com<br />
$TTL 1d<br />
@        IN    SOA    ns.lab.tobyheywood.com.    hostmaster.lab.tobyheywood.com. (<br />
2016022100    ; Serial<br />
1h        ; Refresh<br />
15m        ; Retry<br />
10d        ; Expire (10 days should be enough in the lab)<br />
1h )        ; Negative Cache<br />
;<br />
; Name Servers<br />
IN    NS    ns.lab.tobyheywood.com.<br />
;<br />
; MX Records (Mail eXchange)<br />
;<br />
; CNAME (Canonical Name a.k.a. Aliases)<br />
provision    IN    CNAME    ns.lab.tobyheywood.com.<br />
;<br />
; A Records (IPv4 addresses)<br />
ns        IN    A    192.168.20.1<br />
rhc-server    IN    A    192.168.20.1</p>
<p>;<br />
; AAAA Records (IPv6 Records)<br />
; - Not used yet but at a later stage in the lab</p>
<p>

As you can probably spot, I am using the IPv4 address 192.168.20.1 as the primary IP address for my server.

The next step is to updated the /etc/named.conf file so that it is listening on the right ip address and also to define the zone I have just created.

<br />
//<br />
// named.conf<br />
//<br />
// Provided by Red Hat bind package to configure the ISC BIND named(8) DNS<br />
// server as a caching only nameserver (as a localhost DNS resolver only).<br />
//<br />
// See /usr/share/doc/bind*/sample/ for example named configuration files.<br />
//</p>
<p>options {<br />
listen-on port 53 { 192.168.20.1; };<br />
//listen-on-v6 port 53 { ::1; };<br />
directory     &quot;/var/named&quot;;<br />
dump-file     &quot;/var/named/data/cache_dump.db&quot;;<br />
statistics-file &quot;/var/named/data/named_stats.txt&quot;;<br />
memstatistics-file &quot;/var/named/data/named_mem_stats.txt&quot;;<br />
allow-query     { any; };</p>
<p>dnssec-enable yes;<br />
dnssec-validation yes;<br />
dnssec-lookaside auto;</p>
<p>/* Path to ISC DLV key */<br />
bindkeys-file &quot;/etc/named.iscdlv.key&quot;;</p>
<p>managed-keys-directory &quot;/var/named/dynamic&quot;;</p>
<p>pid-file &quot;/run/named/named.pid&quot;;<br />
session-keyfile &quot;/run/named/session.key&quot;;<br />
};</p>
<p>logging {<br />
channel default_debug {<br />
file &quot;data/named.run&quot;;<br />
severity dynamic;<br />
};<br />
};</p>
<p>zone &quot;.&quot; IN {<br />
type hint;<br />
file &quot;named.ca&quot;;<br />
};</p>
<p>zone &quot;lab.tobyheywood.com&quot; IN {<br />
type master;<br />
file &quot;data/lab.tobyheywood.com&quot;;<br />
};</p>
<p>include &quot;/etc/named.rfc1912.zones&quot;;<br />
include &quot;/etc/named.root.key&quot;;</p>
<p>

To maintain a level of sanity, lets just do a couple of checks to make sure everything is, as it should be.

</p>
<p>[root@rhc-server etc]# named-checkzone lab.tobyheywood.com /var/named/data/lab.tobyheywood.com<br />
zone lab.tobyheywood.com/IN: loaded serial 2016022100<br />
OK<br />
[root@rhc-server etc]# named-checkconf<br />
[root@rhc-server etc]# echo $?<br />
0<br />
[root@rhc-server etc]#</p>
<p>

And now time to enable the service, start it and then test that I have got everything right.  Also as part of this step I have installed bind-utils so that I can confirm the zone is active by way of querying the name server.;

</p>
<p>[root@rhc-server etc]# systemctl enable named<br />
ln -s '/usr/lib/systemd/system/named.service' '/etc/systemd/system/multi-user.target.wants/named.service'<br />
[root@rhc-server etc]# systemctl start named.service<br />
[root@rhc-server etc]# yum install bind-utils -y<br />
[root@rhc-server etc]# ping rhc-server.lab.tobyheywood.com -c 5<br />
PING rhc-server.lab.tobyheywood.com (192.168.20.1) 56(84) bytes of data.<br />
64 bytes from 192.168.20.1: icmp_seq=1 ttl=64 time=0.021 ms<br />
64 bytes from 192.168.20.1: icmp_seq=2 ttl=64 time=0.093 ms<br />
64 bytes from 192.168.20.1: icmp_seq=3 ttl=64 time=0.091 ms<br />
64 bytes from 192.168.20.1: icmp_seq=4 ttl=64 time=0.053 ms<br />
64 bytes from 192.168.20.1: icmp_seq=5 ttl=64 time=0.093 ms</p>
<p>--- rhc-server.lab.tobyheywood.com ping statistics ---<br />
5 packets transmitted, 5 received, 0% packet loss, time 4002ms<br />
rtt min/avg/max/mdev = 0.021/0.070/0.093/0.029 ms<br />
[root@rhc-server etc]# dig ns.lab.tobyheywood.com</p>
<p>; &lt;&lt;&gt;&gt; DiG 9.9.4-RedHat-9.9.4-14.el7 &lt;&lt;&gt;&gt; ns.lab.tobyheywood.com<br />
;; global options: +cmd<br />
;; Got answer:<br />
;; -&gt;&gt;HEADER&lt;&lt;- opcode: QUERY, status: NOERROR, id: 56872<br />
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 1</p>
<p>;; OPT PSEUDOSECTION:<br />
; EDNS: version: 0, flags:; udp: 4096<br />
;; QUESTION SECTION:<br />
;ns.lab.tobyheywood.com.        IN    A</p>
<p>;; ANSWER SECTION:<br />
ns.lab.tobyheywood.com.    86400    IN    A    192.168.20.1</p>
<p>;; AUTHORITY SECTION:<br />
lab.tobyheywood.com.    86400    IN    NS    ns.lab.tobyheywood.com.</p>
<p>;; Query time: 0 msec<br />
;; SERVER: 192.168.20.1#53(192.168.20.1)<br />
;; WHEN: Sun Feb 21 18:50:48 GMT 2016<br />
;; MSG SIZE  rcvd: 81</p>
<p>

The only thing that I had done ahead of time was to make sure that my /etc/resolv.conf file was updated to reflect the correct search and nameserver parameters.  So all in all looking good.

Till next time.

UPDATE!!!!

Err, well.  That’s embarrassing!  So as part of the above post though it work, somethings will not.  More specifically, if you try to perform a reverse look up it will fail miserably.  So to complete the picture, you can see what I did with regards the reverse zone here.