ISC DHCP 4.4.3-P1
A reference DHCPv4 and DHCPv6 implementation
 
Loading...
Searching...
No Matches
socket.c
Go to the documentation of this file.
1/* socket.c
2
3 BSD socket interface code... */
4
5/*
6 * Copyright (C) 2004-2022 Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 1995-2003 by Internet Software Consortium
8 *
9 * This Source Code Form is subject to the terms of the Mozilla Public
10 * License, v. 2.0. If a copy of the MPL was not distributed with this
11 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
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 * PO Box 360
23 * Newmarket, NH 03857 USA
24 * <info@isc.org>
25 * https://www.isc.org/
26 *
27 */
28
29/* SO_BINDTODEVICE support added by Elliot Poger (poger@leland.stanford.edu).
30 * This sockopt allows a socket to be bound to a particular interface,
31 * thus enabling the use of DHCPD on a multihomed host.
32 * If SO_BINDTODEVICE is defined in your system header files, the use of
33 * this sockopt will be automatically enabled.
34 * I have implemented it under Linux; other systems should be doable also.
35 */
36
37#include "dhcpd.h"
38#include <isc/util.h>
39#include <errno.h>
40#include <sys/ioctl.h>
41#include <sys/uio.h>
42#include <sys/uio.h>
43
44#if defined(sun) && defined(USE_V4_PKTINFO)
45#include <sys/sysmacros.h>
46#include <net/if.h>
47#include <sys/sockio.h>
48#include <net/if_dl.h>
49#include <sys/dlpi.h>
50#endif
51
52#ifdef USE_SOCKET_FALLBACK
53# if !defined (USE_SOCKET_SEND)
54# define if_register_send if_register_fallback
55# define send_packet send_fallback
56# define if_reinitialize_send if_reinitialize_fallback
57# endif
58#endif
59
60#if defined(DHCPv6)
61/*
62 * XXX: this is gross. we need to go back and overhaul the API for socket
63 * handling.
64 */
65static int no_global_v6_socket = 0;
66static unsigned int global_v6_socket_references = 0;
67static int global_v6_socket = -1;
68#if defined(RELAY_PORT)
69static unsigned int relay_port_v6_socket_references = 0;
70static int relay_port_v6_socket = -1;
71#endif
72
73static 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)
82static unsigned int global_v4_socket_references = 0;
83static 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)
92static 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)
99void 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
113void 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... */
128int
129if_register_socket(struct interface_info *info, int family,
130 int *do_multicast, struct in6_addr *linklocal6)
131{
132 struct sockaddr_storage name;
133 int name_len;
134 int sock;
135 int flag;
136 int domain;
137#ifdef DHCPv6
138 struct sockaddr_in6 *addr6;
139#endif
140 struct sockaddr_in *addr;
141
142 /* INSIST((family == AF_INET) || (family == AF_INET6)); */
143
144#if !defined(SO_BINDTODEVICE) && !defined(USE_FALLBACK)
145 /* Make sure only one interface is registered. */
146 if (once) {
147 log_fatal ("The standard socket API can only support %s",
148 "hosts with a single network interface.");
149 }
150 once = 1;
151#endif
152
153 /*
154 * Set up the address we're going to bind to, depending on the
155 * address family.
156 */
157 memset(&name, 0, sizeof(name));
158 switch (family) {
159#ifdef DHCPv6
160 case AF_INET6:
161 addr6 = (struct sockaddr_in6 *)&name;
162 addr6->sin6_family = AF_INET6;
163 addr6->sin6_port = local_port;
164#if defined(RELAY_PORT)
165 if (relay_port &&
167 addr6->sin6_port = relay_port;
168#endif
169 /* A server feature */
171 memcpy(&addr6->sin6_addr,
173 sizeof(addr6->sin6_addr));
174 }
175 /* A client feature */
176 if (linklocal6) {
177 memcpy(&addr6->sin6_addr,
178 linklocal6,
179 sizeof(addr6->sin6_addr));
180 }
181 if (IN6_IS_ADDR_LINKLOCAL(&addr6->sin6_addr)) {
182 addr6->sin6_scope_id = if_nametoindex(info->name);
183 }
184#ifdef HAVE_SA_LEN
185 addr6->sin6_len = sizeof(*addr6);
186#endif
187 name_len = sizeof(*addr6);
188 domain = PF_INET6;
189 if ((info->flags & INTERFACE_STREAMS) == INTERFACE_UPSTREAM) {
190 *do_multicast = 0;
191 }
192 break;
193#endif /* DHCPv6 */
194
195 case AF_INET:
196 default:
197 addr = (struct sockaddr_in *)&name;
198 addr->sin_family = AF_INET;
199 addr->sin_port = relay_port ? relay_port : local_port;
200 memcpy(&addr->sin_addr,
202 sizeof(addr->sin_addr));
203#ifdef HAVE_SA_LEN
204 addr->sin_len = sizeof(*addr);
205#endif
206 name_len = sizeof(*addr);
207 domain = PF_INET;
208 break;
209 }
210
211 /* Make a socket... */
212 sock = socket(domain, SOCK_DGRAM, IPPROTO_UDP);
213 if (sock < 0) {
214 log_fatal("Can't create dhcp socket for %s: %m", info->name);
215 }
216
217 /* Set the REUSEADDR option so that we don't fail to start if
218 we're being restarted. */
219 flag = 1;
220 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
221 (char *)&flag, sizeof(flag)) < 0) {
222 log_fatal("Can't set SO_REUSEADDR on dhcp socket for"
223 " %s: %m", info->name);
224 }
225
226 /* Set the BROADCAST option so that we can broadcast DHCP responses.
227 We shouldn't do this for fallback devices, and we can detect that
228 a device is a fallback because it has no ifp structure. */
229 if (info->ifp &&
230 (setsockopt(sock, SOL_SOCKET, SO_BROADCAST,
231 (char *)&flag, sizeof(flag)) < 0)) {
232 log_fatal("Can't set SO_BROADCAST on dhcp socket for"
233 " %s: %m", info->name);
234 }
235
236#if defined(DHCPv6) && defined(SO_REUSEPORT)
237 /*
238 * We only set SO_REUSEPORT on AF_INET6 sockets, so that multiple
239 * daemons can bind to their own sockets and get data for their
240 * respective interfaces. This does not (and should not) affect
241 * DHCPv4 sockets; we can't yet support BSD sockets well, much
242 * less multiple sockets. Make sense only with multicast.
243 * RedHat defines SO_REUSEPORT with a kernel which does not support
244 * it and returns ENOPROTOOPT so in this case ignore the error.
245 */
246 if ((local_family == AF_INET6) && *do_multicast) {
247 flag = 1;
248 if ((setsockopt(sock, SOL_SOCKET, SO_REUSEPORT,
249 (char *)&flag, sizeof(flag)) < 0) &&
250 (errno != ENOPROTOOPT)) {
251 log_fatal("Can't set SO_REUSEPORT on dhcp socket for"
252 " %s: %m", info->name);
253 }
254 }
255#endif
256
257 /* Bind the socket to this interface's IP address. */
258 if (bind(sock, (struct sockaddr *)&name, name_len) < 0) {
259 log_error("Can't bind to dhcp address: %m");
260 log_error("Please make sure there is no other dhcp server");
261 log_error("running and that there's no entry for dhcp or");
262 log_error("bootp in /etc/inetd.conf. Also make sure you");
263 log_error("are not running HP JetAdmin software, which");
264 log_fatal("includes a bootp server.");
265 }
266
267#if defined(SO_BINDTODEVICE)
268 /* Bind this socket to this interface. */
269 if ((local_family != AF_INET6) && (info->ifp != NULL) &&
270 setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE,
271 (char *)(info -> ifp), sizeof(*(info -> ifp))) < 0) {
272 log_fatal("Can't set SO_BINDTODEVICE on dhcp socket for"
273 " %s : %m", (char *)(info->ifp));
274 }
275#endif
276
277 /* IP_BROADCAST_IF instructs the kernel which interface to send
278 * IP packets whose destination address is 255.255.255.255. These
279 * will be treated as subnet broadcasts on the interface identified
280 * by ip address (info -> primary_address). This is only known to
281 * be defined in SCO system headers, and may not be defined in all
282 * releases.
283 */
284#if defined(SCO) && defined(IP_BROADCAST_IF)
285 if (info->address_count &&
286 setsockopt(sock, IPPROTO_IP, IP_BROADCAST_IF, &info->addresses[0],
287 sizeof(info->addresses[0])) < 0)
288 log_fatal("Can't set IP_BROADCAST_IF on dhcp socket for"
289 " %s: %m", info->name);
290#endif
291
292#if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && defined(USE_V4_PKTINFO)
293 /*
294 * If we turn on IP_RECVPKTINFO we will be able to receive
295 * the interface index information of the received packet.
296 */
297 if (family == AF_INET) {
298 int on = 1;
299 if (setsockopt(sock, IPPROTO_IP, IP_RECVPKTINFO,
300 &on, sizeof(on)) != 0) {
301 log_fatal("Can't set IP_RECVPTKINFO on dhcp socket for"
302 " %s: %m", info->name);
303 }
304 }
305#endif
306
307#ifdef DHCPv6
308 /*
309 * If we turn on IPV6_PKTINFO, we will be able to receive
310 * additional information, such as the destination IP address.
311 * We need this to spot unicast packets.
312 */
313 if (family == AF_INET6) {
314 int on = 1;
315#ifdef IPV6_RECVPKTINFO
316 /* RFC3542 */
317 if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
318 &on, sizeof(on)) != 0) {
319 log_fatal("setsockopt: IPV6_RECVPKTINFO for %s: %m",
320 info->name);
321 }
322#else
323 /* RFC2292 */
324 if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO,
325 &on, sizeof(on)) != 0) {
326 log_fatal("setsockopt: IPV6_PKTINFO for %s: %m",
327 info->name);
328 }
329#endif
330 }
331
332#endif /* DHCPv6 */
333
334 return sock;
335}
336
337#ifdef DHCPv6
338void set_multicast_hop_limit(struct interface_info* info, int hop_limit) {
339 if (setsockopt(info->wfdesc, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
340 &hop_limit, sizeof(int)) < 0) {
341 log_fatal("setsockopt: IPV6_MULTICAST_HOPS for %s: %m",
342 info->name);
343 }
344
345 log_debug("Setting hop count limit to %d for interface %s",
346 hop_limit, info->name);
347
348}
349#endif /* DHCPv6 */
350
351#endif /* USE_SOCKET_SEND || USE_SOCKET_RECEIVE || USE_SOCKET_FALLBACK */
352
353#if defined (USE_SOCKET_SEND) || defined (USE_SOCKET_FALLBACK)
354void if_register_send (info)
355 struct interface_info *info;
356{
357#ifndef USE_SOCKET_RECEIVE
358 info->wfdesc = if_register_socket(info, AF_INET, 0, NULL);
359 /* If this is a normal IPv4 address, get the hardware address. */
360 if (strcmp(info->name, "fallback") != 0)
361 get_hw_addr(info);
362#if defined (USE_SOCKET_FALLBACK)
363 /* Fallback only registers for send, but may need to receive as
364 well. */
365 info->rfdesc = info->wfdesc;
366#endif
367#else
368 info->wfdesc = info->rfdesc;
369#endif
371 log_info ("Sending on Socket/%s%s%s",
372 info->name,
373 (info->shared_network ? "/" : ""),
374 (info->shared_network ?
375 info->shared_network->name : ""));
376}
377
378#if defined (USE_SOCKET_SEND)
379void if_deregister_send (info)
380 struct interface_info *info;
381{
382#ifndef USE_SOCKET_RECEIVE
383 close (info -> wfdesc);
384#endif
385 info -> wfdesc = -1;
386
388 log_info ("Disabling output on Socket/%s%s%s",
389 info -> name,
390 (info -> shared_network ? "/" : ""),
391 (info -> shared_network ?
392 info -> shared_network -> name : ""));
393}
394#endif /* USE_SOCKET_SEND */
395#endif /* USE_SOCKET_SEND || USE_SOCKET_FALLBACK */
396
397#ifdef USE_SOCKET_RECEIVE
398void if_register_receive (info)
399 struct interface_info *info;
400{
401
402#if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && defined(USE_V4_PKTINFO)
403 if (global_v4_socket_references == 0) {
404 global_v4_socket = if_register_socket(info, AF_INET, 0, NULL);
405 if (global_v4_socket < 0) {
406 /*
407 * if_register_socket() fatally logs if it fails to
408 * create a socket, this is just a sanity check.
409 */
410 log_fatal("Failed to create AF_INET socket %s:%d",
411 MDL);
412 }
413 }
414
415 info->rfdesc = global_v4_socket;
416 global_v4_socket_references++;
417#else
418 /* If we're using the socket API for sending and receiving,
419 we don't need to register this interface twice. */
420 info->rfdesc = if_register_socket(info, AF_INET, 0, NULL);
421#endif /* IP_PKTINFO... */
422 /* If this is a normal IPv4 address, get the hardware address. */
423 if (strcmp(info->name, "fallback") != 0)
424 get_hw_addr(info);
425
427 log_info ("Listening on Socket/%s%s%s",
428 info->name,
429 (info->shared_network ? "/" : ""),
430 (info->shared_network ?
431 info->shared_network->name : ""));
432}
433
434void if_deregister_receive (info)
435 struct interface_info *info;
436{
437#if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && defined(USE_V4_PKTINFO)
438 /* Dereference the global v4 socket. */
439 if ((info->rfdesc == global_v4_socket) &&
440 (global_v4_socket_references > 0)) {
441 global_v4_socket_references--;
442 info->rfdesc = -1;
443 } else {
444 log_fatal("Impossible condition at %s:%d", MDL);
445 }
446
447 if (global_v4_socket_references == 0) {
448 close(global_v4_socket);
449 global_v4_socket = -1;
450 }
451#else
452 close(info->rfdesc);
453 info->rfdesc = -1;
454#endif /* IP_PKTINFO... */
456 log_info ("Disabling input on Socket/%s%s%s",
457 info -> name,
458 (info -> shared_network ? "/" : ""),
459 (info -> shared_network ?
460 info -> shared_network -> name : ""));
461}
462#endif /* USE_SOCKET_RECEIVE */
463
464
465#ifdef DHCPv6
466/*
467 * This function joins the interface to DHCPv6 multicast groups so we will
468 * receive multicast messages.
469 */
470static void
471if_register_multicast(struct interface_info *info) {
472 int sock = info->rfdesc;
473 struct ipv6_mreq mreq;
474
475 if (inet_pton(AF_INET6, All_DHCP_Relay_Agents_and_Servers,
476 &mreq.ipv6mr_multiaddr) <= 0) {
477 log_fatal("inet_pton: unable to convert '%s'",
479 }
480 mreq.ipv6mr_interface = if_nametoindex(info->name);
481 if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
482 &mreq, sizeof(mreq)) < 0) {
483 log_fatal("setsockopt: IPV6_JOIN_GROUP for %s: %m",
484 info->name);
485 }
486
487 /*
488 * The relay agent code sets the streams so you know which way
489 * is up and down. But a relay agent shouldn't join to the
490 * Server address, or else you get fun loops. So up or down
491 * doesn't matter, we're just using that config to sense this is
492 * a relay agent.
493 */
494 if ((info->flags & INTERFACE_STREAMS) == 0) {
495 if (inet_pton(AF_INET6, All_DHCP_Servers,
496 &mreq.ipv6mr_multiaddr) <= 0) {
497 log_fatal("inet_pton: unable to convert '%s'",
499 }
500 mreq.ipv6mr_interface = if_nametoindex(info->name);
501 if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
502 &mreq, sizeof(mreq)) < 0) {
503 log_fatal("setsockopt: IPV6_JOIN_GROUP for %s: %m",
504 info->name);
505 }
506 }
507}
508
509void
510if_register6(struct interface_info *info, int do_multicast) {
511 /* Bounce do_multicast to a stack variable because we may change it. */
512 int req_multi = do_multicast;
513
514 if (no_global_v6_socket) {
515 log_fatal("Impossible condition at %s:%d", MDL);
516 }
517
518#if defined(RELAY_PORT)
519 if (!relay_port ||
521#endif
522 if (global_v6_socket_references == 0) {
523 global_v6_socket = if_register_socket(info, AF_INET6,
524 &req_multi, NULL);
525 if (global_v6_socket < 0) {
526 /*
527 * if_register_socket() fatally logs if it fails to
528 * create a socket, this is just a sanity check.
529 */
530 log_fatal("Impossible condition at %s:%d", MDL);
531 } else if (bind_local_address6) {
532 char addr6_str[INET6_ADDRSTRLEN];
533
534 if (inet_ntop(AF_INET6,
536 addr6_str,
537 sizeof(addr6_str)) == NULL) {
538 log_fatal("inet_ntop: unable to convert "
539 "local-address6");
540 }
541 log_info("Bound to [%s]:%d",
542 addr6_str,
543 (int) ntohs(local_port));
544 } else {
545 log_info("Bound to *:%d", (int) ntohs(local_port));
546 }
547 }
548
549 info->rfdesc = global_v6_socket;
550 info->wfdesc = global_v6_socket;
551 global_v6_socket_references++;
552
553#if defined(RELAY_PORT)
554 } else {
555 /*
556 * If relay port is defined, we need to register one
557 * IPv6 UPD socket to handle upstream server or relay agent
558 * with a non-547 UDP local port.
559 */
560 if ((relay_port_v6_socket_references == 0) &&
562 relay_port_v6_socket = if_register_socket(info, AF_INET6,
563 &req_multi, NULL);
564 if (relay_port_v6_socket < 0) {
565 log_fatal("Impossible condition at %s:%d", MDL);
566 } else {
567 log_info("Bound to relay port *:%d",
568 (int) ntohs(relay_port));
569 }
570 }
571 info->rfdesc = relay_port_v6_socket;
572 info->wfdesc = relay_port_v6_socket;
573 relay_port_v6_socket_references++;
574 }
575#endif
576
577 if (req_multi)
578 if_register_multicast(info);
579
580 get_hw_addr(info);
581
583 if (info->shared_network != NULL) {
584 log_info("Listening on Socket/%d/%s/%s",
585 global_v6_socket, info->name,
586 info->shared_network->name);
587 log_info("Sending on Socket/%d/%s/%s",
588 global_v6_socket, info->name,
589 info->shared_network->name);
590 } else {
591 log_info("Listening on Socket/%s", info->name);
592 log_info("Sending on Socket/%s", info->name);
593 }
594 }
595}
596
597/*
598 * Register an IPv6 socket bound to the link-local address of
599 * the argument interface (used by clients on a multiple interface box,
600 * vs. a server or a relay using the global IPv6 socket and running
601 * *only* in a single instance).
602 */
603void
605 int sock;
606 int count;
607 struct in6_addr *addr6 = NULL;
608 int req_multi = 0;
609
610 if (global_v6_socket >= 0) {
611 log_fatal("Impossible condition at %s:%d", MDL);
612 }
613
614 no_global_v6_socket = 1;
615
616 /* get the (?) link-local address */
617 for (count = 0; count < info->v6address_count; count++) {
618 addr6 = &info->v6addresses[count];
619 if (IN6_IS_ADDR_LINKLOCAL(addr6))
620 break;
621 }
622
623 if (!addr6) {
624 log_fatal("no link-local IPv6 address for %s", info->name);
625 }
626
627 sock = if_register_socket(info, AF_INET6, &req_multi, addr6);
628
629 if (sock < 0) {
630 log_fatal("if_register_socket for %s fails", info->name);
631 }
632
633 info->rfdesc = sock;
634 info->wfdesc = sock;
635
636 get_hw_addr(info);
637
639 if (info->shared_network != NULL) {
640 log_info("Listening on Socket/%d/%s/%s",
641 global_v6_socket, info->name,
642 info->shared_network->name);
643 log_info("Sending on Socket/%d/%s/%s",
644 global_v6_socket, info->name,
645 info->shared_network->name);
646 } else {
647 log_info("Listening on Socket/%s", info->name);
648 log_info("Sending on Socket/%s", info->name);
649 }
650 }
651}
652
653void
654if_deregister6(struct interface_info *info) {
655 /* client case */
656 if (no_global_v6_socket) {
657 close(info->rfdesc);
658 info->rfdesc = -1;
659 info->wfdesc = -1;
660 } else if ((info->rfdesc == global_v6_socket) &&
661 (info->wfdesc == global_v6_socket) &&
662 (global_v6_socket_references > 0)) {
663 /* Dereference the global v6 socket. */
664 global_v6_socket_references--;
665 info->rfdesc = -1;
666 info->wfdesc = -1;
667#if defined(RELAY_PORT)
668 } else if (relay_port &&
669 (info->rfdesc == relay_port_v6_socket) &&
670 (info->wfdesc == relay_port_v6_socket) &&
671 (relay_port_v6_socket_references > 0)) {
672 /* Dereference the relay port v6 socket. */
673 relay_port_v6_socket_references--;
674 info->rfdesc = -1;
675 info->wfdesc = -1;
676#endif
677 } else {
678 log_fatal("Impossible condition at %s:%d", MDL);
679 }
680
682 if (info->shared_network != NULL) {
683 log_info("Disabling input on Socket/%s/%s", info->name,
684 info->shared_network->name);
685 log_info("Disabling output on Socket/%s/%s", info->name,
686 info->shared_network->name);
687 } else {
688 log_info("Disabling input on Socket/%s", info->name);
689 log_info("Disabling output on Socket/%s", info->name);
690 }
691 }
692
693 if (!no_global_v6_socket) {
694 if (global_v6_socket_references == 0) {
695 close(global_v6_socket);
696 global_v6_socket = -1;
697
698 log_info("Unbound from *:%d",
699 (int) ntohs(local_port));
700 }
701#if defined(RELAY_PORT)
702 if (relay_port && (relay_port_v6_socket_references == 0)) {
703 close(relay_port_v6_socket);
704 relay_port_v6_socket = -1;
705
706 log_info("Unbound from relay port *:%d",
707 (int) ntohs(relay_port));
708 }
709#endif
710 }
711}
712#endif /* DHCPv6 */
713
714#if defined (USE_SOCKET_SEND) || defined (USE_SOCKET_FALLBACK)
715ssize_t send_packet (interface, packet, raw, len, from, to, hto)
716 struct interface_info *interface;
717 struct packet *packet;
718 struct dhcp_packet *raw;
719 size_t len;
720 struct in_addr from;
721 struct sockaddr_in *to;
722 struct hardware *hto;
723{
724 int result;
725#ifdef IGNORE_HOSTUNREACH
726 int retry = 0;
727 do {
728#endif
729#if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && defined(USE_V4_PKTINFO)
730 struct in_pktinfo pktinfo;
731
732 if (interface->ifp != NULL) {
733 memset(&pktinfo, 0, sizeof (pktinfo));
734 pktinfo.ipi_ifindex = interface->ifp->ifr_index;
735 if (setsockopt(interface->wfdesc, IPPROTO_IP,
736 IP_PKTINFO, (char *)&pktinfo,
737 sizeof(pktinfo)) < 0)
738 log_fatal("setsockopt: IP_PKTINFO for %s: %m",
739 (char*)(interface->ifp));
740 }
741#endif
742 result = sendto (interface -> wfdesc, (char *)raw, len, 0,
743 (struct sockaddr *)to, sizeof *to);
744#ifdef IGNORE_HOSTUNREACH
745 } while (to -> sin_addr.s_addr == htonl (INADDR_BROADCAST) &&
746 result < 0 &&
747 (errno == EHOSTUNREACH ||
748 errno == ECONNREFUSED) &&
749 retry++ < 10);
750#endif
751 if (result < 0) {
752 log_error ("send_packet: %m");
753 if (errno == ENETUNREACH)
754 log_error ("send_packet: please consult README file%s",
755 " regarding broadcast address.");
756 }
757 return result;
758}
759
760#endif /* USE_SOCKET_SEND || USE_SOCKET_FALLBACK */
761
762#ifdef DHCPv6
763/*
764 * Solaris 9 is missing the CMSG_LEN and CMSG_SPACE macros, so we will
765 * synthesize them (based on the BIND 9 technique).
766 */
767
768#ifndef CMSG_LEN
769static size_t CMSG_LEN(size_t len) {
770 size_t hdrlen;
771 /*
772 * Cast NULL so that any pointer arithmetic performed by CMSG_DATA
773 * is correct.
774 */
775 hdrlen = (size_t)CMSG_DATA(((struct cmsghdr *)NULL));
776 return hdrlen + len;
777}
778#endif /* !CMSG_LEN */
779
780#ifndef CMSG_SPACE
781static size_t CMSG_SPACE(size_t len) {
782 struct msghdr msg;
783 struct cmsghdr *cmsgp;
784
785 /*
786 * XXX: The buffer length is an ad-hoc value, but should be enough
787 * in a practical sense.
788 */
789 union {
790 struct cmsghdr cmsg_sizer;
791 u_int8_t pktinfo_sizer[sizeof(struct cmsghdr) + 1024];
792 } dummybuf;
793
794 memset(&msg, 0, sizeof(msg));
795 msg.msg_control = &dummybuf;
796 msg.msg_controllen = sizeof(dummybuf);
797
798 cmsgp = (struct cmsghdr *)&dummybuf;
799 cmsgp->cmsg_len = CMSG_LEN(len);
800
801 cmsgp = CMSG_NXTHDR(&msg, cmsgp);
802 if (cmsgp != NULL) {
803 return (char *)cmsgp - (char *)msg.msg_control;
804 } else {
805 return 0;
806 }
807}
808#endif /* !CMSG_SPACE */
809
810#endif /* DHCPv6 */
811
812#if defined(DHCPv6) || \
813 (defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && \
814 defined(USE_V4_PKTINFO))
815/*
816 * For both send_packet6() and receive_packet6() we need to allocate
817 * space for the cmsg header information. We do this once and reuse
818 * the buffer. We also need the control buf for send_packet() and
819 * receive_packet() when we use a single socket and IP_PKTINFO to
820 * send the packet out the correct interface.
821 */
822static void *control_buf = NULL;
823static size_t control_buf_len = 0;
824
825static void
826allocate_cmsg_cbuf(void) {
827 control_buf_len = CMSG_SPACE(sizeof(struct in6_pktinfo));
828 control_buf = dmalloc(control_buf_len, MDL);
829 return;
830}
831#endif /* DHCPv6, IP_PKTINFO ... */
832
833#ifdef DHCPv6
834/*
835 * For both send_packet6() and receive_packet6() we need to use the
836 * sendmsg()/recvmsg() functions rather than the simpler send()/recv()
837 * functions.
838 *
839 * In the case of send_packet6(), we need to do this in order to insure
840 * that the reply packet leaves on the same interface that it arrived
841 * on.
842 *
843 * In the case of receive_packet6(), we need to do this in order to
844 * get the IP address the packet was sent to. This is used to identify
845 * whether a packet is multicast or unicast.
846 *
847 * Helpful man pages: recvmsg, readv (talks about the iovec stuff), cmsg.
848 *
849 * Also see the sections in RFC 3542 about IPV6_PKTINFO.
850 */
851
852/* Send an IPv6 packet */
853ssize_t send_packet6(struct interface_info *interface,
854 const unsigned char *raw, size_t len,
855 struct sockaddr_in6 *to) {
856 struct msghdr m;
857 struct iovec v;
858 struct sockaddr_in6 dst;
859 int result;
860 struct in6_pktinfo *pktinfo;
861 struct cmsghdr *cmsg;
862 unsigned int ifindex;
863
864 /*
865 * If necessary allocate space for the control message header.
866 * The space is common between send and receive.
867 */
868
869 if (control_buf == NULL) {
870 allocate_cmsg_cbuf();
871 if (control_buf == NULL) {
872 log_error("send_packet6: unable to allocate cmsg header");
873 return(ENOMEM);
874 }
875 }
876 memset(control_buf, 0, control_buf_len);
877
878 /*
879 * Initialize our message header structure.
880 */
881 memset(&m, 0, sizeof(m));
882
883 /*
884 * Set the target address we're sending to.
885 * Enforce the scope ID for bogus BSDs.
886 */
887 memcpy(&dst, to, sizeof(dst));
888 m.msg_name = &dst;
889 m.msg_namelen = sizeof(dst);
890 ifindex = if_nametoindex(interface->name);
891
892// Per OpenBSD patch-common_socket_c,v 1.7 2018/03/06 08:37:39 sthen Exp
893// always set the scope id. We'll leave the test for no global socket
894// in place for all others.
895#ifndef __OpenBSD__
896 if (no_global_v6_socket)
897#endif
898 dst.sin6_scope_id = ifindex;
899
900 /*
901 * Set the data buffer we're sending. (Using this wacky
902 * "scatter-gather" stuff... we only have a single chunk
903 * of data to send, so we declare a single vector entry.)
904 */
905 v.iov_base = (char *)raw;
906 v.iov_len = len;
907 m.msg_iov = &v;
908 m.msg_iovlen = 1;
909
910 /*
911 * Setting the interface is a bit more involved.
912 *
913 * We have to create a "control message", and set that to
914 * define the IPv6 packet information. We could set the
915 * source address if we wanted, but we can safely let the
916 * kernel decide what that should be.
917 */
918 m.msg_control = control_buf;
919 m.msg_controllen = control_buf_len;
920 cmsg = CMSG_FIRSTHDR(&m);
921 INSIST(cmsg != NULL);
922 cmsg->cmsg_level = IPPROTO_IPV6;
923 cmsg->cmsg_type = IPV6_PKTINFO;
924 cmsg->cmsg_len = CMSG_LEN(sizeof(*pktinfo));
925 pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
926 memset(pktinfo, 0, sizeof(*pktinfo));
927 pktinfo->ipi6_addr = local_address6;
928 pktinfo->ipi6_ifindex = ifindex;
929
930 result = sendmsg(interface->wfdesc, &m, 0);
931 if (result < 0) {
932 log_error("send_packet6: %m");
933 }
934 return result;
935}
936#endif /* DHCPv6 */
937
938#ifdef USE_SOCKET_RECEIVE
939ssize_t receive_packet (interface, buf, len, from, hfrom)
940 struct interface_info *interface;
941 unsigned char *buf;
942 size_t len;
943 struct sockaddr_in *from;
944 struct hardware *hfrom;
945{
946#if !(defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && defined(USE_V4_PKTINFO))
947 SOCKLEN_T flen = sizeof *from;
948#endif
949 int result;
950
951 /*
952 * The normal Berkeley socket interface doesn't give us any way
953 * to know what hardware interface we received the message on,
954 * but we should at least make sure the structure is emptied.
955 */
956 memset(hfrom, 0, sizeof(*hfrom));
957
958#ifdef IGNORE_HOSTUNREACH
959 int retry = 0;
960 do {
961#endif
962
963#if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && defined(USE_V4_PKTINFO)
964 struct msghdr m;
965 struct iovec v;
966 struct cmsghdr *cmsg;
967 struct in_pktinfo *pktinfo;
968 unsigned int ifindex;
969
970 /*
971 * If necessary allocate space for the control message header.
972 * The space is common between send and receive.
973 */
974 if (control_buf == NULL) {
975 allocate_cmsg_cbuf();
976 if (control_buf == NULL) {
977 log_error("receive_packet: unable to allocate cmsg "
978 "header");
979 return(ENOMEM);
980 }
981 }
982 memset(control_buf, 0, control_buf_len);
983
984 /*
985 * Initialize our message header structure.
986 */
987 memset(&m, 0, sizeof(m));
988
989 /*
990 * Point so we can get the from address.
991 */
992 m.msg_name = from;
993 m.msg_namelen = sizeof(*from);
994
995 /*
996 * Set the data buffer we're receiving. (Using this wacky
997 * "scatter-gather" stuff... but we that doesn't really make
998 * sense for us, so we use a single vector entry.)
999 */
1000 v.iov_base = buf;
1001 v.iov_len = len;
1002 m.msg_iov = &v;
1003 m.msg_iovlen = 1;
1004
1005 /*
1006 * Getting the interface is a bit more involved.
1007 *
1008 * We set up some space for a "control message". We have
1009 * previously asked the kernel to give us packet
1010 * information (when we initialized the interface), so we
1011 * should get the interface index from that.
1012 */
1013 m.msg_control = control_buf;
1014 m.msg_controllen = control_buf_len;
1015
1016 result = recvmsg(interface->rfdesc, &m, 0);
1017
1018 if (result >= 0) {
1019 /*
1020 * If we did read successfully, then we need to loop
1021 * through the control messages we received and
1022 * find the one with our inteface index.
1023 */
1024 cmsg = CMSG_FIRSTHDR(&m);
1025 while (cmsg != NULL) {
1026 if ((cmsg->cmsg_level == IPPROTO_IP) &&
1027 (cmsg->cmsg_type == IP_PKTINFO)) {
1028 pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
1029 ifindex = pktinfo->ipi_ifindex;
1030 /*
1031 * We pass the ifindex back to the caller
1032 * using the unused hfrom parameter avoiding
1033 * interface changes between sockets and
1034 * the discover code.
1035 */
1036 memcpy(hfrom->hbuf, &ifindex, sizeof(ifindex));
1037 return (result);
1038 }
1039 cmsg = CMSG_NXTHDR(&m, cmsg);
1040 }
1041
1042 /*
1043 * We didn't find the necessary control message
1044 * flag it as an error
1045 */
1046 result = -1;
1047 errno = EIO;
1048 }
1049#else
1050 result = recvfrom(interface -> rfdesc, (char *)buf, len, 0,
1051 (struct sockaddr *)from, &flen);
1052#endif /* IP_PKTINFO ... */
1053#ifdef IGNORE_HOSTUNREACH
1054 } while (result < 0 &&
1055 (errno == EHOSTUNREACH ||
1056 errno == ECONNREFUSED) &&
1057 retry++ < 10);
1058#endif
1059 return (result);
1060}
1061
1062#endif /* USE_SOCKET_RECEIVE */
1063
1064#ifdef DHCPv6
1065ssize_t
1066receive_packet6(struct interface_info *interface,
1067 unsigned char *buf, size_t len,
1068 struct sockaddr_in6 *from, struct in6_addr *to_addr,
1069 unsigned int *if_idx)
1070{
1071 struct msghdr m;
1072 struct iovec v;
1073 int result;
1074 struct cmsghdr *cmsg;
1075 struct in6_pktinfo *pktinfo;
1076
1077 /*
1078 * If necessary allocate space for the control message header.
1079 * The space is common between send and receive.
1080 */
1081 if (control_buf == NULL) {
1082 allocate_cmsg_cbuf();
1083 if (control_buf == NULL) {
1084 log_error("receive_packet6: unable to allocate cmsg "
1085 "header");
1086 return(ENOMEM);
1087 }
1088 }
1089 memset(control_buf, 0, control_buf_len);
1090
1091 /*
1092 * Initialize our message header structure.
1093 */
1094 memset(&m, 0, sizeof(m));
1095
1096 /*
1097 * Point so we can get the from address.
1098 */
1099 m.msg_name = from;
1100 m.msg_namelen = sizeof(*from);
1101
1102 /*
1103 * Set the data buffer we're receiving. (Using this wacky
1104 * "scatter-gather" stuff... but we that doesn't really make
1105 * sense for us, so we use a single vector entry.)
1106 */
1107 v.iov_base = buf;
1108 v.iov_len = len;
1109 m.msg_iov = &v;
1110 m.msg_iovlen = 1;
1111
1112 /*
1113 * Getting the interface is a bit more involved.
1114 *
1115 * We set up some space for a "control message". We have
1116 * previously asked the kernel to give us packet
1117 * information (when we initialized the interface), so we
1118 * should get the destination address from that.
1119 */
1120 m.msg_control = control_buf;
1121 m.msg_controllen = control_buf_len;
1122
1123 result = recvmsg(interface->rfdesc, &m, 0);
1124
1125 if (result >= 0) {
1126 /*
1127 * If we did read successfully, then we need to loop
1128 * through the control messages we received and
1129 * find the one with our destination address.
1130 */
1131 cmsg = CMSG_FIRSTHDR(&m);
1132 while (cmsg != NULL) {
1133 if ((cmsg->cmsg_level == IPPROTO_IPV6) &&
1134 (cmsg->cmsg_type == IPV6_PKTINFO)) {
1135 pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
1136 *to_addr = pktinfo->ipi6_addr;
1137 *if_idx = pktinfo->ipi6_ifindex;
1138
1139 return (result);
1140 }
1141 cmsg = CMSG_NXTHDR(&m, cmsg);
1142 }
1143
1144 /*
1145 * We didn't find the necessary control message
1146 * flag is as an error
1147 */
1148 result = -1;
1149 errno = EIO;
1150 }
1151
1152 return (result);
1153}
1154#endif /* DHCPv6 */
1155
1156#if defined (USE_SOCKET_FALLBACK)
1157/* This just reads in a packet and silently discards it. */
1158
1159isc_result_t fallback_discard (object)
1160 omapi_object_t *object;
1161{
1162 char buf [1540];
1163 struct sockaddr_in from;
1164 SOCKLEN_T flen = sizeof from;
1165 int status;
1166 struct interface_info *interface;
1167
1168 if (object -> type != dhcp_type_interface)
1169 return DHCP_R_INVALIDARG;
1170 interface = (struct interface_info *)object;
1171
1172 status = recvfrom (interface -> wfdesc, buf, sizeof buf, 0,
1173 (struct sockaddr *)&from, &flen);
1174#if defined (DEBUG)
1175 /* Only report fallback discard errors if we're debugging. */
1176 if (status < 0) {
1177 log_error ("fallback_discard: %m");
1178 return ISC_R_UNEXPECTED;
1179 }
1180#else
1181 /* ignore the fact that status value is never used */
1182 IGNORE_UNUSED(status);
1183#endif
1184 return ISC_R_SUCCESS;
1185}
1186#endif /* USE_SOCKET_FALLBACK */
1187
1188#if defined (USE_SOCKET_SEND)
1190 struct interface_info *ip;
1191{
1192 return 0;
1193}
1194
1196 struct interface_info *ip;
1197{
1198#if defined (SOCKET_CAN_RECEIVE_UNICAST_UNCONFIGURED)
1199 return 1;
1200#else
1201 return 0;
1202#endif
1203}
1204
1206 struct interface_info *ip;
1207{
1208#if defined(SO_BINDTODEVICE) || \
1209 (defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && \
1210 defined(USE_V4_PKTINFO))
1211 return(1);
1212#else
1213 return(0);
1214#endif
1215}
1216
1217/* If we have SO_BINDTODEVICE, set up a fallback interface; otherwise,
1218 do not. */
1219
1221{
1222#if defined (USE_SOCKET_FALLBACK)
1223 isc_result_t status;
1224 struct interface_info *fbi = (struct interface_info *)0;
1225 if (setup_fallback (&fbi, MDL)) {
1226 fbi -> wfdesc = if_register_socket (fbi, AF_INET, 0, NULL);
1227 fbi -> rfdesc = fbi -> wfdesc;
1228 log_info ("Sending on Socket/%s%s%s",
1229 fbi -> name,
1230 (fbi -> shared_network ? "/" : ""),
1231 (fbi -> shared_network ?
1232 fbi -> shared_network -> name : ""));
1233
1235 if_readsocket, 0,
1236 fallback_discard, 0, 0);
1237 if (status != ISC_R_SUCCESS)
1238 log_fatal ("Can't register I/O handle for %s: %s",
1239 fbi -> name, isc_result_totext (status));
1240 interface_dereference (&fbi, MDL);
1241 }
1242#endif
1243}
1244
1245
1246#if defined(sun) && defined(USE_V4_PKTINFO)
1247/* This code assumes the existence of SIOCGLIFHWADDR */
1248void
1249get_hw_addr(const char *name, struct hardware *hw) {
1250 struct sockaddr_dl *dladdrp;
1251 int sock, i;
1252 struct lifreq lifr;
1253
1254 memset(&lifr, 0, sizeof (lifr));
1255 (void) strlcpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1256 /*
1257 * Check if the interface is a virtual or IPMP interface - in those
1258 * cases it has no hw address, so generate a random one.
1259 */
1260 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ||
1261 ioctl(sock, SIOCGLIFFLAGS, &lifr) < 0) {
1262 if (sock != -1)
1263 (void) close(sock);
1264
1265#ifdef DHCPv6
1266 /*
1267 * If approrpriate try this with an IPv6 socket
1268 */
1269 if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) >= 0 &&
1270 ioctl(sock, SIOCGLIFFLAGS, &lifr) >= 0) {
1271 goto flag_check;
1272 }
1273 if (sock != -1)
1274 (void) close(sock);
1275#endif
1276 log_fatal("Couldn't get interface flags for %s: %m", name);
1277
1278 }
1279
1280 flag_check:
1281 if (lifr.lifr_flags & (IFF_VIRTUAL|IFF_IPMP)) {
1282 hw->hlen = sizeof (hw->hbuf);
1283 srandom((long)gethrtime());
1284
1285 hw->hbuf[0] = HTYPE_IPMP;
1286 for (i = 1; i < hw->hlen; ++i) {
1287 hw->hbuf[i] = random() % 256;
1288 }
1289
1290 if (sock != -1)
1291 (void) close(sock);
1292 return;
1293 }
1294
1295 if (ioctl(sock, SIOCGLIFHWADDR, &lifr) < 0)
1296 log_fatal("Couldn't get interface hardware address for %s: %m",
1297 name);
1298 dladdrp = (struct sockaddr_dl *)&lifr.lifr_addr;
1299 hw->hlen = dladdrp->sdl_alen+1;
1300 switch (dladdrp->sdl_type) {
1301 case DL_CSMACD: /* IEEE 802.3 */
1302 case DL_ETHER:
1303 hw->hbuf[0] = HTYPE_ETHER;
1304 break;
1305 case DL_TPR:
1306 hw->hbuf[0] = HTYPE_IEEE802;
1307 break;
1308 case DL_FDDI:
1309 hw->hbuf[0] = HTYPE_FDDI;
1310 break;
1311 case DL_IB:
1312 hw->hbuf[0] = HTYPE_INFINIBAND;
1313 break;
1314 default:
1315 log_fatal("%s: unsupported DLPI MAC type %lu", name,
1316 (unsigned long)dladdrp->sdl_type);
1317 }
1318
1319 memcpy(hw->hbuf+1, LLADDR(dladdrp), hw->hlen-1);
1320
1321 if (sock != -1)
1322 (void) close(sock);
1323}
1324#endif /* defined(sun) */
1325
1326#endif /* USE_SOCKET_SEND */
#define IGNORE_UNUSED(x)
Definition cdefs.h:67
u_int16_t local_port
Definition discover.c:48
#define All_DHCP_Relay_Agents_and_Servers
Definition dhcp6.h:189
#define All_DHCP_Servers
Definition dhcp6.h:190
#define HTYPE_IPMP
Definition dhcp.h:79
#define HTYPE_IEEE802
Definition dhcp.h:76
#define HTYPE_FDDI
Definition dhcp.h:77
#define HTYPE_ETHER
Definition dhcp.h:75
#define HTYPE_INFINIBAND
Definition dhcp.h:78
void if_reinitialize_receive(struct interface_info *)
void maybe_setup_fallback(void)
#define INTERFACE_UPSTREAM
Definition dhcpd.h:1428
#define INTERFACE_DOWNSTREAM
Definition dhcpd.h:1427
int supports_multiple_interfaces(struct interface_info *)
void if_deregister_send(struct interface_info *)
#define INTERFACE_STREAMS
Definition dhcpd.h:1429
void if_reinitialize_send(struct interface_info *)
isc_result_t fallback_discard(omapi_object_t *)
ssize_t send_packet(struct interface_info *, struct packet *, struct dhcp_packet *, size_t, struct in_addr, struct sockaddr_in *, struct hardware *)
void if_register_linklocal6(struct interface_info *info)
void if_deregister6(struct interface_info *info)
int can_receive_unicast_unconfigured(struct interface_info *)
ssize_t receive_packet(struct interface_info *, unsigned char *, size_t, struct sockaddr_in *, struct hardware *)
void get_hw_addr(struct interface_info *info)
struct in6_addr local_address6
void if_register_receive(struct interface_info *)
void if_register6(struct interface_info *info, int do_multicast)
int bind_local_address6
int if_register_socket(struct interface_info *, int, int *, struct in6_addr *)
ssize_t send_packet6(struct interface_info *, const unsigned char *, size_t, struct sockaddr_in6 *)
void set_multicast_hop_limit(struct interface_info *info, int hop_limit)
int can_unicast_without_arp(struct interface_info *)
void if_deregister_receive(struct interface_info *)
ssize_t receive_packet6(struct interface_info *interface, unsigned char *buf, size_t len, struct sockaddr_in6 *from, struct in6_addr *to_addr, unsigned int *if_index)
void if_register_send(struct interface_info *)
u_int16_t relay_port
Definition discover.c:50
int local_family
Definition discover.c:59
int setup_fallback(struct interface_info **fp, const char *file, int line)
Definition discover.c:1059
int quiet_interface_discovery
Definition discover.c:47
struct in_addr local_address
Definition discover.c:60
#define SIOCGLIFFLAGS
Definition discover.c:201
omapi_object_type_t * dhcp_type_interface
Definition discover.c:83
int if_readsocket(omapi_object_t *h)
Definition discover.c:1048
#define ISC_R_SUCCESS
#define MDL
Definition omapip.h:567
isc_result_t omapi_register_io_object(omapi_object_t *, int(*)(omapi_object_t *), int(*)(omapi_object_t *), isc_result_t(*)(omapi_object_t *), isc_result_t(*)(omapi_object_t *), isc_result_t(*)(omapi_object_t *))
Definition dispatch.c:198
struct __omapi_object omapi_object_t
Definition omapip.h:39
void * dmalloc(size_t, const char *, int)
Definition alloc.c:57
int log_error(const char *,...) __attribute__((__format__(__printf__
int int int log_debug(const char *,...) __attribute__((__format__(__printf__
void log_fatal(const char *,...) __attribute__((__format__(__printf__
int int log_info(const char *,...) __attribute__((__format__(__printf__
#define SOCKLEN_T
Definition osdep.h:280
#define DHCP_R_INVALIDARG
Definition result.h:49
u_int8_t hlen
Definition dhcpd.h:492
u_int8_t hbuf[HARDWARE_ADDR_LEN+1]
Definition dhcpd.h:493
char name[IFNAMSIZ]
Definition dhcpd.h:1408
struct in6_addr * v6addresses
Definition dhcpd.h:1393
struct ifreq * ifp
Definition dhcpd.h:1419
int address_count
Definition dhcpd.h:1391
struct shared_network * shared_network
Definition dhcpd.h:1384
u_int32_t flags
Definition dhcpd.h:1423
struct in_addr * addresses
Definition dhcpd.h:1388
int v6address_count
Definition dhcpd.h:1395
Definition ip.h:47
char * name
Definition dhcpd.h:1060