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