| Kea 3.0.2-git

iface_mgr_bsd.cc
Go to the documentation of this file.
1// Copyright (C) 2011-2024 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>
12#include <dhcp/iface_mgr_error_handler.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 (detect_callback_) {
35 if (!detect_callback_(update_only)) {
36 return;
37 }
38 }
39
40 struct ifaddrs* iflist = 0;// The whole interface list
41 struct ifaddrs* ifptr = 0; // The interface we're processing now
42
43 // Gets list of ifaddrs struct
44 if (getifaddrs(&iflist) != 0) {
45 isc_throw(Unexpected, "Network interfaces detection failed.");
46 }
47
48 typedef map<string, IfacePtr> IfaceLst;
49 IfaceLst::iterator iface_iter;
50 IfaceLst ifaces;
51
52 // First lookup for getting interfaces ...
53 for (ifptr = iflist; ifptr != 0; ifptr = ifptr->ifa_next) {
54 const char * ifname = ifptr->ifa_name;
55 uint ifindex = 0;
56
57 if (!(ifindex = if_nametoindex(ifname))) {
58 // Interface name does not have corresponding index ...
59 freeifaddrs(iflist);
60 isc_throw(Unexpected, "Interface " << ifname << " has no index");
61 }
62
63 iface_iter = ifaces.find(ifname);
64 if (iface_iter != ifaces.end()) {
65 continue;
66 }
67
68 IfacePtr iface;
69 if (update_only) {
70 iface = getIface(ifname);
71 }
72 if (!iface) {
73 iface.reset(new Iface(ifname, ifindex));
74 }
75 iface->setFlags(ifptr->ifa_flags);
76 ifaces.insert(pair<string, IfacePtr>(ifname, iface));
77 }
78
79 // Second lookup to get MAC and IP addresses
80 for (ifptr = iflist; ifptr != 0; ifptr = ifptr->ifa_next) {
81 iface_iter = ifaces.find(ifptr->ifa_name);
82 if (iface_iter == ifaces.end()) {
83 continue;
84 }
85 // Common byte pointer for following data
86 const uint8_t * ptr = 0;
87 if (ifptr->ifa_addr->sa_family == AF_LINK) {
88 // HWAddr
89 struct sockaddr_dl * ldata =
90 reinterpret_cast<struct sockaddr_dl *>(ifptr->ifa_addr);
91 ptr = reinterpret_cast<uint8_t *>(LLADDR(ldata));
92
93 iface_iter->second->setHWType(ldata->sdl_type);
94 iface_iter->second->setMac(ptr, ldata->sdl_alen);
95 } else if (ifptr->ifa_addr->sa_family == AF_INET6) {
96 // IPv6 Addr
97 struct sockaddr_in6 * adata =
98 reinterpret_cast<struct sockaddr_in6 *>(ifptr->ifa_addr);
99 ptr = reinterpret_cast<uint8_t *>(&adata->sin6_addr);
100
101 IOAddress a = IOAddress::fromBytes(AF_INET6, ptr);
102 iface_iter->second->addAddress(a);
103 } else {
104 // IPv4 Addr
105 struct sockaddr_in * adata =
106 reinterpret_cast<struct sockaddr_in *>(ifptr->ifa_addr);
107 ptr = reinterpret_cast<uint8_t *>(&adata->sin_addr);
108
109 IOAddress a = IOAddress::fromBytes(AF_INET, ptr);
110 iface_iter->second->addAddress(a);
111 }
112 }
113
114 freeifaddrs(iflist);
115
116 // Interfaces registering
117 for (auto const& iface_it : ifaces) {
118 IfacePtr iface;
119 if (update_only) {
120 iface = getIface(iface_it.first);
121 }
122 if (!iface) {
123 addInterface(iface_it.second);
124 }
125 }
126}
127
133 void Iface::setFlags(uint64_t flags) {
134 flags_ = flags;
135
136 flag_loopback_ = flags & IFF_LOOPBACK;
137 flag_up_ = flags & IFF_UP;
138 flag_running_ = flags & IFF_RUNNING;
139 flag_multicast_ = flags & IFF_MULTICAST;
140 flag_broadcast_ = flags & IFF_BROADCAST;
141}
142
143 void
144 IfaceMgr::setMatchingPacketFilter(const bool direct_response_desired) {
145 // If direct response is desired we have to use BPF. If the direct
146 // response is not desired we use datagram socket supported by the
147 // PktFilterInet class. Note however that on BSD systems binding the
148 // datagram socket to the device is not supported and the server would
149 // have no means to determine on which interface the packet has been
150 // received. Hence, it is discouraged to use PktFilterInet for the
151 // server.
152 if (direct_response_desired) {
153 setPacketFilter(PktFilterPtr(new PktFilterBPF()));
154
155 } else {
156 setPacketFilter(PktFilterPtr(new PktFilterInet()));
157
158 }
159}
160
161 bool
162IfaceMgr::openMulticastSocket(Iface& iface,
163 const isc::asiolink::IOAddress& addr,
164 const uint16_t port,
165 IfaceMgrErrorMsgCallback error_handler) {
166 try {
167 // This should open a socket, bind it to link-local address
168 // and join multicast group.
169 openSocket(iface.getName(), addr, port, iface.flag_multicast_);
170
171 } catch (const Exception& ex) {
172 IFACEMGR_ERROR(SocketConfigError, error_handler, IfacePtr(),
173 "Failed to open link-local socket on "
174 "interface " << iface.getName() << ": "
175 << ex.what());
176 return (false);
177
178 }
179 return (true);
180}
181
182 int
183 IfaceMgr::openSocket6(Iface& iface, const IOAddress& addr, uint16_t port,
184 const bool join_multicast) {
185 // On BSD, we bind the socket to in6addr_any and join multicast group
186 // to receive multicast traffic. So, if the multicast is requested,
187 // replace the address specified by the caller with the "unspecified"
188 // address.
189 IOAddress actual_address = join_multicast ? IOAddress("::") : addr;
190 SocketInfo info = packet_filter6_->openSocket(iface, actual_address, port,
191 join_multicast);
192 iface.addSocket(info);
193 return (info.sockfd_);
194}
195
196} // end of isc::dhcp namespace
197} // end of dhcp namespace
198
199#endif
Exception::what
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
Definition exceptions/exceptions.cc:32
isc::asiolink::IOAddress
The IOAddress class represents an IP addresses (version agnostic).
Definition io_address.h:45
isc::asiolink::IOAddress::fromBytes
static IOAddress fromBytes(short family, const uint8_t *data)
Creates an address from over wire data.
Definition io_address.cc:66
isc::dhcp::IfaceMgr::openSocket
int openSocket(const std::string &ifname, const isc::asiolink::IOAddress &addr, const uint16_t port, const bool receive_bcast=false, const bool send_bcast=false)
Opens UDP/IP socket and binds it to address, interface and port.
Definition iface_mgr.cc:932
isc::dhcp::IfaceMgr::getIface
IfacePtr getIface(const unsigned int ifindex)
Returns interface specified interface index.
Definition iface_mgr.cc:879
isc::dhcp::IfaceMgr::setPacketFilter
void setPacketFilter(const PktFilterPtr &packet_filter)
Set packet filter object to handle sending and receiving DHCPv4 messages.
Definition iface_mgr.cc:405
isc::dhcp::IfaceMgr::detectIfaces
void detectIfaces(bool update_only=false)
Detects network interfaces.
isc::dhcp::IfaceMgr::openSocket6
int openSocket6(Iface &iface, const isc::asiolink::IOAddress &addr, uint16_t port, const bool join_multicast)
Opens IPv6 socket.
isc::dhcp::IfaceMgr::addInterface
void addInterface(const IfacePtr &iface)
Adds an interface to list of known interfaces.
Definition iface_mgr.cc:775
isc::dhcp::IfaceMgr::setMatchingPacketFilter
void setMatchingPacketFilter(const bool direct_response_desired=false)
Set Packet Filter object to handle send/receive packets.
isc::dhcp::Iface
Represents a single network interface.
Definition iface_mgr.h:118
isc::dhcp::Iface::flags_
uint64_t flags_
Interface flags (this value is as is returned by OS, it may mean different things on different OSes).
Definition iface_mgr.h:460
isc::dhcp::Iface::flag_multicast_
bool flag_multicast_
Flag specifies if selected interface is multicast capable.
Definition iface_mgr.h:451
isc::dhcp::Iface::getName
std::string getName() const
Returns interface name.
Definition iface_mgr.h:224
isc::dhcp::Iface::setFlags
void setFlags(uint64_t flags)
Sets flag_*_ fields based on bitmask value returned by OS.
isc::dhcp::Iface::flag_running_
bool flag_running_
Flag specifies if selected interface is running (e.g.
Definition iface_mgr.h:448
isc::dhcp::Iface::flag_loopback_
bool flag_loopback_
Specifies if selected interface is loopback.
Definition iface_mgr.h:441
isc::dhcp::Iface::addSocket
void addSocket(const SocketInfo &sock)
Adds socket descriptor to an interface.
Definition iface_mgr.h:321
isc::dhcp::Iface::flag_up_
bool flag_up_
Specifies if selected interface is up.
Definition iface_mgr.h:444
isc::dhcp::Iface::flag_broadcast_
bool flag_broadcast_
Flag specifies if selected interface is broadcast capable.
Definition iface_mgr.h:454
exceptions.h
isc_throw
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Definition exceptions/exceptions.h:210
iface_mgr.h
iface_mgr_error_handler.h
IFACEMGR_ERROR
#define IFACEMGR_ERROR(ex_type, handler, iface, stream)
A macro which handles an error in IfaceMgr.
Definition iface_mgr_error_handler.h:34
isc::asiolink
Definition addr_utilities.cc:170
isc::db::info
@ info
Definition db_log.h:120
isc::dhcp
Definition dhcp4/client_handler.cc:20
isc::dhcp::PktFilterPtr
boost::shared_ptr< PktFilter > PktFilterPtr
Pointer to a PktFilter object.
Definition pkt_filter.h:144
isc::dhcp::IfacePtr
boost::shared_ptr< Iface > IfacePtr
Type definition for the pointer to an Iface object.
Definition iface_mgr.h:487
isc::dhcp::IfaceMgrErrorMsgCallback
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
isc
Defines the logger used by the top-level component of kea-lfc.
Definition agent_parser.cc:148
pkt_filter_bpf.h
pkt_filter_inet.h