PFsense custom DHCPD configuration

pfSense is my prefered router/firewall distro. It’s rock solid and has tons of features.
You can run pfSense on any PC, but if you want to keep the power and heat down to a minimum you can use an Alix board (http://www.pcengines.ch/alix.htm) APU2 board (https://www.pcengines.ch/apu2.htm) or similar. Alix boards are no long supported, but APU2 works fine.

One of the few things you can’t do in pfSense is modify your dhcpd.conf file directly.
For the vast majority of deployments, the built in control you have will be more than enough. It supports multiple vlans, and custom options. But…
If you need something special, like running a DHCP Server for several IP subnets over Layer 3 switches, then you need a different approach. Or maybe you just like to maintain a single file instead of using the GUI interface.

This is not a common requirement for a network, but it does happen.
I had a test-lab with a few Layer 3 switches and several subnets. I wanted to have an easy one-file configuration for the entire network using only the low-power pfSense router. So I had to figure out a way to do that.

There is no dhcpd.conf file you can edit in pfsense because it’s generated on each boot using the config.xml file (managed by all the settings in the GUI). The problem is that if you want any special settings in your dhcpd.conf file, it might not be supported by the config.xml markup and/or the GUI.

The solution is pretty simple. Just stop the DHCP daemon after boot, replace the dhcpd.conf file and restart the daemon.

DHCP daemon starts in a chrooted environment in /var/dhcpd, so all files are located with this folder as a parent.

If you don’t have a monitor on your router, you can enable SSH or use a serial console cable.
It’s also possible to do almost everything using the Diagnostics -> Edit File menu item in the GUI. To create a file, just enter the full path and click Save.

ScreenClip

This solution requires two files.

1) 
The first one is a script, like this:

#/bin/bash
killall -3 dhcpd
cp /var/dhcpd/etc/dhcpd.override /var/dhcpd/etc/dhcpd.conf
/usr/local/sbin/dhcpd -user dhcpd -group _dhcp -chroot /var/dhcpd -cf /etc/dhcpd.conf -pf /var/run/dhcpd.pid le1 le0

Save it as: /usr/local/etc/rc.d/dhcpdoverride.sh

pfSense will run any script in this folder (/urs/local/etc/rc.d/) after it has started. The only requirements is the execute flag and that the file ends with .sh
So you’ll need to run this command as well:

chmod +x /usr/local/etc/rc.d/dhcpdoverride.sh

IMPORTANT NOTE!
The last command in this file may be different from system to system. Notice that one or more interfaces are being listed at the end. It’s easy to get the exact command of your system if you have done the initial configuration in GUI (included the interfaces you’ll be using).

Just run this command:

ps axww | grep dhcpd

The output should look something like this:

[2.1.3-RELEASE][root@pfSense.localdomain]/var(35): ps axww | grep dhcpd
38392  ??  Ss     0:00.04 /usr/local/sbin/dhcpd -user dhcpd -group _dhcp -chroot /var/dhcpd -cf /etc/dhcpd.conf -pf /var/run/dhcpd.pid le1 le0

I’m using two interfaces with DCHPD, so two interfaces are listed at the end.

2)
The second file is your own dhcpd.conf file.
If you have a file already then just save it as:
/var/dhcpd/etc/dhcpd.conf.override

If you don’t have a file already made, you can do the initial configuration in the GUI and just copy the file that is created. Then you have a good starting point.

After you have done your initial configuration in the GUI you can copy it like this:

cp /var/dhcpd/etc/dhcpd.conf /var/dhcpd/etc/dhcpd.conf.override

OR, using the GUI, like this

Go to Using Diagnostics -> Edit file:
open /var/dhcpd/etc/dhcpd.conf
then edit the filepath to /var/dhcpd/etc/dhcpd.conf.override and click Save

And that’s all!

Now you can edit dhcpd.conf.override with IP subnets, or anything you like.
An example of dhcpd.conf with multiple subnets:

option domain-name "localdomain";
default-lease-time 7200;
max-lease-time 86400;
log-facility local7;
ddns-update-style none;
authoritative;

#Subnet Alpha
subnet 10.50.150.0 netmask 255.255.255.0 {
  pool {
    range 10.50.150.100 10.50.150.200;
  }
  option routers 10.50.150.3;
  option domain-name-servers 10.50.150.3;
}

#Subnet Delta
subnet 10.18.200.0 netmask 255.255.255.0 {
  pool {
    range 10.18.200.100 10.18.200.200;
  }
  option routers 10.18.200.2;
  option domain-name-servers 10.50.150.3;# ex. a static IP address for a printer

  host HPPrinter { # example of a static IP address for a device
    hardware ethernet xx:xx:xx:xx:xx:xx; # replace the MAC address
    fixed-address 10.18.200.10;
    option host-name "HPLaserJet";
  }
}

NOTE!
You’ll need to replace the xx:xx:xx…  with the actual MAC address of your device.
And also;
If you are doing this to create subnets, you will also need to enable DHCP relay on your switch or routers between these subnets.

 

You can edit the override file from WebGui using the edit file menu.

 

8 comments

  1. That’s a pretty painless way of dealing with this, however I’m surprised that the multiple subnet dhcpd.conf example you showed works. If you want to have multiple subnets that share the same interface, you need to have those subnets enclosed in a shared-network statement or dhcpd will exit with the error “Multiple interfaces match the same shared network”.

    You need do something like this:

    shared-network MyNetExample {

    #Subnet Alpha
    subnet 10.50.150.0 netmask 255.255.255.0 {
    pool {
    range 10.50.150.100 10.50.150.200;
    }
    option routers 10.50.150.3;
    option domain-name-servers 10.50.150.3;
    }

    #Subnet Delta
    subnet 10.18.200.0 netmask 255.255.255.0 {
    pool {
    range 10.18.200.100 10.18.200.200;
    }
    option routers 10.18.200.2;
    option domain-name-servers 10.50.150.3;# ex. a static IP address for a printer
    }

    }

    1. thank you for the input!
      That is indeed the correct way of doing it. But it just didn’t work when I tried it.
      I should probably give it another go.
      Anyway, the example I listed worked (on on my setup at least).

  2. Hi, my config gets overridden every time i change something else in the webgui. I tried to remove write rights for everyone, but it still gets overridden. Help please 😦

    1. I am not completely sure what your problem is, so I will try to cover a few angles. Forgive me for information that is irrelevant for your particular problem (it might help others).

      The solution in this blogpost replaces the dhcpd configuration after boot. If you modify configuration in GUI it might trigger a regeneration of configuration files (including dhcpd.conf).
      To get back to the override dhcpd.conf you either need to reboot or run the dhcpdoverride.sh script, either from GUI or command line.

      On the other hand, changes to the dhcp configuration in GUI after implementing this solution will of course not be effective. As the configuration will be overridden after each boot.

      I am not sure what you mean by remove write rights for everyone.

      If you or someone else needs to do frequent changes in the GUI this might not be the best solution. I would try to get by using VLANs, then you can use the built in GUI configuration.

      May I ask what changes you are doing?

      1. My pfsense 2.1.5 was triggering itself a regeneration of configuration files from time to time. I was not doing antyhing. I tried to change the permissions on my dhcpd.conf so not even root could write to the file, but it didn’t helped.

        But i found a solution elsewhere. If you want to use the GUI with no fear of config changes. You have to modify the “service.inc” file. There is a line where pfsense opens the dhcpd.conf
        just change it to something like “dhcpd.conf.auto”

        pfSense is then generating its webgui config into dhcpd.conf.auto. Your own config is not touched and you can freely use the webgui.

      2. That is interesting, and it would result in a more robust solution.
        I have never had the dhcpd.conf file get regenerated other than during boot, so I didn’t even consider this as an issue.
        Thank you for sharing!

      3. The solution of changing the name of the file that the config is written to for dhcpd.conf.auto is good but not perfect. After a pfSense upgrade, the services.inc file will be updated and that hack will be lost. At the first reboot, the original dhcpd.conf file will be written again, making you lose your custom config.

        I have found a slight variation of what you did to circumvent this problem. Instead of changing the name of the configuration file being written by pfSense, I change the -cf argument in the command used to launch dhcpd to something like “/usr/local/sbin/dhcpd …. -cf /etc/dhcpd_custom.conf …”. This way, the worst it can happen is that the launch command will revert to the default one and the config generated by pfsense will be used instead and my custom config file will remain intact. All that would be left after an upgrade is to change the services.inc file again to point the -cf argument to my own config file and restart the DHCP Server.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s