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