123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181 |
- // Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC")
- //
- // This Source Code Form is subject to the terms of the Mozilla Public
- // License, v. 2.0. If a copy of the MPL was not distributed with this
- // file, You can obtain one at http://mozilla.org/MPL/2.0/.
- #include <config.h>
- #if defined(OS_BSD)
- #include <dhcp/iface_mgr.h>
- #include <dhcp/iface_mgr_error_handler.h>
- #include <dhcp/pkt_filter_bpf.h>
- #include <dhcp/pkt_filter_inet.h>
- #include <exceptions/exceptions.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <net/if_dl.h>
- #include <net/if.h>
- #include <ifaddrs.h>
- using namespace std;
- using namespace isc;
- using namespace isc::asiolink;
- using namespace isc::dhcp;
- namespace isc {
- namespace dhcp {
- /// This is a BSD specific interface detection method.
- void
- IfaceMgr::detectIfaces() {
- struct ifaddrs* iflist = 0;// The whole interface list
- struct ifaddrs* ifptr = 0; // The interface we're processing now
- // Gets list of ifaddrs struct
- if(getifaddrs(&iflist) != 0) {
- isc_throw(Unexpected, "Network interfaces detection failed.");
- }
- typedef map<string, IfacePtr> IfaceLst;
- IfaceLst::iterator iface_iter;
- IfaceLst ifaces;
- // First lookup for getting interfaces ...
- for (ifptr = iflist; ifptr != 0; ifptr = ifptr->ifa_next) {
- const char * ifname = ifptr->ifa_name;
- uint ifindex = 0;
- if (!(ifindex = if_nametoindex(ifname))) {
- // Interface name does not have corresponding index ...
- freeifaddrs(iflist);
- isc_throw(Unexpected, "Interface " << ifname << " has no index");
- }
- if ((iface_iter = ifaces.find(ifname)) != ifaces.end()) {
- continue;
- }
- IfacePtr iface(new Iface(ifname, ifindex));
- iface->setFlags(ifptr->ifa_flags);
- ifaces.insert(pair<string, IfacePtr>(ifname, iface));
- }
- // Second lookup to get MAC and IP addresses
- for (ifptr = iflist; ifptr != 0; ifptr = ifptr->ifa_next) {
- if ((iface_iter = ifaces.find(ifptr->ifa_name)) == ifaces.end()) {
- continue;
- }
- // Common byte pointer for following data
- const uint8_t * ptr = 0;
- if(ifptr->ifa_addr->sa_family == AF_LINK) {
- // HWAddr
- struct sockaddr_dl * ldata =
- reinterpret_cast<struct sockaddr_dl *>(ifptr->ifa_addr);
- ptr = reinterpret_cast<uint8_t *>(LLADDR(ldata));
- iface_iter->second->setHWType(ldata->sdl_type);
- iface_iter->second->setMac(ptr, ldata->sdl_alen);
- } else if(ifptr->ifa_addr->sa_family == AF_INET6) {
- // IPv6 Addr
- struct sockaddr_in6 * adata =
- reinterpret_cast<struct sockaddr_in6 *>(ifptr->ifa_addr);
- ptr = reinterpret_cast<uint8_t *>(&adata->sin6_addr);
- IOAddress a = IOAddress::fromBytes(AF_INET6, ptr);
- iface_iter->second->addAddress(a);
- } else {
- // IPv4 Addr
- struct sockaddr_in * adata =
- reinterpret_cast<struct sockaddr_in *>(ifptr->ifa_addr);
- ptr = reinterpret_cast<uint8_t *>(&adata->sin_addr);
- IOAddress a = IOAddress::fromBytes(AF_INET, ptr);
- iface_iter->second->addAddress(a);
- }
- }
- freeifaddrs(iflist);
- // Interfaces registering
- for(IfaceLst::const_iterator iface_iter = ifaces.begin();
- iface_iter != ifaces.end(); ++iface_iter) {
- addInterface(iface_iter->second);
- }
- }
- /// @brief sets flag_*_ fields
- ///
- /// Like Linux version, os specific flags
- ///
- /// @params flags
- void Iface::setFlags(uint64_t flags) {
- flags_ = flags;
- flag_loopback_ = flags & IFF_LOOPBACK;
- flag_up_ = flags & IFF_UP;
- flag_running_ = flags & IFF_RUNNING;
- flag_multicast_ = flags & IFF_MULTICAST;
- flag_broadcast_ = flags & IFF_BROADCAST;
- }
- void
- IfaceMgr::setMatchingPacketFilter(const bool direct_response_desired) {
- // If direct response is desired we have to use BPF. If the direct
- // response is not desired we use datagram socket supported by the
- // PktFilterInet class. Note however that on BSD systems binding the
- // datagram socket to the device is not supported and the server would
- // have no means to determine on which interface the packet has been
- // received. Hence, it is discouraged to use PktFilterInet for the
- // server.
- if (direct_response_desired) {
- setPacketFilter(PktFilterPtr(new PktFilterBPF()));
- } else {
- setPacketFilter(PktFilterPtr(new PktFilterInet()));
- }
- }
- bool
- IfaceMgr::openMulticastSocket(Iface& iface,
- const isc::asiolink::IOAddress& addr,
- const uint16_t port,
- IfaceMgrErrorMsgCallback error_handler) {
- try {
- // This should open a socket, bind it to link-local address
- // and join multicast group.
- openSocket(iface.getName(), addr, port, iface.flag_multicast_);
- } catch (const Exception& ex) {
- IFACEMGR_ERROR(SocketConfigError, error_handler,
- "Failed to open link-local socket on "
- " interface " << iface.getName() << ": "
- << ex.what());
- return (false);
- }
- return (true);
- }
- int
- IfaceMgr::openSocket6(Iface& iface, const IOAddress& addr, uint16_t port,
- const bool join_multicast) {
- // On BSD, we bind the socket to in6addr_any and join multicast group
- // to receive multicast traffic. So, if the multicast is requested,
- // replace the address specified by the caller with the "unspecified"
- // address.
- IOAddress actual_address = join_multicast ? IOAddress("::") : addr;
- SocketInfo info = packet_filter6_->openSocket(iface, actual_address, port,
- join_multicast);
- iface.addSocket(info);
- return (info.sockfd_);
- }
- } // end of isc::dhcp namespace
- } // end of dhcp namespace
- #endif
|