#include #include #include #include #include #include #include #include #include #include // https://netfilter.org/projects/libmnl/doxygen/html/modules.html typedef size_t yaml_indent_level_t; class YamlObject { virtual void write_yaml(std::ostream &stream, const yaml_indent_level_t indent_level = 0) const = 0; }; struct HardwareAddress : public YamlObject { uint8_t bytes[IFHWADDRLEN]; HardwareAddress &operator=(const nlattr *attr) { assert(mnl_attr_get_payload_len(attr) == IFHWADDRLEN); memcpy(this->bytes, mnl_attr_get_payload(attr), IFHWADDRLEN); return *this; } std::string format() const { std::stringstream ss; ss << std::hex << std::setfill('0'); for (int i = 0; i < IFHWADDRLEN; i++) { if (i != 0) { ss << ':'; } ss << std::setw(2) << (int)bytes[i]; } return ss.str(); } void write_yaml(std::ostream &stream, const yaml_indent_level_t indent_level = 0) const { stream << format(); } }; struct Link : public YamlObject { std::string ifname; HardwareAddress hwaddr, broadcast; void write_yaml(std::ostream &stream, const yaml_indent_level_t indent_level = 0) const { const std::string indent(indent_level, ' '); stream << "ifname: " + ifname + "\n"; stream << indent + "hwaddr: "; hwaddr.write_yaml(stream); stream << "\n"; stream << indent + "broadcast: "; broadcast.write_yaml(stream); stream << "\n"; } }; template class vector : public std::vector, YamlObject { public: void write_yaml(std::ostream &stream, const yaml_indent_level_t indent_level = 0) const { if (this->empty()) { stream << "[]"; } else { const std::string indent(indent_level, ' '); stream << "\n"; for (auto it = this->begin(); it != this->end(); it++) { stream << indent << "- "; it->write_yaml(stream, indent_level + 2); } } } }; static int link_attr_cb(const nlattr *attr, void *data) { Link *link = (Link *)data; // /usr/include/linux/if_link.h switch (mnl_attr_get_type(attr)) { case IFLA_ADDRESS: link->hwaddr = attr; break; case IFLA_BROADCAST: link->broadcast = attr; break; case IFLA_IFNAME: link->ifname = mnl_attr_get_str(attr); break; } return MNL_CB_OK; } static int link_cb(const nlmsghdr *nlh, void *data) { vector *links = (vector *)data; links->emplace_back(); mnl_attr_parse(nlh, sizeof(ifinfomsg), link_attr_cb, &links->back()); return MNL_CB_OK; } int main(int argc, char *argv[]) { mnl_socket *nl = mnl_socket_open(NETLINK_ROUTE); assert(nl); assert(mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) == 0); unsigned int nlpid = mnl_socket_get_portid(nl); uint8_t msgbuf[MNL_SOCKET_BUFFER_SIZE]; nlmsghdr *nlh = mnl_nlmsg_put_header(msgbuf); nlh->nlmsg_type = RTM_GETLINK; nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; nlh->nlmsg_seq = 0; mnl_nlmsg_put_extra_header(nlh, sizeof(rtgenmsg)); assert(mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) > 0); vector links; size_t numbytes = mnl_socket_recvfrom(nl, msgbuf, sizeof(msgbuf)); while (numbytes > 0) { if (mnl_cb_run(msgbuf, numbytes, nlh->nlmsg_seq, nlpid, link_cb, &links) <= MNL_CB_STOP) { break; } else { numbytes = mnl_socket_recvfrom(nl, msgbuf, sizeof(msgbuf)); } } assert(numbytes != -1); links.write_yaml(std::cout); std::cout << std::endl; mnl_socket_close(nl); return EXIT_SUCCESS; }