1 #include "snmp_util.hpp"
2
3 #include "xyz/openbmc_project/Common/error.hpp"
4
5 #include <arpa/inet.h>
6 #include <netdb.h>
7
8 #include <phosphor-logging/elog-errors.hpp>
9 #include <phosphor-logging/lg2.hpp>
10
11 #include <string>
12
13 namespace phosphor
14 {
15
16 using namespace phosphor::logging;
17 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
18
getManagedObjects(sdbusplus::bus_t & bus,const std::string & service,const std::string & objPath)19 ObjectValueTree getManagedObjects(sdbusplus::bus_t& bus,
20 const std::string& service,
21 const std::string& objPath)
22 {
23 ObjectValueTree interfaces;
24
25 auto method = bus.new_method_call(service.c_str(), objPath.c_str(),
26 "org.freedesktop.DBus.ObjectManager",
27 "GetManagedObjects");
28
29 try
30 {
31 auto reply = bus.call(method);
32 reply.read(interfaces);
33 }
34 catch (const sdbusplus::exception_t& e)
35 {
36 lg2::error("Failed to get managed objects: {PATH}", "PATH", objPath);
37 elog<InternalFailure>();
38 }
39
40 return interfaces;
41 }
42
43 namespace network
44 {
45
resolveAddress(const std::string & address)46 std::string resolveAddress(const std::string& address)
47 {
48 addrinfo hints{};
49 addrinfo* addr = nullptr;
50
51 hints.ai_family = AF_UNSPEC;
52 hints.ai_socktype = SOCK_STREAM;
53 hints.ai_flags |= AI_CANONNAME;
54
55 auto result = getaddrinfo(address.c_str(), NULL, &hints, &addr);
56 if (result)
57 {
58 lg2::error("getaddrinfo failed {ADDRESS}: {RC}", "ADDRESS", address,
59 "RC", result);
60 elog<InternalFailure>();
61 }
62
63 AddrPtr addrPtr{addr};
64 addr = nullptr;
65
66 char ipaddress[INET6_ADDRSTRLEN]{0};
67 result = getnameinfo(addrPtr->ai_addr, addrPtr->ai_addrlen, ipaddress,
68 sizeof(ipaddress), NULL, 0, NI_NUMERICHOST);
69 if (result)
70 {
71 lg2::error("getnameinfo failed {ADDRESS}: {RC}", "ADDRESS", address,
72 "RC", result);
73 elog<InternalFailure>();
74 }
75
76 unsigned char buf[sizeof(struct in6_addr)];
77 int isValid = inet_pton(AF_INET, ipaddress, buf);
78 if (isValid < 0)
79 {
80 lg2::error("Invalid address {ADDRESS}: {RC}", "ADDRESS", address, "RC",
81 isValid);
82 elog<InternalFailure>();
83 }
84 if (isValid == 0)
85 {
86 int isValid6 = inet_pton(AF_INET6, ipaddress, buf);
87 if (isValid6 < 1)
88 {
89 lg2::error("Invalid address {ADDRESS}: {RC}", "ADDRESS", address,
90 "RC", isValid);
91 elog<InternalFailure>();
92 }
93 }
94
95 return ipaddress;
96 }
97
98 namespace snmp
99 {
100
101 static constexpr auto busName = "xyz.openbmc_project.Network.SNMP";
102 static constexpr auto root = "/xyz/openbmc_project/network/snmp/manager";
103 static constexpr auto clientIntf = "xyz.openbmc_project.Network.Client";
104
105 /** @brief Gets the sdbus object for this process.
106 * @return the bus object.
107 */
getBus()108 static auto& getBus()
109 {
110 static auto bus = sdbusplus::bus::new_default();
111 return bus;
112 }
113
getManagers()114 std::vector<std::string> getManagers()
115 {
116 std::vector<std::string> managers;
117 auto& bus = getBus();
118 try
119 {
120 auto objTree = phosphor::getManagedObjects(bus, busName, root);
121 for (const auto& [_, intfMap] : objTree)
122 {
123 if (!intfMap.contains(clientIntf))
124 {
125 continue;
126 }
127
128 auto& snmpClientProps = intfMap.at(clientIntf);
129 auto& address =
130 std::get<std::string>(snmpClientProps.at("Address"));
131 auto& port = std::get<uint16_t>(snmpClientProps.at("Port"));
132 auto ipaddress = phosphor::network::resolveAddress(address);
133 auto mgr = std::move(ipaddress);
134 if (port > 0)
135 {
136 mgr += ":";
137 mgr += std::to_string(port);
138 }
139 managers.push_back(mgr);
140 }
141 }
142 catch (const std::exception& e)
143 {
144 lg2::error("Invalid address: {ERROR}", "ERROR", e);
145 }
146
147 return managers;
148 }
149
150 } // namespace snmp
151 } // namespace network
152 } // namespace phosphor
153