1: /* socket.c
2:
3: BSD socket interface code... */
4:
5: /*
6: * Copyright (c) 2004-2011 by Internet Systems Consortium, Inc. ("ISC")
7: * Copyright (c) 1995-2003 by Internet Software Consortium
8: *
9: * Permission to use, copy, modify, and distribute this software for any
10: * purpose with or without fee is hereby granted, provided that the above
11: * copyright notice and this permission notice appear in all copies.
12: *
13: * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
16: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19: * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20: *
21: * Internet Systems Consortium, Inc.
22: * 950 Charter Street
23: * Redwood City, CA 94063
24: * <info@isc.org>
25: * https://www.isc.org/
26: *
27: * This software has been written for Internet Systems Consortium
28: * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
29: * To learn more about Internet Systems Consortium, see
30: * ``https://www.isc.org/''. To learn more about Vixie Enterprises,
31: * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
32: * ``http://www.nominum.com''.
33: */
34:
35: /* SO_BINDTODEVICE support added by Elliot Poger (poger@leland.stanford.edu).
36: * This sockopt allows a socket to be bound to a particular interface,
37: * thus enabling the use of DHCPD on a multihomed host.
38: * If SO_BINDTODEVICE is defined in your system header files, the use of
39: * this sockopt will be automatically enabled.
40: * I have implemented it under Linux; other systems should be doable also.
41: */
42:
43: #include "dhcpd.h"
44: #include <errno.h>
45: #include <sys/ioctl.h>
46: #include <sys/uio.h>
47: #include <sys/uio.h>
48: #include <signal.h>
49:
50: #if defined(sun) && defined(USE_V4_PKTINFO)
51: #include <sys/sysmacros.h>
52: #include <net/if.h>
53: #include <sys/sockio.h>
54: #include <net/if_dl.h>
55: #endif
56:
57: #ifdef USE_SOCKET_FALLBACK
58: # if !defined (USE_SOCKET_SEND)
59: # define if_register_send if_register_fallback
60: # define send_packet send_fallback
61: # define if_reinitialize_send if_reinitialize_fallback
62: # endif
63: #endif
64:
65: #if defined(DHCPv6)
66: /*
67: * XXX: this is gross. we need to go back and overhaul the API for socket
68: * handling.
69: */
70: static unsigned int global_v6_socket_references = 0;
71: static int global_v6_socket = -1;
72:
73: static void if_register_multicast(struct interface_info *info);
74: #endif
75:
76: /*
77: * We can use a single socket for AF_INET (similar to AF_INET6) on all
78: * interfaces configured for DHCP if the system has support for IP_PKTINFO
79: * and IP_RECVPKTINFO (for example Solaris 11).
80: */
81: #if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && defined(USE_V4_PKTINFO)
82: static unsigned int global_v4_socket_references = 0;
83: static int global_v4_socket = -1;
84: #endif
85:
86: /*
87: * If we can't bind() to a specific interface, then we can only have
88: * a single socket. This variable insures that we don't try to listen
89: * on two sockets.
90: */
91: #if !defined(SO_BINDTODEVICE) && !defined(USE_FALLBACK)
92: static int once = 0;
93: #endif /* !defined(SO_BINDTODEVICE) && !defined(USE_FALLBACK) */
94:
95: /* Reinitializes the specified interface after an address change. This
96: is not required for packet-filter APIs. */
97:
98: #if defined (USE_SOCKET_SEND) || defined (USE_SOCKET_FALLBACK)
99: void if_reinitialize_send (info)
100: struct interface_info *info;
101: {
102: #if 0
103: #ifndef USE_SOCKET_RECEIVE
104: once = 0;
105: close (info -> wfdesc);
106: #endif
107: if_register_send (info);
108: #endif
109: }
110: #endif
111:
112: #ifdef USE_SOCKET_RECEIVE
113: void if_reinitialize_receive (info)
114: struct interface_info *info;
115: {
116: #if 0
117: once = 0;
118: close (info -> rfdesc);
119: if_register_receive (info);
120: #endif
121: }
122: #endif
123:
124: #if defined (USE_SOCKET_SEND) || \
125: defined (USE_SOCKET_RECEIVE) || \
126: defined (USE_SOCKET_FALLBACK)
127: /* Generic interface registration routine... */
128: int
129: if_register_socket(struct interface_info *info, int family,
130: int *do_multicast)
131: {
132: struct sockaddr_storage name;
133: int name_len;
134: int sock;
135: int flag;
136: int domain;
137:
138: /* INSIST((family == AF_INET) || (family == AF_INET6)); */
139:
140: #if !defined(SO_BINDTODEVICE) && !defined(USE_FALLBACK)
141: /* Make sure only one interface is registered. */
142: if (once) {
143: log_fatal ("The standard socket API can only support %s",
144: "hosts with a single network interface.");
145: }
146: once = 1;
147: #endif
148:
149: /*
150: * Set up the address we're going to bind to, depending on the
151: * address family.
152: */
153: memset(&name, 0, sizeof(name));
154: #ifdef DHCPv6
155: if (family == AF_INET6) {
156: struct sockaddr_in6 *addr = (struct sockaddr_in6 *)&name;
157: addr->sin6_family = AF_INET6;
158: addr->sin6_port = local_port;
159: /* XXX: What will happen to multicasts if this is nonzero? */
160: memcpy(&addr->sin6_addr,
161: &local_address6,
162: sizeof(addr->sin6_addr));
163: #ifdef HAVE_SA_LEN
164: addr->sin6_len = sizeof(*addr);
165: #endif
166: name_len = sizeof(*addr);
167: domain = PF_INET6;
168: if ((info->flags & INTERFACE_STREAMS) == INTERFACE_UPSTREAM) {
169: *do_multicast = 0;
170: }
171: } else {
172: #else
173: {
174: #endif /* DHCPv6 */
175: struct sockaddr_in *addr = (struct sockaddr_in *)&name;
176: addr->sin_family = AF_INET;
177: addr->sin_port = local_port;
178: memcpy(&addr->sin_addr,
179: &local_address,
180: sizeof(addr->sin_addr));
181: #ifdef HAVE_SA_LEN
182: addr->sin_len = sizeof(*addr);
183: #endif
184: name_len = sizeof(*addr);
185: domain = PF_INET;
186: }
187:
188: /* Make a socket... */
189: sock = socket(domain, SOCK_DGRAM, IPPROTO_UDP);
190: if (sock < 0) {
191: log_fatal("Can't create dhcp socket: %m");
192: }
193:
194: /* Set the REUSEADDR option so that we don't fail to start if
195: we're being restarted. */
196: flag = 1;
197: if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
198: (char *)&flag, sizeof(flag)) < 0) {
199: log_fatal("Can't set SO_REUSEADDR option on dhcp socket: %m");
200: }
201:
202: /* Set the BROADCAST option so that we can broadcast DHCP responses.
203: We shouldn't do this for fallback devices, and we can detect that
204: a device is a fallback because it has no ifp structure. */
205: if (info->ifp &&
206: (setsockopt(sock, SOL_SOCKET, SO_BROADCAST,
207: (char *)&flag, sizeof(flag)) < 0)) {
208: log_fatal("Can't set SO_BROADCAST option on dhcp socket: %m");
209: }
210:
211: #if defined(DHCPv6) && defined(SO_REUSEPORT)
212: /*
213: * We only set SO_REUSEPORT on AF_INET6 sockets, so that multiple
214: * daemons can bind to their own sockets and get data for their
215: * respective interfaces. This does not (and should not) affect
216: * DHCPv4 sockets; we can't yet support BSD sockets well, much
217: * less multiple sockets.
218: */
219: if (local_family == AF_INET6) {
220: flag = 1;
221: if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT,
222: (char *)&flag, sizeof(flag)) < 0) {
223: log_fatal("Can't set SO_REUSEPORT option on dhcp "
224: "socket: %m");
225: }
226: }
227: #endif
228:
229: /* Bind the socket to this interface's IP address. */
230: if (bind(sock, (struct sockaddr *)&name, name_len) < 0) {
231: log_error("Can't bind to dhcp address: %m");
232: log_error("Please make sure there is no other dhcp server");
233: log_error("running and that there's no entry for dhcp or");
234: log_error("bootp in /etc/inetd.conf. Also make sure you");
235: log_error("are not running HP JetAdmin software, which");
236: log_fatal("includes a bootp server.");
237: }
238:
239: #if defined(SO_BINDTODEVICE)
240: /* Bind this socket to this interface. */
241: if ((local_family != AF_INET6) && (info->ifp != NULL) &&
242: setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE,
243: (char *)(info -> ifp), sizeof(*(info -> ifp))) < 0) {
244: log_fatal("setsockopt: SO_BINDTODEVICE: %m");
245: }
246: #endif
247:
248: /* IP_BROADCAST_IF instructs the kernel which interface to send
249: * IP packets whose destination address is 255.255.255.255. These
250: * will be treated as subnet broadcasts on the interface identified
251: * by ip address (info -> primary_address). This is only known to
252: * be defined in SCO system headers, and may not be defined in all
253: * releases.
254: */
255: #if defined(SCO) && defined(IP_BROADCAST_IF)
256: if (info->address_count &&
257: setsockopt(sock, IPPROTO_IP, IP_BROADCAST_IF, &info->addresses[0],
258: sizeof(info->addresses[0])) < 0)
259: log_fatal("Can't set IP_BROADCAST_IF on dhcp socket: %m");
260: #endif
261:
262: #if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && defined(USE_V4_PKTINFO)
263: /*
264: * If we turn on IP_RECVPKTINFO we will be able to receive
265: * the interface index information of the received packet.
266: */
267: if (family == AF_INET) {
268: int on = 1;
269: if (setsockopt(sock, IPPROTO_IP, IP_RECVPKTINFO,
270: &on, sizeof(on)) != 0) {
271: log_fatal("setsockopt: IPV_RECVPKTINFO: %m");
272: }
273: }
274: #endif
275:
276: #ifdef DHCPv6
277: /*
278: * If we turn on IPV6_PKTINFO, we will be able to receive
279: * additional information, such as the destination IP address.
280: * We need this to spot unicast packets.
281: */
282: if (family == AF_INET6) {
283: int on = 1;
284: #ifdef IPV6_RECVPKTINFO
285: /* RFC3542 */
286: if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
287: &on, sizeof(on)) != 0) {
288: log_fatal("setsockopt: IPV6_RECVPKTINFO: %m");
289: }
290: #else
291: /* RFC2292 */
292: if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO,
293: &on, sizeof(on)) != 0) {
294: log_fatal("setsockopt: IPV6_PKTINFO: %m");
295: }
296: #endif
297: }
298:
299: if ((family == AF_INET6) &&
300: ((info->flags & INTERFACE_UPSTREAM) != 0)) {
301: int hop_limit = 32;
302: if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
303: &hop_limit, sizeof(int)) < 0) {
304: log_fatal("setsockopt: IPV6_MULTICAST_HOPS: %m");
305: }
306: }
307: #endif /* DHCPv6 */
308:
309: return sock;
310: }
311: #endif /* USE_SOCKET_SEND || USE_SOCKET_RECEIVE || USE_SOCKET_FALLBACK */
312:
313: #if defined (USE_SOCKET_SEND) || defined (USE_SOCKET_FALLBACK)
314: void if_register_send (info)
315: struct interface_info *info;
316: {
317: #ifndef USE_SOCKET_RECEIVE
318: info->wfdesc = if_register_socket(info, AF_INET, 0);
319: /* If this is a normal IPv4 address, get the hardware address. */
320: if (strcmp(info->name, "fallback") != 0)
321: get_hw_addr(info->name, &info->hw_address);
322: #if defined (USE_SOCKET_FALLBACK)
323: /* Fallback only registers for send, but may need to receive as
324: well. */
325: info->rfdesc = info->wfdesc;
326: #endif
327: #else
328: info->wfdesc = info->rfdesc;
329: #endif
330: if (!quiet_interface_discovery)
331: log_info ("Sending on Socket/%s%s%s",
332: info->name,
333: (info->shared_network ? "/" : ""),
334: (info->shared_network ?
335: info->shared_network->name : ""));
336: }
337:
338: #if defined (USE_SOCKET_SEND)
339: void if_deregister_send (info)
340: struct interface_info *info;
341: {
342: #ifndef USE_SOCKET_RECEIVE
343: close (info -> wfdesc);
344: #endif
345: info -> wfdesc = -1;
346:
347: if (!quiet_interface_discovery)
348: log_info ("Disabling output on Socket/%s%s%s",
349: info -> name,
350: (info -> shared_network ? "/" : ""),
351: (info -> shared_network ?
352: info -> shared_network -> name : ""));
353: }
354: #endif /* USE_SOCKET_SEND */
355: #endif /* USE_SOCKET_SEND || USE_SOCKET_FALLBACK */
356:
357: #ifdef USE_SOCKET_RECEIVE
358: void if_register_receive (info)
359: struct interface_info *info;
360: {
361:
362: #if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && defined(USE_V4_PKTINFO)
363: if (global_v4_socket_references == 0) {
364: global_v4_socket = if_register_socket(info, AF_INET, 0);
365: if (global_v4_socket < 0) {
366: /*
367: * if_register_socket() fatally logs if it fails to
368: * create a socket, this is just a sanity check.
369: */
370: log_fatal("Failed to create AF_INET socket %s:%d",
371: MDL);
372: }
373: }
374:
375: info->rfdesc = global_v4_socket;
376: global_v4_socket_references++;
377: #else
378: /* If we're using the socket API for sending and receiving,
379: we don't need to register this interface twice. */
380: info->rfdesc = if_register_socket(info, AF_INET, 0);
381: #endif /* IP_PKTINFO... */
382: /* If this is a normal IPv4 address, get the hardware address. */
383: if (strcmp(info->name, "fallback") != 0)
384: get_hw_addr(info->name, &info->hw_address);
385:
386: if (!quiet_interface_discovery)
387: log_info ("Listening on Socket/%s%s%s",
388: info->name,
389: (info->shared_network ? "/" : ""),
390: (info->shared_network ?
391: info->shared_network->name : ""));
392: }
393:
394: void if_deregister_receive (info)
395: struct interface_info *info;
396: {
397: #if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && defined(USE_V4_PKTINFO)
398: /* Dereference the global v4 socket. */
399: if ((info->rfdesc == global_v4_socket) &&
400: (info->wfdesc == global_v4_socket) &&
401: (global_v4_socket_references > 0)) {
402: global_v4_socket_references--;
403: info->rfdesc = -1;
404: } else {
405: log_fatal("Impossible condition at %s:%d", MDL);
406: }
407:
408: if (global_v4_socket_references == 0) {
409: close(global_v4_socket);
410: global_v4_socket = -1;
411: }
412: #else
413: close(info->rfdesc);
414: info->rfdesc = -1;
415: #endif /* IP_PKTINFO... */
416: if (!quiet_interface_discovery)
417: log_info ("Disabling input on Socket/%s%s%s",
418: info -> name,
419: (info -> shared_network ? "/" : ""),
420: (info -> shared_network ?
421: info -> shared_network -> name : ""));
422: }
423: #endif /* USE_SOCKET_RECEIVE */
424:
425:
426: #ifdef DHCPv6
427: /*
428: * This function joins the interface to DHCPv6 multicast groups so we will
429: * receive multicast messages.
430: */
431: static void
432: if_register_multicast(struct interface_info *info) {
433: int sock = info->rfdesc;
434: struct ipv6_mreq mreq;
435:
436: if (inet_pton(AF_INET6, All_DHCP_Relay_Agents_and_Servers,
437: &mreq.ipv6mr_multiaddr) <= 0) {
438: log_fatal("inet_pton: unable to convert '%s'",
439: All_DHCP_Relay_Agents_and_Servers);
440: }
441: mreq.ipv6mr_interface = if_nametoindex(info->name);
442: if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
443: &mreq, sizeof(mreq)) < 0) {
444: log_fatal("setsockopt: IPV6_JOIN_GROUP: %m");
445: }
446:
447: /*
448: * The relay agent code sets the streams so you know which way
449: * is up and down. But a relay agent shouldn't join to the
450: * Server address, or else you get fun loops. So up or down
451: * doesn't matter, we're just using that config to sense this is
452: * a relay agent.
453: */
454: if ((info->flags & INTERFACE_STREAMS) == 0) {
455: if (inet_pton(AF_INET6, All_DHCP_Servers,
456: &mreq.ipv6mr_multiaddr) <= 0) {
457: log_fatal("inet_pton: unable to convert '%s'",
458: All_DHCP_Servers);
459: }
460: mreq.ipv6mr_interface = if_nametoindex(info->name);
461: if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
462: &mreq, sizeof(mreq)) < 0) {
463: log_fatal("setsockopt: IPV6_JOIN_GROUP: %m");
464: }
465: }
466: }
467:
468: void
469: if_register6(struct interface_info *info, int do_multicast) {
470: /* Bounce do_multicast to a stack variable because we may change it. */
471: int req_multi = do_multicast;
472:
473: if (global_v6_socket_references == 0) {
474: global_v6_socket = if_register_socket(info, AF_INET6,
475: &req_multi);
476: if (global_v6_socket < 0) {
477: /*
478: * if_register_socket() fatally logs if it fails to
479: * create a socket, this is just a sanity check.
480: */
481: log_fatal("Impossible condition at %s:%d", MDL);
482: } else {
483: log_info("Bound to *:%d", ntohs(local_port));
484: }
485: }
486:
487: info->rfdesc = global_v6_socket;
488: info->wfdesc = global_v6_socket;
489: global_v6_socket_references++;
490:
491: if (req_multi)
492: if_register_multicast(info);
493:
494: get_hw_addr(info->name, &info->hw_address);
495:
496: if (!quiet_interface_discovery) {
497: if (info->shared_network != NULL) {
498: log_info("Listening on Socket/%d/%s/%s",
499: global_v6_socket, info->name,
500: info->shared_network->name);
501: log_info("Sending on Socket/%d/%s/%s",
502: global_v6_socket, info->name,
503: info->shared_network->name);
504: } else {
505: log_info("Listening on Socket/%s", info->name);
506: log_info("Sending on Socket/%s", info->name);
507: }
508: }
509: }
510:
511: void
512: if_deregister6(struct interface_info *info) {
513: /* Dereference the global v6 socket. */
514: if ((info->rfdesc == global_v6_socket) &&
515: (info->wfdesc == global_v6_socket) &&
516: (global_v6_socket_references > 0)) {
517: global_v6_socket_references--;
518: info->rfdesc = -1;
519: info->wfdesc = -1;
520: } else {
521: log_fatal("Impossible condition at %s:%d", MDL);
522: }
523:
524: if (!quiet_interface_discovery) {
525: if (info->shared_network != NULL) {
526: log_info("Disabling input on Socket/%s/%s", info->name,
527: info->shared_network->name);
528: log_info("Disabling output on Socket/%s/%s", info->name,
529: info->shared_network->name);
530: } else {
531: log_info("Disabling input on Socket/%s", info->name);
532: log_info("Disabling output on Socket/%s", info->name);
533: }
534: }
535:
536: if (global_v6_socket_references == 0) {
537: close(global_v6_socket);
538: global_v6_socket = -1;
539:
540: log_info("Unbound from *:%d", ntohs(local_port));
541: }
542: }
543: #endif /* DHCPv6 */
544:
545: #if defined (USE_SOCKET_SEND) || defined (USE_SOCKET_FALLBACK)
546: ssize_t send_packet (interface, packet, raw, len, from, to, hto)
547: struct interface_info *interface;
548: struct packet *packet;
549: struct dhcp_packet *raw;
550: size_t len;
551: struct in_addr from;
552: struct sockaddr_in *to;
553: struct hardware *hto;
554: {
555: int result;
556: #ifdef IGNORE_HOSTUNREACH
557: int retry = 0;
558: do {
559: #endif
560: #if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && defined(USE_V4_PKTINFO)
561: struct in_pktinfo pktinfo;
562:
563: if (interface->ifp != NULL) {
564: memset(&pktinfo, 0, sizeof (pktinfo));
565: pktinfo.ipi_ifindex = interface->ifp->ifr_index;
566: if (setsockopt(interface->wfdesc, IPPROTO_IP,
567: IP_PKTINFO, (char *)&pktinfo,
568: sizeof(pktinfo)) < 0)
569: log_fatal("setsockopt: IP_PKTINFO: %m");
570: }
571: #endif
572: result = sendto (interface -> wfdesc, (char *)raw, len, 0,
573: (struct sockaddr *)to, sizeof *to);
574: #ifdef IGNORE_HOSTUNREACH
575: } while (to -> sin_addr.s_addr == htonl (INADDR_BROADCAST) &&
576: result < 0 &&
577: (errno == EHOSTUNREACH ||
578: errno == ECONNREFUSED) &&
579: retry++ < 10);
580: #endif
581: if (result < 0) {
582: log_error ("send_packet: %m");
583: if (errno == ENETUNREACH)
584: log_error ("send_packet: please consult README file%s",
585: " regarding broadcast address.");
586: }
587: return result;
588: }
589:
590: #endif /* USE_SOCKET_SEND || USE_SOCKET_FALLBACK */
591:
592: #ifdef DHCPv6
593: /*
594: * Solaris 9 is missing the CMSG_LEN and CMSG_SPACE macros, so we will
595: * synthesize them (based on the BIND 9 technique).
596: */
597:
598: #ifndef CMSG_LEN
599: static size_t CMSG_LEN(size_t len) {
600: size_t hdrlen;
601: /*
602: * Cast NULL so that any pointer arithmetic performed by CMSG_DATA
603: * is correct.
604: */
605: hdrlen = (size_t)CMSG_DATA(((struct cmsghdr *)NULL));
606: return hdrlen + len;
607: }
608: #endif /* !CMSG_LEN */
609:
610: #ifndef CMSG_SPACE
611: static size_t CMSG_SPACE(size_t len) {
612: struct msghdr msg;
613: struct cmsghdr *cmsgp;
614:
615: /*
616: * XXX: The buffer length is an ad-hoc value, but should be enough
617: * in a practical sense.
618: */
619: union {
620: struct cmsghdr cmsg_sizer;
621: u_int8_t pktinfo_sizer[sizeof(struct cmsghdr) + 1024];
622: } dummybuf;
623:
624: memset(&msg, 0, sizeof(msg));
625: msg.msg_control = &dummybuf;
626: msg.msg_controllen = sizeof(dummybuf);
627:
628: cmsgp = (struct cmsghdr *)&dummybuf;
629: cmsgp->cmsg_len = CMSG_LEN(len);
630:
631: cmsgp = CMSG_NXTHDR(&msg, cmsgp);
632: if (cmsgp != NULL) {
633: return (char *)cmsgp - (char *)msg.msg_control;
634: } else {
635: return 0;
636: }
637: }
638: #endif /* !CMSG_SPACE */
639:
640: #endif /* DHCPv6 */
641:
642: #if defined(DHCPv6) || \
643: (defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && \
644: defined(USE_V4_PKTINFO))
645: /*
646: * For both send_packet6() and receive_packet6() we need to allocate
647: * space for the cmsg header information. We do this once and reuse
648: * the buffer. We also need the control buf for send_packet() and
649: * receive_packet() when we use a single socket and IP_PKTINFO to
650: * send the packet out the correct interface.
651: */
652: static void *control_buf = NULL;
653: static size_t control_buf_len = 0;
654:
655: static void
656: allocate_cmsg_cbuf(void) {
657: control_buf_len = CMSG_SPACE(sizeof(struct in6_pktinfo));
658: control_buf = dmalloc(control_buf_len, MDL);
659: return;
660: }
661: #endif /* DHCPv6, IP_PKTINFO ... */
662:
663: #ifdef DHCPv6
664: /*
665: * For both send_packet6() and receive_packet6() we need to use the
666: * sendmsg()/recvmsg() functions rather than the simpler send()/recv()
667: * functions.
668: *
669: * In the case of send_packet6(), we need to do this in order to insure
670: * that the reply packet leaves on the same interface that it arrived
671: * on.
672: *
673: * In the case of receive_packet6(), we need to do this in order to
674: * get the IP address the packet was sent to. This is used to identify
675: * whether a packet is multicast or unicast.
676: *
677: * Helpful man pages: recvmsg, readv (talks about the iovec stuff), cmsg.
678: *
679: * Also see the sections in RFC 3542 about IPV6_PKTINFO.
680: */
681:
682: /* Send an IPv6 packet */
683: ssize_t send_packet6(struct interface_info *interface,
684: const unsigned char *raw, size_t len,
685: struct sockaddr_in6 *to) {
686: struct msghdr m;
687: struct iovec v;
688: int result;
689: struct in6_pktinfo *pktinfo;
690: struct cmsghdr *cmsg;
691:
692: /*
693: * If necessary allocate space for the control message header.
694: * The space is common between send and receive.
695: */
696:
697: if (control_buf == NULL) {
698: allocate_cmsg_cbuf();
699: if (control_buf == NULL) {
700: log_error("send_packet6: unable to allocate cmsg header");
701: return(ENOMEM);
702: }
703: }
704: memset(control_buf, 0, control_buf_len);
705:
706: /*
707: * Initialize our message header structure.
708: */
709: memset(&m, 0, sizeof(m));
710:
711: /*
712: * Set the target address we're sending to.
713: */
714: m.msg_name = to;
715: m.msg_namelen = sizeof(*to);
716:
717: /*
718: * Set the data buffer we're sending. (Using this wacky
719: * "scatter-gather" stuff... we only have a single chunk
720: * of data to send, so we declare a single vector entry.)
721: */
722: v.iov_base = (char *)raw;
723: v.iov_len = len;
724: m.msg_iov = &v;
725: m.msg_iovlen = 1;
726:
727: /*
728: * Setting the interface is a bit more involved.
729: *
730: * We have to create a "control message", and set that to
731: * define the IPv6 packet information. We could set the
732: * source address if we wanted, but we can safely let the
733: * kernel decide what that should be.
734: */
735: m.msg_control = control_buf;
736: m.msg_controllen = control_buf_len;
737: cmsg = CMSG_FIRSTHDR(&m);
738: cmsg->cmsg_level = IPPROTO_IPV6;
739: cmsg->cmsg_type = IPV6_PKTINFO;
740: cmsg->cmsg_len = CMSG_LEN(sizeof(*pktinfo));
741: pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
742: memset(pktinfo, 0, sizeof(*pktinfo));
743: pktinfo->ipi6_ifindex = if_nametoindex(interface->name);
744: m.msg_controllen = cmsg->cmsg_len;
745:
746: result = sendmsg(interface->wfdesc, &m, 0);
747: if (result < 0) {
748: log_error("send_packet6: %m");
749: }
750: return result;
751: }
752: #endif /* DHCPv6 */
753:
754: #ifdef USE_SOCKET_RECEIVE
755: ssize_t receive_packet (interface, buf, len, from, hfrom)
756: struct interface_info *interface;
757: unsigned char *buf;
758: size_t len;
759: struct sockaddr_in *from;
760: struct hardware *hfrom;
761: {
762: #if !defined(USE_V4_PKTINFO)
763: SOCKLEN_T flen = sizeof *from;
764: #endif
765: int result;
766:
767: /*
768: * The normal Berkeley socket interface doesn't give us any way
769: * to know what hardware interface we received the message on,
770: * but we should at least make sure the structure is emptied.
771: */
772: memset(hfrom, 0, sizeof(*hfrom));
773:
774: #ifdef IGNORE_HOSTUNREACH
775: int retry = 0;
776: do {
777: #endif
778:
779: #if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && defined(USE_V4_PKTINFO)
780: struct msghdr m;
781: struct iovec v;
782: struct cmsghdr *cmsg;
783: struct in_pktinfo *pktinfo;
784: unsigned int ifindex;
785: int found_pktinfo;
786:
787: /*
788: * If necessary allocate space for the control message header.
789: * The space is common between send and receive.
790: */
791: if (control_buf == NULL) {
792: allocate_cmsg_cbuf();
793: if (control_buf == NULL) {
794: log_error("receive_packet: unable to allocate cmsg "
795: "header");
796: return(ENOMEM);
797: }
798: }
799: memset(control_buf, 0, control_buf_len);
800:
801: /*
802: * Initialize our message header structure.
803: */
804: memset(&m, 0, sizeof(m));
805:
806: /*
807: * Point so we can get the from address.
808: */
809: m.msg_name = from;
810: m.msg_namelen = sizeof(*from);
811:
812: /*
813: * Set the data buffer we're receiving. (Using this wacky
814: * "scatter-gather" stuff... but we that doesn't really make
815: * sense for us, so we use a single vector entry.)
816: */
817: v.iov_base = buf;
818: v.iov_len = len;
819: m.msg_iov = &v;
820: m.msg_iovlen = 1;
821:
822: /*
823: * Getting the interface is a bit more involved.
824: *
825: * We set up some space for a "control message". We have
826: * previously asked the kernel to give us packet
827: * information (when we initialized the interface), so we
828: * should get the destination address from that.
829: */
830: m.msg_control = control_buf;
831: m.msg_controllen = control_buf_len;
832:
833: result = recvmsg(interface->rfdesc, &m, 0);
834:
835: if (result >= 0) {
836: /*
837: * If we did read successfully, then we need to loop
838: * through the control messages we received and
839: * find the one with our destination address.
840: *
841: * We also keep a flag to see if we found it. If we
842: * didn't, then we consider this to be an error.
843: */
844: found_pktinfo = 0;
845: cmsg = CMSG_FIRSTHDR(&m);
846: while (cmsg != NULL) {
847: if ((cmsg->cmsg_level == IPPROTO_IP) &&
848: (cmsg->cmsg_type == IP_PKTINFO)) {
849: pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
850: ifindex = pktinfo->ipi_ifindex;
851: /*
852: * We pass the ifindex back to the caller
853: * using the unused hfrom parameter avoiding
854: * interface changes between sockets and
855: * the discover code.
856: */
857: memcpy(hfrom->hbuf, &ifindex, sizeof(ifindex));
858: found_pktinfo = 1;
859: }
860: cmsg = CMSG_NXTHDR(&m, cmsg);
861: }
862: if (!found_pktinfo) {
863: result = -1;
864: errno = EIO;
865: }
866: }
867: #else
868: result = recvfrom (interface -> rfdesc, (char *)buf, len, 0,
869: (struct sockaddr *)from, &flen);
870: #endif /* IP_PKTINFO ... */
871: #ifdef IGNORE_HOSTUNREACH
872: } while (result < 0 &&
873: (errno == EHOSTUNREACH ||
874: errno == ECONNREFUSED) &&
875: retry++ < 10);
876: #endif
877: return result;
878: }
879:
880: #endif /* USE_SOCKET_RECEIVE */
881:
882: #ifdef DHCPv6
883: ssize_t
884: receive_packet6(struct interface_info *interface,
885: unsigned char *buf, size_t len,
886: struct sockaddr_in6 *from, struct in6_addr *to_addr,
887: unsigned int *if_idx)
888: {
889: struct msghdr m;
890: struct iovec v;
891: int result;
892: struct cmsghdr *cmsg;
893: struct in6_pktinfo *pktinfo;
894: int found_pktinfo;
895:
896: /*
897: * If necessary allocate space for the control message header.
898: * The space is common between send and receive.
899: */
900: if (control_buf == NULL) {
901: allocate_cmsg_cbuf();
902: if (control_buf == NULL) {
903: log_error("receive_packet6: unable to allocate cmsg "
904: "header");
905: return(ENOMEM);
906: }
907: }
908: memset(control_buf, 0, control_buf_len);
909:
910: /*
911: * Initialize our message header structure.
912: */
913: memset(&m, 0, sizeof(m));
914:
915: /*
916: * Point so we can get the from address.
917: */
918: m.msg_name = from;
919: m.msg_namelen = sizeof(*from);
920:
921: /*
922: * Set the data buffer we're receiving. (Using this wacky
923: * "scatter-gather" stuff... but we that doesn't really make
924: * sense for us, so we use a single vector entry.)
925: */
926: v.iov_base = buf;
927: v.iov_len = len;
928: m.msg_iov = &v;
929: m.msg_iovlen = 1;
930:
931: /*
932: * Getting the interface is a bit more involved.
933: *
934: * We set up some space for a "control message". We have
935: * previously asked the kernel to give us packet
936: * information (when we initialized the interface), so we
937: * should get the destination address from that.
938: */
939: m.msg_control = control_buf;
940: m.msg_controllen = control_buf_len;
941:
942: result = recvmsg(interface->rfdesc, &m, 0);
943:
944: if (result >= 0) {
945: /*
946: * If we did read successfully, then we need to loop
947: * through the control messages we received and
948: * find the one with our destination address.
949: *
950: * We also keep a flag to see if we found it. If we
951: * didn't, then we consider this to be an error.
952: */
953: found_pktinfo = 0;
954: cmsg = CMSG_FIRSTHDR(&m);
955: while (cmsg != NULL) {
956: if ((cmsg->cmsg_level == IPPROTO_IPV6) &&
957: (cmsg->cmsg_type == IPV6_PKTINFO)) {
958: pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
959: *to_addr = pktinfo->ipi6_addr;
960: *if_idx = pktinfo->ipi6_ifindex;
961: found_pktinfo = 1;
962: }
963: cmsg = CMSG_NXTHDR(&m, cmsg);
964: }
965: if (!found_pktinfo) {
966: result = -1;
967: errno = EIO;
968: }
969: }
970:
971: return result;
972: }
973: #endif /* DHCPv6 */
974:
975: #if defined (USE_SOCKET_FALLBACK)
976: /* This just reads in a packet and silently discards it. */
977:
978: isc_result_t fallback_discard (object)
979: omapi_object_t *object;
980: {
981: char buf [1540];
982: struct sockaddr_in from;
983: SOCKLEN_T flen = sizeof from;
984: int status;
985: struct interface_info *interface;
986:
987: if (object -> type != dhcp_type_interface)
988: return ISC_R_INVALIDARG;
989: interface = (struct interface_info *)object;
990:
991: status = recvfrom (interface -> wfdesc, buf, sizeof buf, 0,
992: (struct sockaddr *)&from, &flen);
993: #if defined (DEBUG)
994: /* Only report fallback discard errors if we're debugging. */
995: if (status < 0) {
996: log_error ("fallback_discard: %m");
997: return ISC_R_UNEXPECTED;
998: }
999: #endif
1000: return ISC_R_SUCCESS;
1001: }
1002: #endif /* USE_SOCKET_FALLBACK */
1003:
1004: #if defined (USE_SOCKET_SEND)
1005: int can_unicast_without_arp (ip)
1006: struct interface_info *ip;
1007: {
1008: return 0;
1009: }
1010:
1011: int can_receive_unicast_unconfigured (ip)
1012: struct interface_info *ip;
1013: {
1014: #if defined (SOCKET_CAN_RECEIVE_UNICAST_UNCONFIGURED)
1015: return 1;
1016: #else
1017: return 0;
1018: #endif
1019: }
1020:
1021: int supports_multiple_interfaces (ip)
1022: struct interface_info *ip;
1023: {
1024: #if defined(SO_BINDTODEVICE) || \
1025: (defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && \
1026: defined(USE_V4_PKTINFO))
1027: return(1);
1028: #else
1029: return(0);
1030: #endif
1031: }
1032:
1033: /* If we have SO_BINDTODEVICE, set up a fallback interface; otherwise,
1034: do not. */
1035:
1036: void maybe_setup_fallback ()
1037: {
1038: #if defined (USE_SOCKET_FALLBACK)
1039: isc_result_t status;
1040: struct interface_info *fbi = (struct interface_info *)0;
1041: if (setup_fallback (&fbi, MDL)) {
1042: fbi -> wfdesc = if_register_socket (fbi, AF_INET, 0);
1043: fbi -> rfdesc = fbi -> wfdesc;
1044: log_info ("Sending on Socket/%s%s%s",
1045: fbi -> name,
1046: (fbi -> shared_network ? "/" : ""),
1047: (fbi -> shared_network ?
1048: fbi -> shared_network -> name : ""));
1049:
1050: status = omapi_register_io_object ((omapi_object_t *)fbi,
1051: if_readsocket, 0,
1052: fallback_discard, 0, 0);
1053: if (status != ISC_R_SUCCESS)
1054: log_fatal ("Can't register I/O handle for %s: %s",
1055: fbi -> name, isc_result_totext (status));
1056: interface_dereference (&fbi, MDL);
1057: }
1058: #endif
1059: }
1060:
1061:
1062: #if defined(sun) && defined(USE_V4_PKTINFO)
1063: /* This code assumes the existence of SIOCGLIFHWADDR */
1064: void
1065: get_hw_addr(const char *name, struct hardware *hw) {
1066: struct sockaddr_dl *dladdrp;
1067: int rv, sock, i;
1068: struct lifreq lifr;
1069:
1070: memset(&lifr, 0, sizeof (lifr));
1071: (void) strlcpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1072: /*
1073: * Check if the interface is a virtual or IPMP interface - in those
1074: * cases it has no hw address, so generate a random one.
1075: */
1076: if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ||
1077: ioctl(sock, SIOCGLIFFLAGS, &lifr) < 0) {
1078: if (sock != -1)
1079: (void) close(sock);
1080:
1081: #ifdef DHCPv6
1082: /*
1083: * If approrpriate try this with an IPv6 socket
1084: */
1085: if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) >= 0 &&
1086: ioctl(sock, SIOCGLIFFLAGS, &lifr) >= 0) {
1087: goto flag_check;
1088: }
1089: if (sock != -1)
1090: (void) close(sock);
1091: #endif
1092: log_fatal("Couldn't get interface flags for %s: %m", name);
1093:
1094: }
1095:
1096: flag_check:
1097: if (lifr.lifr_flags & (IFF_VIRTUAL|IFF_IPMP)) {
1098: hw->hlen = sizeof (hw->hbuf);
1099: srandom((long)gethrtime());
1100:
1101: for (i = 0; i < hw->hlen; ++i) {
1102: hw->hbuf[i] = random() % 256;
1103: }
1104:
1105: if (sock != -1)
1106: (void) close(sock);
1107: return;
1108: }
1109:
1110: if (ioctl(sock, SIOCGLIFHWADDR, &lifr) < 0)
1111: log_fatal("Couldn't get interface hardware address for %s: %m",
1112: name);
1113: dladdrp = (struct sockaddr_dl *)&lifr.lifr_addr;
1114: hw->hlen = dladdrp->sdl_alen;
1115: memcpy(hw->hbuf, LLADDR(dladdrp), hw->hlen);
1116:
1117: if (sock != -1)
1118: (void) close(sock);
1119: }
1120: #endif /* defined(sun) */
1121:
1122: #endif /* USE_SOCKET_SEND */
1123:
1124: /*
1125: * Code to set a handler for signals. This
1126: * exists to allow us to ignore SIGPIPE signals
1127: * but could be used for other purposes in the
1128: * future.
1129: */
1130:
1131: isc_result_t
1132: dhcp_handle_signal(int sig, void (*handler)(int)) {
1133: struct sigaction sa;
1134:
1135: memset(&sa, 0, sizeof(sa));
1136: sa.sa_handler = handler;
1137:
1138: if (sigfillset(&sa.sa_mask) != 0 ||
1139: sigaction(sig, &sa, NULL) < 0) {
1140: log_error("Unable to set up signal handler for %d, %m", sig);
1141: return (ISC_R_UNEXPECTED);
1142: }
1143:
1144: return (ISC_R_SUCCESS);
1145: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>