Update dnsmasq.adoc to use sudo commands where relevant and to avoid using vim in commands which requires a user to understand and navigate a particular editor. I used HEREDOC syntax to pipe content into files. A user can edit the content before they copy/paste into the command line.

This commit is contained in:
Rowan Puttergill 2026-07-06 15:21:43 +01:00
commit 972f693217

View file

@ -1,8 +1,8 @@
= Setting up dnsmasq - a lightweight DHCP and DNS server
Peter Boy; Emmmanuel Seyman
Peter Boy; Emmmanuel Seyman, Rowan Puttergill
:page-authors: {author}, {author_2}
:revnumber: F35-F44
:revdate: 2026-05-11
:revdate: 2026-07-01
// :revremark: a new beginning
:page-aliases: sysadmin-dnsmasq.adoc
@ -37,7 +37,7 @@ You should get something like
+
[source,console]
----
# firewall-cmd --get-active-zones
$ firewall-cmd --get-active-zones
FedoraServer (default)
interfaces: <IF01> ...
<MY_ZONE>
@ -48,8 +48,8 @@ Fix the zone assignments if necessary
+
[source,console]
----
# firewall-cmd --permanent --zone=<zone_name> --change-interface=<interface_name>
# firewall-cmd --reload
$ sudo firewall-cmd --permanent --zone=<zone_name> --change-interface=<interface_name>
$ sudo firewall-cmd --reload
----
* **Check auto forwarding**
@ -58,8 +58,8 @@ The system should automatically forward between the interfaces. Check the forwar
+
[source,console]
----
# cat /proc/sys/net/ipv4/ip_forward
# cat /proc/sys/net/ipv6/conf/default/forwarding
$ cat /proc/sys/net/ipv4/ip_forward
$ cat /proc/sys/net/ipv6/conf/default/forwarding
----
+
In both cases a value of 1 indicates an active forwarding.
@ -68,15 +68,16 @@ Otherwise, enable it immediately and configure it permanently.
+
[source,console]
----
# echo 1 > /proc/sys/net/ipv4/ip_forward
# echo 1 > /proc/sys/net/ipv6/conf/all/forwarding
$ echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
$ echo 1 | sudo tee /proc/sys/net/ipv6/conf/all/forwarding
# vim /etc/sysctl.d/50-enable-forwarding.conf
$ sudo tee /etc/sysctl.d/50-enable-forwarding.conf << 'EOF'
# local customizations
#
# enable forwarding for dual stack
net.ipv4.ip_forward=1
net.ipv6.conf.all.forwarding=1
EOF
----
@ -86,7 +87,7 @@ The NetworkManager dnsmasq plugin included by default provides a basic configur
In case dnsmasq is not already installed
[source,console]
----
# dnf install dnsmasq
$ sudo dnf install dnsmasq
----
[IMPORTANT]
@ -113,119 +114,125 @@ The example here uses 2 interfaces, an external public interface enp1s0 (public.
+
[source,console]
----
# vim /etc/NetworkManager/conf.d/00-use-dnsmasq.conf
# /etc/NetworkManager/conf.d/00-use-dnsmasq.conf
# This enables the dnsmasq plugin.
[main]
dns=dnsmasq
$ sudo tee /etc/NetworkManager/conf.d/00-use-dnsmasq.conf << 'EOF'
# /etc/NetworkManager/conf.d/00-use-dnsmasq.conf
# This enables the dnsmasq plugin.
[main]
dns=dnsmasq
EOF
----
2. **Configuration of the name resolution (DNS) for the internal private network (internal.lan)**
+
[source,console]
----
# vim /etc/NetworkManager/dnsmasq.d/01-DNS-<INTERNAL>.conf
$ sudo tee /etc/NetworkManager/dnsmasq.d/01-DNS-<INTERNAL>.conf << 'EOF'
# /etc/NetworkManager/dnsmasq.d/01-DNS-<INTERNAL>.conf
# This file sets up DNS for the private local net domain '<INTERNAL>.lan'
local=/<INTERNAL>.lan/
# file where to find the list of IP - hostname mapping
addn-hosts=/etc/dnsmasq-<INTERNAL>.hosts
domain-needed
bogus-priv
# Automatically add <domain> to simple names in a hosts-file.
expand-hosts
# interfaces to listen on
interface=lo
interface=<ENPxyz>
# in case of a bridge don't use the attached server virtual ethernet interface here!
# Upstream public net DNS server (max.three)
no-poll
server=<uuu.vv.xx.yy>
server=<www.vv.xx.zz>
server=<2001:www:xxx:yyy::zz>
domain-needed
bogus-priv
# Automatically add <domain> to simple names in a hosts-file.
expand-hosts
# interfaces to listen on
interface=lo
interface=<ENPxyz>
# in case of a bridge don't use the attached server virtual ethernet interface here!
# Upstream public net DNS server (max.three)
no-poll
server=<uuu.vv.xx.yy>
server=<www.vv.xx.zz>
server=<2001:www:xxx:yyy::zz>
EOF
----
+
Provide an empty host file
+
[source,console]
----
# touch /etc/dnsmasq-<INTERNAL>.hosts
$ sudo touch /etc/dnsmasq-<INTERNAL>.hosts
----
3. **Configuration of the DHCP service for the internal private network (<INTERNAL>.lan)**
+
[source,console]
----
# vim /etc/NetworkManager/dnsmasq.d/02-DHCP-<INTERNAL>.conf
# etc/NetworkManager/dnsmasq.d/02-DHCP-<INTERNAL>.conf
# This file sets up DHCP for the private local net domain '<INTERNAL>.lan'
# The domain the DHCP part of dnsmasq is responsible for:
domain=<INTERNAL>.lan,<uuu.vv.xx.y/24>,local
# interfaces to listen on (redundant, same as for DNS)
interface=<ENPxyz>
# general DHCP stuff (options, see RFC 2132)
# 1: subnet masq
# 3: default router
# 6: DNS server
# 12: hostname
# 15: DNS domain (unneeded with option 'domain')
# 28: broadcast address
dhcp-authoritative
dhcp-option=1,<255.255.255.24>
dhcp-option=3,<www.xxx.yy.zz>
dhcp-option=6,<www.xx.yy.z>
# Assign fixed IP addresses based on MAC address
# dhcp-host=00:1a:64:ce:89:4a,NAME01,www.xx.yy.zz,infinite
# dhcp-host=52:54:00:42:6a:43,NAME02,www.xx.yy.zz,infinite
# Assign dynamically IP addresses to interface to listen on
# Range for distributed addresses, tagged <int> for further references
dhcp-range=tag:<ENPxyz>,<vvv.ww.xx.y,vvv.ww.xx.z>,24h
$ sudo tee /etc/NetworkManager/dnsmasq.d/02-DHCP-<INTERNAL>.conf << 'EOF'
# etc/NetworkManager/dnsmasq.d/02-DHCP-<INTERNAL>.conf
# This file sets up DHCP for the private local net domain '<INTERNAL>.lan'
# The domain the DHCP part of dnsmasq is responsible for:
domain=<INTERNAL>.lan,<uuu.vv.xx.y/24>,local
# interfaces to listen on (redundant, same as for DNS)
interface=<ENPxyz>
# general DHCP stuff (options, see RFC 2132)
# 1: subnet masq
# 3: default router
# 6: DNS server
# 12: hostname
# 15: DNS domain (unneeded with option 'domain')
# 28: broadcast address
dhcp-authoritative
dhcp-option=1,<255.255.255.24>
dhcp-option=3,<www.xxx.yy.zz>
dhcp-option=6,<www.xx.yy.z>
# Assign fixed IP addresses based on MAC address
# dhcp-host=00:1a:64:ce:89:4a,NAME01,www.xx.yy.zz,infinite
# dhcp-host=52:54:00:42:6a:43,NAME02,www.xx.yy.zz,infinite
# Assign dynamically IP addresses to interface to listen on
# Range for distributed addresses, tagged <int> for further references
dhcp-range=tag:<ENPxyz>,<vvv.ww.xx.y,vvv.ww.xx.z>,24h
EOF
----
+ The example shows the binding of the network interface and then sets the different DHCP responses for various client request options.
+ The subnet mask (dhcp-option=1) is set to <255.255.255.24>, the default router or gateway (dhcp-option=3) is set to <www.xxx.yy.zz>, and the DNS server (dhcp-option=6) is set to <www.xx.yy.z>. Substitute values appropriate to your network.
+ In this example, no permanent or fixed IP addresses are assigned, but examples are provided as commented lines, so that you can see how to add an entry to assign a particular IP address to a host based on it's MAC address.
+ The example enables a DHCP range within the network and assigns hosts IP addresses from <vvv.ww.xx.y> to <vvv.ww.xx.z> with leases lasting for 24 hours.
4. **Configuration of the DHCP service for the public network (<PUBLIC.TLD>)**
+
[source,console]
----
# vim /etc/NetworkManager/dnsmasq.d/03-DHCP-<PUBLIC>.conf
# etc/NetworkManager/dnsmasq.d/03-DHCP-<PUBLIC>.conf
# This file sets up DNCP for the public '<PUBLIC.TLD>' domain interface
$ sudo tee /etc/NetworkManager/dnsmasq.d/03-DHCP-<PUBLIC>.conf << 'EOF'
# etc/NetworkManager/dnsmasq.d/03-DHCP-<PUBLIC>.conf
# This file sets up DHCP for the public '<PUBLIC.TLD>' domain interface
# The domain the DHCP part of dnsmasq is responsible for:
domain=<PUBLIC.TLD>,<uuu.vv.ww.xx/24>
# the public interfaces to listen on
interface=<ENPuvw>
# general DHCP stuff (options, see RFC 2132)
# 1: subnet masq
# 3: default router
# 6: DNS server
# 12: hostname
# 15: DNS domain (unneeded with option 'domain')
# 28: broadcast address
# The domain the DHCP part of dnsmasq is responsible for:
domain=<PUBLIC.TLD>,<uuu.vv.ww.xx/24>
##dhcp-authoritative
## we just send the bare minimum, e.g. no DNS server
##dhcp-option=1,<255.255.255.0>
dhcp-option=tag:<ENPuvw>,option=router,<uuu.vv.ww.zz>
# Assign fixed IP addresses based on MAC address
# dhcp-host=00:1a:64:ce:89:4a,thootes,10.10.10.50,infinite
# dhcp-host=52:54:00:42:6a:43,apollon,10.10.10.51,infinite
# Assign dynamically IP addresses to interface to listen on
# Range for distributed addresses, tagged <int> for further references dhcp-range=tag:<ENPuvw>,<uuu.vvv.w.x,uuu.vvv.w.y6,1h
# the public interfaces to listen on
interface=<ENPuvw>
# general DHCP stuff (options, see RFC 2132)
# 1: subnet masq
# 3: default router
# 6: DNS server
# 12: hostname
# 15: DNS domain (unneeded with option 'domain')
# 28: broadcast address
##dhcp-authoritative
## we just send the bare minimum, e.g. no DNS server
##dhcp-option=1,<255.255.255.0>
dhcp-option=tag:<ENPuvw>,option=router,<uuu.vv.ww.zz>
# Assign fixed IP addresses based on MAC address
# dhcp-host=00:1a:64:ce:89:4a,thootes,10.10.10.50,infinite
# dhcp-host=52:54:00:42:6a:43,apollon,10.10.10.51,infinite
# Assign dynamically IP addresses to interface to listen on
# Range for distributed addresses, tagged <int> for further references dhcp-range=tag:<ENPuvw>,<uuu.vvv.w.x,uuu.vvv.w.y6,1h
EOF
----
+
There is no DNS configuration for the external interface following, assuming that a official public DNS server is used to resolve all public facing interfaces of the domain public.tld.
@ -234,28 +241,28 @@ There is no DNS configuration for the external interface following, assuming tha
+
[source,console]
----
# dnsmasq --test
$ dnsmasq --test
----
6. **Adjusting the firewall**
+
Allow ports for DHCP and DNS (53) service on the public interface.
Allow ports for DHCP (UDP port 67) and DNS (TCP port 53) service on the public interface. If the system is running firewalld, you can configure these services as follows:
+
[source,console]
----
# firewall-cmd --get-services
# firewall-cmd --zone=<YOUR_ZONE> --permanent --add-service=dhcp
# firewall-cmd --zone=<YOUR_ZONE> --permanent --add-service=dns
# firewall-cmd --reload
# firewall-cmd --list-all --zone=<YOUR_ZONE>
$ firewall-cmd --get-services
$ sudo firewall-cmd --zone=<YOUR_ZONE> --permanent --add-service=dhcp
$ sudo firewall-cmd --zone=<YOUR_ZONE> --permanent --add-service=dns
$ sudo firewall-cmd --reload
$ firewall-cmd --list-all --zone=<YOUR_ZONE>
----
7. **Restart NetworkManager to start dnsmasq**
+
[source,console]
----
# systemctl restart NetworkManager
# ps -ef | grep dnsmasq
$ sudo systemctl restart NetworkManager
$ ps -ef | grep dnsmasq
dnsmasq 2114 2072 0 08:33 ? 00:00:00 /usr/sbin/dnsmasq --no-resolv ...
----
+
@ -266,8 +273,8 @@ command above.
+
[source,console]
----
# systemctl restart systemd-resolved
# resolvectl status
$ sudo systemctl restart systemd-resolved
$ resolvectl status
----
+
The systemd-resolved should recognize the dnsmasq nameserver attached to interfaces as configured.
@ -278,19 +285,19 @@ a. Test DHCP in the public using a machine without IP address
+
[source,console]
----
# ip a # no IPv4 address associated with interface
# dhclient -4 -1 -v eth0
# ip a # expect new IPv4 address associated with interface
# dhclient -4 -1 -r -v eth0 # expected: no IPv4 again
# ip a # expect no IPv4 address associated with interface again
$ ip a # no IPv4 address associated with interface
$ sudo dhclient -4 -1 -v eth0
$ ip a # expect new IPv4 address associated with interface
$ sudo dhclient -4 -1 -r -v eth0 # expected: no IPv4 again
$ ip a # expect no IPv4 address associated with interface again
----
b. Try on an other server
b. Validate that a DNS lookup for the system works correctly on another server, by running any of the following:
+
[source,console]
----
# dig app1 @10.10.10.1
# nslookup app1 10.10.10.1
# dhclient -v -d -s 10.10.10.1 enp6s0
$ dig app1 @10.10.10.1
$ nslookup app1 10.10.10.1
$ dhclient -v -d -s 10.10.10.1 enp6s0
----
@ -302,15 +309,15 @@ If machines in the private network need access to the public network, add masque
+
[source,console]
----
# firewall-cmd --zone=FedoraServer --add-masquerade --permanent
$ sudo firewall-cmd --zone=FedoraServer --add-masquerade --permanent
success
# firewall-cmd --zone=trusted --add-masquerade --permanent
$ sudo firewall-cmd --zone=trusted --add-masquerade --permanent
success
# firewall-cmd --reload
# firewall-cmd --zone=FedoraServer --query-masquerade
$ sudo firewall-cmd --reload
$ sudo firewall-cmd --zone=FedoraServer --query-masquerade
yes
# firewall-cmd --zone=trusted --query-masquerade
$ sudo firewall-cmd --zone=trusted --query-masquerade
yes
----
@ -321,16 +328,16 @@ a. A commonly used way to accomplish this is to set 'rules' in the firewall conf
+
[source,console]
----
# firewall-cmd --get-active-zones
$ firewall-cmd --get-active-zones
FedoraServer
interfaces: enp1s0
trusted
interfaces: vbr2s0 enp2s0
# firewall-cmd --direct --add-rule ipv4 nat POSTROUTING 0 -o enp1s0 -j MASQUERADE
$ sudo firewall-cmd --direct --add-rule ipv4 nat POSTROUTING 0 -o enp1s0 -j MASQUERADE
success
# firewall-cmd --direct --add-rule ipv4 filter FORWARD 0 -i vbr2s0 -o enp2s0 -j ACCEPT
$ sudo firewall-cmd --direct --add-rule ipv4 filter FORWARD 0 -i vbr2s0 -o enp2s0 -j ACCEPT
success
# firewall-cmd --direct --add-rule ipv4 filter FORWARD 0 -i enp1s0 -o vbr2s0 -m state --state RELATED,ESTABLISHED -j ACCEPT
$ sudo firewall-cmd --direct --add-rule ipv4 filter FORWARD 0 -i enp1s0 -o vbr2s0 -m state --state RELATED,ESTABLISHED -j ACCEPT
success
----
@ -338,20 +345,20 @@ b. Fedora's firewall daemon, however, offers with release 35 and beyond a more e
+
[source,console]
----
# firewall-cmd --get-active-zones
$ firewall-cmd --get-active-zones
FedoraServer
interfaces: enp1s0
trusted
interfaces: vbr2s0 enp2s0
# firewall-cmd --permanent --new-policy trustedToExt
$ sudo firewall-cmd --permanent --new-policy trustedToExt
success
# firewall-cmd --permanent --policy trustedToExt --add-ingress-zone trusted
$ sudo firewall-cmd --permanent --policy trustedToExt --add-ingress-zone trusted
success
# firewall-cmd --permanent --policy trustedToExt --add-egress-zone FedoraServer
$ sudo firewall-cmd --permanent --policy trustedToExt --add-egress-zone FedoraServer
success
# firewall-cmd --permanent --policy trustedToExt --set-target ACCEPT
$ sudo firewall-cmd --permanent --policy trustedToExt --set-target ACCEPT
success
# firewall-cmd --reload
$ sudo firewall-cmd --reload
success
----
+
@ -367,39 +374,39 @@ We just add the name resolution (DNS) for the libvirt virtual network (libvirt.l
[source,console]
----
# vim /etc/NetworkManager/dnsmasq.d/30-DNS-libvirt.conf
$ sudo tee /etc/NetworkManager/dnsmasq.d/30-DNS-libvirt.conf << 'EOF'
# /etc/NetworkManager/dnsmasq.d/30-DNS-libvirt.conf
# /etc/NetworkManager/dnsmasq.d/30-DNS-libvirt.conf
# This file directs dnsmasq to forward any request to resolve
# names under the .libvirt.lan domain to 192.168.122.1, the
# local libvirt DNS server default address.
server=/libvirt.lan/192.168.122.1
# This file directs dnsmasq to forward any request to resolve
# names under the .libvirt.lan domain to 192.168.122.1, the
# local libvirt DNS server default address.
server=/libvirt.lan/192.168.122.1
EOF
----
== Managing static DNS Entries
1. Edit the dnsmasq host file
+
The format is the same as /etc/hosts .
The format is the same as /etc/hosts. See the hosts(5) man page for more information.
+
[source,console]
----
# vim /etc/dnsmasq.hosts
$ sudo vim /etc/dnsmasq-<INTERNAL>.hosts
----
2. Restart NetworkManager to read the modified file.
+
[source,console]
----
# systemctl restart NetworkManager
$ sudo systemctl restart NetworkManager
----
3. Test the modification
+
[source,console]
----
# nslookup {NAME}
# nslookup {NAME}.example.lan
$ sudo nslookup {NAME}
$ sudo nslookup {NAME}.example.lan
----