Browse Source

show ipv6 addresses

Fabian Peter Hammerle 7 years ago
parent
commit
d76d635f2b
5 changed files with 97 additions and 17 deletions
  1. 2 0
      README.md
  2. 30 7
      address.h
  3. 45 0
      inet6_address.h
  4. 17 9
      inet_address.h
  5. 3 1
      main.cpp

+ 2 - 0
README.md

@@ -32,6 +32,8 @@ addresses:
 - 127.0.0.1
 - 192.168.2.101
 - 192.168.20.11
+- fe80::1322:33ff:fe44:5566
+- fe80::7588:99ff:fe00:aabb
 
 ```
 

+ 30 - 7
address.h

@@ -1,25 +1,44 @@
 #ifndef _IPYML_ADDRESS_H
 #define _IPYML_ADDRESS_H
 
+#include "inet6_address.h"
 #include "inet_address.h"
 #include "yaml.h"
 
-#include <libmnl/libmnl.h>
-#include <linux/if_addr.h>
-#include <linux/netlink.h>
-#include <ostream>
+#include <bits/socket.h>   // AF_*
+#include <libmnl/libmnl.h> // mnl_attr_get_type
+#include <linux/if_addr.h> // struct ifaddrmsg
+#include <linux/netlink.h> // struct nlattr
+#include <ostream>         // std::ostream
 
 class Address : public YamlObject {
-  InetAddress inet_addr;
+  unsigned char family;
+  union {
+    InetAddress inet_addr;
+    Inet6Address inet6_addr;
+  };
 
 public:
+  Address() : family(AF_UNSPEC) {}
+
+  Address &operator=(const ifaddrmsg *msg) {
+    family = msg->ifa_family;
+    assert(family == AF_INET || family == AF_INET6);
+    return *this;
+  }
+
   // typedef int (*mnl_attr_cb_t)(const struct nlattr *attr, void *data);
   static int mnl_attr_cb(const nlattr *attr, void *data) {
     Address *addr = (Address *)data;
+    assert(addr->family != AF_UNSPEC);
     // /usr/include/linux/if_addr.h
     switch (mnl_attr_get_type(attr)) {
     case IFA_ADDRESS:
-      addr->inet_addr = attr;
+      if (addr->family == AF_INET) {
+        addr->inet_addr = attr;
+      } else if (addr->family == AF_INET6) {
+        addr->inet6_addr = attr;
+      }
       break;
     }
   }
@@ -27,7 +46,11 @@ public:
   void write_yaml(std::ostream &stream,
                   const yaml_indent_level_t indent_level = 0) const {
     // const std::string indent(indent_level, ' ');
-    inet_addr.write_yaml(stream, indent_level + 2);
+    if (family == AF_INET) {
+      inet_addr.write_yaml(stream, indent_level + 2);
+    } else if (family == AF_INET6) {
+      inet6_addr.write_yaml(stream, indent_level + 2);
+    }
   }
 };
 

+ 45 - 0
inet6_address.h

@@ -0,0 +1,45 @@
+#ifndef _IPYML_INET6_ADDRESS_H
+#define _IPYML_INET6_ADDRESS_H
+
+#include "yaml.h"
+
+#include <arpa/inet.h>     // inet_ntop, socklen_t
+#include <bits/socket.h>   // AF_*, socklen_t
+#include <cassert>         // assert
+#include <cstring>         // memcpy
+#include <libmnl/libmnl.h> // mnl_attr_*
+#include <linux/in6.h>     // struct in6_addr
+#include <linux/netlink.h> // struct nlattr
+#include <netinet/in.h>    // INET6_ADDRSTRLEN
+#include <ostream>         // std::ostream
+
+/*
+class may not have any virtual member due to:
+> error: union member ‘Address::<anonymous union>::inet6_addr’
+> with non-trivial ‘constexpr Inet6Address::Inet6Address(Inet6Address&&)’
+*/
+
+class Inet6Address { // : public YamlObject {
+  unsigned char bytes[sizeof(in6_addr)];
+
+public:
+  Inet6Address &operator=(const nlattr *attr) {
+    assert(mnl_attr_validate(attr, MNL_TYPE_BINARY) == 0);
+    assert(mnl_attr_get_payload_len(attr) == sizeof(bytes));
+    memcpy(this->bytes, mnl_attr_get_payload(attr), sizeof(bytes));
+    return *this;
+  }
+
+  void format(char *dst, socklen_t size) const {
+    inet_ntop(AF_INET6, bytes, dst, size);
+  }
+
+  void write_yaml(std::ostream &stream,
+                  const yaml_indent_level_t indent_level = 0) const {
+    char str[INET6_ADDRSTRLEN];
+    format(str, sizeof(str));
+    stream << str << '\n';
+  }
+};
+
+#endif

+ 17 - 9
inet_address.h

@@ -3,15 +3,23 @@
 
 #include "yaml.h"
 
-#include <arpa/inet.h>
-#include <cassert>
-#include <cstring>
-#include <libmnl/libmnl.h>
-#include <linux/netlink.h>
-#include <netinet/in.h>
-#include <ostream>
-
-class InetAddress : public YamlObject {
+#include <arpa/inet.h>     // inet_ntop, socklen_t
+#include <bits/socket.h>   // AF_*, socklen_t
+#include <cassert>         // assert
+#include <cstring>         // memcpy
+#include <libmnl/libmnl.h> // mnl_attr_*
+#include <linux/in.h>      // struct in_addr_t
+#include <linux/netlink.h> // struct nlattr
+#include <netinet/in.h>    // INET_ADDRSTRLEN
+#include <ostream>         // std::ostream
+
+/*
+class may not have any virtual member due to:
+> error: union member ‘Address::<anonymous union>::inet_addr’
+> with non-trivial ‘constexpr InetAddress::InetAddress(InetAddress&&)’
+*/
+
+class InetAddress { // : public YamlObject {
   unsigned char bytes[sizeof(in_addr_t)];
 
 public:

+ 3 - 1
main.cpp

@@ -7,6 +7,7 @@
 #include <cstdlib>
 #include <iostream>
 #include <libmnl/libmnl.h>
+#include <linux/if_addr.h>
 #include <linux/netlink.h>
 #include <linux/rtnetlink.h>
 
@@ -45,6 +46,7 @@ void mnl_read_links(const mnl_socket *nl, vector<Link> *links) {
 static int address_cb(const struct nlmsghdr *nlh, void *data) {
   vector<Address> *addrs = (vector<Address> *)data;
   addrs->emplace_back();
+  addrs->back() = (const ifaddrmsg *)mnl_nlmsg_get_payload(nlh);
   mnl_attr_parse(nlh, sizeof(ifaddrmsg), Address::mnl_attr_cb, &addrs->back());
   return MNL_CB_OK;
 }
@@ -55,7 +57,7 @@ void mnl_read_addresses(const mnl_socket *nl, vector<Address> *addrs) {
   nlh->nlmsg_type = RTM_GETADDR;
   nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
   rtgenmsg *rt = (rtgenmsg *)mnl_nlmsg_put_extra_header(nlh, sizeof(rtgenmsg));
-  rt->rtgen_family = AF_INET;
+  rt->rtgen_family = AF_UNSPEC;
   assert(mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) > 0);
   mnl_recv_run_cb_all(nl, msgbuf, sizeof(msgbuf), address_cb, addrs);
 }