26 #include "../network-address.hpp" 27 #include "../network-interface.hpp" 28 #include "../../util/logger.hpp" 29 #include "../../util/time.hpp" 31 #include <boost/asio/write.hpp> 35 #include <net/if_arp.h> 36 #include <sys/socket.h> 44 : m_socket(make_shared<
boost::asio::posix::stream_descriptor>(io))
46 , m_sequenceNo(static_cast<uint32_t>(
time::system_clock::now().time_since_epoch().count()))
47 , m_isEnumeratingLinks(false)
48 , m_isEnumeratingAddresses(false)
54 sendDumpRequest(RTM_GETLINK);
55 m_isEnumeratingLinks =
true;
60 boost::system::error_code error;
61 m_socket->close(error);
64 shared_ptr<const NetworkInterface>
67 for (
const auto& e : m_interfaces) {
68 if (e.second->getName() == ifname)
74 std::vector<shared_ptr<const NetworkInterface>>
77 std::vector<shared_ptr<const NetworkInterface>> v;
78 v.reserve(m_interfaces.size());
80 for (
const auto& e : m_interfaces) {
81 v.push_back(e.second);
87 NetworkMonitorImplRtnl::isEnumerating()
const 89 return m_isEnumeratingLinks || m_isEnumeratingAddresses;
93 NetworkMonitorImplRtnl::initSocket()
97 int fd = ::socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
99 BOOST_THROW_EXCEPTION(
Error(std::string(
"Cannot create netlink socket (") +
100 std::strerror(errno) +
")"));
102 m_socket->assign(fd);
105 addr.nl_family = AF_NETLINK;
106 addr.nl_groups = RTMGRP_LINK | RTMGRP_NOTIFY |
107 RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE |
108 RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE;
109 if (::bind(fd, reinterpret_cast<sockaddr*>(&addr),
sizeof(addr)) < 0) {
110 BOOST_THROW_EXCEPTION(
Error(std::string(
"Cannot bind netlink socket (") +
111 std::strerror(errno) +
")"));
115 socklen_t len =
sizeof(addr);
116 if (::getsockname(fd, reinterpret_cast<sockaddr*>(&addr), &len) < 0) {
117 BOOST_THROW_EXCEPTION(
Error(std::string(
"Cannot obtain netlink socket address (") +
118 std::strerror(errno) +
")"));
120 if (len !=
sizeof(addr)) {
121 BOOST_THROW_EXCEPTION(
Error(
"Wrong address length (" +
to_string(len) +
")"));
123 if (addr.nl_family != AF_NETLINK) {
124 BOOST_THROW_EXCEPTION(
Error(
"Wrong address family (" +
to_string(addr.nl_family) +
")"));
131 NetworkMonitorImplRtnl::sendDumpRequest(uint16_t nlmsgType)
133 auto request = make_shared<RtnlRequest>();
134 request->nlh.nlmsg_len =
sizeof(RtnlRequest);
135 request->nlh.nlmsg_type = nlmsgType;
136 request->nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
137 request->nlh.nlmsg_seq = ++m_sequenceNo;
138 request->nlh.nlmsg_pid = m_pid;
139 request->ifi.ifi_family = AF_UNSPEC;
140 request->rta.rta_type = IFLA_EXT_MASK;
141 request->rta.rta_len = RTA_LENGTH(
sizeof(request->rtext));
142 request->rtext = 1 << 3;
144 boost::asio::async_write(*m_socket, boost::asio::buffer(request.get(),
sizeof(RtnlRequest)),
146 [request] (
const boost::system::error_code& error, size_t) {
147 if (error && error != boost::asio::error::operation_aborted) {
149 BOOST_THROW_EXCEPTION(
Error(
"Failed to send netlink request (" + error.message() +
")"));
157 #define NLMSG_STRINGIFY(x) case NLMSG_##x: return "<" #x ">" 158 #define RTM_STRINGIFY(x) case RTM_##x: return "<" #x ">" 173 #undef NLMSG_STRINGIFY 183 case ARPHRD_LOOPBACK:
207 case RT_SCOPE_NOWHERE:
219 NetworkMonitorImplRtnl::asyncRead()
221 m_socket->async_read_some(boost::asio::buffer(m_buffer),
222 bind(&NetworkMonitorImplRtnl::handleRead,
this, _1, _2, m_socket));
226 NetworkMonitorImplRtnl::handleRead(
const boost::system::error_code& error,
size_t nBytesRead,
227 const shared_ptr<boost::asio::posix::stream_descriptor>& socket)
229 if (!socket->is_open() ||
230 error == boost::asio::error::operation_aborted) {
237 BOOST_THROW_EXCEPTION(
Error(
"Netlink socket read failed (" + error.message() +
")"));
240 NDN_LOG_TRACE(
"read " << nBytesRead <<
" bytes from netlink socket");
242 const nlmsghdr* nlh =
reinterpret_cast<const nlmsghdr*
>(m_buffer.data());
243 if (!isEnumerating() || (nlh->nlmsg_seq == m_sequenceNo && nlh->nlmsg_pid == m_pid)) {
244 parseNetlinkMessage(nlh, nBytesRead);
254 NetworkMonitorImplRtnl::parseNetlinkMessage(
const nlmsghdr* nlh,
size_t len)
256 while (NLMSG_OK(nlh, len)) {
257 NDN_LOG_TRACE(
"parsing " << (nlh->nlmsg_flags & NLM_F_MULTI ?
"multi-part " :
"") <<
259 " len=" << nlh->nlmsg_len <<
260 " seq=" << nlh->nlmsg_seq <<
261 " pid=" << nlh->nlmsg_pid);
263 if (nlh->nlmsg_flags & NLM_F_DUMP_INTR) {
269 if (nlh->nlmsg_type == NLMSG_DONE)
272 switch (nlh->nlmsg_type) {
275 parseLinkMessage(nlh, reinterpret_cast<const ifinfomsg*>(NLMSG_DATA(nlh)));
276 if (!isEnumerating())
282 parseAddressMessage(nlh, reinterpret_cast<const ifaddrmsg*>(NLMSG_DATA(nlh)));
283 if (!isEnumerating())
289 parseRouteMessage(nlh, reinterpret_cast<const rtmsg*>(NLMSG_DATA(nlh)));
290 if (!isEnumerating())
295 const nlmsgerr* err =
reinterpret_cast<const nlmsgerr*
>(NLMSG_DATA(nlh));
296 if (nlh->nlmsg_len < NLMSG_LENGTH(
sizeof(nlmsgerr)))
298 else if (err->error == 0)
307 nlh = NLMSG_NEXT(nlh, len);
310 if (nlh->nlmsg_type == NLMSG_DONE && m_isEnumeratingLinks) {
312 m_isEnumeratingLinks =
false;
314 sendDumpRequest(RTM_GETADDR);
315 m_isEnumeratingAddresses =
true;
317 else if (nlh->nlmsg_type == NLMSG_DONE && m_isEnumeratingAddresses) {
319 m_isEnumeratingAddresses =
false;
327 NetworkMonitorImplRtnl::parseLinkMessage(
const nlmsghdr* nlh,
const ifinfomsg* ifi)
334 shared_ptr<NetworkInterface> interface;
335 auto it = m_interfaces.find(ifi->ifi_index);
336 if (it != m_interfaces.end()) {
337 interface = it->second;
338 BOOST_ASSERT(interface !=
nullptr);
339 BOOST_ASSERT(interface->getIndex() == ifi->ifi_index);
342 if (nlh->nlmsg_type == RTM_DELLINK) {
343 if (interface !=
nullptr) {
344 NDN_LOG_DEBUG(
"removing interface " << interface->getName());
345 m_interfaces.erase(it);
351 if (interface ==
nullptr) {
353 interface->setIndex(ifi->ifi_index);
356 interface->setFlags(ifi->ifi_flags);
358 const rtattr* rta =
reinterpret_cast<const rtattr*
>(IFLA_RTA(ifi));
359 size_t rtaTotalLen = IFLA_PAYLOAD(nlh);
360 uint8_t operState = linux_if::OPER_STATE_UNKNOWN;
362 while (RTA_OK(rta, rtaTotalLen)) {
363 size_t attrLen = RTA_PAYLOAD(rta);
365 switch (rta->rta_type) {
368 ethernet::Address addr(reinterpret_cast<const uint8_t*>(RTA_DATA(rta)));
369 interface->setEthernetAddress(addr);
375 ethernet::Address addr(reinterpret_cast<const uint8_t*>(RTA_DATA(rta)));
376 interface->setEthernetBroadcastAddress(addr);
381 auto attrData =
reinterpret_cast<const char*
>(RTA_DATA(rta));
382 if (::strnlen(attrData, attrLen) <= attrLen)
383 interface->setName(attrData);
388 if (attrLen ==
sizeof(uint32_t))
389 interface->setMtu(*(reinterpret_cast<const uint32_t*>(RTA_DATA(rta))));
393 if (attrLen ==
sizeof(uint8_t))
394 operState = *(
reinterpret_cast<const uint8_t*
>RTA_DATA(rta));
398 rta = RTA_NEXT(rta, rtaTotalLen);
401 updateInterfaceState(*interface, operState);
403 if (it == m_interfaces.end()) {
405 m_interfaces[interface->getIndex()] = interface;
411 NetworkMonitorImplRtnl::parseAddressMessage(
const nlmsghdr* nlh,
const ifaddrmsg* ifa)
413 auto it = m_interfaces.find(ifa->ifa_index);
414 if (it == m_interfaces.end()) {
419 auto interface = it->second;
420 BOOST_ASSERT(interface !=
nullptr);
422 namespace ip = boost::asio::ip;
423 ip::address ipAddr, broadcastAddr;
424 uint32_t flags = ifa->ifa_flags;
426 const rtattr* rta =
reinterpret_cast<const rtattr*
>(IFA_RTA(ifa));
427 size_t rtaTotalLen = IFA_PAYLOAD(nlh);
429 while (RTA_OK(rta, rtaTotalLen)) {
430 auto attrData =
reinterpret_cast<const unsigned char*
>(RTA_DATA(rta));
431 size_t attrLen = RTA_PAYLOAD(rta);
433 switch (rta->rta_type) {
435 if (ifa->ifa_family == AF_INET && attrLen ==
sizeof(ip::address_v4::bytes_type)) {
436 ip::address_v4::bytes_type bytes;
437 std::copy_n(attrData, bytes.size(), bytes.begin());
438 ipAddr = ip::address_v4(bytes);
443 if (ifa->ifa_family == AF_INET6 && attrLen ==
sizeof(ip::address_v6::bytes_type)) {
444 ip::address_v6::bytes_type bytes;
445 std::copy_n(attrData, bytes.size(), bytes.begin());
446 ip::address_v6 v6Addr(bytes);
447 if (v6Addr.is_link_local())
448 v6Addr.scope_id(ifa->ifa_index);
454 if (ifa->ifa_family == AF_INET && attrLen ==
sizeof(ip::address_v4::bytes_type)) {
455 ip::address_v4::bytes_type bytes;
456 std::copy_n(attrData, bytes.size(), bytes.begin());
457 broadcastAddr = ip::address_v4(bytes);
461 #ifdef NDN_CXX_HAVE_IFA_FLAGS 463 if (attrLen ==
sizeof(uint32_t))
464 flags = *(
reinterpret_cast<const uint32_t*
>(attrData));
466 #endif // NDN_CXX_HAVE_IFA_FLAGS 469 rta = RTA_NEXT(rta, rtaTotalLen);
480 if (nlh->nlmsg_type == RTM_NEWADDR)
481 interface->addNetworkAddress(address);
482 else if (nlh->nlmsg_type == RTM_DELADDR)
483 interface->removeNetworkAddress(address);
487 NetworkMonitorImplRtnl::parseRouteMessage(
const nlmsghdr* nlh,
const rtmsg* rtm)
493 NetworkMonitorImplRtnl::updateInterfaceState(NetworkInterface& interface, uint8_t operState)
495 if (operState == linux_if::OPER_STATE_UP) {
498 else if (operState == linux_if::OPER_STATE_DORMANT) {
503 auto flags = interface.getFlags();
504 if ((flags & linux_if::FLAG_LOWER_UP) && !(flags & linux_if::FLAG_DORMANT))
506 else if (flags & IFF_UP)
interface is administratively down
static AddressScope ifaScopeToAddressScope(uint8_t scope)
Copyright (c) 2011-2015 Regents of the University of California.
interface can be used to send and receive packets
interface is administratively up but has no carrier
static shared_ptr< NetworkInterface > makeNetworkInterface()
const size_t ADDR_LEN
Octets in one Ethernet address.
static const char * nlmsgTypeToString(uint16_t type)
static AddressFamily ifaFamilyToAddressFamily(uint8_t family)
#define NLMSG_STRINGIFY(x)
#define emitSignal(...)
(implementation detail)
InterfaceType
Indicates the hardware type of a network interface.
constexpr duration< Rep, Period > abs(duration< Rep, Period > d)
static InterfaceType ifiTypeToInterfaceType(uint16_t type)
shared_ptr< const NetworkInterface > getNetworkInterface(const std::string &ifname) const final
util::Signal< NetworkMonitorImpl > onEnumerationCompleted
#define NDN_LOG_INIT(name)
declare a log module
#define NDN_LOG_DEBUG(expression)
util::Signal< NetworkMonitorImpl, shared_ptr< const NetworkInterface > > onInterfaceRemoved
NetworkMonitorImplRtnl(boost::asio::io_service &io)
initialize netlink socket and start enumerating interfaces
util::Signal< NetworkMonitorImpl, shared_ptr< const NetworkInterface > > onInterfaceAdded
interface has a carrier but it cannot send or receive normal user traffic yet
NetworkMonitor::Error Error
~NetworkMonitorImplRtnl()
#define NDN_LOG_ERROR(expression)
std::string to_string(const V &v)
util::Signal< NetworkMonitorImpl > onNetworkStateChanged
#define NDN_LOG_TRACE(expression)
std::vector< shared_ptr< const NetworkInterface > > listNetworkInterfaces() const final