Convert IPv4-mapped IPv6 ClientIP back to IPv4
Current HTTP server creates an IPv6 acceptor to accept both IPv4 and
IPv6 connections. In this way, IPv4 address will be presented as IPv6
address in IPv4-mapped format. This patch converts it back to IPv4.
Tested:
Verified the ClientOriginIP in Session is shown in native IPv4 format
instead of IPv4-mapped IPv6 format.
Change-Id: Icd51260b2d4572d52f5c670128b7f07f6b5e6912
Signed-off-by: Jiaqing Zhao <jiaqing.zhao@intel.com>
diff --git a/http/http_connection.hpp b/http/http_connection.hpp
index 2e9ff38..ccc2f28 100644
--- a/http/http_connection.hpp
+++ b/http/http_connection.hpp
@@ -266,8 +266,7 @@
sessionIsFromTransport = true;
userSession = persistent_data::SessionStore::getInstance()
.generateUserSession(
- sslUser, req->ipAddress.to_string(),
- unsupportedClientId,
+ sslUser, req->ipAddress, unsupportedClientId,
persistent_data::PersistenceType::TIMEOUT);
if (userSession != nullptr)
{
diff --git a/include/authorization.hpp b/include/authorization.hpp
index 202628c..27d7b32 100644
--- a/include/authorization.hpp
+++ b/include/authorization.hpp
@@ -87,7 +87,7 @@
// calling directly into pam for every request
std::string unsupportedClientId = "";
return persistent_data::SessionStore::getInstance().generateUserSession(
- user, clientIp.to_string(), unsupportedClientId,
+ user, clientIp, unsupportedClientId,
persistent_data::PersistenceType::SINGLE_REQUEST, isConfigureSelfOnly);
}
#endif
diff --git a/include/login_routes.hpp b/include/login_routes.hpp
index 42eebfe..8810356 100644
--- a/include/login_routes.hpp
+++ b/include/login_routes.hpp
@@ -143,8 +143,7 @@
auto session =
persistent_data::SessionStore::getInstance()
.generateUserSession(
- username, req.ipAddress.to_string(),
- unsupportedClientId,
+ username, req.ipAddress, unsupportedClientId,
persistent_data::PersistenceType::TIMEOUT,
isConfigureSelfOnly);
diff --git a/include/sessions.hpp b/include/sessions.hpp
index 13a335a..a05e47b 100644
--- a/include/sessions.hpp
+++ b/include/sessions.hpp
@@ -15,6 +15,7 @@
#include <pam_authenticate.hpp>
#include <random.hpp>
#include <sdbusplus/bus/match.hpp>
+#include <utils/ip_utils.hpp>
#include <csignal>
#include <random>
@@ -211,7 +212,8 @@
{
public:
std::shared_ptr<UserSession> generateUserSession(
- const std::string_view username, const std::string_view clientIp,
+ const std::string_view username,
+ const boost::asio::ip::address& clientIp,
const std::string_view clientId,
PersistenceType persistence = PersistenceType::TIMEOUT,
bool isConfigureSelfOnly = false)
@@ -261,11 +263,12 @@
return nullptr;
}
}
- auto session = std::make_shared<UserSession>(
- UserSession{uniqueId, sessionToken, std::string(username),
- csrfToken, std::string(clientId), std::string(clientIp),
- std::chrono::steady_clock::now(), persistence, false,
- isConfigureSelfOnly});
+
+ auto session = std::make_shared<UserSession>(UserSession{
+ uniqueId, sessionToken, std::string(username), csrfToken,
+ std::string(clientId), redfish::ip_util::toString(clientIp),
+ std::chrono::steady_clock::now(), persistence, false,
+ isConfigureSelfOnly});
auto it = authTokens.emplace(std::make_pair(sessionToken, session));
// Only need to write to disk if session isn't about to be destroyed.
needWrite = persistence == PersistenceType::TIMEOUT;
diff --git a/meson.build b/meson.build
index ff07103..a6c8caf 100644
--- a/meson.build
+++ b/meson.build
@@ -392,6 +392,7 @@
'redfish-core/ut/time_utils_test.cpp',
'redfish-core/ut/stl_utils_test.cpp',
'redfish-core/ut/hex_utils_test.cpp',
+ 'redfish-core/ut/ip_utils_test.cpp',
'http/ut/utility_test.cpp'
]
diff --git a/redfish-core/include/utils/ip_utils.hpp b/redfish-core/include/utils/ip_utils.hpp
new file mode 100644
index 0000000..ff65eb6
--- /dev/null
+++ b/redfish-core/include/utils/ip_utils.hpp
@@ -0,0 +1,32 @@
+#pragma once
+
+#include <boost/asio/ip/address.hpp>
+
+#include <string>
+
+namespace redfish
+{
+namespace ip_util
+{
+
+/**
+ * @brief Converts boost::asio::ip::address to string
+ * Will automatically convert IPv4-mapped IPv6 address back to IPv4.
+ *
+ * @param[in] ipAddr IP address to convert
+ *
+ * @return IP address string
+ */
+inline std::string toString(const boost::asio::ip::address& ipAddr)
+{
+ if (ipAddr.is_v6() && ipAddr.to_v6().is_v4_mapped())
+ {
+ return boost::asio::ip::make_address_v4(boost::asio::ip::v4_mapped,
+ ipAddr.to_v6())
+ .to_string();
+ }
+ return ipAddr.to_string();
+}
+
+} // namespace ip_util
+} // namespace redfish
diff --git a/redfish-core/lib/redfish_sessions.hpp b/redfish-core/lib/redfish_sessions.hpp
index 929e0c8..234a524 100644
--- a/redfish-core/lib/redfish_sessions.hpp
+++ b/redfish-core/lib/redfish_sessions.hpp
@@ -201,7 +201,7 @@
std::shared_ptr<persistent_data::UserSession> session =
persistent_data::SessionStore::getInstance()
.generateUserSession(
- username, req.ipAddress.to_string(), clientId,
+ username, req.ipAddress, clientId,
persistent_data::PersistenceType::TIMEOUT,
isConfigureSelfOnly);
asyncResp->res.addHeader("X-Auth-Token", session->sessionToken);
diff --git a/redfish-core/ut/ip_utils_test.cpp b/redfish-core/ut/ip_utils_test.cpp
new file mode 100644
index 0000000..455433b
--- /dev/null
+++ b/redfish-core/ut/ip_utils_test.cpp
@@ -0,0 +1,20 @@
+#include "utils/ip_utils.hpp"
+
+#include "gtest/gtest.h"
+
+using boost::asio::ip::make_address;
+using redfish::ip_util::toString;
+
+TEST(IpToString, v4mapped)
+{
+ EXPECT_EQ(toString(make_address("127.0.0.1")), "127.0.0.1");
+ EXPECT_EQ(toString(make_address("192.168.1.1")), "192.168.1.1");
+ EXPECT_EQ(toString(make_address("::1")), "::1");
+ EXPECT_EQ(toString(make_address("fd03:f9ab:25de:89ec::0001")),
+ "fd03:f9ab:25de:89ec::1");
+ EXPECT_EQ(toString(make_address("fd03:f9ab:25de:89ec::1234:abcd")),
+ "fd03:f9ab:25de:89ec::1234:abcd");
+ EXPECT_EQ(toString(make_address("fd03:f9ab:25de:89ec:1234:5678:90ab:cdef")),
+ "fd03:f9ab:25de:89ec:1234:5678:90ab:cdef");
+ EXPECT_EQ(toString(make_address("::ffff:127.0.0.1")), "127.0.0.1");
+}