Kea  2.3.4-git
iface_mgr_bsd.cc
Go to the documentation of this file.
1 // Copyright (C) 2011-2022 Internet Systems Consortium, Inc. ("ISC")
2 //
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 
7 #include <config.h>
8 
9 #if defined(OS_BSD)
10 
11 #include <dhcp/iface_mgr.h>
13 #include <dhcp/pkt_filter_bpf.h>
14 #include <dhcp/pkt_filter_inet.h>
15 #include <exceptions/exceptions.h>
16 
17 #include <sys/types.h>
18 #include <sys/socket.h>
19 #include <net/if_dl.h>
20 #include <net/if.h>
21 #include <ifaddrs.h>
22 
23 using namespace std;
24 using namespace isc;
25 using namespace isc::asiolink;
26 using namespace isc::dhcp;
27 
28 namespace isc {
29 namespace dhcp {
30 
32 void
33 IfaceMgr::detectIfaces(bool update_only) {
34  if (isTestMode() && update_only) {
35  return;
36  }
37 
38  struct ifaddrs* iflist = 0;// The whole interface list
39  struct ifaddrs* ifptr = 0; // The interface we're processing now
40 
41  // Gets list of ifaddrs struct
42  if (getifaddrs(&iflist) != 0) {
43  isc_throw(Unexpected, "Network interfaces detection failed.");
44  }
45 
46  typedef map<string, IfacePtr> IfaceLst;
47  IfaceLst::iterator iface_iter;
48  IfaceLst ifaces;
49 
50  // First lookup for getting interfaces ...
51  for (ifptr = iflist; ifptr != 0; ifptr = ifptr->ifa_next) {
52  const char * ifname = ifptr->ifa_name;
53  uint ifindex = 0;
54 
55  if (!(ifindex = if_nametoindex(ifname))) {
56  // Interface name does not have corresponding index ...
57  freeifaddrs(iflist);
58  isc_throw(Unexpected, "Interface " << ifname << " has no index");
59  }
60 
61  iface_iter = ifaces.find(ifname);
62  if (iface_iter != ifaces.end()) {
63  continue;
64  }
65 
66  IfacePtr iface;
67  if (update_only) {
68  iface = getIface(ifname);
69  }
70  if (!iface) {
71  iface.reset(new Iface(ifname, ifindex));
72  }
73  iface->setFlags(ifptr->ifa_flags);
74  ifaces.insert(pair<string, IfacePtr>(ifname, iface));
75  }
76 
77  // Second lookup to get MAC and IP addresses
78  for (ifptr = iflist; ifptr != 0; ifptr = ifptr->ifa_next) {
79  iface_iter = ifaces.find(ifptr->ifa_name);
80  if (iface_iter == ifaces.end()) {
81  continue;
82  }
83  // Common byte pointer for following data
84  const uint8_t * ptr = 0;
85  if (ifptr->ifa_addr->sa_family == AF_LINK) {
86  // HWAddr
87  struct sockaddr_dl * ldata =
88  reinterpret_cast<struct sockaddr_dl *>(ifptr->ifa_addr);
89  ptr = reinterpret_cast<uint8_t *>(LLADDR(ldata));
90 
91  iface_iter->second->setHWType(ldata->sdl_type);
92  iface_iter->second->setMac(ptr, ldata->sdl_alen);
93  } else if (ifptr->ifa_addr->sa_family == AF_INET6) {
94  // IPv6 Addr
95  struct sockaddr_in6 * adata =
96  reinterpret_cast<struct sockaddr_in6 *>(ifptr->ifa_addr);
97  ptr = reinterpret_cast<uint8_t *>(&adata->sin6_addr);
98 
99  IOAddress a = IOAddress::fromBytes(AF_INET6, ptr);
100  iface_iter->second->addAddress(a);
101  } else {
102  // IPv4 Addr
103  struct sockaddr_in * adata =
104  reinterpret_cast<struct sockaddr_in *>(ifptr->ifa_addr);
105  ptr = reinterpret_cast<uint8_t *>(&adata->sin_addr);
106 
107  IOAddress a = IOAddress::fromBytes(AF_INET, ptr);
108  iface_iter->second->addAddress(a);
109  }
110  }
111 
112  freeifaddrs(iflist);
113 
114  // Interfaces registering
115  for (IfaceLst::const_iterator iface_iter = ifaces.begin();
116  iface_iter != ifaces.end(); ++iface_iter) {
117  IfacePtr iface;
118  if (update_only) {
119  iface = getIface(iface_iter->first);
120  }
121  if (!iface) {
122  addInterface(iface_iter->second);
123  }
124  }
125 }
126 
132 void Iface::setFlags(uint64_t flags) {
133  flags_ = flags;
134 
135  flag_loopback_ = flags & IFF_LOOPBACK;
136  flag_up_ = flags & IFF_UP;
137  flag_running_ = flags & IFF_RUNNING;
138  flag_multicast_ = flags & IFF_MULTICAST;
139  flag_broadcast_ = flags & IFF_BROADCAST;
140 }
141 
142 void
143 IfaceMgr::setMatchingPacketFilter(const bool direct_response_desired) {
144  // If direct response is desired we have to use BPF. If the direct
145  // response is not desired we use datagram socket supported by the
146  // PktFilterInet class. Note however that on BSD systems binding the
147  // datagram socket to the device is not supported and the server would
148  // have no means to determine on which interface the packet has been
149  // received. Hence, it is discouraged to use PktFilterInet for the
150  // server.
151  if (direct_response_desired) {
152  setPacketFilter(PktFilterPtr(new PktFilterBPF()));
153 
154  } else {
155  setPacketFilter(PktFilterPtr(new PktFilterInet()));
156 
157  }
158 }
159 
160 bool
161 IfaceMgr::openMulticastSocket(Iface& iface,
162  const isc::asiolink::IOAddress& addr,
163  const uint16_t port,
164  IfaceMgrErrorMsgCallback error_handler) {
165  try {
166  // This should open a socket, bind it to link-local address
167  // and join multicast group.
168  openSocket(iface.getName(), addr, port, iface.flag_multicast_);
169 
170  } catch (const Exception& ex) {
171  IFACEMGR_ERROR(SocketConfigError, error_handler, IfacePtr(),
172  "Failed to open link-local socket on "
173  "interface " << iface.getName() << ": "
174  << ex.what());
175  return (false);
176 
177  }
178  return (true);
179 }
180 
181 int
182 IfaceMgr::openSocket6(Iface& iface, const IOAddress& addr, uint16_t port,
183  const bool join_multicast) {
184  // On BSD, we bind the socket to in6addr_any and join multicast group
185  // to receive multicast traffic. So, if the multicast is requested,
186  // replace the address specified by the caller with the "unspecified"
187  // address.
188  IOAddress actual_address = join_multicast ? IOAddress("::") : addr;
189  SocketInfo info = packet_filter6_->openSocket(iface, actual_address, port,
190  join_multicast);
191  iface.addSocket(info);
192  return (info.sockfd_);
193 }
194 
195 } // end of isc::dhcp namespace
196 } // end of dhcp namespace
197 
198 #endif
Packet handling class using Berkeley Packet Filtering (BPF)
IfaceMgr exception thrown thrown when socket opening or configuration failed.
Definition: iface_mgr.h:63
void addSocket(const SocketInfo &sock)
Adds socket descriptor to an interface.
Definition: iface_mgr.h:321
boost::shared_ptr< Iface > IfacePtr
Type definition for the pointer to an Iface object.
Definition: iface_mgr.h:487
STL namespace.
std::function< void(const std::string &errmsg)> IfaceMgrErrorMsgCallback
This type describes the callback function invoked when error occurs in the IfaceMgr.
Definition: iface_mgr.h:648
Packet handling class using AF_INET socket family.
Represents a single network interface.
Definition: iface_mgr.h:118
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
boost::shared_ptr< PktFilter > PktFilterPtr
Pointer to a PktFilter object.
Definition: pkt_filter.h:134
int sockfd_
IPv4 or IPv6.
Definition: socket_info.h:26
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
bool flag_multicast_
Flag specifies if selected interface is multicast capable.
Definition: iface_mgr.h:451
#define IFACEMGR_ERROR(ex_type, handler, iface, stream)
A macro which handles an error in IfaceMgr.
A generic exception that is thrown when an unexpected error condition occurs.
std::string getName() const
Returns interface name.
Definition: iface_mgr.h:224
This is a base class for exceptions thrown from the DNS library module.
Defines the logger used by the top-level component of kea-lfc.
Holds information about socket.
Definition: socket_info.h:19