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