prepare CA path+file options, use ssl lib defaults, fix reconnect with https
This commit is contained in:
@@ -26,7 +26,6 @@
|
||||
#include <algorithm>
|
||||
#include "ebusd/main.h"
|
||||
#include "lib/utils/log.h"
|
||||
#include "lib/utils/httpclient.h"
|
||||
#include "lib/ebus/data.h"
|
||||
|
||||
namespace ebusd {
|
||||
@@ -108,7 +107,8 @@ result_t UserList::addFromFile(const string& filename, unsigned int lineNo, map<
|
||||
MainLoop::MainLoop(const struct options& opt, Device *device, MessageMap* messages)
|
||||
: Thread(), m_device(device), m_reconnectCount(0), m_userList(opt.accessLevel), m_messages(messages),
|
||||
m_address(opt.address), m_scanConfig(opt.scanConfig), m_initialScan(opt.readOnly ? ESC : opt.initialScan),
|
||||
m_polling(opt.pollInterval > 0), m_enableHex(opt.enableHex), m_shutdown(false), m_runUpdateCheck(opt.updateCheck) {
|
||||
m_polling(opt.pollInterval > 0), m_enableHex(opt.enableHex), m_shutdown(false), m_runUpdateCheck(opt.updateCheck),
|
||||
m_httpClient(nullptr, nullptr) {
|
||||
m_device->setListener(this);
|
||||
// open Device
|
||||
result_t result = m_device->open();
|
||||
@@ -331,8 +331,7 @@ void MainLoop::run() {
|
||||
}
|
||||
}
|
||||
if (m_runUpdateCheck && !m_shutdown && now > nextCheckRun) {
|
||||
HttpClient client;
|
||||
if (!client.connect("upd.ebusd.eu",
|
||||
if (!m_httpClient.connect("upd.ebusd.eu",
|
||||
#ifdef HAVE_SSL
|
||||
443, true,
|
||||
#else
|
||||
@@ -363,7 +362,7 @@ void MainLoop::run() {
|
||||
m_busHandler->formatUpdateInfo(&ostr);
|
||||
ostr << "}";
|
||||
string response;
|
||||
if (!client.post("/", ostr.str(), &response)) {
|
||||
if (!m_httpClient.post("/", ostr.str(), &response)) {
|
||||
logError(lf_main, "update check error: %s", response.c_str());
|
||||
} else {
|
||||
m_updateCheck = response.empty() ? "unknown" : response;
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "lib/ebus/filereader.h"
|
||||
#include "lib/ebus/message.h"
|
||||
#include "lib/utils/rotatefile.h"
|
||||
#include "lib/utils/httpclient.h"
|
||||
|
||||
namespace ebusd {
|
||||
|
||||
@@ -430,6 +431,9 @@ class MainLoop : public Thread, DeviceListener {
|
||||
/** perform automatic update check. */
|
||||
bool m_runUpdateCheck;
|
||||
|
||||
/** the @a HttpClient for performing the update check. */
|
||||
HttpClient m_httpClient;
|
||||
|
||||
/** the created @a BusHandler instance. */
|
||||
BusHandler* m_busHandler;
|
||||
|
||||
|
||||
@@ -21,6 +21,11 @@
|
||||
#include <cstdlib>
|
||||
#include <sstream>
|
||||
#include <csignal>
|
||||
#ifdef HAVE_SSL
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10101000L
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#endif // HAVE_SSL
|
||||
#include "lib/utils/log.h"
|
||||
|
||||
namespace ebusd {
|
||||
@@ -32,6 +37,15 @@ using std::hex;
|
||||
|
||||
#ifdef HAVE_SSL
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10101000L
|
||||
// default CA path
|
||||
#define DEFAULT_CAFILE "/etc/ssl/certs/ca-certificates.crt"
|
||||
|
||||
// default CA path
|
||||
#define DEFAULT_CAPATH "/etc/ssl/certs"
|
||||
#endif
|
||||
|
||||
// the time slice to sleep between repeated SSL reads/writes
|
||||
#define SLEEP_NANOS 50000
|
||||
|
||||
bool checkError(const char* call) {
|
||||
@@ -131,7 +145,8 @@ bool SSLSocket::isValid() {
|
||||
// general switch for future insecure option
|
||||
static const bool verifyPeer = true;
|
||||
|
||||
SSLSocket* SSLSocket::connect(const string& host, const uint16_t& port, bool https, int timeout) {
|
||||
SSLSocket* SSLSocket::connect(const string& host, const uint16_t& port, bool https, int timeout, const char* caFile,
|
||||
const char* caPath) {
|
||||
BIO *bio = nullptr;
|
||||
SSL_CTX *ctx = nullptr;
|
||||
ostringstream ostr;
|
||||
@@ -159,8 +174,21 @@ SSLSocket* SSLSocket::connect(const string& host, const uint16_t& port, bool htt
|
||||
break;
|
||||
}
|
||||
SSL_CTX_set_verify(ctx, verifyPeer ? SSL_VERIFY_PEER : SSL_VERIFY_NONE, nullptr);
|
||||
if (verifyPeer && isError("verify_loc", SSL_CTX_load_verify_locations(ctx, nullptr, "/etc/ssl/certs"), 1)) {
|
||||
break;
|
||||
if (verifyPeer) {
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10101000L
|
||||
SSL_CTX_set_default_verify_paths(ctx);
|
||||
#else
|
||||
struct stat stat_buf = {};
|
||||
if (!caFile && stat(DEFAULT_CAFILE, &stat_buf) == 0) {
|
||||
caFile = DEFAULT_CAFILE; // use default CA file
|
||||
}
|
||||
if (!caPath && stat(DEFAULT_CAPATH, &stat_buf) == 0) {
|
||||
caPath = DEFAULT_CAPATH; // use default CA path
|
||||
}
|
||||
#endif
|
||||
if ((caFile || caPath) && isError("verify_loc", SSL_CTX_load_verify_locations(ctx, caFile, caPath), 1)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
const long flags = SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION;
|
||||
SSL_CTX_set_options(ctx, flags);
|
||||
@@ -291,7 +319,8 @@ bool HttpClient::connect(const string& host, const uint16_t port, bool https, co
|
||||
const int timeout) {
|
||||
disconnect();
|
||||
#ifdef HAVE_SSL
|
||||
m_socket = SSLSocket::connect(host, port, https, timeout);
|
||||
m_socket = SSLSocket::connect(host, port, https, timeout, m_caFile, m_caPath);
|
||||
m_https = https;
|
||||
#else
|
||||
if (https) {
|
||||
return false;
|
||||
@@ -313,7 +342,11 @@ bool HttpClient::reconnect() {
|
||||
if (m_host.empty() || !m_port) {
|
||||
return false;
|
||||
}
|
||||
m_socket = SocketClass::connect(m_host, m_port, m_timeout);
|
||||
#ifdef HAVE_SSL
|
||||
m_socket = SSLSocket::connect(m_host, m_port, m_https, m_timeout, m_caFile, m_caPath);
|
||||
#else
|
||||
m_socket = TCPSocket::connect(m_host, m_port, m_timeout);
|
||||
#endif
|
||||
if (!m_socket) {
|
||||
return false;
|
||||
}
|
||||
@@ -458,7 +491,7 @@ bool HttpClient::request(const string& method, const string& uri, const string&
|
||||
return pos == length;
|
||||
}
|
||||
|
||||
size_t HttpClient::readUntil(const string& delim, const size_t length, string* result) {
|
||||
size_t HttpClient::readUntil(const string& delim, size_t length, string* result) {
|
||||
if (!m_buffer) {
|
||||
m_buffer = reinterpret_cast<char*>(malloc(1024+1)); // 1 extra for final terminator
|
||||
if (!m_buffer) {
|
||||
|
||||
@@ -67,9 +67,12 @@ class SSLSocket {
|
||||
* @param port the port number.
|
||||
* @param https true for HTTPS, false for HTTP.
|
||||
* @param timeout the connect, send, and receive timeout in seconds, or 0 for blocking mode.
|
||||
* @param caFile the CA file to use (uses defaults if neither caFile nor caPath are set).
|
||||
* @param caPath the path with CA files to use (uses defaults if neither caFile nor caPath are set).
|
||||
* @return the connected SSLSocket, or nullptr on error.
|
||||
*/
|
||||
static SSLSocket* connect(const string& server, const uint16_t& port, const bool https, int timeout = 0);
|
||||
static SSLSocket* connect(const string& server, const uint16_t& port, bool https, int timeout,
|
||||
const char* caFile = nullptr, const char* caPath = nullptr);
|
||||
|
||||
/**
|
||||
* Write bytes to the socket.
|
||||
@@ -119,8 +122,17 @@ class HttpClient {
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
* @param caFile the CA file to use (uses defaults if neither caFile nor caPath are set).
|
||||
* @param caPath the path with CA files to use (uses defaults if neither caFile nor caPath are set).
|
||||
*/
|
||||
HttpClient() : m_socket(nullptr), m_port(0), m_timeout(0), m_bufferSize(0), m_buffer(nullptr) {
|
||||
explicit HttpClient(const char* caFile = nullptr, const char* caPath = nullptr) :
|
||||
#ifdef HAVE_SSL
|
||||
m_https(false),
|
||||
m_caFile(caFile),
|
||||
m_caPath(caPath),
|
||||
#endif
|
||||
m_socket(nullptr), m_port(0), m_timeout(0), m_bufferSize(0), m_buffer(nullptr)
|
||||
{
|
||||
initialize();
|
||||
}
|
||||
|
||||
@@ -156,8 +168,8 @@ class HttpClient {
|
||||
* @param host the host name to connect to.
|
||||
* @param port the port to connect to.
|
||||
* @param https true for HTTPS, false for HTTP.
|
||||
* @param timeout the timeout in seconds, defaults to 5 seconds.
|
||||
* @param userAgent the optional user agent to send in the request header.
|
||||
* @param timeout the timeout in seconds, defaults to 5 seconds.
|
||||
* @return true on success, false on connect failure.
|
||||
*/
|
||||
bool connect(const string& host, uint16_t port, bool https = false, const string& userAgent = "", int timeout = 5);
|
||||
@@ -217,12 +229,21 @@ class HttpClient {
|
||||
* @param result the string to append the read data to and in which to find the delimiter.
|
||||
* @return the position of the delimiter if delimiter was set or the number of bytes received, or string::npos if not found.
|
||||
*/
|
||||
size_t readUntil(const string& delim, const size_t length, string* result);
|
||||
size_t readUntil(const string& delim, size_t length, string* result);
|
||||
|
||||
private:
|
||||
#ifdef HAVE_SSL
|
||||
/** true once @a initialize() was called. */
|
||||
static bool s_initialized;
|
||||
|
||||
/** true for HTTPS, false for HTTP. */
|
||||
bool m_https;
|
||||
|
||||
/** the CA file to use. */
|
||||
const char* m_caFile;
|
||||
|
||||
/** the path with CA files to use. */
|
||||
const char* m_caPath;
|
||||
#endif
|
||||
|
||||
/** the currently connected socket. */
|
||||
|
||||
Reference in New Issue
Block a user