How To Prevent FreeBSD's Base ntpd(8) From Binding To All Interfaces
Particularly useful with jail hosts
For quite some time I have been using openntpd instead of FreeBSD's base ntpd(8), exclusively because of the latter's tendency to bind to all available interfaces and addresses, and its former inability to be configured in a way that it binds to specific IP address. Hhowever, it appears that from FreeBSD 11.1 onwards we can specify ntpd's listen IP address(es). The following article explains how to bind FreeBSD's base ntpd to single IPv4 address, and IPv4 loopback address.
To Cut A Long Story Short
In order to bind FreeBSD's base ntpd to single IPv4 address and IPv4 loopback address, and restrict its usage to clients on the same subnet, use the following ntp.conf:
tos minclock 3 maxclock 6
pool 0.freebsd.pool.ntp.org iburst
restrict default limited kod nomodify notrap noquery nopeer
restrict source limited kod nomodify notrap noquery
restrict 127.0.0.1
restrict 192.0.2.0 mask 255.255.255.0 nomodify notrap noquery nopeer # <--- CHANGE THIS TO YOUR SUBNET
leapfile "/var/db/ntpd.leap-seconds.list"
interface ignore wildcard
interface listen 192.0.2.36 # <--- CHANGE THIS TO SERVER'S IP ADDRESS
Make sure to adjust lines ending with "CHANGE THIS" for your environment
Original Article
This article was originally written in 2017, when production FreeBSD was at version 11.1. At the time, ntp.conf already had interface option, but it wasn't yet described in FreeBSD's ntp.conf manpage. All of the logic in the article below still apply, but some statements are no longer true.
Setting default NTP server in FreeBSD is easy. Just add 'ntpd_enable="YES"' to rc.conf, start the daemon with 'service ntpd start' and you are good to go. However, if you intend to use jails you will need to do a few more things. "EXAMPLES" section of jail(8), under "Setting up the Host Environment" reads:
First, set up the real system's environment to be "jail-friendly". For consistency, we will refer to the parent box as the "host environment", and to the jailed virtual machine as the "jail environment". Since jails are implemented using IP aliases, one of the first things to do is to disable IP services on the host system that listen on all local IP addresses for a service. If a network service is present in the host environment that binds all available IP addresses rather than specific IP addresses, it may service requests sent to jail IP addresses if the jail did not bind the port.
Let's check our network services and their binds:
# netstat -an
Active Internet connections (including servers)
Proto Recv-Q Send-Q Local Address Foreign Address (state)
tcp4 0 0 192.0.2.36.22 192.0.2.45.46309 ESTABLISHED
tcp4 0 0 192.0.2.36.22 *.* LISTEN
udp4 0 0 192.0.2.36.123 *.*
udp4 0 0 127.0.0.1.123 *.*
udp6 0 0 fe80::1%lo0.123 *.*
udp6 0 0 ::1.123 *.*
udp4 0 0 *.123 *.*
udp6 0 0 *.123 *.*
Last two lines show that ntpd listens on wildcard address (any available), for both IPv4 and IPv6, on udp port 123. We should change this so it listens only on addresses we want. Now, although it can't be found in manpage for ntp.conf(5), I found quite recent article on NixCraft which correctly states that an interface directive can be used to control ntpd's binding to IP adresses.
FreeBSD has since upgraded ntpd.conf manpage. Statement above was applicable to FreeBSD 11.1.
Here are the two lines I have appended to default ntp.conf in order to get ntpd to listen on single IPv4 address only:
interface ignore wildcard
interface listen 192.0.2.36
I also added a line to limit service to hosts on the same subnet:
restrict 192.0.2.0 mask 255.255.255.0 nomodify notrap noquery nopeer
Here's my complete ntp.conf:
tos minclock 3 maxclock 6
pool 0.freebsd.pool.ntp.org iburst
restrict default limited kod nomodify notrap noquery nopeer
restrict source limited kod nomodify notrap noquery
restrict 127.0.0.1
restrict 192.0.2.0 mask 255.255.255.0 nomodify notrap noquery nopeer # <--- CHANGE THIS TO YOUR SUBNET
leapfile "/var/db/ntpd.leap-seconds.list"
interface ignore wildcard
interface listen 192.0.2.36 # <--- CHANGE THIS TO SERVER'S IP ADDRESS
After (re)starting of ntpd daemon, we should see it bound to 127.0.0.1 and 192.0.2.36 only. Let's check with netstat:
# netstat -an
Active Internet connections (including servers)
Proto Recv-Q Send-Q Local Address Foreign Address (state)
tcp4 0 0 192.0.2.36.22 192.0.2.45.46309 ESTABLISHED
tcp4 0 0 192.0.2.36.22 *.* LISTEN
udp4 0 0 192.0.2.36.123 *.*
udp4 0 0 127.0.0.1.123 *.*
udp6 0 0 ::1.123 *.*
Ok, no more wildcards in "Local Address" column, which is good. But I don't use IPv6 on this server (yet), so I'd like to prevent ntpd to listen on localhost's IPv6 address as well. This part is not accomplished in ntp.conf, but by passing appropriate flags to ntpd in rc.conf.
Let's check which are default flags for ntpd:
# cat /etc/defaults/rc.conf | grep ntpd_flags
ntpd_flags="" # Additional flags to ntpd
We can now paste above line into rc.conf and slightly modify it (add '-4'), in order to instruct ntpd to listen on IPv4 addresses only. Our ntpd-related portion of rc.conf looks as follows:
ntpd_enable="YES"
ntpd_flags="-4"
After 'service ntpd restart', we can use netstat to confirm that ntpd indeed listens only on specified IPv4 address, and IPv4 loopback:
# netstat -an
Active Internet connections (including servers)
Proto Recv-Q Send-Q Local Address Foreign Address (state)
tcp4 0 0 192.0.2.36.22 192.0.2.45.46309 ESTABLISHED
tcp4 0 0 192.0.2.36.22 *.* LISTEN
udp4 0 0 192.0.2.36.123 *.*
udp4 0 0 127.0.0.1.123 *.*