summaryrefslogtreecommitdiffstats
path: root/src/lib/dhcp/iface_mgr_bsd.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/dhcp/iface_mgr_bsd.cc')
-rw-r--r--src/lib/dhcp/iface_mgr_bsd.cc198
1 files changed, 198 insertions, 0 deletions
diff --git a/src/lib/dhcp/iface_mgr_bsd.cc b/src/lib/dhcp/iface_mgr_bsd.cc
new file mode 100644
index 0000000..bc77d96
--- /dev/null
+++ b/src/lib/dhcp/iface_mgr_bsd.cc
@@ -0,0 +1,198 @@
+// Copyright (C) 2011-2022 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(bool update_only) {
+ if (isTestMode() && update_only) {
+ return;
+ }
+
+ 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");
+ }
+
+ iface_iter = ifaces.find(ifname);
+ if (iface_iter != ifaces.end()) {
+ continue;
+ }
+
+ IfacePtr iface;
+ if (update_only) {
+ iface = getIface(ifname);
+ }
+ if (!iface) {
+ iface.reset(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) {
+ iface_iter = ifaces.find(ifptr->ifa_name);
+ if (iface_iter == 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) {
+ IfacePtr iface;
+ if (update_only) {
+ iface = getIface(iface_iter->first);
+ }
+ if (!iface) {
+ 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, IfacePtr(),
+ "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