Discussion:
bug / misunderstanding in how pf interacts with dhclient
Bohdan Tashchuk
2013-01-29 00:13:20 UTC
Permalink
Hi guys,

For many years, I've read pf and dhcp related threads like, e.g.:
http://marc.info/?l=openbsd-misc&m=125907434809727&w=2

Some text from that post:
"dhcp packets are grabbed by dhclient or dhcpd before pf sees them."

My understanding, based on comments in a number of threads like that,
is that NO MATTER WHAT IS IN PF RULES, that dhcpd and dhclient should
both work fine. This is because dhcpd and dhclient both use bpf to
completely bypass pf.

However, I'm running OpenBSD 5.2 release, and I don't think dhclient
is able to renew its lease without pf cooperation. I recently tightened
up my pf rules, which is how I ran into this.

Here's what I see, based on tcpdump and daemon logs:

1) on startup, my dhclient negotiates with my ISP's dhcp server properly.
It makes a request, it gets a lease, as logged in /var/log/daemon:
Jan 27 02:55:00 (myname) dhclient[24372]: DHCPREQUEST on em1 to 255.255.255.255 port 67
Jan 27 02:55:00 (myname) dhclient[24372]: DHCPACK from 73.88.146.1 (00:1d:70:af:ec:e2)
Jan 27 02:55:00 (myname) dhclient[24372]: bound to 76.27.218.121 -- renewal in 116353 seconds.

2) this lease is properly recorded in my dhclient.leases.em1 file:
lease {
interface "em1";
fixed-address 76.27.218.121;
option subnet-mask 255.255.252.0;
option routers 76.27.216.1;
...
option broadcast-address 255.255.255.255;
option dhcp-lease-time 232706;
option dhcp-message-type 5;
option dhcp-server-identifier 76.96.95.6;
renew 1 2013/1/28 19:14:13;
...
}

3) but when it comes time to renew, my pf rules block outgoing UDP to port 67,
so the following is in pflog:
Jan 28 11:14:13.977566 rule 73/(match) block out on em1:
76.27.218.121.68 > 76.96.95.6.67: xid:0x2530b3a4 C:76.27.218.121
ether 00:07:e9:1a:37:6b [|bootp] [tos 0x10]

4) I see a corresponding message in /var/log/daemon:
Jan 28 11:14:13 (myname) dhclient[27723]: DHCPREQUEST on em1 to 76.96.95.6 port 67
Jan 28 11:14:13 (myname) dhclient[27723]: send_packet: No route to host

5) My dhclient.leases.em1 file is not updated. My dhclient is unable to renew
its lease. As time goes on, dhclient makes more and more DHCPREQUESTs at
shorter and shorter intervals.

6) So, is this a bug in the dhclient implementation, or am I misunderstanding
something? Either way, it's not a big deal, I can just allow DHCP packets in
the firewall like I was doing until just recently.

Thanks,
Bohdan
Andres Perera
2013-01-29 05:22:08 UTC
Permalink
Post by Bohdan Tashchuk
Hi guys,
http://marc.info/?l=openbsd-misc&m=125907434809727&w=2
"dhcp packets are grabbed by dhclient or dhcpd before pf sees them."
My understanding, based on comments in a number of threads like that,
is that NO MATTER WHAT IS IN PF RULES, that dhcpd and dhclient should
both work fine. This is because dhcpd and dhclient both use bpf to
completely bypass pf.
when dhclient sends an unicast message, such as when renewing a lease,
it doesn't use bpf fd... it uses a "regular" socket and writes to it
using sendmsg()

the relevant code is send_packet() in src/sbin/dhclient/bpf.c and
if_register_send() in the same file for the unicast socket
instantiation routine
Andres Perera
2013-01-29 05:39:35 UTC
Permalink
Post by Andres Perera
Post by Bohdan Tashchuk
Hi guys,
http://marc.info/?l=openbsd-misc&m=125907434809727&w=2
"dhcp packets are grabbed by dhclient or dhcpd before pf sees them."
My understanding, based on comments in a number of threads like that,
is that NO MATTER WHAT IS IN PF RULES, that dhcpd and dhclient should
both work fine. This is because dhcpd and dhclient both use bpf to
completely bypass pf.
when dhclient sends an unicast message, such as when renewing a lease,
it doesn't use bpf fd... it uses a "regular" socket and writes to it
using sendmsg()
the relevant code is send_packet() in src/sbin/dhclient/bpf.c and
if_register_send() in the same file for the unicast socket
instantiation routine
more than that, really, why should you or anybody care

using bpf or not should be an implementation detail. no one should be
making decisions as far as their pf config goes based upon whether
dhclient uses bpf or not

ideally dhclient should be able to write broadcast messages without
bpf! it wouldn't be a significant simplification but it's still
something
Bohdan Tashchuk
2013-01-29 08:58:40 UTC
Permalink
Post by Andres Perera
more than that, really, why should you or anybody care
using bpf or not should be an implementation detail. no one should
be making decisions as far as their pf config goes based upon
whether dhclient uses bpf or not
Thanks for your comments on the source code. I briefly looked thru
/usr/src/sbin/dhclient, but there were 6289 lines of *.c code there.
I'm not that familiar with networking code so there was too much
for me to easily comprehend.

I agree that bpf is simply an implementation technique; I don't really care
*how* dhclient does what it does. But I want to understand the required pf
rules for two reasons:

1) there have been people who have said (e.g. in the thread I quoted):

"Using DHCP is not possible, pf block it, and i don't understand why"

Missing pf rules are one reason why dhcp would fail. Many people search
for similar problems years later; I don't want them to be confused as I was.

2) This is the important one for me. I want to be a "good Internet citizen".
So I try to write my pf rules to be as restrictive as possible. I want to
keep machines behind my firewall from being "bad Internet citizens".
Right now my outgoing UDP below port 1024 is restricted to ports domain,
kerberos, and ntp. I will add dhcp to that list.

I know I'm being a little quixotic (or perhaps pedantic) here. If there's
a misbehaving machine behind my firewall, I don't think that restricting
its UDP ports is going to make a whole lot of difference to the Internet
at large. But I'm trying to do what I can.
Andres Perera
2013-01-29 09:19:02 UTC
Permalink
Post by Bohdan Tashchuk
Post by Andres Perera
more than that, really, why should you or anybody care
using bpf or not should be an implementation detail. no one should
be making decisions as far as their pf config goes based upon
whether dhclient uses bpf or not
Thanks for your comments on the source code. I briefly looked thru
/usr/src/sbin/dhclient, but there were 6289 lines of *.c code there.
I'm not that familiar with networking code so there was too much
for me to easily comprehend.
in the future, you can use systrace to find out what fd programs are
really writing to. it has saved me enormous amounts of time when
troubleshooting, e.g., cvs slowness. familiarizing myself with cvs's
code base would've undoubtedly been more expensive
Post by Bohdan Tashchuk
I agree that bpf is simply an implementation technique; I don't really care
*how* dhclient does what it does. But I want to understand the required pf
"Using DHCP is not possible, pf block it, and i don't understand why"
Missing pf rules are one reason why dhcp would fail. Many people search
for similar problems years later; I don't want them to be confused as I was.
2) This is the important one for me. I want to be a "good Internet citizen".
So I try to write my pf rules to be as restrictive as possible. I want to
keep machines behind my firewall from being "bad Internet citizens".
Right now my outgoing UDP below port 1024 is restricted to ports domain,
kerberos, and ntp. I will add dhcp to that list.
I know I'm being a little quixotic (or perhaps pedantic) here. If there's
a misbehaving machine behind my firewall, I don't think that restricting
its UDP ports is going to make a whole lot of difference to the Internet
at large. But I'm trying to do what I can.
as it stands, i would wait for an "official" recommendation before
jumping to conclusions. i'm only pointing out the problem. it could be
that routing these unicast messages is useful, which is why they
aren't being written directly to the interface's output buffer via
bpf, or it could very well be that someone is devising a patch to
write them through bpf regardless because the routing isn't
required... that's a problem area i'm not familiar with, but i would
expect $router_network == $dhcpd_network in common configurations...
and even if not, having them potentially route through different
interfaces makes no friggen sense

Loading...