ISC DHCP  4.4.3
A reference DHCPv4 and DHCPv6 implementation
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  */
65 static int no_global_v6_socket = 0;
66 static unsigned int global_v6_socket_references = 0;
67 static int global_v6_socket = -1;
68 #if defined(RELAY_PORT)
69 static unsigned int relay_port_v6_socket_references = 0;
70 static int relay_port_v6_socket = -1;
71 #endif
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, 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 */
170  if (bind_local_address6) {
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,
201  &local_address,
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
338 void 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)
354 void 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)
379 void 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
398 void 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 
434 void 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  */
470 static void
471 if_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 
509 void
510 if_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) &&
561  ((info->flags & INTERFACE_STREAMS) == INTERFACE_UPSTREAM)) {
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  */
603 void
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 
653 void
654 if_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)
715 ssize_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
769 static 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
781 static 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  */
822 static void *control_buf = NULL;
823 static size_t control_buf_len = 0;
824 
825 static void
826 allocate_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 */
853 ssize_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
939 ssize_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
1065 ssize_t
1066 receive_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 
1159 isc_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 
1220 void maybe_setup_fallback ()
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 
1234  status = omapi_register_io_object ((omapi_object_t *)fbi,
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 */
1248 void
1249 get_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
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
Definition: dhcpd.h:405
char * name
Definition: dhcpd.h:1060