util: Add InAddrAny population function

We commonly want to be able to turn netlink network order address data
into the corresponding InAddrAny when parsing netlink data. This makes
it trivial given the address family and data buffer.

Tested:
    Ran throgh unit tests and builds fine in a BMC image.

Change-Id: I4ebe1dbd284f150ea03ee091cddda5a06806c01f
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/test/test_util.cpp b/test/test_util.cpp
index 25953a1..0e58081 100644
--- a/test/test_util.cpp
+++ b/test/test_util.cpp
@@ -45,6 +45,30 @@
     EXPECT_EQ("70:FF:84:09:35:09", mac_address::toString(mac2));
 }
 
+TEST_F(TestUtil, AddrFromBuf)
+{
+    std::string tooSmall(1, 'a');
+    std::string tooLarge(24, 'a');
+
+    struct in_addr ip1;
+    EXPECT_EQ(1, inet_pton(AF_INET, "192.168.10.1", &ip1));
+    std::string_view buf1(reinterpret_cast<char*>(&ip1), sizeof(ip1));
+    InAddrAny res1 = addrFromBuf(AF_INET, buf1);
+    EXPECT_EQ(0, memcmp(&ip1, &std::get<struct in_addr>(res1), sizeof(ip1)));
+    EXPECT_THROW(addrFromBuf(AF_INET, tooSmall), std::runtime_error);
+    EXPECT_THROW(addrFromBuf(AF_INET, tooLarge), std::runtime_error);
+    EXPECT_THROW(addrFromBuf(AF_UNSPEC, buf1), std::runtime_error);
+
+    struct in6_addr ip2;
+    EXPECT_EQ(1, inet_pton(AF_INET6, "fdd8:b5ad:9d93:94ee::2:1", &ip2));
+    std::string_view buf2(reinterpret_cast<char*>(&ip2), sizeof(ip2));
+    InAddrAny res2 = addrFromBuf(AF_INET6, buf2);
+    EXPECT_EQ(0, memcmp(&ip2, &std::get<struct in6_addr>(res2), sizeof(ip2)));
+    EXPECT_THROW(addrFromBuf(AF_INET6, tooSmall), std::runtime_error);
+    EXPECT_THROW(addrFromBuf(AF_INET6, tooLarge), std::runtime_error);
+    EXPECT_THROW(addrFromBuf(AF_UNSPEC, buf2), std::runtime_error);
+}
+
 TEST_F(TestUtil, IpToString)
 {
     struct in_addr ip1;
diff --git a/util.cpp b/util.cpp
index db164e6..b1300fb 100644
--- a/util.cpp
+++ b/util.cpp
@@ -204,6 +204,32 @@
     return networkString;
 }
 
+InAddrAny addrFromBuf(int addressFamily, std::string_view buf)
+{
+    if (addressFamily == AF_INET)
+    {
+        struct in_addr ret;
+        if (buf.size() != sizeof(ret))
+        {
+            throw std::runtime_error("Buf not in_addr sized");
+        }
+        memcpy(&ret, buf.data(), sizeof(ret));
+        return ret;
+    }
+    else if (addressFamily == AF_INET6)
+    {
+        struct in6_addr ret;
+        if (buf.size() != sizeof(ret))
+        {
+            throw std::runtime_error("Buf not in6_addr sized");
+        }
+        memcpy(&ret, buf.data(), sizeof(ret));
+        return ret;
+    }
+
+    throw std::runtime_error("Unsupported address family");
+}
+
 std::string toString(const InAddrAny& addr)
 {
     std::string ip;
diff --git a/util.hpp b/util.hpp
index 537c6a0..a07fa49 100644
--- a/util.hpp
+++ b/util.hpp
@@ -9,6 +9,7 @@
 #include <regex>
 #include <sdbusplus/bus.hpp>
 #include <string>
+#include <string_view>
 
 namespace phosphor
 {
@@ -93,6 +94,13 @@
  */
 uint8_t toCidr(int addressFamily, const std::string& mask);
 
+/* @brief converts a sockaddr for the specified address family into
+ *        a type_safe InAddrAny.
+ * @param[in] addressFamily - The address family of the buf
+ * @param[in] buf - The network byte order address
+ */
+InAddrAny addrFromBuf(int addressFamily, std::string_view buf);
+
 /* @brief converts the ip bytes into a string representation
  * @param[in] addr - input ip address to convert.
  * @returns String representation of the ip.