svn commit: r198412 - stable/6/sbin/dhclient

Philip Paeps philip at FreeBSD.org
Fri Oct 23 15:42:23 UTC 2009


Author: philip
Date: Fri Oct 23 15:42:23 2009
New Revision: 198412
URL: http://svn.freebsd.org/changeset/base/198412

Log:
  MFC r198352
  
    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.
  
  Obtained from:	OpenBSD
  Reviewed by:	brooks
  Approved by:	re (kib)

Modified:
  stable/6/sbin/dhclient/   (props changed)
  stable/6/sbin/dhclient/bpf.c
  stable/6/sbin/dhclient/dhcpd.h
  stable/6/sbin/dhclient/packet.c

Modified: stable/6/sbin/dhclient/bpf.c
==============================================================================
--- stable/6/sbin/dhclient/bpf.c	Fri Oct 23 15:14:54 2009	(r198411)
+++ stable/6/sbin/dhclient/bpf.c	Fri Oct 23 15:42:23 2009	(r198412)
@@ -90,11 +90,23 @@ if_register_bpf(struct interface_info *i
 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 *inter
 {
 	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);

Modified: stable/6/sbin/dhclient/dhcpd.h
==============================================================================
--- stable/6/sbin/dhclient/dhcpd.h	Fri Oct 23 15:14:54 2009	(r198411)
+++ stable/6/sbin/dhclient/dhcpd.h	Fri Oct 23 15:42:23 2009	(r198412)
@@ -37,6 +37,8 @@
  * Enterprises.  To learn more about the Internet Software Consortium,
  * see ``http://www.vix.com/isc''.  To learn more about Vixie
  * Enterprises, see ``http://www.vix.com''.
+ *
+ * $FreeBSD$
  */
 
 #include <sys/types.h>
@@ -194,6 +196,7 @@ struct interface_info {
 	char			 name[IFNAMSIZ];
 	int			 rfdesc;
 	int			 wfdesc;
+	int			 ufdesc;
 	unsigned char		*rbuf;
 	size_t			 rbuf_max;
 	size_t			 rbuf_offset;

Modified: stable/6/sbin/dhclient/packet.c
==============================================================================
--- stable/6/sbin/dhclient/packet.c	Fri Oct 23 15:14:54 2009	(r198411)
+++ stable/6/sbin/dhclient/packet.c	Fri Oct 23 15:42:23 2009	(r198412)
@@ -135,6 +135,17 @@ assemble_udp_ip_header(unsigned char *bu
 	ip.ip_dst.s_addr = to;
 
 	ip.ip_sum = wrapsum(checksum((unsigned char *)&ip, sizeof(ip), 0));
+
+	/*
+	 * While the BPF -- used for broadcasts -- expects a "true" IP header
+	 * with all the bytes in network byte order, the raw socket interface
+	 * which is used for unicasts expects the ip_len field to be in host
+	 * byte order.  In both cases, the checksum has to be correct, so this
+	 * is as good a place as any to turn the bytes around again.
+	 */
+	if (to != INADDR_BROADCAST)
+		ip.ip_len = ntohs(ip.ip_len);
+
 	memcpy(&buf[*bufix], &ip, sizeof(ip));
 	*bufix += sizeof(ip);
 


More information about the svn-src-stable-6 mailing list