My home network has traditionally been the polar opposite of the systems I work with – it has always used kit provided by the ISP as the CE router and unmanaged switches where required in the name of keeping it low-cost and simple. The frequency that I’m now working from home has caused me to re-evaluate that position in the name of segmenting my work equipment from my home equipment.
To that end, I recently bought a second-hand Juniper SRX 300 with the intention of using it to replace the VDSL2 router provided by Sky/NowTV. A second-hand but unused Draytek Vigor followed soon after and, after adding the required configuration to the SRX, I connected it all up and found that I couldn’t get a DHCP lease from Sky/NowTV’s kit, despite having the now-famous DHCP Option 61 set to the value that the ISP-provided kit sends.
Some investigation with Wireshark revealed that the SRX wasn’t sending Option 61 at all – a bug that some Google searching confirmed, along with a workaround of setting the SRX to use the interface description for the client-identifier, and to put the string in there instead. Option 61 was now being set, but I still couldn’t get a lease. Another Wireshark capture revealed that Junos’ JDHCP process inserts a character at the beginning of the string, making it different from the original. Reverting to Junos 15 and using the old client appeared to work fine, but wouldn’t allow me to run a DHCPv6 client at the same time – something I badly want. I confirmed that the bug in JDHCP exists right up to the latest release and packed the kit away for a while.
Fast-forward a couple of weeks when I find a Raspberry Pi 2 in my shed, and have a eureka moment. With a USB NIC, I could create an ethernet bridge on the Pi and man-in-the-middle the DHCP discovers to insert the correct option string. The next day, my USB NIC turned up and I set about making the Pi do some discover/request re-writing.
I’d initially envisaged using Scapy to rewrite the packets, but after a quick search, came across dhcpoptinj, which already does everything I’d have to write. Perfect!
Configuration of the Pi is simple…
Having connected the Pi to my existing LAN, I got the IP address from my DHCP server and SSH’d to it. I found that although dhcpoptinj has packages in the Debian Sid repo, there aren’t any in the buster one. Never mind, just get the Sid one for the correct architecture (armhf for the Pi 2) and use that. Install bridge-utils and iptables-persist whilst you’re there too.
wget http://ftp.us.debian.org/debian/pool/main/d/dhcpoptinj/dhcpoptinj_0.5.3-1_armhf.deb apt install dhcpoptinj_0.5.3-1_armhf.deb apt install bridge-utils iptables-persist
I then created a new systemd service unit at /etc/systemd/system/dhcpoptinj.service:
[Unit] Description=dhcpoptinj [Service] Type=simple Restart=always ExecStart=/usr/sbin/dhcpoptinj [Install] WantedBy=multi-user.target
and proceeded to make a config file for dhcpoptinj at /etc/dhcpoptinj.conf
queue = 2 remove-existing-opt option=3d<see below>
The option set in the config file can be obtained for a Wireshark capture of your Sky/NowTV provided router – I’ll not detail how to do the capture itself as that’s covered in a great many blogs (here’s an example), but once you have it, find your DHCP discover and right click on the ‘Option: (61) Client Identifier’ line under ‘Bootstrap Protocol – Discover’ and choose ‘Show packet bytes’. Once you have that window open, change ‘Show as:’ to ‘Raw’ to get the hexadecimal string that will be used by dhcpoptinj.
Remove the third and fourth characters (1b in my example, likely to be 1c on Sky), which defines the length of the following string and is calculated by dhcpoptinj (the 3d at the beginning is 61 in decimal, which is the number of the option we’re working with), and use that as the option in your configuration. For example, if you had 3d1b3a3057343235633566373438406e6f7774767c61652b4707030604 in your Wireshark capture, you would add the below to your /etc/dhcpoptinj.conf:
queue = 2 remove-existing-opt option=3d3a3057343235633566373438406e6f7774767c61652b4707030604
That’s dhcpoptinj configured, so now is a good time to enable the service in systemd:
systemctl daemon-reload systemctl enable dhcpoptinj
Now that is done, you should add the accompanying iptables rule to redirect DHCP to the queue that dhcpoptinj will be on:
iptables -t mangle -A PREROUTING -m physdev --physdev-in eth0 -p udp --dport 67 -j NFQUEUE --queue-num 2 --queue-bypass
You’ll want this to persist after a reboot. The iptables-persistent package is my preferred way of doing this, so you could install that and choose to save your current rules:
apt install iptables-persistent
The last thing to do is configure your network interfaces. I added the below to my /etc/network/interfaces file:
auto eth0 auto eth1 iface eth0 inet manual iface eth1 inet manual auto br0 iface br0 inet manual bridge_ports eth0 eth1
In my use-case, I don’t want any IP connectivity on the Pi, so I inserted the below to my /etc/dhcpcd.conf file, but you may choose to add a static address to br0 if it pleases you:
denyinterfaces eth0 eth1 br0
After that, I shut down the Pi, connected it in-line between my SRX’s WAN interface and the Draytek Vigor 130 modem, and got a DHCP lease straight away!
My topology for this now looks like the below:
I now have fully functioning IPv4 and IPv6 (with prefix-delegation) on this installation. Once I have a managed switch, more VLANs and security zones will be created and distributed over the WAPs.
I note that this is a potential workaround for users of other IPoE services where DHCP Option 61 is used for authentication. Unfortunately, I can’t think of a solution where you could use the Mini-PIM in an SRX320 (they can’t go into ethernet-switching mode, so you couldn’t configure a L3 interface and an ethernet-switching interface to do the MITM and bridge to the modem), so it looks like this will only work for people with external modems.