main.cpp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. #include <assert.h>
  2. #include <cstring>
  3. #include <iomanip>
  4. #include <iostream>
  5. #include <libmnl/libmnl.h>
  6. #include <linux/if.h>
  7. #include <linux/rtnetlink.h>
  8. #include <sstream>
  9. #include <string>
  10. #include <vector>
  11. // https://netfilter.org/projects/libmnl/doxygen/html/modules.html
  12. typedef size_t yaml_indent_level_t;
  13. class YamlObject {
  14. virtual void write_yaml(std::ostream &stream,
  15. const yaml_indent_level_t indent_level = 0) const = 0;
  16. };
  17. struct HardwareAddress : public YamlObject {
  18. uint8_t bytes[IFHWADDRLEN];
  19. HardwareAddress &operator=(const nlattr *attr) {
  20. assert(mnl_attr_get_payload_len(attr) == IFHWADDRLEN);
  21. memcpy(this->bytes, mnl_attr_get_payload(attr), IFHWADDRLEN);
  22. return *this;
  23. }
  24. std::string format() const {
  25. std::stringstream ss;
  26. ss << std::hex << std::setfill('0');
  27. for (int i = 0; i < IFHWADDRLEN; i++) {
  28. if (i != 0) {
  29. ss << ':';
  30. }
  31. ss << std::setw(2) << (int)bytes[i];
  32. }
  33. return ss.str();
  34. }
  35. void write_yaml(std::ostream &stream,
  36. const yaml_indent_level_t indent_level = 0) const {
  37. stream << format();
  38. }
  39. };
  40. struct Link : public YamlObject {
  41. std::string ifname;
  42. HardwareAddress hwaddr, broadcast;
  43. void write_yaml(std::ostream &stream,
  44. const yaml_indent_level_t indent_level = 0) const {
  45. const std::string indent(indent_level, ' ');
  46. stream << "ifname: " + ifname + "\n";
  47. stream << indent + "hwaddr: ";
  48. hwaddr.write_yaml(stream);
  49. stream << "\n";
  50. stream << indent + "broadcast: ";
  51. broadcast.write_yaml(stream);
  52. stream << "\n";
  53. }
  54. };
  55. template <class T> class vector : public std::vector<T>, YamlObject {
  56. public:
  57. void write_yaml(std::ostream &stream,
  58. const yaml_indent_level_t indent_level = 0) const {
  59. if (this->empty()) {
  60. stream << "[]";
  61. } else {
  62. const std::string indent(indent_level, ' ');
  63. stream << "\n";
  64. for (auto it = this->begin(); it != this->end(); it++) {
  65. stream << indent << "- ";
  66. it->write_yaml(stream, indent_level + 2);
  67. }
  68. }
  69. }
  70. };
  71. static int link_attr_cb(const nlattr *attr, void *data) {
  72. Link *link = (Link *)data;
  73. // /usr/include/linux/if_link.h
  74. switch (mnl_attr_get_type(attr)) {
  75. case IFLA_ADDRESS:
  76. link->hwaddr = attr;
  77. break;
  78. case IFLA_BROADCAST:
  79. link->broadcast = attr;
  80. break;
  81. case IFLA_IFNAME:
  82. link->ifname = mnl_attr_get_str(attr);
  83. break;
  84. }
  85. return MNL_CB_OK;
  86. }
  87. static int link_cb(const nlmsghdr *nlh, void *data) {
  88. vector<Link> *links = (vector<Link> *)data;
  89. links->emplace_back();
  90. mnl_attr_parse(nlh, sizeof(ifinfomsg), link_attr_cb, &links->back());
  91. return MNL_CB_OK;
  92. }
  93. int main(int argc, char *argv[]) {
  94. mnl_socket *nl = mnl_socket_open(NETLINK_ROUTE);
  95. assert(nl);
  96. assert(mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) == 0);
  97. unsigned int nlpid = mnl_socket_get_portid(nl);
  98. uint8_t msgbuf[MNL_SOCKET_BUFFER_SIZE];
  99. nlmsghdr *nlh = mnl_nlmsg_put_header(msgbuf);
  100. nlh->nlmsg_type = RTM_GETLINK;
  101. nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
  102. nlh->nlmsg_seq = 0;
  103. mnl_nlmsg_put_extra_header(nlh, sizeof(rtgenmsg));
  104. assert(mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) > 0);
  105. vector<Link> links;
  106. size_t numbytes = mnl_socket_recvfrom(nl, msgbuf, sizeof(msgbuf));
  107. while (numbytes > 0) {
  108. if (mnl_cb_run(msgbuf, numbytes, nlh->nlmsg_seq, nlpid, link_cb, &links) <= MNL_CB_STOP) {
  109. break;
  110. } else {
  111. numbytes = mnl_socket_recvfrom(nl, msgbuf, sizeof(msgbuf));
  112. }
  113. }
  114. assert(numbytes != -1);
  115. links.write_yaml(std::cout);
  116. std::cout << std::endl;
  117. mnl_socket_close(nl);
  118. return EXIT_SUCCESS;
  119. }