|
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 /* |