xref: /openbmc/bmcweb/include/async_resolve.hpp (revision 08bbe119)
1 #pragma once
2 #ifdef BMCWEB_DBUS_DNS_RESOLVER
3 #include "dbus_singleton.hpp"
4 #include "logging.hpp"
5 
6 #include <boost/asio/ip/address.hpp>
7 #include <boost/asio/ip/basic_endpoint.hpp>
8 #include <boost/asio/ip/tcp.hpp>
9 #include <sdbusplus/message.hpp>
10 
11 #include <charconv>
12 #include <iostream>
13 #include <memory>
14 
15 namespace crow
16 {
17 
18 namespace async_resolve
19 {
20 
21 class Resolver
22 {
23   public:
24     // unused io param used to keep interface identical to
25     // boost::asio::tcp:::resolver
26     explicit Resolver(boost::asio::io_context& /*io*/) {}
27 
28     ~Resolver() = default;
29 
30     Resolver(const Resolver&) = delete;
31     Resolver(Resolver&&) = delete;
32     Resolver& operator=(const Resolver&) = delete;
33     Resolver& operator=(Resolver&&) = delete;
34 
35     using results_type = std::vector<boost::asio::ip::tcp::endpoint>;
36 
37     template <typename ResolveHandler>
38     // This function is kept using snake case so that it is interoperable with
39     // boost::asio::ip::tcp::resolver
40     // NOLINTNEXTLINE(readability-identifier-naming)
41     void async_resolve(const std::string& host, std::string_view port,
42                        ResolveHandler&& handler)
43     {
44         BMCWEB_LOG_DEBUG << "Trying to resolve: " << host << ":" << port;
45 
46         uint16_t portNum = 0;
47 
48         auto it = std::from_chars(&*port.begin(), &*port.end(), portNum);
49         if (it.ec != std::errc())
50         {
51             BMCWEB_LOG_ERROR << "Failed to get the Port";
52             handler(std::make_error_code(std::errc::invalid_argument),
53                     results_type{});
54 
55             return;
56         }
57 
58         uint64_t flag = 0;
59         crow::connections::systemBus->async_method_call(
60             [host, portNum, handler{std::forward<ResolveHandler>(handler)}](
61                 const boost::system::error_code& ec,
62                 const std::vector<
63                     std::tuple<int32_t, int32_t, std::vector<uint8_t>>>& resp,
64                 const std::string& hostName, const uint64_t flagNum) {
65             results_type endpointList;
66             if (ec)
67             {
68                 BMCWEB_LOG_ERROR << "Resolve failed: " << ec.message();
69                 handler(ec, endpointList);
70                 return;
71             }
72             BMCWEB_LOG_DEBUG << "ResolveHostname returned: " << hostName << ":"
73                              << flagNum;
74             // Extract the IP address from the response
75             for (const std::tuple<int32_t, int32_t, std::vector<uint8_t>>&
76                      resolveList : resp)
77             {
78                 const std::vector<uint8_t>& ipAddress =
79                     std::get<2>(resolveList);
80                 boost::asio::ip::tcp::endpoint endpoint;
81                 if (ipAddress.size() == 4) // ipv4 address
82                 {
83                     BMCWEB_LOG_DEBUG << "ipv4 address";
84                     boost::asio::ip::address_v4 ipv4Addr(
85                         {ipAddress[0], ipAddress[1], ipAddress[2],
86                          ipAddress[3]});
87                     endpoint.address(ipv4Addr);
88                 }
89                 else if (ipAddress.size() == 16) // ipv6 address
90                 {
91                     BMCWEB_LOG_DEBUG << "ipv6 address";
92                     boost::asio::ip::address_v6 ipv6Addr(
93                         {ipAddress[0], ipAddress[1], ipAddress[2], ipAddress[3],
94                          ipAddress[4], ipAddress[5], ipAddress[6], ipAddress[7],
95                          ipAddress[8], ipAddress[9], ipAddress[10],
96                          ipAddress[11], ipAddress[12], ipAddress[13],
97                          ipAddress[14], ipAddress[15]});
98                     endpoint.address(ipv6Addr);
99                 }
100                 else
101                 {
102                     BMCWEB_LOG_ERROR
103                         << "Resolve failed to fetch the IP address";
104                     handler(ec, endpointList);
105                     return;
106                 }
107                 endpoint.port(portNum);
108                 BMCWEB_LOG_DEBUG << "resolved endpoint is : " << endpoint;
109                 endpointList.push_back(endpoint);
110             }
111             // All the resolved data is filled in the endpointList
112             handler(ec, endpointList);
113             },
114             "org.freedesktop.resolve1", "/org/freedesktop/resolve1",
115             "org.freedesktop.resolve1.Manager", "ResolveHostname", 0, host,
116             AF_UNSPEC, flag);
117     }
118 };
119 
120 } // namespace async_resolve
121 } // namespace crow
122 #endif
123