Improve the way you make use of FreeBSD in your company.
Find out more about what makes us the most reliable FreeBSD development organization, and take the next step in engaging with us for your next FreeBSD project.
FreeBSD Support FreeBSD DevelopmentAdditional Articles
Here are more interesting articles on FreeBSD that you may find useful:
- Winter 2024 Roundup: Storage and Network Diagnostics
- FreeBSD 14 replaces Sendmail with DMA
- Fall 2024 Top Reads for Open Source Enthusiasts
- Deploying pNFS file sharing with FreeBSD
- Open Source FreeBSD NAS: Maintenance Best Practices
Understanding Core Internet Services
Among the many crucial protocols and services that underlie the modern internet, there are two in particular that are typically ignored by sysadmins and enterprises, but offer a lot of reasons to pay attention to them. These services are the Domain Name Service (DNS), and the Network Time Protocol (NTP). Without these, none of the devices under your control could visit a web page or keep time.
Almost everyone outsources these services to a motley collection of their ISPs, IoT devices, and commercial operating systems. But, there are several reasons to not do this. This article, the first in a two-part series, focuses on taking control of DNS services and the benefits it brings to your infrastructure.
What Is DNS?
Domain Name Service (DNS) is an essential protocol that translates human-readable domain names into IP addresses, allowing devices to communicate on the internet. Every packet that flows across the internet is IPv4 (or, IPv6, but we will simplify the discussion by assuming IPv4 throughout). The first bytes of each of these packets tell the routers of the internet everything they need to know about the packet. Among this information are two fields that show the packet’s origin and destination IP address, each consisting of four bytes.
It may come as a shock that there is no place nor meaning to address packets with familiar host names like “google.com” or “www.ebay.com” in source or destination fields! Somehow, the IP address[1] must be determined and placed in those packets by your operating system[2]. The service that does this is DNS[3], and the host that does this for you is the DNS server.
No matter how fast your computer and network are, you are not going anywhere on the internet until some DNS server makes this translation for you. You typically have no idea where this DNS server is; it could be thousands of miles away. Who runs it? How did your devices even learn about it and know to use it? How many DNS servers are out there? How do they all keep their answers straight? Is there a final, authoritative, DNS server to rule them all? Great questions!! We will see them largely answered in what follows.
To illustrate how DNS operates in practice, let’s examine a real-world packet exchange and understand the steps involved in resolving domain names.

How Does DNS work?
How DNS Queries and Responses Work
Classic DNS, which still accounts for most DNS, is a simple call-and-response service dating back to approximately 1985. The modern instantiation of DNS is almost wholly described by the Internet Engineering Task Force (IETF) in RFC 1034 and RFC 1035.
As far as an end user (client) is concerned, DNS works as follows: A specially crafted query packet (typically UDP, but can be TCP) is sent, almost always on port 53, to a known “nameserver”. While several different types of information can be requested from a nameserver, the most basic case is querying for an “A record” (or “AAAA record”, in the case of IPv6), which requests resolution to one or more appropriate IP addresses for the queried domain.
The nameserver will typically reply with one of three cases. First, it may provide the requested A record. Second, it might return a CNAME record, where the server says, “The domain you queried should be queried under this other name.” Third, an error may be returned to explain why the requested record was not provided.
For example, in Figure 1, packet 14 shows the initial query for “www.etsy.com”, packet 15 resolves it to a CNAME, packet 16 is our local system now requesting the resolution for the CNAME, and packet 17 shows four valid IP addresses, any of which may be used by the querying system to reach the site. Note that this exchange took only 18ms. DNS servers can also return a plethora of other types of records, including MX records for routing mail, and relatively freeform TXT records with a variety of interesting uses.
The Recursive Resolution Process
The resolution mechanism itself is typically recursive. That means when you query a nameserver, that nameserver (if the answer is not cached) queries an upstream nameserver, and so on up to the root of the DNS tree. For most users, the buck stops at the final, authoritative “root nameservers” managed by ICANN[4], physically numbering approximately 2000 as of this writing. In reality, very few queries will ultimately require resolution by a root nameserver, since each recursive host typically has significant caches of previously provided DNS answers.
How to Set Up and Run Your Own DNS Server
Unless you take other steps, the nameserver’s address is typically established dynamically in the secondary information automatically provided during the same initial DHCP configuration in which you also receive your IP address. If you are behind a NAT router (most people are), it gets DNS nameserver information from the internet service provider (ISP) during its own DHCP exchange. The hosts in your network will either receive this same information from your router, or the router will offer to provide its own DNS services to you using that external nameserver. In either case, you are relying on the provided external nameserver. These ISP-provided nameservers can work adequately, but come with several limitations and potential drawbacks.
Why Relying on ISP Nameservers Isn’t Ideal
- Your ISP can easily monitor (and sell) information on what sites you visit and what businesses you engage with,
- You create a lot of unnecessary internet traffic,
- The ISP may have little incentive to provide a very performant DNS server.For this reason, your overall performance could be limited by potentially poor ISP DNS performance,
- You fail to take advantage of local LAN-wide caching of DNS lookups.
The first two of these are compelling reasons requiring no further explanation. As for the other two performance-related reasons, they are underappreciated. The devices inside of a LAN (an office, or a home) are likely to be interested in many of the same sites, and thus, many of the same DNS lookups. Therefore, it makes a great deal of sense for a LAN to have a shared, universal DNS cache for its hosts, against which queries are resolved in just a few milliseconds and involve little or no internet traffic.
Choosing Software for Your DNS Server Setup
Fortunately, running your own caching, recursive DNS servers for a home or small office requires no special technological mastery and is so lightweight that you are likely to be quite hard-pressed to measure any load[5]. In what follows, we explain how this might be accomplished on FreeBSD, though the software mentioned and techniques and considerations should apply to all server operating systems equally.
As you would imagine, there are several well-regarded pieces of software that provide DNS functionality. An exhaustive comparison of these is beyond the scope of the article. As of this writing, the FreeBSD Project’s “ports” tree contains 241 DNS-related software packages in the “dns” directory, many of which are full-fledged DNS servers ranging from extremely lightweight and basic to the most byzantine and matronly options for a DNS server setup.
The software that the FreeBSD project has adopted as its default DNS resolver, offering a good balance between capability and performance is unbound(8). It can be installed with default options via pkg install dns/unbound. Alternatively, installing this DNS server via ports offers several advantages to more advanced users. These include options to build with or without threading, with and without advanced event handlers, and enable various plugins support. As a result, this provides flexibility for tailoring your DNS server setup to your specific needs.
Configuring Unbound for a Basic Setup
Once you have installed the software, you will be able to edit the (very-well documented) configuration file at /usr/local/etc/unbound/unbound.conf. There are many wonderful and subtle options for controlling the behavior of your DNS server, and you should familiarize yourself with them. For the time being, in its default configuration, it will not even respond to your DNS queries. So, there are a few things you will have to configure in the server: section of your config file to get a minimal DNS server setup for your home or small office use:
- access-control: This is where you set which IP addresses may query the server.You may set to allow, deny, and so on, as many address ranges as you wish. Due to the history of DNS amplification attacks, you should keep this restricted to only your localhost and an appropriate LAN range, often something like:
access-control: 127.0.0.1/8 allow
access-control: 192.168.0.0/16 allow - module-config: Here, you have a choice of “iterator” and/or “validator”.A local caching DNS server of the type we are discussing here only requires “iterator” functionality.
module-config: “iterator”
You will also have to configure at least one forwarding (i.e., downstream DNS server) address in the forward-zone: portion of the configuration file. Please look at the documentation to get a feel for the various ways this can be configured to resolve domains, but the following configuration will resolve everything for the time being through Google’s public DNS[6]:
forward-zone:
forward-tls-upstream: no
forward-addr: 8.8.8.8
It is very important you do this. Otherwise, in the default configuration, your DNS server setup will very inefficiently resolve DNS using the ultimate root-servers of the internet, an even worse condition than using your ISP’s default resolver.
Testing and Verifying Your DNS Server Setup
With this minimal configuration, your ultra-fast, caching, local, recursive DNS server setup is running and ready to serve. You may start the service with:
service unbound onestart
Now, to query the DNS server manually, any recent version of FreeBSD (and probably Linux) offers the drill(1) utility[7] for exactly this purpose:
root@testarea:/usr/local/etc/unbound # drill www.klarasystems.com @127.0.0.1
;; ->>HEADER<<- opcode: QUERY, rcode: NOERROR, id: 49317
;; flags: qr rd ra ; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;; www.klarasystems.com. IN A
;; ANSWER SECTION:
www.klarasystems.com. 300 IN CNAME 5o9o6utec66l.wpeproxy.com.
5o9o6utec66l.wpeproxy.com. 300 IN A 141.193.213.21
5o9o6utec66l.wpeproxy.com. 300 IN A 141.193.213.20
;; AUTHORITY SECTION:
;; ADDITIONAL SECTION:
;; Query time: 62 msec
;; SERVER: 127.0.0.1
;; WHEN: Sat Jan 11 15:34:19 2025
;; MSG SIZE rcvd: 106
Here, the return code is NOERROR, which means that the DNS server provided an answer to the query as expected, from the server I have highlighted in blue, which is the localhost where unbound is running. Also in red is a statement that the entire query process from request to response required 62 milliseconds[8].
An interesting thing happens if we immediately run the same command again, and look at the query time:
;; Query time: 0 msec
This is one of the huge wins to running your own DNS caching server. Now, with a well-optimized DNS server setup, the query took less than 1 ms, because the answer was already known to unbound from the previous query! Anyone on your network using this DNS server will resolve this query now instantaneously (until the data expires).
Addressing IoT Devices and DNS Queries
Managing High Query Volumes Efficiently
In my home environment, the total number of DNS queries hitting my server ranges around six thousand queries per hour, depending on the time of day, with no discernible load on the server itself. About 70% of these queries are resolved in less than 1 millisecond from cache, and over one thousand queries per hour that would have otherwise needlessly gone to the internet (allowing harvesting of the information, and creating needless traffic) are interceded.
To boot, there is extraordinary responsiveness when browsing the web. Few people appreciate how their web browsing experience is delayed by the fact that two or three dozen DNS queries must be resolved before they can fully load a page on their favorite site.
A Basic DNS Server Configuration
Configuring a DNS server properly involves many case-specific factors. Below, I show a non-encrypted and single threaded conservative configuration that works well for my particular server. You should not use this configuration blindly. Instead, it should serve as inspiration for the parameters you may want to learn about and adjust for your specific use case:
server:
interface: 0.0.0.0
# The following line assumes your LAN is on the usual 192.168.x.x network. Change
# this setting if necessary.
access-control: 192.168.0.0/16 allow
access-control: 127.0.0.1/8 allow
verbosity: 1
statistics-interval: 3600
statistics-cumulative: yes
outgoing-range: 256
num-threads: 1
msg-cache-size: 4m
msg-cache-slabs: 1
num-queries-per-thread: 512
rrset-cache-size: 8m
rrset-cache-slabs: 1
infra-cache-numhosts: 16
infra-cache-slabs: 1
do-ip4: yes
do-ip6: no
do-udp: yes
do-tcp: yes
outgoing-num-tcp: 50
incoming-num-tcp: 5
logfile: "unbound.log"
use-syslog: no
log-time-ascii: yes
private-address: 10.0.0.0/8
private-address: 172.16.0.0/12
private-address: 192.168.0.0/16
private-address: 169.254.0.0/16
private-address: 127.0.0.0/8
do-not-query-localhost: yes
log-queries: no
target-fetch-policy: "0 0 0 0 0"
prefetch: yes
cache-max-ttl: 604800
cache-min-ttl: 10
module-config: "iterator"
private-domain: "plex.direct"
private-domain: "home"
## If you had local domain static DNS names, you could
## put them in an include file here…
# include: /usr/local/etc/unbound/unbound.localdata.conf
## This is a good set of resolvers for the eastern US. Recommend
## that you investigate the best servers for your location. I suggest
## Steve Gibson's DNSBench: GRC's | DNS Nameserver Performance Benchmark
forward-zone:
name: "."
forward-tls-upstream: no
forward-addr: 74.82.42.42
forward-addr: 199.45.32.43
forward-addr: 216.52.126.1
forward-addr: 1.1.1.1
forward-addr: 8.8.8.8
forward-addr: 9.9.9.9
forward-addr: 141.1.1.1
forward-addr: 151.199.0.39
# OPTIONAL REMOTE CONTROL SETTINGS (comment out if desired)
# You must run unbound-control-setup before unbound-control can be used.
remote-control:
control-enable: yes
control-interface: 127.0.0.1
control-use-cert: yes
The final step is to get all of the devices on your LAN to actually use the server. While that discussion is mostly beyond the scope of this article, you will likely need to change your DNS configuration in your router to use your own servers. Besides, you may wish to look over
man resolv.conf
for FreeBSD hosts.
Mitigating IoT Device DNS Behavior
Unfortunately, many IoT devices (e.g., smart plugs, smart bulbs, voice assistants) may have permanently hard-coded DNS (and NTP) servers in their operating systems. As a result, they will often ignore any instructions from your router regarding which DNS (and NTP) servers to use. This can be a very significant number of queries. For example, in the past month at my home, there have been a whopping more than 275000 such DNS queries[9] from hard-coded IoT devices.
While the performance and security trade-offs with IoT devices are already a given, if you want them to use your LAN DNS server as a matter of principle, you will need to intercept all egressing port 53 packets (UDP and TCP) and redirect them using a firewall like pf. It might seem like added complexity, but it's key to keeping your network consistent and protecting your privacy.
Key Takeaways
Taking control of your DNS server setup can transform your network’s efficiency, security, and flexibility. Key insights include:
- Unmatched Performance: Local caching eliminates delays and ensuring near-instantaneous DNS resolution for frequently accessed domains.
- Enhanced Privacy: By avoiding ISP-provided servers, you keep sensitive browsing data within your control, reducing exposure to tracking.
- Purpose-Built Configurations: Tailor DNS functionality to suit your network’s unique demands, from custom forwarders to advanced caching strategies.
Self-hosting a DNS server isn’t just about control—it’s about building a robust foundation for your network.
Looking to optimize your system beyond DNS? Klara specializes in expert support for FreeBSD- based solutions. Explore our services and reach out to discuss how we can enhance your infrastructure.
─────────────────────────────
Additional Notes:
[1] Honestly, it’s a lot more than one IP address that will be needed to visit most pages. Whenever you load a page like www.ebay.com, every hosted element on that page, including ads and images, must be fetched. In turn, every one of those must be resolved by a new DNS query. See Figure 1.
[2] Unless, of course, you place the IP address directly in your software or function call. However, this is typically only done for very special IP addresses, like 192.168.1.1 that you might use to access your router. It can also be used for fixed IP addresses on a LAN that you administer.
[3] There is a long-standing saying in the sysadmin community about problems that are hard to nail down in the network: “It’s always DNS.”
[4] As you might expect, there are “alternative” root name servers as well, of varying reputation and purpose. If you are interested, you might start reading here.
[5] My main DNS server runs on hardware eight years old, services hundreds of thousands of LANside queries per day. It consumes 0.1% of the RAM, and has logged about 8 minutes of CPU time over the past two weeks. As a result, this amounts to roughly 0.04% of one CPU core on average. This efficiency demonstrates how a properly optimized DNS server setup can handle significant workloads without requiring high-end hardware.
[6] There are any number of other DNS servers you can choose here. For example, 1.1.1.1 and 9.9.9.9 are famous global DNS services, and Vodafone offers a public resolver on 141.1.1.1. Furthermore, you can also specify several forward-addr lines to rotate through potential servers.
[7] If drill, is not installed on your system, try dig. As a last resort, use nslookup.
[8] For the curious, this is because the Google DNS servers are about 10 milliseconds away each way, and they had to be queried twice (the second time to resolve the CNAME), for a total of four legs plus DNS query times.
[9] Yes, you read that right, that’s more than one every ten seconds, constantly.

Kyle Kneisl
Kyle “DrKK” Kneisl is a mathematician and C programmer that lives in the Washington, DC area, coming into the FreeBSD community about ten years ago after encountering the FreeNAS storage appliance. He contributes an occasional article, and can be found on the #bsd-social channel on Libera.Chat IRC.
Learn About Klara