xref: /openbmc/bmcweb/redfish-core/lib/network_protocol.hpp (revision 4859bdbafbb2b78ae414fb050ad197db2f2cb28b)
1 /*
2 // Copyright (c) 2018 Intel Corporation
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 */
16 #pragma once
17 
18 #include "error_messages.hpp"
19 #include "node.hpp"
20 
21 namespace redfish {
22 
23 enum NetworkProtocolUnitStructFields {
24   NET_PROTO_UNIT_NAME,
25   NET_PROTO_UNIT_DESC,
26   NET_PROTO_UNIT_LOAD_STATE,
27   NET_PROTO_UNIT_ACTIVE_STATE,
28   NET_PROTO_UNIT_SUB_STATE,
29   NET_PROTO_UNIT_DEVICE,
30   NET_PROTO_UNIT_OBJ_PATH,
31   NET_PROTO_UNIT_ALWAYS_0,
32   NET_PROTO_UNIT_ALWAYS_EMPTY,
33   NET_PROTO_UNIT_ALWAYS_ROOT_PATH
34 };
35 
36 enum NetworkProtocolListenResponseElements {
37   NET_PROTO_LISTEN_TYPE,
38   NET_PROTO_LISTEN_STREAM
39 };
40 
41 /**
42  * @brief D-Bus Unit structure returned in array from ListUnits Method
43  */
44 using UnitStruct =
45     std::tuple<std::string, std::string, std::string, std::string, std::string,
46                std::string, sdbusplus::message::object_path, uint32_t,
47                std::string, sdbusplus::message::object_path>;
48 
49 struct ServiceConfiguration {
50   const char* serviceName;
51   const char* socketPath;
52 };
53 
54 const static boost::container::flat_map<const char*, ServiceConfiguration>
55     protocolToDBus{
56         {"SSH",
57          {"dropbear.service",
58           "/org/freedesktop/systemd1/unit/dropbear_2esocket"}},
59         {"HTTPS",
60          {"phosphor-gevent.service",
61           "/org/freedesktop/systemd1/unit/phosphor_2dgevent_2esocket"}},
62         {"IPMI",
63          {"phosphor-ipmi-net.service",
64           "/org/freedesktop/systemd1/unit/phosphor_2dipmi_2dnet_2esocket"}}};
65 
66 class NetworkProtocol : public Node {
67  public:
68   NetworkProtocol(CrowApp& app)
69       : Node(app, "/redfish/v1/Managers/openbmc/NetworkProtocol") {
70     Node::json["@odata.type"] =
71         "#ManagerNetworkProtocol.v1_1_0.ManagerNetworkProtocol";
72     Node::json["@odata.id"] = "/redfish/v1/Managers/openbmc/NetworkProtocol";
73     Node::json["@odata.context"] =
74         "/redfish/v1/$metadata#ManagerNetworkProtocol.ManagerNetworkProtocol";
75     Node::json["Id"] = "NetworkProtocol";
76     Node::json["Name"] = "Manager Network Protocol";
77     Node::json["Description"] = "Manager Network Service";
78     Node::json["Status"]["Health"] = "OK";
79     Node::json["Status"]["HealthRollup"] = "OK";
80     Node::json["Status"]["State"] = "Enabled";
81 
82     for (auto& protocol : protocolToDBus) {
83       Node::json[protocol.first]["ProtocolEnabled"] = false;
84     }
85 
86     entityPrivileges = {
87         {boost::beast::http::verb::get, {{"Login"}}},
88         {boost::beast::http::verb::head, {{"Login"}}},
89         {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
90         {boost::beast::http::verb::put, {{"ConfigureManager"}}},
91         {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
92         {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
93   }
94 
95  private:
96   void doGet(crow::Response& res, const crow::Request& req,
97              const std::vector<std::string>& params) override {
98     std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
99 
100     getData(asyncResp);
101   }
102 
103   std::string getHostName() const {
104     std::string hostName;
105 
106     std::array<char, HOST_NAME_MAX> hostNameCStr;
107     if (gethostname(hostNameCStr.data(), hostNameCStr.size()) == 0) {
108       hostName = hostNameCStr.data();
109     }
110     return hostName;
111   }
112 
113   void getData(const std::shared_ptr<AsyncResp>& asyncResp) {
114     Node::json["HostName"] = getHostName();
115     asyncResp->res.jsonValue = Node::json;
116 
117     crow::connections::systemBus->async_method_call(
118         [asyncResp](const boost::system::error_code ec,
119                     const std::vector<UnitStruct>& resp) {
120           if (ec) {
121             asyncResp->res.jsonValue = nlohmann::json::object();
122             messages::addMessageToErrorJson(asyncResp->res.jsonValue,
123                                             messages::internalError());
124             asyncResp->res.result(
125                 boost::beast::http::status::internal_server_error);
126             return;
127           }
128 
129           for (auto& unit : resp) {
130             for (auto& kv : protocolToDBus) {
131               if (kv.second.serviceName ==
132                   std::get<NET_PROTO_UNIT_NAME>(unit)) {
133                 continue;
134               }
135               const char* service = kv.first;
136               const char* socketPath = kv.second.socketPath;
137 
138               asyncResp->res.jsonValue[service]["ProtocolEnabled"] =
139                   std::get<NET_PROTO_UNIT_SUB_STATE>(unit) == "running";
140 
141               crow::connections::systemBus->async_method_call(
142                   [ asyncResp, service{std::string(service)}, socketPath ](
143                       const boost::system::error_code ec,
144                       const sdbusplus::message::variant<std::vector<
145                           std::tuple<std::string, std::string>>>& resp) {
146                     if (ec) {
147                       messages::addMessageToJson(asyncResp->res.jsonValue,
148                                                  messages::internalError(),
149                                                  "/" + service);
150                       return;
151                     }
152                     const std::vector<std::tuple<std::string, std::string>>*
153                         responsePtr = mapbox::getPtr<const std::vector<
154                             std::tuple<std::string, std::string>>>(resp);
155                     if (responsePtr == nullptr || responsePtr->size() < 1) {
156                       return;
157                     }
158 
159                     const std::string& listenStream =
160                         std::get<NET_PROTO_LISTEN_STREAM>((*responsePtr)[0]);
161                     std::size_t lastColonPos = listenStream.rfind(":");
162                     if (lastColonPos == std::string::npos) {
163                       // Not a port
164                       return;
165                     }
166                     std::string portStr = listenStream.substr(lastColonPos + 1);
167                     char* endPtr = nullptr;
168                     // Use strtol instead of stroi to avoid exceptions
169                     long port = std::strtol(portStr.c_str(), &endPtr, 10);
170 
171                     if (*endPtr != '\0' || portStr.empty()) {
172                       // Invalid value
173                       asyncResp->res.jsonValue[service]["Port"] = nullptr;
174                     } else {
175                       // Everything OK
176                       asyncResp->res.jsonValue[service]["Port"] = port;
177                     }
178                   },
179                   "org.freedesktop.systemd1", socketPath,
180                   "org.freedesktop.DBus.Properties", "Get",
181                   "org.freedesktop.systemd1.Socket", "Listen");
182             }
183           }
184         },
185         "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
186         "org.freedesktop.systemd1.Manager", "ListUnits");
187   }
188 };
189 
190 }  // namespace redfish
191