Protect resolv.conf From DHCP On FreeBSD 10

Published on: Sun, Nov 29, 2015 at 12:39 pm EST
BSD Networking

If you are running your own resolver, or wish to use one from a 3rd-party provider, you may find that your /etc/resolv.conf file is being overwritten by DHCP. There are a handful of ways to resolve this problem. Since you're likely going to want to reboot to make sure that your changes stick, and since you're going to be monkeying with network settings in the first place, I strongly suggest doing this on a test instance and/or outside of peak hours.

Now then, here are three methods, from worst to best. Note that all methods in this guide were written for FreeBSD 10. Linux users can refer to this guide.

Method 1: Use static interface settings

In my limited testing, this results in slightly faster boot times since you don't have to wait for DHCP to assign your network settings. However, I have seen mention in several Vultr docs that using static interface settings is frowned upon and that you should stick to DHCP. I assume they have a good reason for this and thus I have continued to use DHCP myself. Nevertheless, should you decide to go this route, follow the steps below.

  • Determine your server's IP, network mask, and gateway IP.
  • Modify /etc/rc.conf to use these values instead of DHCP.
  • Reboot to test settings.

Determine IP/netmask/gateway

Assuming your interface is vtnet0, perform the following:

ifconfig vtnet0 | grep inet

This should get you the IP address and netmask for your server:

inet 10.10.10.10 netmask 0xffffff00 broadcast 10.10.10.255

FreeBSD likes to use hex for the netmask. The above converts to 255.255.255.0 if you're curious. You can find a handy table here, but fear not: you can just copy the hex address into your config files (or convert it to decimal if you prefer).

You can find the gateway a number of ways. Here's one:

route get default | grep gateway will return something along the lines of:

gateway: 10.10.10.1

Modify /etc/rc.conf with new values

Armed with the IP, netmask, and gateway, it's now time to add them to the system config. I strongly recommend backing up this file before making any changes, as it will make it much easier to undo should you mess up. Now then, open up /etc/rc.conf in your editor of choice, and make the following changes:

# Comment out this line:
# ifconfig_vtnet0="dhcp"

# Add these lines:
defaultrouter="10.10.10.1"
ifconfig_vtnet0="inet 10.10.10.10 netmask 0xffffff00"

Obviously, you should be sure to substitute your actual IP, netmask, and gateway for my obvious fakes.

Reboot and test

Reboot your server using shutdown -r now and make sure that it comes back up properly. Perform whatever tests you deem necessary to ensure everything is working properly. If the network is inaccessible, login via console and revert your changes. If everything is fine, at this point you can put whatever you please into resolv.conf without fear of it being obliterated.

If for whatever reason you can't reboot, this should work, but I'd really do a proper reboot if I were you:

service netif restart && service routing restart

Method 2: Make resolv.conf immutable

This is a bit of a hack, but it's easily the quickest solution. I don't recommend it because I can't guarantee this won't cause some weirdness in the future when you upgrade to a new release of the operating system, and dhclient is likely going to complain a bunch. That said, a simple chflags schg /etc/resolv.conf is all that's needed. The file is now completely write-protected, even from root. You can verify like so:

vultr [~]# chflags schg /etc/resolv.conf
vultr [~]# ls -ol /etc/resolv.conf
-rw-r--r--  1 root  wheel  schg 50 Nov 29 06:28 /etc/resolv.conf
vultr [~]# echo "so very untouchable" >> /etc/resolv.conf
/etc/resolv.conf: Operation not permitted.

Undo with: chflags noschg /etc/resolv.conf

Method 3: Politely tell FreeBSD to leave your settings alone

This is by far the cleanest, most proper way to get this done. There are two approaches you can take:

Configure dhclient

Let's take the example from way up top, and say all you want to do is put your custom nameserver in resolv.conf and don't want to lose it every time DHCP does its thing. In my case, I want to use the caching resolver I installed that listens on localhost, so I edit /etc/dhclient.conf (which will likely be blank aside from comments) and add the following:

interface "vtnet0" {
    supersede domain-name-servers 127.0.0.1;
}

This will allow dhclient to do everything else you need it to do, but when the DHCP server sends it a list of nameservers to use, yours will supersede (as in, completely replace) the ones it offers. If you'd prefer to supplement (rather than replace) the ones offered, you can "append" or "prepend" instead of "supersede", as appropriate.

Incidentally, should you require more than one custom server, specify them like this:

supersede domain-name-servers 127.0.0.1, 127.0.0.2;

After making your changes, restart dhclient to have them go into effect immediately:

service dhclient restart vtnet0

Examine your /etc/resolv.conf and you should find it now has your custom nameserver(s) in it.

As of this writing, nameservers are the only thing Vultr's DHCP server has ever put into my resolv.conf, and the only thing I've cared to customize. However, if you ever need to override any other settings, consult the excellent manual for a comprehensive list:

man 5 dhclient.conf

There are great examples at the bottom that should give you an idea of what you can do. Off the top of my head, I can imagine you might want to add something like supersede domain-name "example.com"; if you normally have a line like that in your resolv.conf. Again, consult the docs.

Configure resolvconf

This is the simplest solution if you just want your resolv.conf to be left alone. Per the manual:

resolvconf manages resolv.conf(5) files from multiple sources, such as DHCP and VPN clients

Its configuration resides in /etc/resolvconf.conf, which likely doesn't exist on your system, so feel free to create it. To make your resolv.conf immutable, add this:

# prevent all updates to resolv.conf:
resolv_conf="/dev/null"

If you use unbound as your local caching resolver, that's the line it adds (along with a few for itself). That's basically tricking resolvconf into thinking your /etc/resolv.conf is located at /dev/null. Something slightly less mean, but equally effective, would be:

# disable resolvconf from running any subscribers:
resolvconf="NO"

If you want to do something more sophisticated than just turning it off, the man pages for resolvconf and resolvconf.conf have plenty of info.

Want to contribute ?

You could earn up to $300 by adding new articles