Browse Source

show ifname, hwaddr & broadcast addr per link

- ifname: lo
  hwaddr: 00:00:00:00:00:00
  broadcast: 00:00:00:00:00:00
- ifname: eth0
  hwaddr: 11:22:33:44:55:66
  broadcast: ff:ff:ff:ff:ff:ff
- ifname: wlan0
  hwaddr: 77:88:99:00:aa:bb
  broadcast: ff:ff:ff:ff:ff:ff
Fabian Peter Hammerle 7 years ago
commit
dc63b72611
3 changed files with 163 additions and 0 deletions
  1. 2 0
      Makefile
  2. 26 0
      README.md
  3. 135 0
      main.cpp

+ 2 - 0
Makefile

@@ -0,0 +1,2 @@
+ipyml : main.cpp
+	g++ -std=c++11 $^ -lmnl -o $@

+ 26 - 0
README.md

@@ -0,0 +1,26 @@
+# ipyml
+
+Show network device configuration in YAML format.
+
+## Build Dependencies
+
+```sh
+apt install libmnl-dev linux-libc-dev g++
+```
+
+## Example
+
+```yaml
+$ ipyml
+
+- ifname: lo
+  hwaddr: 00:00:00:00:00:00
+  broadcast: 00:00:00:00:00:00
+- ifname: eth0
+  hwaddr: 11:22:33:44:55:66
+  broadcast: ff:ff:ff:ff:ff:ff
+- ifname: wlan0
+  hwaddr: 77:88:99:00:aa:bb
+  broadcast: ff:ff:ff:ff:ff:ff
+
+```

+ 135 - 0
main.cpp

@@ -0,0 +1,135 @@
+#include <assert.h>
+#include <cstring>
+#include <iomanip>
+#include <iostream>
+#include <libmnl/libmnl.h>
+#include <linux/if.h>
+#include <linux/rtnetlink.h>
+#include <sstream>
+#include <string>
+#include <vector>
+
+// 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 T> class vector : public std::vector<T>, 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<Link> *links = (vector<Link> *)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<Link> 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;
+}