xref: /openbmc/phosphor-logging/phosphor-rsyslog-config/server-conf.cpp (revision 25291157927273a4ac459c6479c1d3090ddc6a16)
1c4966192SDeepak Kodihalli #include "server-conf.hpp"
2f18bf836SPatrick Venture 
3c4966192SDeepak Kodihalli #include "utils.hpp"
44db8146dSDeepak Kodihalli #include "xyz/openbmc_project/Common/error.hpp"
5f18bf836SPatrick Venture 
64db8146dSDeepak Kodihalli #include <phosphor-logging/elog.hpp>
72544b419SPatrick Williams 
82544b419SPatrick Williams #include <fstream>
94db8146dSDeepak Kodihalli #if __has_include("../../usr/include/phosphor-logging/elog-errors.hpp")
104db8146dSDeepak Kodihalli #include "../../usr/include/phosphor-logging/elog-errors.hpp"
114db8146dSDeepak Kodihalli #else
124db8146dSDeepak Kodihalli #include <phosphor-logging/elog-errors.hpp>
134db8146dSDeepak Kodihalli #endif
144db8146dSDeepak Kodihalli #include <arpa/inet.h>
15f18bf836SPatrick Venture #include <netdb.h>
16c4966192SDeepak Kodihalli 
17a1c4338eSLei YU #include <optional>
1830047bf9SPatrick Venture #include <string>
1930047bf9SPatrick Venture 
20c4966192SDeepak Kodihalli namespace phosphor
21c4966192SDeepak Kodihalli {
22c4966192SDeepak Kodihalli namespace rsyslog_config
23c4966192SDeepak Kodihalli {
24c4966192SDeepak Kodihalli 
25c4966192SDeepak Kodihalli namespace utils = phosphor::rsyslog_utils;
264db8146dSDeepak Kodihalli using namespace phosphor::logging;
276ddbf69eSWilly Tu using namespace sdbusplus::error::xyz::openbmc_project::common;
28c4966192SDeepak Kodihalli 
29a1c4338eSLei YU namespace internal
30a1c4338eSLei YU {
31a1c4338eSLei YU 
isIPv6Address(const std::string & addr)32a1c4338eSLei YU bool isIPv6Address(const std::string& addr)
33a1c4338eSLei YU {
34a1c4338eSLei YU     struct in6_addr result;
35a1c4338eSLei YU     return inet_pton(AF_INET6, addr.c_str(), &result) == 1;
36a1c4338eSLei YU }
37a1c4338eSLei YU 
3822e8695fSIvan Mikhaylov std::optional<
3922e8695fSIvan Mikhaylov     std::tuple<std::string, uint32_t, NetworkClient::TransportProtocol>>
parseConfig(std::istream & ss)4022e8695fSIvan Mikhaylov     parseConfig(std::istream& ss)
41a1c4338eSLei YU {
42a1c4338eSLei YU     std::string line;
43a1c4338eSLei YU     std::getline(ss, line);
44a1c4338eSLei YU 
45a1c4338eSLei YU     std::string serverAddress;
46a1c4338eSLei YU     std::string serverPort;
4722e8695fSIvan Mikhaylov     NetworkClient::TransportProtocol serverTransportProtocol =
4822e8695fSIvan Mikhaylov         NetworkClient::TransportProtocol::TCP;
49a1c4338eSLei YU 
50a1c4338eSLei YU     // Ignore if line is commented
51a1c4338eSLei YU     if (!line.empty() && '#' != line.at(0))
52a1c4338eSLei YU     {
5322e8695fSIvan Mikhaylov         //"*.* @@<address>:<port>" or
5422e8695fSIvan Mikhaylov         //"*.* @@[<ipv6-address>:<port>"
5522e8695fSIvan Mikhaylov         auto start = line.find('@');
5622e8695fSIvan Mikhaylov         if (start == std::string::npos)
5722e8695fSIvan Mikhaylov             return {};
5822e8695fSIvan Mikhaylov 
5922e8695fSIvan Mikhaylov         // Skip "*.* @@" or "*.* @"
6022e8695fSIvan Mikhaylov         if (line.at(start + 1) == '@')
6122e8695fSIvan Mikhaylov         {
6222e8695fSIvan Mikhaylov             serverTransportProtocol = NetworkClient::TransportProtocol::TCP;
6322e8695fSIvan Mikhaylov             start += 2;
6422e8695fSIvan Mikhaylov         }
6522e8695fSIvan Mikhaylov         else
6622e8695fSIvan Mikhaylov         {
6722e8695fSIvan Mikhaylov             serverTransportProtocol = NetworkClient::TransportProtocol::UDP;
6822e8695fSIvan Mikhaylov             start++;
6922e8695fSIvan Mikhaylov         }
7022e8695fSIvan Mikhaylov 
71a1c4338eSLei YU         // Check if there is "[]", and make IPv6 address from it
72a1c4338eSLei YU         auto posColonLeft = line.find('[');
73a1c4338eSLei YU         auto posColonRight = line.find(']');
74a1c4338eSLei YU         if (posColonLeft != std::string::npos ||
75a1c4338eSLei YU             posColonRight != std::string::npos)
76a1c4338eSLei YU         {
77a1c4338eSLei YU             // It contains [ or ], so it should be an IPv6 address
78a1c4338eSLei YU             if (posColonLeft == std::string::npos ||
79a1c4338eSLei YU                 posColonRight == std::string::npos)
80a1c4338eSLei YU             {
81a1c4338eSLei YU                 // There either '[' or ']', invalid config
82a1c4338eSLei YU                 return {};
83a1c4338eSLei YU             }
84a1c4338eSLei YU             if (line.size() < posColonRight + 2 ||
85a1c4338eSLei YU                 line.at(posColonRight + 1) != ':')
86a1c4338eSLei YU             {
87a1c4338eSLei YU                 // There is no ':', or no more content after ':', invalid config
88a1c4338eSLei YU                 return {};
89a1c4338eSLei YU             }
90075c7923SPatrick Williams             serverAddress =
91075c7923SPatrick Williams                 line.substr(posColonLeft + 1, posColonRight - posColonLeft - 1);
92a1c4338eSLei YU             serverPort = line.substr(posColonRight + 2);
93a1c4338eSLei YU         }
94a1c4338eSLei YU         else
95a1c4338eSLei YU         {
96a1c4338eSLei YU             auto pos = line.find(':');
97a1c4338eSLei YU             if (pos == std::string::npos)
98a1c4338eSLei YU             {
99a1c4338eSLei YU                 // There is no ':', invalid config
100a1c4338eSLei YU                 return {};
101a1c4338eSLei YU             }
102a1c4338eSLei YU             serverAddress = line.substr(start, pos - start);
103a1c4338eSLei YU             serverPort = line.substr(pos + 1);
104a1c4338eSLei YU         }
105a1c4338eSLei YU     }
106a1c4338eSLei YU     if (serverAddress.empty() || serverPort.empty())
107a1c4338eSLei YU     {
108a1c4338eSLei YU         return {};
109a1c4338eSLei YU     }
110a1c4338eSLei YU     try
111a1c4338eSLei YU     {
11222e8695fSIvan Mikhaylov         return std::make_tuple(std::move(serverAddress), std::stoul(serverPort),
11322e8695fSIvan Mikhaylov                                serverTransportProtocol);
114a1c4338eSLei YU     }
115a1c4338eSLei YU     catch (const std::exception& ex)
116a1c4338eSLei YU     {
117a1c4338eSLei YU         log<level::ERR>("Invalid config", entry("ERR=%s", ex.what()));
118a1c4338eSLei YU         return {};
119a1c4338eSLei YU     }
120a1c4338eSLei YU }
121a1c4338eSLei YU 
122a1c4338eSLei YU } // namespace internal
123a1c4338eSLei YU 
address(std::string value)124c4966192SDeepak Kodihalli std::string Server::address(std::string value)
125c4966192SDeepak Kodihalli {
1266ddbf69eSWilly Tu     using Argument = xyz::openbmc_project::common::InvalidArgument;
1274db8146dSDeepak Kodihalli     std::string result{};
1284db8146dSDeepak Kodihalli 
1294db8146dSDeepak Kodihalli     try
1304db8146dSDeepak Kodihalli     {
1310febd26bSDeepak Kodihalli         auto serverAddress = address();
1320febd26bSDeepak Kodihalli         if (serverAddress == value)
1330febd26bSDeepak Kodihalli         {
1340febd26bSDeepak Kodihalli             return serverAddress;
1350febd26bSDeepak Kodihalli         }
1360febd26bSDeepak Kodihalli 
1374db8146dSDeepak Kodihalli         if (!value.empty() && !addressValid(value))
1384db8146dSDeepak Kodihalli         {
1394db8146dSDeepak Kodihalli             elog<InvalidArgument>(Argument::ARGUMENT_NAME("Address"),
1404db8146dSDeepak Kodihalli                                   Argument::ARGUMENT_VALUE(value.c_str()));
1414db8146dSDeepak Kodihalli         }
1424db8146dSDeepak Kodihalli 
14322e8695fSIvan Mikhaylov         writeConfig(value, port(), transportProtocol(), configFilePath.c_str());
144511a4752SPatrick Williams         result = NetworkClient::address(value);
1454db8146dSDeepak Kodihalli     }
1464db8146dSDeepak Kodihalli     catch (const InvalidArgument& e)
1474db8146dSDeepak Kodihalli     {
1484db8146dSDeepak Kodihalli         throw;
1494db8146dSDeepak Kodihalli     }
1504db8146dSDeepak Kodihalli     catch (const InternalFailure& e)
1514db8146dSDeepak Kodihalli     {
1524db8146dSDeepak Kodihalli         throw;
1534db8146dSDeepak Kodihalli     }
1544db8146dSDeepak Kodihalli     catch (const std::exception& e)
1554db8146dSDeepak Kodihalli     {
1564db8146dSDeepak Kodihalli         log<level::ERR>(e.what());
1574db8146dSDeepak Kodihalli         elog<InternalFailure>();
1584db8146dSDeepak Kodihalli     }
1594db8146dSDeepak Kodihalli 
160c4966192SDeepak Kodihalli     return result;
161c4966192SDeepak Kodihalli }
162c4966192SDeepak Kodihalli 
port(uint16_t value)163c4966192SDeepak Kodihalli uint16_t Server::port(uint16_t value)
164c4966192SDeepak Kodihalli {
1654db8146dSDeepak Kodihalli     uint16_t result{};
1664db8146dSDeepak Kodihalli 
1674db8146dSDeepak Kodihalli     try
1684db8146dSDeepak Kodihalli     {
1690febd26bSDeepak Kodihalli         auto serverPort = port();
1700febd26bSDeepak Kodihalli         if (serverPort == value)
1710febd26bSDeepak Kodihalli         {
1720febd26bSDeepak Kodihalli             return serverPort;
1730febd26bSDeepak Kodihalli         }
1740febd26bSDeepak Kodihalli 
17522e8695fSIvan Mikhaylov         writeConfig(address(), value, transportProtocol(),
17622e8695fSIvan Mikhaylov                     configFilePath.c_str());
1774db8146dSDeepak Kodihalli         result = NetworkClient::port(value);
1784db8146dSDeepak Kodihalli     }
1794db8146dSDeepak Kodihalli     catch (const InternalFailure& e)
1804db8146dSDeepak Kodihalli     {
1814db8146dSDeepak Kodihalli         throw;
1824db8146dSDeepak Kodihalli     }
1834db8146dSDeepak Kodihalli     catch (const std::exception& e)
1844db8146dSDeepak Kodihalli     {
1854db8146dSDeepak Kodihalli         log<level::ERR>(e.what());
1864db8146dSDeepak Kodihalli         elog<InternalFailure>();
1874db8146dSDeepak Kodihalli     }
1884db8146dSDeepak Kodihalli 
189c4966192SDeepak Kodihalli     return result;
190c4966192SDeepak Kodihalli }
191c4966192SDeepak Kodihalli 
transportProtocol(NetworkClient::TransportProtocol value)192*25291157SPatrick Williams NetworkClient::TransportProtocol Server::transportProtocol(
193*25291157SPatrick Williams     NetworkClient::TransportProtocol value)
19422e8695fSIvan Mikhaylov {
19522e8695fSIvan Mikhaylov     TransportProtocol result{};
19622e8695fSIvan Mikhaylov 
19722e8695fSIvan Mikhaylov     try
19822e8695fSIvan Mikhaylov     {
19922e8695fSIvan Mikhaylov         auto serverTransportProtocol = transportProtocol();
20022e8695fSIvan Mikhaylov         if (serverTransportProtocol == value)
20122e8695fSIvan Mikhaylov         {
20222e8695fSIvan Mikhaylov             return serverTransportProtocol;
20322e8695fSIvan Mikhaylov         }
20422e8695fSIvan Mikhaylov 
20522e8695fSIvan Mikhaylov         writeConfig(address(), port(), value, configFilePath.c_str());
20622e8695fSIvan Mikhaylov         result = NetworkClient::transportProtocol(value);
20722e8695fSIvan Mikhaylov     }
20822e8695fSIvan Mikhaylov     catch (const InternalFailure& e)
20922e8695fSIvan Mikhaylov     {
21022e8695fSIvan Mikhaylov         throw;
21122e8695fSIvan Mikhaylov     }
21222e8695fSIvan Mikhaylov     catch (const std::exception& e)
21322e8695fSIvan Mikhaylov     {
21422e8695fSIvan Mikhaylov         log<level::ERR>(e.what());
21522e8695fSIvan Mikhaylov         elog<InternalFailure>();
21622e8695fSIvan Mikhaylov     }
21722e8695fSIvan Mikhaylov 
21822e8695fSIvan Mikhaylov     return result;
21922e8695fSIvan Mikhaylov }
22022e8695fSIvan Mikhaylov 
writeConfig(const std::string & serverAddress,uint16_t serverPort,NetworkClient::TransportProtocol serverTransportProtocol,const char * filePath)22122e8695fSIvan Mikhaylov void Server::writeConfig(
22222e8695fSIvan Mikhaylov     const std::string& serverAddress, uint16_t serverPort,
22322e8695fSIvan Mikhaylov     NetworkClient::TransportProtocol serverTransportProtocol,
224c4966192SDeepak Kodihalli     const char* filePath)
225c4966192SDeepak Kodihalli {
2260febd26bSDeepak Kodihalli     std::fstream stream(filePath, std::fstream::out);
2270febd26bSDeepak Kodihalli 
228c4966192SDeepak Kodihalli     if (serverPort && !serverAddress.empty())
229c4966192SDeepak Kodihalli     {
23022e8695fSIvan Mikhaylov         std::string type =
23122e8695fSIvan Mikhaylov             (serverTransportProtocol == NetworkClient::TransportProtocol::UDP)
23222e8695fSIvan Mikhaylov                 ? "@"
23322e8695fSIvan Mikhaylov                 : "@@";
23422e8695fSIvan Mikhaylov         // write '*.* @@<remote-host>:<port>' or '*.* @<remote-host>:<port>'
235a1c4338eSLei YU         if (internal::isIPv6Address(serverAddress))
236a1c4338eSLei YU         {
23722e8695fSIvan Mikhaylov             stream << "*.* " << type << "[" << serverAddress
23822e8695fSIvan Mikhaylov                    << "]:" << serverPort;
239a1c4338eSLei YU         }
240a1c4338eSLei YU         else
241a1c4338eSLei YU         {
24222e8695fSIvan Mikhaylov             stream << "*.* " << type << serverAddress << ":" << serverPort;
2430febd26bSDeepak Kodihalli         }
244a1c4338eSLei YU     }
2450febd26bSDeepak Kodihalli     else // this is a disable request
2460febd26bSDeepak Kodihalli     {
247445665afSPaul Fertser         // dummy action to avoid error 2103 on startup
248445665afSPaul Fertser         stream << "*.* /dev/null";
2490febd26bSDeepak Kodihalli     }
250c4966192SDeepak Kodihalli 
251445665afSPaul Fertser     stream << std::endl;
252445665afSPaul Fertser 
2532ce7b2c3SDeepak Kodihalli     restart();
254c4966192SDeepak Kodihalli }
255c4966192SDeepak Kodihalli 
addressValid(const std::string & address)2564db8146dSDeepak Kodihalli bool Server::addressValid(const std::string& address)
2574db8146dSDeepak Kodihalli {
2584db8146dSDeepak Kodihalli     addrinfo hints{};
2594db8146dSDeepak Kodihalli     addrinfo* res = nullptr;
2604db8146dSDeepak Kodihalli     hints.ai_family = AF_UNSPEC;
2614db8146dSDeepak Kodihalli     hints.ai_socktype = SOCK_STREAM;
2624db8146dSDeepak Kodihalli     hints.ai_flags |= AI_CANONNAME;
2634db8146dSDeepak Kodihalli 
2644db8146dSDeepak Kodihalli     auto result = getaddrinfo(address.c_str(), nullptr, &hints, &res);
2654db8146dSDeepak Kodihalli     if (result)
2664db8146dSDeepak Kodihalli     {
267f18bf836SPatrick Venture         log<level::ERR>("bad address", entry("ADDRESS=%s", address.c_str()),
2684db8146dSDeepak Kodihalli                         entry("ERRNO=%d", result));
2694db8146dSDeepak Kodihalli         return false;
2704db8146dSDeepak Kodihalli     }
271a40c2165SPatrick Williams 
272a40c2165SPatrick Williams     freeaddrinfo(res);
2734db8146dSDeepak Kodihalli     return true;
2744db8146dSDeepak Kodihalli }
2754db8146dSDeepak Kodihalli 
restore(const char * filePath)2769fab279fSDeepak Kodihalli void Server::restore(const char* filePath)
2779fab279fSDeepak Kodihalli {
2789fab279fSDeepak Kodihalli     std::fstream stream(filePath, std::fstream::in);
2799fab279fSDeepak Kodihalli 
280a1c4338eSLei YU     auto ret = internal::parseConfig(stream);
281a1c4338eSLei YU     if (ret)
2829fab279fSDeepak Kodihalli     {
28322e8695fSIvan Mikhaylov         NetworkClient::address(std::get<0>(*ret));
28422e8695fSIvan Mikhaylov         NetworkClient::port(std::get<1>(*ret));
28522e8695fSIvan Mikhaylov         NetworkClient::transportProtocol(std::get<2>(*ret));
2869fab279fSDeepak Kodihalli     }
2879fab279fSDeepak Kodihalli }
2889fab279fSDeepak Kodihalli 
restart()2892ce7b2c3SDeepak Kodihalli void Server::restart()
2902ce7b2c3SDeepak Kodihalli {
2912ce7b2c3SDeepak Kodihalli     utils::restart();
2922ce7b2c3SDeepak Kodihalli }
2932ce7b2c3SDeepak Kodihalli 
294c4966192SDeepak Kodihalli } // namespace rsyslog_config
295c4966192SDeepak Kodihalli } // namespace phosphor
296