#include "server-conf.hpp" #include "utils.hpp" #include "xyz/openbmc_project/Common/error.hpp" #include #include #if __has_include("../../usr/include/phosphor-logging/elog-errors.hpp") #include "../../usr/include/phosphor-logging/elog-errors.hpp" #else #include #endif #include #include #include #include namespace phosphor { namespace rsyslog_config { namespace utils = phosphor::rsyslog_utils; using namespace phosphor::logging; using namespace sdbusplus::xyz::openbmc_project::Common::Error; namespace internal { bool isIPv6Address(const std::string& addr) { struct in6_addr result; return inet_pton(AF_INET6, addr.c_str(), &result) == 1; } std::optional> parseConfig(std::istream& ss) { std::string line; std::getline(ss, line); //"*.* @@
:" or //"*.* @@[:" constexpr auto start = 6; // Skip "*.* @@" std::string serverAddress; std::string serverPort; // Ignore if line is commented if (!line.empty() && '#' != line.at(0)) { // Check if there is "[]", and make IPv6 address from it auto posColonLeft = line.find('['); auto posColonRight = line.find(']'); if (posColonLeft != std::string::npos || posColonRight != std::string::npos) { // It contains [ or ], so it should be an IPv6 address if (posColonLeft == std::string::npos || posColonRight == std::string::npos) { // There either '[' or ']', invalid config return {}; } if (line.size() < posColonRight + 2 || line.at(posColonRight + 1) != ':') { // There is no ':', or no more content after ':', invalid config return {}; } serverAddress = line.substr(posColonLeft + 1, posColonRight - posColonLeft - 1); serverPort = line.substr(posColonRight + 2); } else { auto pos = line.find(':'); if (pos == std::string::npos) { // There is no ':', invalid config return {}; } serverAddress = line.substr(start, pos - start); serverPort = line.substr(pos + 1); } } if (serverAddress.empty() || serverPort.empty()) { return {}; } try { uint32_t port = std::stoul(serverPort); return std::make_pair(std::move(serverAddress), port); } catch (const std::exception& ex) { log("Invalid config", entry("ERR=%s", ex.what())); return {}; } } } // namespace internal std::string Server::address(std::string value) { using Argument = xyz::openbmc_project::Common::InvalidArgument; std::string result{}; try { auto serverAddress = address(); if (serverAddress == value) { return serverAddress; } if (!value.empty() && !addressValid(value)) { elog(Argument::ARGUMENT_NAME("Address"), Argument::ARGUMENT_VALUE(value.c_str())); } writeConfig(value, port(), configFilePath.c_str()); result = std::move(NetworkClient::address(value)); } catch (const InvalidArgument& e) { throw; } catch (const InternalFailure& e) { throw; } catch (const std::exception& e) { log(e.what()); elog(); } return result; } uint16_t Server::port(uint16_t value) { uint16_t result{}; try { auto serverPort = port(); if (serverPort == value) { return serverPort; } writeConfig(address(), value, configFilePath.c_str()); result = NetworkClient::port(value); } catch (const InternalFailure& e) { throw; } catch (const std::exception& e) { log(e.what()); elog(); } return result; } void Server::writeConfig(const std::string& serverAddress, uint16_t serverPort, const char* filePath) { std::fstream stream(filePath, std::fstream::out); if (serverPort && !serverAddress.empty()) { // write '*.* @@:' if (internal::isIPv6Address(serverAddress)) { stream << "*.* @@[" << serverAddress << "]:" << serverPort; } else { stream << "*.* @@" << serverAddress << ":" << serverPort; } } else // this is a disable request { // write '*.* ~' - this causes rsyslog to discard all messages stream << "*.* ~"; } restart(); } bool Server::addressValid(const std::string& address) { addrinfo hints{}; addrinfo* res = nullptr; hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags |= AI_CANONNAME; auto result = getaddrinfo(address.c_str(), nullptr, &hints, &res); if (result) { log("bad address", entry("ADDRESS=%s", address.c_str()), entry("ERRNO=%d", result)); return false; } freeaddrinfo(res); return true; } void Server::restore(const char* filePath) { std::fstream stream(filePath, std::fstream::in); auto ret = internal::parseConfig(stream); if (ret) { NetworkClient::address(ret->first); NetworkClient::port(ret->second); } } void Server::restart() { utils::restart(); } } // namespace rsyslog_config } // namespace phosphor