Validate the client address

Address could be hostname or IPaddress,Address validation
is being done by calling the gethostbyname system function.

Change-Id: I7d7eecd164c471c80af0b440a4b541badd2f966f
Signed-off-by: Ratan Gupta <ratagupt@in.ibm.com>
diff --git a/Makefile.am b/Makefile.am
index 68c7ab7..015a558 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -16,6 +16,7 @@
 		snmp_main.cpp \
 		snmp_conf_manager.cpp \
 		snmp_client.cpp \
+		snmp_util.cpp \
 		xyz/openbmc_project/Network/Client/Create/server.cpp
 
 CLEANFILES = \
diff --git a/snmp_conf_manager.cpp b/snmp_conf_manager.cpp
index 30d0815..3c7eaa6 100644
--- a/snmp_conf_manager.cpp
+++ b/snmp_conf_manager.cpp
@@ -1,9 +1,15 @@
 #include "config.h"
 #include "snmp_conf_manager.hpp"
+#include "snmp_util.hpp"
+#include "xyz/openbmc_project/Common/error.hpp"
+
+#include <phosphor-logging/elog-errors.hpp>
 #include <phosphor-logging/log.hpp>
 
 #include <experimental/filesystem>
 
+#include <arpa/inet.h>
+
 namespace phosphor
 {
 namespace network
@@ -12,6 +18,8 @@
 {
 
 using namespace phosphor::logging;
+using namespace sdbusplus::xyz::openbmc_project::Common::Error;
+using Argument = xyz::openbmc_project::Common::InvalidArgument;
 
 ConfManager::ConfManager(sdbusplus::bus::bus& bus, const char* objPath) :
     details::CreateIface(bus, objPath, true), bus(bus), objectPath(objPath)
@@ -21,16 +29,31 @@
 void ConfManager::client(std::string address, uint16_t port)
 {
     auto clientEntry = this->clients.find(address);
-    if (clientEntry == this->clients.end())
+    if (clientEntry != this->clients.end())
     {
-        std::experimental::filesystem::path objPath;
-        objPath /= objectPath;
-        objPath /= generateId(address, port);
-
-        this->clients.emplace(
-            address, std::make_unique<phosphor::network::snmp::Client>(
-                         bus, objPath.string().c_str(), *this, address, port));
+        // address is already there
+        return;
     }
+    try
+    {
+        // just to check whether given address is valid or not.
+        resolveAddress(address);
+    }
+    catch (InternalFailure& e)
+    {
+        log<level::ERR>("Not a valid address"),
+            entry("ADDRESS=%s", address.c_str());
+        elog<InvalidArgument>(Argument::ARGUMENT_NAME("Address"),
+                              Argument::ARGUMENT_VALUE(address.c_str()));
+    }
+    // create the D-Bus object
+    std::experimental::filesystem::path objPath;
+    objPath /= objectPath;
+    objPath /= generateId(address, port);
+
+    this->clients.emplace(
+        address, std::make_unique<phosphor::network::snmp::Client>(
+                     bus, objPath.string().c_str(), *this, address, port));
 }
 
 std::string ConfManager::generateId(const std::string& address, uint16_t port)
diff --git a/snmp_util.cpp b/snmp_util.cpp
index a8a1ff8..25342ea 100644
--- a/snmp_util.cpp
+++ b/snmp_util.cpp
@@ -1,6 +1,8 @@
 #include "snmp_util.hpp"
 #include "xyz/openbmc_project/Common/error.hpp"
 
+#include <arpa/inet.h>
+
 #include <phosphor-logging/elog-errors.hpp>
 #include <phosphor-logging/log.hpp>
 
diff --git a/test/Makefile.am.include b/test/Makefile.am.include
index 7926d09..f99ab24 100644
--- a/test/Makefile.am.include
+++ b/test/Makefile.am.include
@@ -29,10 +29,12 @@
 
 test_notification_SOURCES = \
 	%reldir%/test_error_notification.cpp \
-	%reldir%/test_snmp_conf_manager.cpp
+	%reldir%/test_snmp_conf_manager.cpp \
+	%reldir%/test_snmp_util.cpp
 
 test_notification_LDADD = $(top_builddir)/phosphor_network_snmpconf-snmp_conf_manager.o \
 	$(top_builddir)/phosphor_network_snmpconf-snmp_client.o \
+    $(top_builddir)/phosphor_network_snmpconf-snmp_util.o \
 	$(top_builddir)/xyz/openbmc_project/Network/Client/Create/phosphor_network_snmpconf-server.o
 
 check_PROGRAMS += %reldir%/notification
diff --git a/test/test_snmp_util.cpp b/test/test_snmp_util.cpp
new file mode 100644
index 0000000..e486b7a
--- /dev/null
+++ b/test/test_snmp_util.cpp
@@ -0,0 +1,71 @@
+#include <gtest/gtest.h>
+#include <netinet/in.h>
+#include "snmp_util.hpp"
+#include <xyz/openbmc_project/Common/error.hpp>
+
+namespace phosphor
+{
+namespace network
+{
+namespace snmp
+{
+
+using InternalFailure =
+    sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
+
+TEST(TestUtil, IpValidation)
+{
+    // valid IPv4 address
+    std::string ipaddress = "0.0.0.0";
+    EXPECT_EQ(ipaddress, resolveAddress(ipaddress));
+
+    ipaddress = "9.3.185.83";
+    EXPECT_EQ(ipaddress, resolveAddress(ipaddress));
+
+    // Invalid IPv4 address
+    ipaddress = "9.3.185.a";
+    EXPECT_THROW(resolveAddress(ipaddress), InternalFailure);
+
+    ipaddress = "9.3.a.83";
+    EXPECT_THROW(resolveAddress(ipaddress), InternalFailure);
+
+    ipaddress = "x.x.x.x";
+    EXPECT_THROW(resolveAddress(ipaddress), InternalFailure);
+
+    // valid IPv6 address
+    ipaddress = "0:0:0:0:0:0:0:0";
+    EXPECT_EQ("::", resolveAddress(ipaddress));
+
+    ipaddress = "1:0:0:0:0:0:0:8";
+    EXPECT_EQ("1::8", resolveAddress(ipaddress));
+
+    ipaddress = "1::8";
+    EXPECT_EQ(ipaddress, resolveAddress(ipaddress));
+
+    ipaddress = "0:0:0:0:0:FFFF:204.152.189.116";
+    EXPECT_EQ("::ffff:204.152.189.116", resolveAddress(ipaddress));
+
+    ipaddress = "::ffff:204.152.189.116";
+    EXPECT_EQ(ipaddress, resolveAddress(ipaddress));
+
+    ipaddress = "a:0:0:0:0:FFFF:204.152.189.116";
+    EXPECT_EQ("a::ffff:cc98:bd74", resolveAddress(ipaddress));
+
+    // Invalid IPv6 address
+    ipaddress = "abcd::xyz::";
+    EXPECT_THROW(resolveAddress(ipaddress), InternalFailure);
+
+    // resolve the local host
+    ipaddress = "localhost";
+    auto isLocal = false;
+    auto addr = resolveAddress(ipaddress);
+    if (addr == "127.0.0.1" || addr == "::1")
+    {
+        isLocal = true;
+    }
+    EXPECT_TRUE(isLocal);
+}
+
+} // namespae snmp
+} // namespce network
+} // namespace phosphor