]> git.ipfire.org Git - thirdparty/dhcp.git/blame - common/socket.c
copy rights update
[thirdparty/dhcp.git] / common / socket.c
CommitLineData
d7837182
TL
1/* socket.c
2
3 BSD socket interface code... */
4
5/*
49a7fb58 6 * Copyright (C) 2004-2022 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 21 * Internet Systems Consortium, Inc.
429a56d7
TM
22 * PO Box 360
23 * Newmarket, NH 03857 USA
98311e4b 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
f6b8f48d 33 * this sockopt will be automatically enabled.
469cf3a4
TL
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
f6b8f48d 153 /*
98bd7ca0 154 * Set up the address we're going to bind to, depending on the
f6b8f48d
TM
155 * address family.
156 */
98bd7ca0 157 memset(&name, 0, sizeof(name));
98bf1607 158 switch (family) {
fe5b0fdd 159#ifdef DHCPv6
98bf1607 160 case AF_INET6:
f6b8f48d 161 addr6 = (struct sockaddr_in6 *)&name;
98bf1607
SR
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:
f6b8f48d 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;
f6b8f48d 299 if (setsockopt(sock, IPPROTO_IP, IP_RECVPKTINFO,
7cfeb916 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 308 /*
f6b8f48d 309 * If we turn on IPV6_PKTINFO, we will be able to receive
98bd7ca0
DH
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 */
f6b8f48d 317 if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
98bd7ca0 318 &on, sizeof(on)) != 0) {
8834cc2e
TM
319 log_fatal("setsockopt: IPV6_RECVPKTINFO for %s: %m",
320 info->name);
98bd7ca0
DH
321 }
322#else
323 /* RFC2292 */
f6b8f48d 324 if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO,
98bd7ca0 325 &on, sizeof(on)) != 0) {
8834cc2e
TM
326 log_fatal("setsockopt: IPV6_PKTINFO for %s: %m",
327 info->name);
98bd7ca0
DH
328 }
329#endif
330 }
7de20a95 331
fe5b0fdd 332#endif /* DHCPv6 */
98bd7ca0 333
e23c9055 334 return sock;
d7837182 335}
c2b5b5e8
TM
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) {
5da634c5 341 log_fatal("setsockopt: IPV6_MULTICAST_HOPS for %s: %m",
8834cc2e 342 info->name);
c2b5b5e8
TM
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
a1b705e5 351#endif /* USE_SOCKET_SEND || USE_SOCKET_RECEIVE || USE_SOCKET_FALLBACK */
d7837182 352
a1b705e5 353#if defined (USE_SOCKET_SEND) || defined (USE_SOCKET_FALLBACK)
c3585217 354void if_register_send (info)
c857a7b6 355 struct interface_info *info;
d7837182 356{
e23c9055 357#ifndef USE_SOCKET_RECEIVE
4b8251a0 358 info->wfdesc = if_register_socket(info, AF_INET, 0, NULL);
7cfeb916
SR
359 /* If this is a normal IPv4 address, get the hardware address. */
360 if (strcmp(info->name, "fallback") != 0)
361 get_hw_addr(info->name, &info->hw_address);
2e96d6e7
TL
362#if defined (USE_SOCKET_FALLBACK)
363 /* Fallback only registers for send, but may need to receive as
364 well. */
7cfeb916 365 info->rfdesc = info->wfdesc;
2e96d6e7 366#endif
e23c9055 367#else
7cfeb916 368 info->wfdesc = info->rfdesc;
e23c9055 369#endif
3648a2a1 370 if (!quiet_interface_discovery)
74f45f96 371 log_info ("Sending on Socket/%s%s%s",
7cfeb916
SR
372 info->name,
373 (info->shared_network ? "/" : ""),
374 (info->shared_network ?
375 info->shared_network->name : ""));
d7837182 376}
7203e8ee 377
3782236d 378#if defined (USE_SOCKET_SEND)
7203e8ee
TL
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
387 if (!quiet_interface_discovery)
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}
3782236d 394#endif /* USE_SOCKET_SEND */
a1b705e5 395#endif /* USE_SOCKET_SEND || USE_SOCKET_FALLBACK */
d7837182 396
e23c9055 397#ifdef USE_SOCKET_RECEIVE
c3585217 398void if_register_receive (info)
e23c9055 399 struct interface_info *info;
e23c9055 400{
7cfeb916
SR
401
402#if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && defined(USE_V4_PKTINFO)
403 if (global_v4_socket_references == 0) {
4b8251a0 404 global_v4_socket = if_register_socket(info, AF_INET, 0, NULL);
7cfeb916
SR
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 }
f6b8f48d 414
7cfeb916
SR
415 info->rfdesc = global_v4_socket;
416 global_v4_socket_references++;
417#else
e23c9055
TL
418 /* If we're using the socket API for sending and receiving,
419 we don't need to register this interface twice. */
4b8251a0 420 info->rfdesc = if_register_socket(info, AF_INET, 0, NULL);
7cfeb916
SR
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->name, &info->hw_address);
425
3648a2a1 426 if (!quiet_interface_discovery)
74f45f96 427 log_info ("Listening on Socket/%s%s%s",
7cfeb916
SR
428 info->name,
429 (info->shared_network ? "/" : ""),
430 (info->shared_network ?
431 info->shared_network->name : ""));
e23c9055 432}
7203e8ee
TL
433
434void if_deregister_receive (info)
435 struct interface_info *info;
436{
7cfeb916
SR
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) &&
7cfeb916
SR
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 }
7203e8ee 446
7cfeb916
SR
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... */
7203e8ee
TL
455 if (!quiet_interface_discovery)
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 : ""));
05af5898 461}
e23c9055
TL
462#endif /* USE_SOCKET_RECEIVE */
463
98bd7ca0 464
f6b8f48d 465#ifdef DHCPv6
ecddae64
DH
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) {
f6b8f48d 477 log_fatal("inet_pton: unable to convert '%s'",
ecddae64
DH
478 All_DHCP_Relay_Agents_and_Servers);
479 }
480 mreq.ipv6mr_interface = if_nametoindex(info->name);
f6b8f48d 481 if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
ecddae64 482 &mreq, sizeof(mreq)) < 0) {
5da634c5
TM
483 log_fatal("setsockopt: IPV6_JOIN_GROUP for %s: %m",
484 info->name);
ecddae64
DH
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) {
f6b8f48d 497 log_fatal("inet_pton: unable to convert '%s'",
ecddae64
DH
498 All_DHCP_Servers);
499 }
500 mreq.ipv6mr_interface = if_nametoindex(info->name);
f6b8f48d 501 if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
ecddae64 502 &mreq, sizeof(mreq)) < 0) {
5da634c5
TM
503 log_fatal("setsockopt: IPV6_JOIN_GROUP for %s: %m",
504 info->name);
ecddae64
DH
505 }
506 }
507}
508
98bd7ca0
DH
509void
510if_register6(struct interface_info *info, int do_multicast) {
ecddae64
DH
511 /* Bounce do_multicast to a stack variable because we may change it. */
512 int req_multi = do_multicast;
513
4b8251a0
SR
514 if (no_global_v6_socket) {
515 log_fatal("Impossible condition at %s:%d", MDL);
516 }
517
563f0b8a
FD
518#if defined(RELAY_PORT)
519 if (!relay_port ||
520 ((info->flags & INTERFACE_STREAMS) == INTERFACE_DOWNSTREAM)) {
521#endif
ecddae64
DH
522 if (global_v6_socket_references == 0) {
523 global_v6_socket = if_register_socket(info, AF_INET6,
4b8251a0 524 &req_multi, NULL);
ecddae64
DH
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);
a2a0f98c
FD
531 } else if (bind_local_address6) {
532 char addr6_str[INET6_ADDRSTRLEN];
533
534 if (inet_ntop(AF_INET6,
535 &local_address6,
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));
ecddae64 544 } else {
a2a0f98c 545 log_info("Bound to *:%d", (int) ntohs(local_port));
ecddae64
DH
546 }
547 }
f6b8f48d 548
ecddae64
DH
549 info->rfdesc = global_v6_socket;
550 info->wfdesc = global_v6_socket;
551 global_v6_socket_references++;
552
563f0b8a
FD
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
ecddae64
DH
577 if (req_multi)
578 if_register_multicast(info);
579
580 get_hw_addr(info->name, &info->hw_address);
581
98bd7ca0
DH
582 if (!quiet_interface_discovery) {
583 if (info->shared_network != NULL) {
ecddae64 584 log_info("Listening on Socket/%d/%s/%s",
f6b8f48d 585 global_v6_socket, info->name,
98bd7ca0 586 info->shared_network->name);
ecddae64
DH
587 log_info("Sending on Socket/%d/%s/%s",
588 global_v6_socket, info->name,
98bd7ca0
DH
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
4b8251a0
SR
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
604if_register_linklocal6(struct interface_info *info) {
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 }
f6b8f48d 613
4b8251a0
SR
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->name, &info->hw_address);
637
638 if (!quiet_interface_discovery) {
639 if (info->shared_network != NULL) {
640 log_info("Listening on Socket/%d/%s/%s",
f6b8f48d 641 global_v6_socket, info->name,
4b8251a0
SR
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
f6b8f48d 653void
98bd7ca0 654if_deregister6(struct interface_info *info) {
4b8251a0
SR
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. */
ecddae64
DH
664 global_v6_socket_references--;
665 info->rfdesc = -1;
666 info->wfdesc = -1;
563f0b8a
FD
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
ecddae64
DH
677 } else {
678 log_fatal("Impossible condition at %s:%d", MDL);
679 }
98bd7ca0
DH
680
681 if (!quiet_interface_discovery) {
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 }
ecddae64 692
563f0b8a
FD
693 if (!no_global_v6_socket) {
694 if (global_v6_socket_references == 0) {
695 close(global_v6_socket);
696 global_v6_socket = -1;
ecddae64 697
563f0b8a
FD
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
ecddae64 710 }
98bd7ca0 711}
fe5b0fdd 712#endif /* DHCPv6 */
98bd7ca0 713
a1b705e5 714#if defined (USE_SOCKET_SEND) || defined (USE_SOCKET_FALLBACK)
4595a58c 715ssize_t send_packet (interface, packet, raw, len, from, to, hto)
e23c9055 716 struct interface_info *interface;
a8b53b42
TL
717 struct packet *packet;
718 struct dhcp_packet *raw;
719 size_t len;
0a5d6860 720 struct in_addr from;
c857a7b6 721 struct sockaddr_in *to;
e23c9055 722 struct hardware *hto;
a8b53b42 723{
5145810c
TL
724 int result;
725#ifdef IGNORE_HOSTUNREACH
726 int retry = 0;
727 do {
7cfeb916
SR
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,
f6b8f48d 737 sizeof(pktinfo)) < 0)
5da634c5
TM
738 log_fatal("setsockopt: IP_PKTINFO for %s: %m",
739 (char*)(interface->ifp));
7cfeb916 740 }
5145810c
TL
741#endif
742 result = sendto (interface -> wfdesc, (char *)raw, len, 0,
743 (struct sockaddr *)to, sizeof *to);
744#ifdef IGNORE_HOSTUNREACH
13ee152c 745 } while (to -> sin_addr.s_addr == htonl (INADDR_BROADCAST) &&
5145810c
TL
746 result < 0 &&
747 (errno == EHOSTUNREACH ||
748 errno == ECONNREFUSED) &&
749 retry++ < 10);
750#endif
74f45f96 751 if (result < 0) {
c5b0f529 752 log_error ("send_packet: %m");
74f45f96 753 if (errno == ENETUNREACH)
a1b705e5
TL
754 log_error ("send_packet: please consult README file%s",
755 " regarding broadcast address.");
74f45f96 756 }
af361f2a 757 return result;
a8b53b42 758}
98bd7ca0 759
a1b705e5 760#endif /* USE_SOCKET_SEND || USE_SOCKET_FALLBACK */
a8b53b42 761
cff9b78f
SK
762#ifdef DHCPv6
763/*
f6b8f48d 764 * Solaris 9 is missing the CMSG_LEN and CMSG_SPACE macros, so we will
cff9b78f
SK
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
7cfeb916
SR
812#if defined(DHCPv6) || \
813 (defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && \
814 defined(USE_V4_PKTINFO))
57fbc772
SR
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
7cfeb916
SR
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.
57fbc772
SR
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}
7cfeb916 831#endif /* DHCPv6, IP_PKTINFO ... */
57fbc772 832
7cfeb916 833#ifdef DHCPv6
f6b8f48d
TM
834/*
835 * For both send_packet6() and receive_packet6() we need to use the
20ae1aff 836 * sendmsg()/recvmsg() functions rather than the simpler send()/recv()
98bd7ca0
DH
837 * functions.
838 *
839 * In the case of send_packet6(), we need to do this in order to insure
f6b8f48d
TM
840 * that the reply packet leaves on the same interface that it arrived
841 * on.
98bd7ca0 842 *
f6b8f48d 843 * In the case of receive_packet6(), we need to do this in order to
98bd7ca0
DH
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,
6705543f 854 const unsigned char *raw, size_t len,
98bd7ca0
DH
855 struct sockaddr_in6 *to) {
856 struct msghdr m;
857 struct iovec v;
4b8251a0 858 struct sockaddr_in6 dst;
98bd7ca0
DH
859 int result;
860 struct in6_pktinfo *pktinfo;
98bd7ca0 861 struct cmsghdr *cmsg;
4b8251a0 862 unsigned int ifindex;
57fbc772
SR
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);
98bd7ca0
DH
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.
4b8251a0 885 * Enforce the scope ID for bogus BSDs.
98bd7ca0 886 */
4b8251a0
SR
887 memcpy(&dst, to, sizeof(dst));
888 m.msg_name = &dst;
889 m.msg_namelen = sizeof(dst);
890 ifindex = if_nametoindex(interface->name);
0cd94b5e
TM
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__
4b8251a0 896 if (no_global_v6_socket)
0cd94b5e 897#endif
4b8251a0 898 dst.sin6_scope_id = ifindex;
98bd7ca0
DH
899
900 /*
f6b8f48d
TM
901 * Set the data buffer we're sending. (Using this wacky
902 * "scatter-gather" stuff... we only have a single chunk
98bd7ca0
DH
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.
f6b8f48d
TM
912 *
913 * We have to create a "control message", and set that to
98bd7ca0
DH
914 * define the IPv6 packet information. We could set the
915 * source address if we wanted, but we can safely let the
f6b8f48d 916 * kernel decide what that should be.
98bd7ca0 917 */
57fbc772
SR
918 m.msg_control = control_buf;
919 m.msg_controllen = control_buf_len;
98bd7ca0 920 cmsg = CMSG_FIRSTHDR(&m);
dc9d7b08 921 INSIST(cmsg != NULL);
98bd7ca0
DH
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));
a2a0f98c 927 pktinfo->ipi6_addr = local_address6;
4b8251a0 928 pktinfo->ipi6_ifindex = ifindex;
98bd7ca0
DH
929
930 result = sendmsg(interface->wfdesc, &m, 0);
931 if (result < 0) {
932 log_error("send_packet6: %m");
933 }
934 return result;
935}
fe5b0fdd 936#endif /* DHCPv6 */
98bd7ca0 937
c857a7b6 938#ifdef USE_SOCKET_RECEIVE
4595a58c 939ssize_t receive_packet (interface, buf, len, from, hfrom)
e23c9055
TL
940 struct interface_info *interface;
941 unsigned char *buf;
942 size_t len;
943 struct sockaddr_in *from;
944 struct hardware *hfrom;
a8b53b42 945{
865afd5e 946#if !(defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && defined(USE_V4_PKTINFO))
d1f313b3 947 SOCKLEN_T flen = sizeof *from;
7cfeb916 948#endif
5145810c 949 int result;
e23c9055 950
98bd7ca0
DH
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
5145810c
TL
958#ifdef IGNORE_HOSTUNREACH
959 int retry = 0;
960 do {
961#endif
7cfeb916
SR
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;
7cfeb916
SR
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 /*
f6b8f48d 996 * Set the data buffer we're receiving. (Using this wacky
7cfeb916
SR
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 *
f6b8f48d
TM
1008 * We set up some space for a "control message". We have
1009 * previously asked the kernel to give us packet
7cfeb916 1010 * information (when we initialized the interface), so we
865afd5e 1011 * should get the interface index from that.
7cfeb916
SR
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
f6b8f48d 1021 * through the control messages we received and
865afd5e 1022 * find the one with our inteface index.
7cfeb916 1023 */
7cfeb916
SR
1024 cmsg = CMSG_FIRSTHDR(&m);
1025 while (cmsg != NULL) {
f6b8f48d 1026 if ((cmsg->cmsg_level == IPPROTO_IP) &&
7cfeb916
SR
1027 (cmsg->cmsg_type == IP_PKTINFO)) {
1028 pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
1029 ifindex = pktinfo->ipi_ifindex;
1030 /*
f6b8f48d 1031 * We pass the ifindex back to the caller
7cfeb916 1032 * using the unused hfrom parameter avoiding
f6b8f48d 1033 * interface changes between sockets and
7cfeb916
SR
1034 * the discover code.
1035 */
1036 memcpy(hfrom->hbuf, &ifindex, sizeof(ifindex));
865afd5e 1037 return (result);
7cfeb916
SR
1038 }
1039 cmsg = CMSG_NXTHDR(&m, cmsg);
1040 }
865afd5e
SR
1041
1042 /*
1043 * We didn't find the necessary control message
1044 * flag it as an error
1045 */
1046 result = -1;
1047 errno = EIO;
7cfeb916
SR
1048 }
1049#else
865afd5e
SR
1050 result = recvfrom(interface -> rfdesc, (char *)buf, len, 0,
1051 (struct sockaddr *)from, &flen);
7cfeb916 1052#endif /* IP_PKTINFO ... */
5145810c
TL
1053#ifdef IGNORE_HOSTUNREACH
1054 } while (result < 0 &&
1055 (errno == EHOSTUNREACH ||
1056 errno == ECONNREFUSED) &&
1057 retry++ < 10);
1058#endif
865afd5e 1059 return (result);
c857a7b6 1060}
98bd7ca0 1061
c857a7b6 1062#endif /* USE_SOCKET_RECEIVE */
c5568eb5 1063
fe5b0fdd 1064#ifdef DHCPv6
f6b8f48d
TM
1065ssize_t
1066receive_packet6(struct interface_info *interface,
1067 unsigned char *buf, size_t len,
ecddae64
DH
1068 struct sockaddr_in6 *from, struct in6_addr *to_addr,
1069 unsigned int *if_idx)
1070{
98bd7ca0
DH
1071 struct msghdr m;
1072 struct iovec v;
98bd7ca0
DH
1073 int result;
1074 struct cmsghdr *cmsg;
1075 struct in6_pktinfo *pktinfo;
57fbc772
SR
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) {
436e808a
SR
1084 log_error("receive_packet6: unable to allocate cmsg "
1085 "header");
57fbc772
SR
1086 return(ENOMEM);
1087 }
1088 }
1089 memset(control_buf, 0, control_buf_len);
98bd7ca0
DH
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 /*
f6b8f48d 1103 * Set the data buffer we're receiving. (Using this wacky
98bd7ca0
DH
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 *
f6b8f48d
TM
1115 * We set up some space for a "control message". We have
1116 * previously asked the kernel to give us packet
98bd7ca0
DH
1117 * information (when we initialized the interface), so we
1118 * should get the destination address from that.
1119 */
57fbc772
SR
1120 m.msg_control = control_buf;
1121 m.msg_controllen = control_buf_len;
98bd7ca0
DH
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
f6b8f48d 1128 * through the control messages we received and
98bd7ca0 1129 * find the one with our destination address.
98bd7ca0 1130 */
98bd7ca0
DH
1131 cmsg = CMSG_FIRSTHDR(&m);
1132 while (cmsg != NULL) {
f6b8f48d 1133 if ((cmsg->cmsg_level == IPPROTO_IPV6) &&
98bd7ca0
DH
1134 (cmsg->cmsg_type == IPV6_PKTINFO)) {
1135 pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
1136 *to_addr = pktinfo->ipi6_addr;
ecddae64 1137 *if_idx = pktinfo->ipi6_ifindex;
865afd5e
SR
1138
1139 return (result);
98bd7ca0
DH
1140 }
1141 cmsg = CMSG_NXTHDR(&m, cmsg);
1142 }
865afd5e
SR
1143
1144 /*
1145 * We didn't find the necessary control message
1146 * flag is as an error
1147 */
1148 result = -1;
1149 errno = EIO;
98bd7ca0
DH
1150 }
1151
865afd5e 1152 return (result);
98bd7ca0 1153}
fe5b0fdd 1154#endif /* DHCPv6 */
98bd7ca0 1155
e15381fc 1156#if defined (USE_SOCKET_FALLBACK)
c5568eb5
TL
1157/* This just reads in a packet and silently discards it. */
1158
acc21512 1159isc_result_t fallback_discard (object)
e92653f1 1160 omapi_object_t *object;
c5568eb5
TL
1161{
1162 char buf [1540];
1163 struct sockaddr_in from;
d1f313b3 1164 SOCKLEN_T flen = sizeof from;
c01f1285 1165 int status;
acc21512
TL
1166 struct interface_info *interface;
1167
1168 if (object -> type != dhcp_type_interface)
98bf1607 1169 return DHCP_R_INVALIDARG;
acc21512 1170 interface = (struct interface_info *)object;
c5568eb5 1171
c01f1285
TL
1172 status = recvfrom (interface -> wfdesc, buf, sizeof buf, 0,
1173 (struct sockaddr *)&from, &flen);
4089dd21
M
1174#if defined (DEBUG)
1175 /* Only report fallback discard errors if we're debugging. */
acc21512 1176 if (status < 0) {
8ae2d595 1177 log_error ("fallback_discard: %m");
acc21512
TL
1178 return ISC_R_UNEXPECTED;
1179 }
dd9237c3
TM
1180#else
1181 /* ignore the fact that status value is never used */
1182 IGNORE_UNUSED(status);
4089dd21 1183#endif
acc21512 1184 return ISC_R_SUCCESS;
c5568eb5 1185}
a1b705e5 1186#endif /* USE_SOCKET_FALLBACK */
d2bc90bd 1187
a1b705e5 1188#if defined (USE_SOCKET_SEND)
21d21e91
TL
1189int can_unicast_without_arp (ip)
1190 struct interface_info *ip;
d2bc90bd
TL
1191{
1192 return 0;
1193}
1194
21d21e91
TL
1195int can_receive_unicast_unconfigured (ip)
1196 struct interface_info *ip;
b547818b 1197{
a1b705e5
TL
1198#if defined (SOCKET_CAN_RECEIVE_UNICAST_UNCONFIGURED)
1199 return 1;
1200#else
b547818b 1201 return 0;
a1b705e5 1202#endif
b547818b
TL
1203}
1204
5cefe5e5
TL
1205int supports_multiple_interfaces (ip)
1206 struct interface_info *ip;
1207{
7cfeb916
SR
1208#if defined(SO_BINDTODEVICE) || \
1209 (defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && \
1210 defined(USE_V4_PKTINFO))
1211 return(1);
5cefe5e5 1212#else
7cfeb916 1213 return(0);
5cefe5e5
TL
1214#endif
1215}
1216
d2bc90bd
TL
1217/* If we have SO_BINDTODEVICE, set up a fallback interface; otherwise,
1218 do not. */
1219
1220void maybe_setup_fallback ()
1221{
a1b705e5 1222#if defined (USE_SOCKET_FALLBACK)
acc21512 1223 isc_result_t status;
950c6a06
TL
1224 struct interface_info *fbi = (struct interface_info *)0;
1225 if (setup_fallback (&fbi, MDL)) {
4b8251a0 1226 fbi -> wfdesc = if_register_socket (fbi, AF_INET, 0, NULL);
a47105d6
TL
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 : ""));
f6b8f48d 1233
e48c5c5c 1234 status = omapi_register_io_object ((omapi_object_t *)fbi,
acc21512
TL
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));
950c6a06 1240 interface_dereference (&fbi, MDL);
d2bc90bd
TL
1241 }
1242#endif
1243}
7cfeb916
SR
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;
b047bd38 1251 int sock, i;
7cfeb916
SR
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
b047bd38
SR
1285 hw->hbuf[0] = HTYPE_IPMP;
1286 for (i = 1; i < hw->hlen; ++i) {
7cfeb916
SR
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;
b047bd38
SR
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);
7cfeb916
SR
1320
1321 if (sock != -1)
1322 (void) close(sock);
1323}
1324#endif /* defined(sun) */
1325
a1b705e5 1326#endif /* USE_SOCKET_SEND */