components/isc-dhcp/patches/sockets.patch
changeset 473 b88384d5a7ae
parent 472 b4bf6ad34a2d
child 474 742dc4436b35
equal deleted inserted replaced
472:b4bf6ad34a2d 473:b88384d5a7ae
     1 --- dhcp-4.1-ESV-R1/common/discover.c	Tue Sep 29 12:44:49 2009
       
     2 +++ dhcp-4.1-ESV-R1-patched/common/discover.c	Thu May 26 11:49:33 2011
       
     3 @@ -309,6 +309,7 @@
       
     4  next_iface(struct iface_info *info, int *err, struct iface_conf_list *ifaces) {
       
     5  	struct LIFREQ *p;
       
     6  	struct LIFREQ tmp;
       
     7 +	isc_boolean_t foundif;
       
     8  #if defined(sun) || defined(__linux)
       
     9  	/* Pointer used to remove interface aliases. */
       
    10  	char *s;
       
    11 @@ -315,6 +316,7 @@
       
    12  #endif
       
    13  
       
    14  	do {
       
    15 +		foundif = ISC_FALSE;
       
    16  		if (ifaces->next >= ifaces->num) {
       
    17  			*err = 0;
       
    18  			return 0;
       
    19 @@ -328,6 +330,13 @@
       
    20  			log_error("Interface name '%s' too long", p->lifr_name);
       
    21  			return 0;
       
    22  		}
       
    23 +
       
    24 +		/* Reject if interface address family does not match */
       
    25 +		if (p->lifr_addr.ss_family != local_family) {
       
    26 +			ifaces->next++;
       
    27 +			continue;
       
    28 +		}
       
    29 +
       
    30  		strcpy(info->name, p->lifr_name);
       
    31  		memset(&info->addr, 0, sizeof(info->addr));
       
    32  		memcpy(&info->addr, &p->lifr_addr, sizeof(p->lifr_addr));
       
    33 @@ -340,7 +349,9 @@
       
    34  		}
       
    35  #endif /* defined(sun) || defined(__linux) */
       
    36  
       
    37 -	} while (strncmp(info->name, "dummy", 5) == 0);
       
    38 +		foundif = ISC_TRUE;
       
    39 +	} while ((foundif == ISC_FALSE) ||
       
    40 +	    (strncmp(p->lifr_name, "dummy", 5) == 0));
       
    41  	
       
    42  	memset(&tmp, 0, sizeof(tmp));
       
    43  	strcpy(tmp.lifr_name, info->name);
       
    44 @@ -958,7 +969,12 @@
       
    45  		   point-to-point in case an OS incorrectly marks them
       
    46  		   as broadcast). Also skip down interfaces unless we're
       
    47  		   trying to get a list of configurable interfaces. */
       
    48 -		if (((!(info.flags & IFF_BROADCAST) ||
       
    49 +		if ((((local_family == AF_INET &&
       
    50 +		    !(info.flags & IFF_BROADCAST)) ||
       
    51 +#ifdef DHCPv6
       
    52 +		    (local_family == AF_INET6 &&
       
    53 +		    !(info.flags & IFF_MULTICAST)) ||
       
    54 +#endif
       
    55  		      info.flags & IFF_LOOPBACK ||
       
    56  		      info.flags & IFF_POINTOPOINT) && !tmp) ||
       
    57  		    (!(info.flags & IFF_UP) &&
       
    58 @@ -1386,6 +1402,25 @@
       
    59  	if (result < DHCP_FIXED_NON_UDP - DHCP_SNAME_LEN - DHCP_FILE_LEN)
       
    60  		return ISC_R_UNEXPECTED;
       
    61  
       
    62 +#if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO)
       
    63 +	{
       
    64 +		/* We retrieve the ifindex from the unused hfrom variable */
       
    65 +		unsigned int ifindex;
       
    66 +
       
    67 +		memcpy(&ifindex, hfrom.hbuf, sizeof (ifindex));
       
    68 +
       
    69 +		/*
       
    70 +		 * Seek forward from the first interface to find the matching
       
    71 +		 * source interface by interface index.
       
    72 +		 */
       
    73 +		ip = interfaces;
       
    74 +		while ((ip != NULL) && (if_nametoindex(ip->name) != ifindex))
       
    75 +			ip = ip->next;
       
    76 +		if (ip == NULL)
       
    77 +			return ISC_R_NOTFOUND;
       
    78 +	}
       
    79 +#endif
       
    80 +
       
    81  	if (bootp_packet_handler) {
       
    82  		ifrom.len = 4;
       
    83  		memcpy (ifrom.iabuf, &from.sin_addr, ifrom.len);
       
    84 @@ -1442,7 +1477,11 @@
       
    85  		ifrom.len = 16;
       
    86  		memcpy(ifrom.iabuf, &from.sin6_addr, ifrom.len);
       
    87  
       
    88 -		/* Seek forward to find the matching source interface. */
       
    89 +		/*
       
    90 +		 * Seek forward from the first interface to find the matching
       
    91 +		 * source interface by interface index.
       
    92 +		 */
       
    93 +		ip = interfaces;
       
    94  		while ((ip != NULL) && (if_nametoindex(ip->name) != if_idx))
       
    95  			ip = ip->next;
       
    96  
       
    97 --- dhcp-4.1-ESV-R1/common/socket.c	Tue Oct  5 17:32:52 2010
       
    98 +++ dhcp-4.1-ESV-R1-patched/common/socket.c	Thu May 12 16:11:13 2011
       
    99 @@ -45,6 +45,16 @@
       
   100  #include <sys/ioctl.h>
       
   101  #include <sys/uio.h>
       
   102  #include <sys/uio.h>
       
   103 +#if defined(sun)
       
   104 +#include <sys/sysmacros.h>
       
   105 +#include <net/if.h>
       
   106 +#include <sys/sockio.h>
       
   107 +#if defined(SIOCGLIFHWADDR)
       
   108 +#include <net/if_dl.h>
       
   109 +#else
       
   110 +#include <libdlpi.h>
       
   111 +#endif
       
   112 +#endif
       
   113  #include <signal.h>
       
   114  
       
   115  #ifdef USE_SOCKET_FALLBACK
       
   116 @@ -67,6 +77,16 @@
       
   117  #endif
       
   118  
       
   119  /*
       
   120 + * We can use a single socket for AF_INET (similar to AF_INET6) on all
       
   121 + * interfaces configured for DHCP if the system has support for IP_PKTINFO
       
   122 + * and IP_RECVPKTINFO (f.e. Solaris 11).
       
   123 + */
       
   124 +#if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO)
       
   125 +static unsigned int global_v4_socket_references = 0;
       
   126 +static int global_v4_socket = -1;
       
   127 +#endif
       
   128 +
       
   129 +/*
       
   130   * If we can't bind() to a specific interface, then we can only have
       
   131   * a single socket. This variable insures that we don't try to listen
       
   132   * on two sockets.
       
   133 @@ -242,6 +262,20 @@
       
   134  		log_fatal("Can't set IP_BROADCAST_IF on dhcp socket: %m");
       
   135  #endif
       
   136  
       
   137 +#if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO)
       
   138 +	/*
       
   139 +	 * If we turn on IP_RECVPKTINFO we will be able to receive
       
   140 +	 * the interface index information of the received packet.
       
   141 +	 */
       
   142 +	if (family == AF_INET) {
       
   143 +		int on = 1;
       
   144 +		if (setsockopt(sock, IPPROTO_IP, IP_RECVPKTINFO, 
       
   145 +		               &on, sizeof(on)) != 0) {
       
   146 +			log_fatal("setsockopt: IPV_RECVPKTINFO: %m");
       
   147 +		}
       
   148 +	}
       
   149 +#endif
       
   150 +
       
   151  #ifdef DHCPv6
       
   152  	/*
       
   153  	 * If we turn on IPV6_PKTINFO, we will be able to receive 
       
   154 @@ -275,10 +309,6 @@
       
   155  	}
       
   156  #endif /* DHCPv6 */
       
   157  
       
   158 -	/* If this is a normal IPv4 address, get the hardware address. */
       
   159 -	if ((local_family == AF_INET) && (strcmp(info->name, "fallback") != 0))
       
   160 -		get_hw_addr(info->name, &info->hw_address);
       
   161 -
       
   162  	return sock;
       
   163  }
       
   164  #endif /* USE_SOCKET_SEND || USE_SOCKET_RECEIVE || USE_SOCKET_FALLBACK */
       
   165 @@ -328,9 +358,25 @@
       
   166  void if_register_receive (info)
       
   167  	struct interface_info *info;
       
   168  {
       
   169 +#if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO)
       
   170 +	if (global_v4_socket_references == 0) {
       
   171 +		global_v4_socket = if_register_socket(info, AF_INET, 0);
       
   172 +		if (global_v4_socket < 0) {
       
   173 +			/*
       
   174 +			 * if_register_socket() fatally logs if it fails to
       
   175 +			 * create a socket, this is just a sanity check.
       
   176 +			 */
       
   177 +			log_fatal("Failed to create AF_INET socket %s:%d", MDL);
       
   178 +		}
       
   179 +	}
       
   180 +		
       
   181 +	info->rfdesc = global_v4_socket;
       
   182 +	global_v4_socket_references++;
       
   183 +#else
       
   184  	/* If we're using the socket API for sending and receiving,
       
   185  	   we don't need to register this interface twice. */
       
   186  	info -> rfdesc = if_register_socket (info, AF_INET, 0);
       
   187 +#endif
       
   188  	if (!quiet_interface_discovery)
       
   189  		log_info ("Listening on Socket/%s%s%s",
       
   190  		      info -> name,
       
   191 @@ -337,13 +383,34 @@
       
   192  		      (info -> shared_network ? "/" : ""),
       
   193  		      (info -> shared_network ?
       
   194  		       info -> shared_network -> name : ""));
       
   195 +
       
   196 +	/* If this is a normal IPv4 address, get the hardware address. */
       
   197 +	if (strcmp(info->name, "fallback") != 0)
       
   198 +		get_hw_addr(info->name, &info->hw_address);
       
   199  }
       
   200  
       
   201  void if_deregister_receive (info)
       
   202  	struct interface_info *info;
       
   203  {
       
   204 +#if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO)
       
   205 +	/* Dereference the global v4 socket. */
       
   206 +	if ((info->rfdesc == global_v4_socket) &&
       
   207 +	    (info->wfdesc == global_v4_socket) &&
       
   208 +	    (global_v4_socket_references > 0)) {
       
   209 +		global_v4_socket_references--;
       
   210 +		info->rfdesc = -1;
       
   211 +	} else {
       
   212 +		log_fatal("Impossible condition at %s:%d", MDL);
       
   213 +	}
       
   214 +
       
   215 +	if (global_v4_socket_references == 0) {
       
   216 +		close(global_v4_socket);
       
   217 +		global_v4_socket = -1;
       
   218 +	}
       
   219 +#else
       
   220  	close (info -> rfdesc);
       
   221  	info -> rfdesc = -1;
       
   222 +#endif
       
   223  
       
   224  	if (!quiet_interface_discovery)
       
   225  		log_info ("Disabling input on Socket/%s%s%s",
       
   226 @@ -489,6 +556,17 @@
       
   227  	int retry = 0;
       
   228  	do {
       
   229  #endif
       
   230 +#if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO)
       
   231 +		struct in_pktinfo pktinfo;
       
   232 +
       
   233 +		if (interface->ifp != NULL) {
       
   234 +			memset(&pktinfo, 0, sizeof (pktinfo));
       
   235 +			pktinfo.ipi_ifindex = interface->ifp->ifr_index;
       
   236 +			if (setsockopt(interface -> wfdesc, IPPROTO_IP,
       
   237 +			    IP_PKTINFO, (char *)&pktinfo, sizeof (pktinfo)) < 0)
       
   238 +				log_fatal("setsockopt: IP_PKTINFO: %m");
       
   239 +		}
       
   240 +#endif
       
   241  		result = sendto (interface -> wfdesc, (char *)raw, len, 0,
       
   242  				 (struct sockaddr *)to, sizeof *to);
       
   243  #ifdef IGNORE_HOSTUNREACH
       
   244 @@ -559,11 +637,13 @@
       
   245  
       
   246  #endif /* DHCPv6 */
       
   247  
       
   248 -#ifdef DHCPv6
       
   249 +#ifdef DHCPv6 || (defined(IP_PKTINFO) && defined(IP_RECVPKTINFO))
       
   250  /*
       
   251   * For both send_packet6() and receive_packet6() we need to allocate
       
   252   * space for the cmsg header information.  We do this once and reuse
       
   253 - * the buffer.
       
   254 + * the buffer. We also need the control buf for send_packet and
       
   255 + * receive_packet for AF_INET when we use a single socket and IP_PKTINFO
       
   256 + * to send the packet out the right interface.
       
   257   */
       
   258  static void   *control_buf = NULL;
       
   259  static size_t  control_buf_len = 0;
       
   260 @@ -574,7 +654,9 @@
       
   261  	control_buf = dmalloc(control_buf_len, MDL);
       
   262  	return;
       
   263  }
       
   264 +#endif
       
   265  
       
   266 +#ifdef DHCPv6
       
   267  /* 
       
   268   * For both send_packet6() and receive_packet6() we need to use the 
       
   269   * sendmsg()/recvmsg() functions rather than the simpler send()/recv()
       
   270 @@ -687,8 +769,97 @@
       
   271  	int retry = 0;
       
   272  	do {
       
   273  #endif
       
   274 +#if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO)
       
   275 +	struct msghdr m;
       
   276 +	struct iovec v;
       
   277 +	struct cmsghdr *cmsg;
       
   278 +	struct in_pktinfo *pktinfo;
       
   279 +	unsigned int ifindex;
       
   280 +	int found_pktinfo;
       
   281 +
       
   282 +	/*
       
   283 +	 * If necessary allocate space for the control message header.
       
   284 +	 * The space is common between send and receive.
       
   285 +	 */
       
   286 +	if (control_buf == NULL) {
       
   287 +		allocate_cmsg_cbuf();
       
   288 +		if (control_buf == NULL) {
       
   289 +			log_error("receive_packet: unable to allocate cmsg "
       
   290 +				  "header");
       
   291 +			return(ENOMEM);
       
   292 +		}
       
   293 +	}
       
   294 +	memset(control_buf, 0, control_buf_len);
       
   295 +
       
   296 +	/*
       
   297 +	 * Initialize our message header structure.
       
   298 +	 */
       
   299 +	memset(&m, 0, sizeof(m));
       
   300 +
       
   301 +	/*
       
   302 +	 * Point so we can get the from address.
       
   303 +	 */
       
   304 +	m.msg_name = from;
       
   305 +	m.msg_namelen = sizeof(*from);
       
   306 +
       
   307 +	/*
       
   308 +	 * Set the data buffer we're receiving. (Using this wacky 
       
   309 +	 * "scatter-gather" stuff... but we that doesn't really make
       
   310 +	 * sense for us, so we use a single vector entry.)
       
   311 +	 */
       
   312 +	v.iov_base = buf;
       
   313 +	v.iov_len = len;
       
   314 +	m.msg_iov = &v;
       
   315 +	m.msg_iovlen = 1;
       
   316 +
       
   317 +	/*
       
   318 +	 * Getting the interface is a bit more involved.
       
   319 +	 *
       
   320 +	 * We set up some space for a "control message". We have 
       
   321 +	 * previously asked the kernel to give us packet 
       
   322 +	 * information (when we initialized the interface), so we
       
   323 +	 * should get the destination address from that.
       
   324 +	 */
       
   325 +	m.msg_control = control_buf;
       
   326 +	m.msg_controllen = control_buf_len;
       
   327 +
       
   328 +	result = recvmsg(interface->rfdesc, &m, 0);
       
   329 +
       
   330 +	if (result >= 0) {
       
   331 +		/*
       
   332 +		 * If we did read successfully, then we need to loop
       
   333 +		 * through the control messages we received and 
       
   334 +		 * find the one with our destination address.
       
   335 +		 *
       
   336 +		 * We also keep a flag to see if we found it. If we 
       
   337 +		 * didn't, then we consider this to be an error.
       
   338 +		 */
       
   339 +		found_pktinfo = 0;
       
   340 +		cmsg = CMSG_FIRSTHDR(&m);
       
   341 +		while (cmsg != NULL) {
       
   342 +			if ((cmsg->cmsg_level == IPPROTO_IP) && 
       
   343 +			    (cmsg->cmsg_type == IP_PKTINFO)) {
       
   344 +				pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
       
   345 +				ifindex = pktinfo->ipi_ifindex;
       
   346 +				/*
       
   347 +				 * We pass the ifindex back to the caller using
       
   348 +				 * the unused hfrom parameter avoiding interface
       
   349 +				 * changes between sockets and the discover code.
       
   350 +				 */
       
   351 +				memcpy(hfrom->hbuf, &ifindex, sizeof (ifindex));
       
   352 +				found_pktinfo = 1;
       
   353 +			}
       
   354 +			cmsg = CMSG_NXTHDR(&m, cmsg);
       
   355 +		}
       
   356 +		if (!found_pktinfo) {
       
   357 +			result = -1;
       
   358 +			errno = EIO;
       
   359 +		}
       
   360 +	}
       
   361 +#else
       
   362  		result = recvfrom (interface -> rfdesc, (char *)buf, len, 0,
       
   363  				   (struct sockaddr *)from, &flen);
       
   364 +#endif
       
   365  #ifdef IGNORE_HOSTUNREACH
       
   366  	} while (result < 0 &&
       
   367  		 (errno == EHOSTUNREACH ||
       
   368 @@ -842,7 +1013,7 @@
       
   369  int supports_multiple_interfaces (ip)
       
   370  	struct interface_info *ip;
       
   371  {
       
   372 -#if defined (SO_BINDTODEVICE)
       
   373 +#if defined (SO_BINDTODEVICE) || (defined(IP_PKTINFO) && defined(IP_RECVPKTINFO))
       
   374  	return 1;
       
   375  #else
       
   376  	return 0;
       
   377 @@ -876,6 +1047,80 @@
       
   378  	}
       
   379  #endif
       
   380  }
       
   381 +
       
   382 +#if defined(sun)
       
   383 +void
       
   384 +get_hw_addr(const char *name, struct hardware *hw) {
       
   385 +#if defined(SIOCGLIFHWADDR)
       
   386 +	struct sockaddr_dl *dladdrp;
       
   387 +#else
       
   388 +	dlpi_handle_t dh;
       
   389 +	uint8_t pa_buf[DLPI_PHYSADDR_MAX];
       
   390 +	size_t  len = sizeof (pa_buf);
       
   391 +#endif
       
   392 +	int rv, sock, i;
       
   393 +	struct lifreq lifr;
       
   394 +
       
   395 +	memset(&lifr, 0, sizeof (lifr));
       
   396 +	(void) strlcpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
       
   397 +	/*
       
   398 +	 * Check if the interface is a virtual or IPMP interface - in those
       
   399 +	 * cases it has no hw address, so generate a random one.
       
   400 +	 */
       
   401 +	if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ||
       
   402 +	    ioctl(sock, SIOCGLIFFLAGS, &lifr) < 0) {
       
   403 +		/*
       
   404 +		 * If the interface only has IPv6, try this with an IPv6 socket.
       
   405 +		 */
       
   406 +		if (sock != -1)
       
   407 +			(void) close(sock);
       
   408 +
       
   409 +		if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0 ||
       
   410 +		    ioctl(sock, SIOCGLIFFLAGS, &lifr) < 0) {
       
   411 +			log_fatal("Couldn't get interface flags for %s: %m", name);
       
   412 +		}
       
   413 +	}
       
   414 +
       
   415 +	if (lifr.lifr_flags & (IFF_VIRTUAL|IFF_IPMP)) {
       
   416 +		hw->hlen = sizeof (hw->hbuf);
       
   417 +		srandom((long)gethrtime());
       
   418 +
       
   419 +		for (i = 0; i < hw->hlen; ++i) {
       
   420 +			hw->hbuf[i] = random() % 256;
       
   421 +		}
       
   422 +
       
   423 +		if (sock != -1)
       
   424 +			(void) close(sock);
       
   425 +		return;
       
   426 +	}
       
   427 +
       
   428 +#if defined(SIOCGLIFHWADDR)
       
   429 +	if (ioctl(sock, SIOCGLIFHWADDR, &lifr) < 0)
       
   430 +		log_fatal("Couldn't get interface hardware address for %s: %m", name);
       
   431 +	dladdrp = (struct sockaddr_dl *)&lifr.lifr_addr;
       
   432 +	hw->hlen = dladdrp->sdl_alen;
       
   433 +	memcpy(hw->hbuf, LLADDR(dladdrp), hw->hlen);
       
   434 +#else
       
   435 +	if ((rv = dlpi_open(name, &dh, 0)) != DLPI_SUCCESS) {
       
   436 +		log_fatal("Couldn't open DLPI device for %s: %s", name,
       
   437 +		dlpi_strerror(rv));
       
   438 +	}
       
   439 +
       
   440 +	if ((rv = dlpi_get_physaddr(dh, DL_CURR_PHYS_ADDR, pa_buf, &len))
       
   441 +	    != DLPI_SUCCESS) {
       
   442 +		log_fatal("Couldn't get physical address for device %s: %s",
       
   443 +		name, dlpi_strerror(rv));
       
   444 +	}
       
   445 +
       
   446 +	hw->hlen = MIN(sizeof (hw->hbuf), len);
       
   447 +	memcpy(hw->hbuf, pa_buf, hw->hlen);
       
   448 +
       
   449 +	dlpi_close(dh);
       
   450 +#endif
       
   451 +	if (sock != -1)
       
   452 +		(void) close(sock);
       
   453 +}
       
   454 +#endif /* defined(sun) */
       
   455  #endif /* USE_SOCKET_SEND */
       
   456  
       
   457  /*