Classless static routing from DHCP in pfSense

Apr 12

DHCP Options 121 and 249 provide an opportunity to send more detailed route settings to hosts. There is no convenient way to set this in pfSense, but we can do it.

The key to this solution is that you need to create the dhcp answer manually and set it in hexadecimal format in 'Additional DHCP Options' as a String value.

OK, but how can we create the dhcp answer?

  • First, we need to convert the netmask to hexadecimal. This is the first part of our string.
  • We will need the network address. If netmask is less than 9, remove the last 3 parts of network address. If the netmask is greater than 8 and less than 17, remove the last 2 parts. If the netmask is greater than 16 and less than 25, remove the last part. Convert the remaining numbers to hexadecimal.
  • Finally, convert every part of the gateway's IP address to hexadecimal.
  • Concatenate the two-digits hexadecimal numbers with colons.

Example: We would like to access 192.168.4.0/22 subnet over the gateway whose address is 152.66.83.241.

  • The value of the netmask is 22, which is 16 in hexadecimal.
  • We need the first 3 part of the network address: 192.168.4 = C0:A8:04
  • The address of the gateway is: 152.66.83.241 = 98:42:53:F1 So, the string that we need is: 16:C0:A8:04:98:42:53:F1

Let us be lazy and let the computer to calculate it:

#!/bin/bash
check_ip(){ 
  local n=0 val=1
  for i in ${1//./ }; do 
    [ $i -lt 0 -o $i -gt 255 ] && val=0
    n=$[n+1]
  done 
  [ $n -ne 4 ] && val=0
  if [ $val -ne 1 ] ; then
    echo "Invalid IP: $1" >&2
    exit 1
  fi
}

to_bin(){
  local BIN=({0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1})
  for i in ${1//./ }; do
   echo -n ${BIN[$i]}
  done
}

while [ $# -gt 0 ] ; do
  nw=${1%/*}; nm=${1#*/}; gw=$2
  check_ip $nw; check_ip $gw
  if [ ${#nm} -gt 2 ] ; then
    check_ip $nm
    nmbin=$(to_bin $nm)
    if echo $nmbin | grep -q "01" ; then
      echo "Invalid netmask: $nm" >&2
      exit 1
    else
      nmbin=${nmbin//0/}
    fi
    nm=${#nmbin}
    echo $nm
  fi
  gwhex=$(printf "%02x:%02x:%02x:%02x" ${2//./ })
  nwhex=$(printf "%02x:%02x:%02x:%02x" ${nw//./ })
  nmhex=$(printf "%02x" ${nm//./ })
  [ $nm -le 24 ] && nwhex=${nwhex%:*}
  [ $nm -le 16 ] && nwhex=${nwhex%:*}
  [ $nm -le 8 ]  && nwhex=${nwhex%:*}
  echo -n $nmhex:$nwhex:$gwhex
  shift 2
  [ $# -gt 0 ] && echo -n ":"
done
echo 

Let's try:

$ ./hexroute.sh 10.0.0.0/8 152.66.83.254
08:0a:98:42:53:fe
$ ./hexroute.sh 192.168.128.0/255.255.192.0 152.66.83.254
12:c0:a8:80:98:42:53:fe
$ ./hexroute.sh 10.0.0.0/8 152.66.83.254 192.168.128.0/18 152.66.83.254
08:0a:98:42:53:fe:12:c0:a8:80:98:42:53:fe

Next Post Previous Post