summaryrefslogtreecommitdiffstats
path: root/sbin/dhclient/bpf.c
diff options
context:
space:
mode:
authorphilip <philip@FreeBSD.org>2009-10-21 23:50:35 +0000
committerphilip <philip@FreeBSD.org>2009-10-21 23:50:35 +0000
commita72663b23bf3cf6b649e0ef3794c893c317ed0bd (patch)
tree4932df0222a83ed26798bc6e55796c6d07fa1066 /sbin/dhclient/bpf.c
parentec50bd2dc073063cd6fdb77344b2850072ce342c (diff)
downloadFreeBSD-src-a72663b23bf3cf6b649e0ef3794c893c317ed0bd.zip
FreeBSD-src-a72663b23bf3cf6b649e0ef3794c893c317ed0bd.tar.gz
Make dhclient use bootpc (68) as the source port for unicast DHCPREQUEST
packets instead of allowing the protocol stack to pick a random source port. This fixes the behaviour where dhclient would never transition from RENEWING to BOUND without going through REBINDING in networks which are paranoid about DHCP spoofing, such as most mainstream cable-broadband ISP networks. Reviewed by: brooks Obtained from: OpenBSD (partly - I'm not convinced their solution can work) MFC after: 1 week (pending re approval)
Diffstat (limited to 'sbin/dhclient/bpf.c')
-rw-r--r--sbin/dhclient/bpf.c45
1 files changed, 27 insertions, 18 deletions
diff --git a/sbin/dhclient/bpf.c b/sbin/dhclient/bpf.c
index 8a669e1..9f8e45f 100644
--- a/sbin/dhclient/bpf.c
+++ b/sbin/dhclient/bpf.c
@@ -90,11 +90,23 @@ if_register_bpf(struct interface_info *info)
void
if_register_send(struct interface_info *info)
{
+ int sock, on = 1;
+
/*
* If we're using the bpf API for sending and receiving, we
* don't need to register this interface twice.
*/
info->wfdesc = info->rfdesc;
+
+ /*
+ * Use raw socket for unicast send.
+ */
+ if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_UDP)) == -1)
+ error("socket(SOCK_RAW): %m");
+ if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &on,
+ sizeof(on)) == -1)
+ error("setsockopt(IP_HDRINCL): %m");
+ info->ufdesc = sock;
}
/*
@@ -244,35 +256,32 @@ send_packet(struct interface_info *interface, struct dhcp_packet *raw,
{
unsigned char buf[256];
struct iovec iov[2];
+ struct msghdr msg;
int result, bufp = 0;
- int sock;
-
- if (to->sin_addr.s_addr != INADDR_BROADCAST) {
- note("SENDING DIRECT");
- /* We know who the server is, send the packet via
- normal socket interface */
-
- if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) >= 0) {
- result = sendto (sock, (char *)raw, len, 0,
- (struct sockaddr *)to, sizeof *to);
- close(sock);
- if (result > 0)
- return result;
- }
- }
/* Assemble the headers... */
- assemble_hw_header(interface, buf, &bufp, hto);
+ if (to->sin_addr.s_addr == INADDR_BROADCAST)
+ assemble_hw_header(interface, buf, &bufp, hto);
assemble_udp_ip_header(buf, &bufp, from.s_addr,
to->sin_addr.s_addr, to->sin_port, (unsigned char *)raw, len);
- /* Fire it off */
iov[0].iov_base = (char *)buf;
iov[0].iov_len = bufp;
iov[1].iov_base = (char *)raw;
iov[1].iov_len = len;
- result = writev(interface->wfdesc, iov, 2);
+ /* Fire it off */
+ if (to->sin_addr.s_addr == INADDR_BROADCAST)
+ result = writev(interface->wfdesc, iov, 2);
+ else {
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_name = (struct sockaddr *)to;
+ msg.msg_namelen = sizeof(*to);
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 2;
+ result = sendmsg(interface->ufdesc, &msg, 0);
+ }
+
if (result < 0)
warning("send_packet: %m");
return (result);
OpenPOWER on IntegriCloud