OpenBSD Journal

dhcpd -L : An opensource success story

Contributed by merdely on from the scary-network-stories dept.

Ray Percival writes:

It all started when my PFY and I were asked to figure out how to filter on MAC addresses for a meshed wireless network that we had designed and built in the recent past. Yes, I'm well aware that filtering on MACs is pretty silly, but our options were closed on that front as the request for it was coming from folks above our boss who were very unlikely to listen to reason on this subject. So we set out to find a cool answer to a stupid question.

Ray continues his story explaining how he found a bug, it was confirmed and fixed.

Since we were already running OpenBSD on the DHCP server for that network that seemed the obvious place to start looking. I recalled reading an article about Chris Kuethe's (ckuethe@) work on dhcpd and pf integration and, to be honest, had been hoping for an excuse to play with it for some time. So I set out to build a proof of concept. Setting up the dhcpd to only serve IPs to boxes that we had given it MACs for was easy, thanks to the excellent OpenBSD manpages (dhcpd.conf(5)), the problem was figuring out how to make pf only allow people who had gotten an IP from the server to have access to the network beyond itself.

This is where Chris' work on dhcpd came in. He had created a patch that was committed that allowed dhcpd to pass information about abandoned IPs and IPs that it had leases for to pf tables. Which makes it very easy to filter on those IPs. [-L, -A and -C options explained in dhcpd(8)] After writing a few pf rules, starting dhcpd, and having my test laptop pull an address from my shiny new server it all failed to work. After troubleshooting for a while it became clear that the dhcpd wasn't populating the table and that if I populated the table by hand the pf rules worked.

So I did what any good admin would do: bitched about it on irc. Chris assured me that it worked on his server, Mike Erdely tested it on a box of his and confirmed that it didn't work for him either. At this point Chris suggested looking at pfutils.c. Nicholas Marriott started to do so and a few minutes later reported that as near as he could tell you had to use both -A and -L. For this project I was only using -L. I tested with that and things started working.

And with that the bug had been found and I had a workaround that was more than good enough till it's patched. Try doing that with a closed source product.

Thanks to everybody involved, even those who just idled.

Within 24 hours, ckuethe@ had a fix created, tested and committed.

(Comments are closed)


Comments
  1. By Anonymous Coward (24.37.242.64) on

    Very interesting, I never knew about this and this is something I could use myself in some places.

    I'm not clear how the pf.conf is set to allow/deny traffic for DHCP assigned IP's and non-assigned, respectively - and what about servers in a network that use static IP?

    Do you have a small example? =)

    PS: Thanks for this! This is great!

    Comments
    1. By Ray Percival (sng) on http://undeadly.org/cgi?action=search&sort=time&query=sng

      > Very interesting, I never knew about this and this is something I could use myself in some places.
      >
      > I'm not clear how the pf.conf is set to allow/deny traffic for DHCP assigned IP's and non-assigned, respectively - and what about servers in a network that use static IP?
      >
      > Do you have a small example? =)
      >
      > PS: Thanks for this! This is great!

      Sure. I'll post a commented version of my /etc/pf.conf for this at some point. The box that it's on isn't on the network right now. Also the email with the first patch has a good example in it.

      Comments
      1. By Ray Percival (sng) on http://undeadly.org/cgi?action=search&sort=time&query=sng

        > > Very interesting, I never knew about this and this is something I could use myself in some places.
        > >
        > > I'm not clear how the pf.conf is set to allow/deny traffic for DHCP assigned IP's and non-assigned, respectively - and what about servers in a network that use static IP?
        > >
        > > Do you have a small example? =)
        > >
        > > PS: Thanks for this! This is great!
        >
        > Sure. I'll post a commented version of my /etc/pf.conf for this at some point. The box that it's on isn't on the network right now. Also the email with the first patch has a good example in it.

        Starting the dhcpd with 'dhcpd -L dynamic -A evildoers

        Populates the table dynamic with IPs that it leases and evildoers with addresses that are abandoned. Then, for the quick prototype, I just wrote rules to allow anything in dynamic and drop everything else. If I wanted to allow a specific range/set of static IPs I'd just stick them in a macro and write a rule for them. And, of course, if I was really using -A I'd just write the same rule but to drop instead of allow them.

        table <dynamic> persist
        table <evildoers> persist

        pass in on $int_if proto {tcp udp} from <dynamic> to any keep state

        Comments
        1. By Anonymous Coward (24.37.242.64) on

          > > > Very interesting, I never knew about this and this is something I could use myself in some places.
          > > >
          > > > I'm not clear how the pf.conf is set to allow/deny traffic for DHCP assigned IP's and non-assigned, respectively - and what about servers in a network that use static IP?
          > > >
          > > > Do you have a small example? =)
          > > >
          > > > PS: Thanks for this! This is great!
          > >
          > > Sure. I'll post a commented version of my /etc/pf.conf for this at some point. The box that it's on isn't on the network right now. Also the email with the first patch has a good example in it.
          >
          > Starting the dhcpd with 'dhcpd -L dynamic -A evildoers
          >
          > Populates the table dynamic with IPs that it leases and evildoers with addresses that are abandoned. Then, for the quick prototype, I just wrote rules to allow anything in dynamic and drop everything else. If I wanted to allow a specific range/set of static IPs I'd just stick them in a macro and write a rule for them. And, of course, if I was really using -A I'd just write the same rule but to drop instead of allow them.
          >
          > table <dynamic> persist
          > table <evildoers> persist
          >
          > pass in on $int_if proto {tcp udp} from <dynamic> to any keep state
          >

          Awesome! Thank you!

          With this is mind, I guess it's easy enough to deny 'evildoers' with the exception of say port 80, or even better, rdr port 80 to some sort of responder that says 'please use dhcp'...

    2. By Anonymous Coward (77.123.6.42) apelsin@atmnis.com on http://www.atmnis.com

      > Very interesting, I never knew about this and this is something I could use myself in some places.
      >
      > I'm not clear how the pf.conf is set to allow/deny traffic for DHCP assigned IP's and non-assigned, respectively - and what about servers in a network that use static IP?
      >
      > Do you have a small example? =)
      >
      > PS: Thanks for this! This is great!

      "So I did what any good admin would do: bitched about it on irc". So, and what channel it was? :). Thanks.


      Comments
      1. By Anonymous Coward (24.70.95.204) on

        > and what channel it was? :). Thanks.

        #kokomo
        Thats where you wanna go to get away from it all

      2. By Anonymous Coward (71.211.85.150) on

        > "So I did what any good admin would do: bitched about it on irc". So, and what channel it was? :). Thanks.

        The first rule of unnamed place is that you do not name unnamed places.

  2. By Can Acar (66.75.248.152) canacar@ on

    There are also other solutions to the stupid MAC address filtering problem. Here are a couple off the top of my head:

    1. Use bridge filters: Create a bridge(4), add the interface and create MAC filters to TAG the traffic depending on MAC addresses. Bridges with only one interface work fine. In pf, filter according to the tags.

    2. If your access point is OpenBSD, use hostapd(8) to disassociate any clients with unknown MAC addresses.

    Comments
    1. By Anonymous Coward (70.173.172.228) on

      > 1. Use bridge filters: Create a bridge(4), add the interface and create MAC filters to TAG the traffic depending on MAC addresses. Bridges with only one interface work fine. In pf, filter according to the tags.
      >
      wouldn't disabling learning on the bridge, adding static entries for known MAC addresses and marking the bridge interface to not send out of the interface if the destination is unknown also work, or is that just relevant to multi-interface bridges?

    2. By Anonymous Coward (211.26.61.157) on

      Bridges with only one interface work fine...
      I did not realise this, thanks for the tip!

    3. By Anonymous Coward (82.114.74.96) on

      > Bridges with only one interface work fine.

      Can You explain this? This means that machine will use only one interface? How does it pass the traffic then?

      Good stuff on dhcpd + pf. :-)

      Comments
      1. By Can Acar (66.75.248.152) canacar@ on

        > > Bridges with only one interface work fine.
        >
        > Can You explain this? This means that machine will use only one interface? How does it pass the traffic then?

        The aim in this case is not to "bridge traffic" but to filter. When you create a bridge, and add a single interface to it, you can use the filtering/tagging features of bridge(4).

        Comments
        1. By Bill Marquette (70.88.79.145) on

          > > > Bridges with only one interface work fine.
          > >
          > > Can You explain this? This means that machine will use only one interface? How does it pass the traffic then?
          >
          > The aim in this case is not to "bridge traffic" but to filter. When you create a bridge, and add a single interface to it, you can use the filtering/tagging features of bridge(4).

          Yep, I've done this when I've had machines with multiple upstream gateways. Created a bridge interface with my external interface being a member (the only member), then proceeded to put the mac addresses of the upstream routers in there and applying unique tags. Then in pf I did a pass in reply-to (extif gw1) any tagged GW1. Worked like a charm.

          You can also use bridge to pull in multiple interfaces (don't recall the exact options to disable forwarding and learning) so that you can run one instance of snort listening to multiple interfaces (this obviously is only really useful on a dedicated sensor).

          --Bill

Credits

Copyright © - Daniel Hartmeier. All rights reserved. Articles and comments are copyright their respective authors, submission implies license to publish on this web site. Contents of the archive prior to as well as images and HTML templates were copied from the fabulous original deadly.org with Jose's and Jim's kind permission. This journal runs as CGI with httpd(8) on OpenBSD, the source code is BSD licensed. undeadly \Un*dead"ly\, a. Not subject to death; immortal. [Obs.]