Annotation of embedaddon/dhcp/common/socket.c, revision 1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>