diff --git a/SourceCode/arduino/lib/Firewall/esp32API.cpp b/SourceCode/arduino/lib/Firewall/esp32API.cpp new file mode 100644 index 0000000..6403d29 --- /dev/null +++ b/SourceCode/arduino/lib/Firewall/esp32API.cpp @@ -0,0 +1,194 @@ +#include "esp32API.hpp" + +namespace firewall +{ + API::API(const uint16_t port) + { + this->setup_certificate(); + this->server = new HTTPSServer(this->certificate, port, 5); + this->setup_routing(); + log_i("Starting server..."); + this->server->start(); + if (this->server->isRunning()) + { + log_i("Server ready."); + } + } + + API::~API() + { + } + + void API::handle_clients() + { + this->server->loop(); + } + + void API::setup_certificate() + { + this->certificate = retrieve_certificate(); + if (certificate != NULL) + return; + log_i("Creating the certificate..."); + this->certificate = new SSLCert(); + int createCertResult = createSelfSignedCert( + *this->certificate, + KEYSIZE_2048, + "CN=myesp32.local,O=Firewall,C=DE", + "20220101000000", + "20320101000000"); + if (createCertResult != 0) + { + log_e("Cerating certificate failed. Error Code = 0x%02X, check SSLCert.hpp for details", createCertResult); + while (true) + delay(500); + } + store_certificate(certificate); + log_i("Creating the certificate was successful"); + } + + void API::setup_routing() + { + ResourceNode *get_firewall_rule = new ResourceNode("/api/v1/firewall/*", "GET", std::bind(&API::get_firewall_rule_handler, this, std::placeholders::_1, std::placeholders::_2)); + ResourceNode *get_firewall_rules = new ResourceNode("/api/v1/firewall", "GET", std::bind(&API::get_firewall_rules_handler, this, std::placeholders::_1, std::placeholders::_2)); + ResourceNode *post_firewall = new ResourceNode("/api/v1/firewall", "POST", std::bind(&API::post_firewall_handler, this, std::placeholders::_1, std::placeholders::_2)); + ResourceNode *delete_firewall = new ResourceNode("/api/v1/firewall/*", "DELETE", std::bind(&API::delete_firewall_handler, this, std::placeholders::_1, std::placeholders::_2)); + ResourceNode *not_found = new ResourceNode("", "GET", std::bind(&API::not_found_handler, this, std::placeholders::_1, std::placeholders::_2)); + this->server->registerNode(get_firewall_rule); + this->server->registerNode(get_firewall_rules); + this->server->registerNode(post_firewall); + this->server->registerNode(delete_firewall); + this->server->setDefaultNode(not_found); + } + + void API::not_found_handler(HTTPRequest *request, HTTPResponse *response) + { + this->json_message_response(response, "not found", 404); + } + + void API::get_firewall_rule_handler(HTTPRequest *request, HTTPResponse *response) + { + ResourceParameters *params = request->getParams(); + int rule_number = atoi(params->getPathParameter(0).c_str()); + firewall_rule_t *rule_ptr = get_rule_from_firewall(rule_number); + if (rule_ptr == NULL) + { + this->json_message_response(response, "rule not found", 404); + } + else + { + response->setHeader("Content-Type", "application/json"); + response->setStatusCode(200); + response->print(this->construct_json_firewall_rule(rule_ptr)); + } + } + + void API::get_firewall_rules_handler(HTTPRequest *request, HTTPResponse *response) + { + this->json_generic_response(response, this->construct_json_firewall(), 200); + } + + bool API::request_has_firewall_parameter(ResourceParameters *params) + { + return params->isQueryParameterSet("source") || params->isQueryParameterSet("destination") || params->isQueryParameterSet("protocol") || params->isQueryParameterSet("target"); + } + + void API::post_firewall_handler(HTTPRequest *request, HTTPResponse *response) + { + ResourceParameters *params = request->getParams(); + if (request_has_firewall_parameter(params)) + { + firewall_rule_t *rule_ptr = (firewall_rule_t *)malloc(sizeof(firewall_rule_t)); + rule_ptr->key = ++amount_of_rules; + + // carefully copying c-string that is shorter then the destination char-array length + std::string source; + params->getQueryParameter("source", source); + strcpy(rule_ptr->source, source.length() <= IPV4ADDRESS_LENGTH ? source.c_str() : ""); + std::string destination; + params->getQueryParameter("destination", destination); + strcpy(rule_ptr->destination, destination.length() <= IPV4ADDRESS_LENGTH ? destination.c_str() : ""); + + std::string protocol; + params->getQueryParameter("protocol", protocol); + rule_ptr->protocol = string_to_protocol(protocol); + std::string target; + params->getQueryParameter("target", target); + rule_ptr->target = string_to_target(target); + + add_rule_to_firewall(rule_ptr); + this->json_generic_response(response, this->construct_json_firewall_rule(rule_ptr), 200); + } + else + { + this->json_message_response(response, "not enough parameter", 400); + } + } + + void API::delete_firewall_handler(HTTPRequest *request, HTTPResponse *response) + { + ResourceParameters *params = request->getParams(); + int rule_number = atoi(params->getPathParameter(0).c_str()); + if (delete_rule_from_firewall(rule_number)) + { + this->json_message_response(response, "firewall rule deleted", 200); + } + else + { + this->json_message_response(response, "cannot delete firewall rule", 500); + } + } + + void API::json_generic_response(HTTPResponse *response, String serialized, const uint16_t response_code) + { + response->setHeader("Content-Type", "application/json"); + response->setStatusCode(response_code); + response->println(serialized); + } + + void API::json_message_response(HTTPResponse *response, String message, const uint16_t response_code) + { + response->setHeader("Content-Type", "application/json"); + response->setStatusCode(response_code); + StaticJsonDocument<96> json; + String serialized; + json["message"] = message; + serializeJson(json, serialized); + response->println(serialized); + } + + String API::construct_json_firewall_rule(firewall_rule_t *rule_ptr) + { + StaticJsonDocument<256> doc; + doc["key"] = rule_ptr->key; + doc["source"] = rule_ptr->source; + doc["destination"] = rule_ptr->destination; + doc["protocol"] = protocol_to_string(rule_ptr->protocol); + doc["target"] = target_to_string(rule_ptr->target); + String response; + serializeJson(doc, response); + return response; + } + + String API::construct_json_firewall() + { + firewall_rule_t *rule_ptr = head; + // Size for approx. 12 Rules + StaticJsonDocument<2048> doc; + String response; + doc["amount_of_rules"] = amount_of_rules; + JsonArray rules = doc.createNestedArray("rules"); + while (rule_ptr != NULL) + { + JsonObject rule = rules.createNestedObject(); + rule["key"] = rule_ptr->key; + rule["source"] = rule_ptr->source; + rule["destination"] = rule_ptr->destination; + rule["protocol"] = protocol_to_string(rule_ptr->protocol); + rule["target"] = target_to_string(rule_ptr->target); + rule_ptr = rule_ptr->next; + } + serializeJson(doc, response); + return response; + } +} diff --git a/SourceCode/arduino/lib/Firewall/esp32API.hpp b/SourceCode/arduino/lib/Firewall/esp32API.hpp new file mode 100644 index 0000000..f001d9d --- /dev/null +++ b/SourceCode/arduino/lib/Firewall/esp32API.hpp @@ -0,0 +1,44 @@ +#ifndef ESP32_API_HPP +#define ESP32_API_HPP + +#include "HTTPSServer.hpp" +#include "SSLCert.hpp" +#include "HTTPRequest.hpp" +#include "HTTPResponse.hpp" +#include "ArduinoJson.h" + +#include "FirewallTypes.h" +#include "esp32Firewall.hpp" + +using namespace httpsserver; + +namespace firewall +{ + class API : public Firewall + { + private: + HTTPSServer *server; + SSLCert *certificate; + + void setup_certificate(); + void setup_routing(); + void get_firewall_rule_handler(HTTPRequest *, HTTPResponse *); + void get_firewall_rules_handler(HTTPRequest *, HTTPResponse *); + bool request_has_firewall_parameter(ResourceParameters *); + void post_firewall_handler(HTTPRequest *, HTTPResponse *); + void delete_firewall_handler(HTTPRequest *, HTTPResponse *); + void not_found_handler(HTTPRequest *, HTTPResponse *); + + void json_generic_response(HTTPResponse *, String, const uint16_t); + void json_message_response(HTTPResponse *, String, const uint16_t); + String construct_json_firewall_rule(firewall_rule_t *); + String construct_json_firewall(); + + public: + API(const uint16_t = 8080); + ~API(); + void handle_clients(); + }; +} + +#endif diff --git a/SourceCode/arduino/lib/Firewall/esp32Firewall.cpp b/SourceCode/arduino/lib/Firewall/esp32Firewall.cpp index 14236fd..223c305 100644 --- a/SourceCode/arduino/lib/Firewall/esp32Firewall.cpp +++ b/SourceCode/arduino/lib/Firewall/esp32Firewall.cpp @@ -1,392 +1,150 @@ #include "esp32Firewall.hpp" -esp32Firewall::esp32Firewall(const uint16_t api_port) +namespace firewall { - this->setup_eeprom(); - this->setup_certificate(); - this->firewall_api = new HTTPSServer(this->certificate, api_port, 5); - this->setup_routing(); - log_i("Starting server..."); - this->firewall_api->start(); - if (this->firewall_api->isRunning()) + Firewall::Firewall() { - log_i("Server ready."); + this->amount_of_rules = retrieve_settings_value("amount_of_rules"); + for (uint8_t i = 1; i <= this->amount_of_rules; i++) + { + firewall_rule_t *rule_ptr = retrieve_firewall_rule(i); + add_rule_to_firewall(rule_ptr); + } } -} -void esp32Firewall::handle_firewall_api_clients() -{ - this->firewall_api->loop(); -} - -String esp32Firewall::protocol_to_string(firewall_protocol_t &protocol) -{ - switch (protocol) + Firewall::~Firewall() { - case FW_TCP: - return "TCP"; - case FW_UDP: - return "UDP"; - default: - return "ALL"; } -} -firewall_protocol_t esp32Firewall::string_to_protocol(std::string &protocol) -{ - if (protocol.compare("TCP") == 0) - return FW_TCP; - else if (protocol.compare("UDP") == 0) - return FW_UDP; - else - return FW_ALL; -} - -String esp32Firewall::target_to_string(firewall_target_t &target) -{ - switch (target) + void Firewall::add_rule_to_firewall(firewall_rule_t *rule_ptr) { - case FW_REJECT: - return "REJECT"; - case FW_DROP: - return "DROP"; - default: - return "ACCEPT"; - } -} - -firewall_target_t esp32Firewall::string_to_target(std::string &target) -{ - if (target.compare("REJECT") == 0) - return FW_REJECT; - else if (target.compare("DROP") == 0) - return FW_DROP; - else - return FW_ACCEPT; -} - -void esp32Firewall::setup_eeprom() -{ - EEPROM.begin(this->eeprom_size); - this->amount_of_rules = EEPROM.read(this->eeprom_settings_head); - uint8_t security_number = EEPROM.read(this->eeprom_settings_head + 1); - if (this->amount_of_rules > 50 || security_number != this->security_number) - { - this->amount_of_rules = 0; - EEPROM.write(this->eeprom_settings_head, this->amount_of_rules); - EEPROM.write(this->eeprom_settings_head + 1, this->security_number); - EEPROM.commit(); - } - log_i("Amount of existing Rules %i", this->amount_of_rules); - this->eeprom_read_firewall_rules(); -} - -void esp32Firewall::eeprom_write_firewall_rule(firewall_rule_t *rule_ptr) -{ - EEPROM.write(this->eeprom_settings_head, this->amount_of_rules); - EEPROM.writeString(this->eeprom_rules_head, rule_ptr->source); - this->eeprom_rules_head += IP4ADDR_STRLEN_MAX; - EEPROM.writeString(this->eeprom_rules_head, rule_ptr->destination); - this->eeprom_rules_head += IP4ADDR_STRLEN_MAX; - EEPROM.write(this->eeprom_rules_head, rule_ptr->protocol); - this->eeprom_rules_head += sizeof(firewall_protocol_t); - EEPROM.write(this->eeprom_rules_head, rule_ptr->target); - this->eeprom_rules_head += sizeof(firewall_target_t); - EEPROM.commit(); -} - -void esp32Firewall::eeprom_write_firewall_rules() -{ - this->eeprom_rules_head = eeprom_start_firewall_rules; - firewall_rule_t *rule_ptr = this->head; - while (rule_ptr != NULL) - { - this->eeprom_write_firewall_rule(rule_ptr); - rule_ptr = rule_ptr->next; - } -} - -void esp32Firewall::eeprom_read_firewall_rule(uint8_t &eeprom_address, uint8_t &rule_nr) -{ - firewall_rule_t *rule_ptr = (firewall_rule_t *)malloc(sizeof(firewall_rule_t)); - rule_ptr->key = rule_nr; - strcpy(rule_ptr->source, EEPROM.readString(eeprom_address).c_str()); - eeprom_address += IP4ADDR_STRLEN_MAX; - strcpy(rule_ptr->destination, EEPROM.readString(eeprom_address).c_str()); - eeprom_address += IP4ADDR_STRLEN_MAX; - rule_ptr->protocol = static_cast(EEPROM.read(eeprom_address)); - eeprom_address += sizeof(firewall_protocol_t); - rule_ptr->target = static_cast(EEPROM.read(eeprom_address)); - eeprom_address += sizeof(firewall_target_t); - add_rule_to_firewall(rule_ptr); - log_i("%s, %s, %s, %s", - rule_ptr->source, - rule_ptr->destination, - protocol_to_string(rule_ptr->protocol), - target_to_string(rule_ptr->target)); -} - -void esp32Firewall::eeprom_read_firewall_rules() -{ - uint8_t eeprom_address = eeprom_start_firewall_rules; - for (uint8_t i = 1; i <= this->amount_of_rules; i++) - { - eeprom_read_firewall_rule(eeprom_address, i); - } -} - -void esp32Firewall::add_rule_to_firewall(firewall_rule_t *rule_ptr) -{ - firewall_rule_t *temp; - if (this->head == NULL) - { - this->head = rule_ptr; + store_settings_value("amount_of_rules", this->amount_of_rules); + store_firewall_rule(rule_ptr); + firewall_rule_t *temp; + if (this->head == NULL) + { + this->head = rule_ptr; + rule_ptr->next = NULL; + return; + } + temp = this->head; + while (temp->next != NULL) + { + temp = temp->next; + } + temp->next = rule_ptr; rule_ptr->next = NULL; return; } - temp = this->head; - while (temp->next != NULL) - { - temp = temp->next; - } - temp->next = rule_ptr; - rule_ptr->next = NULL; - return; -} -firewall_rule_t *esp32Firewall::get_rule_from_firewall(uint8_t key) -{ - firewall_rule_t *rule_ptr = this->head; - if (this->head == NULL) + firewall_rule_t *Firewall::get_rule_from_firewall(uint8_t key) { - return NULL; - } - while (rule_ptr->key != key) - { - if (rule_ptr->next == NULL) + firewall_rule_t *rule_ptr = this->head; + if (this->head == NULL) { return NULL; } - else + while (rule_ptr->key != key) { - rule_ptr = rule_ptr->next; + if (rule_ptr->next == NULL) + { + return NULL; + } + else + { + rule_ptr = rule_ptr->next; + } } + return rule_ptr; } - return rule_ptr; -} -bool esp32Firewall::delete_rule_from_firewall(uint8_t key) -{ - if (this->head == NULL) + bool Firewall::delete_rule_from_firewall(uint8_t key) { - return false; - } - firewall_rule_t *current_rule_ptr = this->head; - firewall_rule_t *previous_rule_ptr = NULL; - firewall_rule_t *temp = NULL; - while (current_rule_ptr->key != key) - { - if (current_rule_ptr->next == NULL) + if (this->head == NULL) { return false; } + firewall_rule_t *current_rule_ptr = this->head; + firewall_rule_t *previous_rule_ptr = NULL; + firewall_rule_t *temp = NULL; + while (current_rule_ptr->key != key) + { + if (current_rule_ptr->next == NULL) + { + return false; + } + else + { + previous_rule_ptr = current_rule_ptr; + current_rule_ptr = current_rule_ptr->next; + } + } + if (current_rule_ptr == this->head) + { + this->head = head->next; + temp = this->head; + } else { - previous_rule_ptr = current_rule_ptr; - current_rule_ptr = current_rule_ptr->next; + previous_rule_ptr->next = current_rule_ptr->next; + temp = previous_rule_ptr->next; + } + while (temp != NULL) + { + temp->key--; + temp = temp->next; + } + free(current_rule_ptr); + this->amount_of_rules--; + store_settings_value("amount_of_rules", this->amount_of_rules); + if (this->amount_of_rules != 0) + store_all_firewall_rules(head); + return true; + } + + String Firewall::protocol_to_string(firewall_protocol_t &protocol) + { + switch (protocol) + { + case FW_TCP: + return "TCP"; + case FW_UDP: + return "UDP"; + default: + return "ALL"; } } - if (current_rule_ptr == this->head) + + firewall_protocol_t Firewall::string_to_protocol(std::string &protocol) { - this->head = head->next; - temp = this->head; + if (protocol.compare("TCP") == 0) + return FW_TCP; + else if (protocol.compare("UDP") == 0) + return FW_UDP; + else + return FW_ALL; } - else + + String Firewall::target_to_string(firewall_target_t &target) { - previous_rule_ptr->next = current_rule_ptr->next; - temp = previous_rule_ptr->next; + switch (target) + { + case FW_REJECT: + return "REJECT"; + case FW_DROP: + return "DROP"; + default: + return "ACCEPT"; + } } - while (temp != NULL) + + firewall_target_t Firewall::string_to_target(std::string &target) { - temp->key--; - temp = temp->next; - } - free(current_rule_ptr); - this->amount_of_rules--; - this->eeprom_write_firewall_rules(); - return true; -} - -void esp32Firewall::setup_certificate() -{ - log_i("Creating the certificate..."); - this->certificate = new SSLCert(); - int createCertResult = createSelfSignedCert( - *this->certificate, - KEYSIZE_2048, - "CN=myesp32.local,O=Firewall,C=DE", - "20220101000000", - "20320101000000"); - if (createCertResult != 0) - { - log_e("Cerating certificate failed. Error Code = 0x%02X, check SSLCert.hpp for details", createCertResult); - while (true) - delay(500); - } - log_i("Creating the certificate was successful"); -} - -void esp32Firewall::setup_routing() -{ - ResourceNode *get_firewall_rule = new ResourceNode("/api/v1/firewall/*", "GET", std::bind(&esp32Firewall::get_firewall_rule_handler, this, std::placeholders::_1, std::placeholders::_2)); - ResourceNode *get_firewall_rules = new ResourceNode("/api/v1/firewall", "GET", std::bind(&esp32Firewall::get_firewall_rules_handler, this, std::placeholders::_1, std::placeholders::_2)); - ResourceNode *post_firewall = new ResourceNode("/api/v1/firewall", "POST", std::bind(&esp32Firewall::post_firewall_handler, this, std::placeholders::_1, std::placeholders::_2)); - ResourceNode *delete_firewall = new ResourceNode("/api/v1/firewall/*", "DELETE", std::bind(&esp32Firewall::delete_firewall_handler, this, std::placeholders::_1, std::placeholders::_2)); - ResourceNode *restart_device = new ResourceNode("/api/v1/device/restart", "GET", std::bind(&esp32Firewall::restart_device_handler, this, std::placeholders::_1, std::placeholders::_2)); - ResourceNode *not_found = new ResourceNode("", "GET", std::bind(&esp32Firewall::not_found_handler, this, std::placeholders::_1, std::placeholders::_2)); - this->firewall_api->registerNode(get_firewall_rule); - this->firewall_api->registerNode(get_firewall_rules); - this->firewall_api->registerNode(post_firewall); - this->firewall_api->registerNode(delete_firewall); - this->firewall_api->setDefaultNode(restart_device); - this->firewall_api->setDefaultNode(not_found); -} - -void esp32Firewall::json_generic_response(HTTPResponse *response, String serialized, const uint16_t response_code) -{ - response->setHeader("Content-Type", "application/json"); - response->setStatusCode(response_code); - response->println(serialized); -} - -void esp32Firewall::json_message_response(HTTPResponse *response, String message, const uint16_t response_code) -{ - response->setHeader("Content-Type", "application/json"); - response->setStatusCode(response_code); - StaticJsonDocument<96> json; - String serialized; - json["message"] = message; - serializeJson(json, serialized); - response->println(serialized); -} - -String esp32Firewall::construct_json_firewall_rule(firewall_rule_t *rule_ptr) -{ - StaticJsonDocument<256> doc; - doc["key"] = rule_ptr->key; - doc["source"] = rule_ptr->source; - doc["destination"] = rule_ptr->destination; - doc["protocol"] = protocol_to_string(rule_ptr->protocol); - doc["target"] = target_to_string(rule_ptr->target); - String response; - serializeJson(doc, response); - return response; -} - -String esp32Firewall::construct_json_firewall() -{ - firewall_rule_t *rule_ptr = this->head; - // Size for approx. 12 Rules - StaticJsonDocument<2048> doc; - String response; - doc["amount_of_rules"] = this->amount_of_rules; - JsonArray rules = doc.createNestedArray("rules"); - while (rule_ptr != NULL) - { - JsonObject rule = rules.createNestedObject(); - rule["key"] = rule_ptr->key; - rule["source"] = rule_ptr->source; - rule["destination"] = rule_ptr->destination; - rule["protocol"] = protocol_to_string(rule_ptr->protocol); - rule["target"] = target_to_string(rule_ptr->target); - rule_ptr = rule_ptr->next; - } - serializeJson(doc, response); - return response; -} - -void esp32Firewall::not_found_handler(HTTPRequest *request, HTTPResponse *response) -{ - this->json_message_response(response, "not found", 404); -} - -void esp32Firewall::restart_device_handler(HTTPRequest *request, HTTPResponse *response) -{ - this->json_message_response(response, "restarting device in 2 sec", 200); - sleep(2000); - esp_restart(); -} - -void esp32Firewall::get_firewall_rule_handler(HTTPRequest *request, HTTPResponse *response) -{ - ResourceParameters *params = request->getParams(); - int rule_number = atoi(params->getPathParameter(0).c_str()); - firewall_rule_t *rule_ptr = this->get_rule_from_firewall(rule_number); - if (rule_ptr == NULL) - { - this->json_message_response(response, "rule not found", 404); - } - else - { - response->setHeader("Content-Type", "application/json"); - response->setStatusCode(200); - response->print(this->construct_json_firewall_rule(rule_ptr)); - } -} - -void esp32Firewall::get_firewall_rules_handler(HTTPRequest *request, HTTPResponse *response) -{ - this->json_generic_response(response, this->construct_json_firewall(), 200); -} - -bool esp32Firewall::request_has_firewall_parameter(ResourceParameters *params) -{ - return params->isQueryParameterSet("source") || params->isQueryParameterSet("destination") || params->isQueryParameterSet("protocol") || params->isQueryParameterSet("target"); -} - -void esp32Firewall::post_firewall_handler(HTTPRequest *request, HTTPResponse *response) -{ - ResourceParameters *params = request->getParams(); - if (request_has_firewall_parameter(params)) - { - firewall_rule_t *rule_ptr = (firewall_rule_t *)malloc(sizeof(firewall_rule_t)); - rule_ptr->key = ++amount_of_rules; - - // carefully copying c-string that is shorter then the destination char-array length - std::string source; - params->getQueryParameter("source", source); - strcpy(rule_ptr->source, source.length() <= IPV4ADDRESS_LENGTH ? source.c_str() : ""); - std::string destination; - params->getQueryParameter("destination", destination); - strcpy(rule_ptr->destination, destination.length() <= IPV4ADDRESS_LENGTH ? destination.c_str() : ""); - - std::string protocol; - params->getQueryParameter("protocol", protocol); - rule_ptr->protocol = string_to_protocol(protocol); - std::string target; - params->getQueryParameter("target", target); - rule_ptr->target = string_to_target(target); - - this->add_rule_to_firewall(rule_ptr); - this->eeprom_write_firewall_rule(rule_ptr); - this->json_generic_response(response, this->construct_json_firewall_rule(rule_ptr), 200); - } - else - { - this->json_message_response(response, "not enough parameter", 400); - } -} - -void esp32Firewall::delete_firewall_handler(HTTPRequest *request, HTTPResponse *response) -{ - ResourceParameters *params = request->getParams(); - int rule_number = atoi(params->getPathParameter(0).c_str()); - if (this->delete_rule_from_firewall(rule_number)) - { - this->json_message_response(response, "firewall rule deleted", 200); - } - else - { - this->json_message_response(response, "cannot delete firewall rule", 500); + if (target.compare("REJECT") == 0) + return FW_REJECT; + else if (target.compare("DROP") == 0) + return FW_DROP; + else + return FW_ACCEPT; } } diff --git a/SourceCode/arduino/lib/Firewall/esp32Firewall.hpp b/SourceCode/arduino/lib/Firewall/esp32Firewall.hpp index 5dd9ae6..c03df2e 100644 --- a/SourceCode/arduino/lib/Firewall/esp32Firewall.hpp +++ b/SourceCode/arduino/lib/Firewall/esp32Firewall.hpp @@ -1,68 +1,31 @@ #ifndef ESP32_FIREWALL_HPP #define ESP32_FIREWALL_HPP -#include "Arduino.h" -#include "ArduinoJson.h" -#include "EEPROM.h" - -#include "HTTPSServer.hpp" -#include "SSLCert.hpp" -#include "HTTPRequest.hpp" -#include "HTTPResponse.hpp" - #include "FirewallTypes.h" +#include "esp32Storage.hpp" +#include "WString.h" -#define eeprom_start_firewall_rules 4 -using namespace httpsserver; - -class esp32Firewall +namespace firewall { - uint16_t eeprom_size = 512; - uint8_t amount_of_rules = 0; - uint8_t security_number = 93; - int eeprom_settings_head = 0; - int eeprom_rules_head = eeprom_start_firewall_rules; - struct firewall_rule *head = NULL; + class Firewall : public Storage + { + protected: + uint8_t amount_of_rules = 0; + struct firewall_rule *head = NULL; - HTTPSServer *firewall_api; - SSLCert *certificate; + void add_rule_to_firewall(firewall_rule_t *); + firewall_rule_t *get_rule_from_firewall(uint8_t); + bool delete_rule_from_firewall(uint8_t); - // Protocol / Target conversion - String protocol_to_string(firewall_protocol_t &); - firewall_protocol_t string_to_protocol(std::string &); - String target_to_string(firewall_target_t &); - firewall_target_t string_to_target(std::string &); + String protocol_to_string(firewall_protocol_t &protocol); + firewall_protocol_t string_to_protocol(std::string &protocol); + String target_to_string(firewall_target_t &target); + firewall_target_t string_to_target(std::string &target); - // EEPROM - void setup_eeprom(); - void eeprom_write_firewall_rule(firewall_rule_t *); - void eeprom_write_firewall_rules(); - void eeprom_read_firewall_rule(uint8_t &, uint8_t &); - void eeprom_read_firewall_rules(); - - // Firewall Actions - void add_rule_to_firewall(firewall_rule_t *); - firewall_rule_t *get_rule_from_firewall(uint8_t); - bool delete_rule_from_firewall(uint8_t); - - // Firewall-API Actions - void setup_certificate(); - void setup_routing(); - void json_generic_response(HTTPResponse *, String, const uint16_t); - void json_message_response(HTTPResponse *, String, const uint16_t); - String construct_json_firewall_rule(firewall_rule_t *); - String construct_json_firewall(); - void not_found_handler(HTTPRequest *, HTTPResponse *); - void restart_device_handler(HTTPRequest *, HTTPResponse *); - void get_firewall_rule_handler(HTTPRequest *, HTTPResponse *); - void get_firewall_rules_handler(HTTPRequest *, HTTPResponse *); - bool request_has_firewall_parameter(ResourceParameters *); - void post_firewall_handler(HTTPRequest *, HTTPResponse *); - void delete_firewall_handler(HTTPRequest *, HTTPResponse *); - -public: - esp32Firewall(const uint16_t = 8080); - void handle_firewall_api_clients(); -}; + public: + Firewall(); + ~Firewall(); + }; +} #endif diff --git a/SourceCode/arduino/lib/Firewall/esp32Storage.cpp b/SourceCode/arduino/lib/Firewall/esp32Storage.cpp new file mode 100644 index 0000000..cbdb75b --- /dev/null +++ b/SourceCode/arduino/lib/Firewall/esp32Storage.cpp @@ -0,0 +1,149 @@ +#include "esp32Storage.hpp" + +namespace firewall +{ + Storage::Storage() + { + this->mount_spiffs(); + } + + Storage::~Storage() + { + } + + void Storage::mount_spiffs() + { + if (!SPIFFS.begin(false)) + { + if (!SPIFFS.begin(true)) + { + log_e("SPIFFS cannot be mounted"); + while (true) + delay(500); + }; + } + log_i("SPIFFS mounted"); + } + + uint8_t Storage::retrieve_settings_value(const char *key) + { + uint8_t amount_of_rules; + + this->memory.begin("settings", true); + amount_of_rules = memory.getUChar(key, 0); + this->memory.end(); + + return amount_of_rules; + } + + void Storage::store_settings_value(const char *key, const uint8_t new_amount) + { + this->memory.begin("settings", false); + this->memory.putUChar(key, new_amount); + this->memory.end(); + } + + firewall_rule_t *Storage::retrieve_firewall_rule(const uint8_t key) + { + firewall_rule_t *rule_ptr = (firewall_rule_t *)malloc(sizeof(firewall_rule_t)); + rule_ptr->key = key; + + char rulename[9]; // fwRule99\n + sprintf(rulename, "fwRule%i", key); + + this->memory.begin(rulename, true); + strcpy(rule_ptr->source, this->memory.getString("source", "0.0.0.0").c_str()); + strcpy(rule_ptr->destination, this->memory.getString("destination", "0.0.0.0").c_str()); + rule_ptr->protocol = static_cast(this->memory.getUChar("protocol", FW_ALL)); + rule_ptr->target = static_cast(this->memory.getUChar("target", FW_REJECT)); + this->memory.end(); + + return rule_ptr; + } + + void Storage::store_all_firewall_rules(firewall_rule_t *head) + { + firewall_rule_t *temp = head; + while (temp != NULL) + { + store_firewall_rule(temp); + temp = temp->next; + } + } + + void Storage::store_firewall_rule(firewall_rule_t *rule_ptr) + { + char rulename[9]; // fwRule99\n + sprintf(rulename, "fwRule%i", rule_ptr->key); + + this->memory.begin(rulename, false); + this->memory.putString("source", rule_ptr->source); + this->memory.putString("destination", rule_ptr->destination); + this->memory.putUChar("protocol", rule_ptr->protocol); + this->memory.putUChar("target", rule_ptr->target); + this->memory.end(); + } + + httpsserver::SSLCert *Storage::retrieve_certificate() + { + File keyFile = SPIFFS.open("/key.der"); + File certFile = SPIFFS.open("/cert.der"); + if (!keyFile || !certFile || keyFile.size() == 0 || certFile.size() == 0) + { + log_w("No certificate found in SPIFFS"); + return NULL; + } + size_t keySize = keyFile.size(); + size_t certSize = certFile.size(); + + uint8_t *keyBuffer = new uint8_t[keySize]; + if (keyBuffer == NULL) + { + log_w("Not enough memory to load privat key"); + return NULL; + } + uint8_t *certBuffer = new uint8_t[certSize]; + if (certBuffer == NULL) + { + delete[] keyBuffer; + log_w("Not enough memory to load certificate"); + return NULL; + } + keyFile.read(keyBuffer, keySize); + certFile.read(certBuffer, certSize); + + keyFile.close(); + certFile.close(); + return new httpsserver::SSLCert(certBuffer, certSize, keyBuffer, keySize); + } + + void Storage::store_certificate(httpsserver::SSLCert *certificate) + { + File keyFile = SPIFFS.open("/key.der"); + File certFile = SPIFFS.open("/cert.der"); + bool failure = false; + + keyFile = SPIFFS.open("/key.der", FILE_WRITE); + if (!keyFile || !keyFile.write(certificate->getPKData(), certificate->getPKLength())) + { + log_w("Could not write /key.der"); + failure = true; + } + if (keyFile) + keyFile.close(); + + certFile = SPIFFS.open("/cert.der", FILE_WRITE); + if (!certFile || !certFile.write(certificate->getCertData(), certificate->getCertLength())) + { + log_w("Could not write /key.der"); + failure = true; + } + if (certFile) + certFile.close(); + + if (failure) + { + log_w("Certificate could not be stored permanently, generating new certificate on reboot..."); + } + } +} diff --git a/SourceCode/arduino/lib/Firewall/esp32Storage.hpp b/SourceCode/arduino/lib/Firewall/esp32Storage.hpp new file mode 100644 index 0000000..cd88378 --- /dev/null +++ b/SourceCode/arduino/lib/Firewall/esp32Storage.hpp @@ -0,0 +1,34 @@ +#ifndef ESP32_STORAGE_HPP +#define ESP32_STORAGE_HPP + +#include "Preferences.h" +#include "SPIFFS.h" +#include "FirewallTypes.h" +#include "SSLCert.hpp" + +namespace firewall +{ + class Storage + { + private: + Preferences memory; + void mount_spiffs(); + + protected: + uint8_t retrieve_settings_value(const char *); + void store_settings_value(const char *, const uint8_t); + + firewall_rule_t *retrieve_firewall_rule(const uint8_t); + void store_all_firewall_rules(firewall_rule_t *); + void store_firewall_rule(firewall_rule_t *); + + httpsserver::SSLCert *retrieve_certificate(); + void store_certificate(httpsserver::SSLCert *); + + public: + Storage(); + ~Storage(); + }; +} + +#endif diff --git a/SourceCode/arduino/platformio.ini b/SourceCode/arduino/platformio.ini index 823bfc9..8ea22a8 100644 --- a/SourceCode/arduino/platformio.ini +++ b/SourceCode/arduino/platformio.ini @@ -15,8 +15,7 @@ framework = arduino monitor_speed = 115200 build_flags = -DCORE_DEBUG_LEVEL=3 -lib_deps = - bblanchon/ArduinoJson@^6.19.4 +lib_deps = bblanchon/ArduinoJson@^6.19.4 [env:esp32-dev] platform = espressif32 @@ -25,5 +24,4 @@ framework = arduino monitor_speed = 115200 build_flags = -DCORE_DEBUG_LEVEL=3 -lib_deps = - bblanchon/ArduinoJson@^6.19.4 +lib_deps = bblanchon/ArduinoJson@^6.19.4 diff --git a/SourceCode/arduino/src/main.cpp b/SourceCode/arduino/src/main.cpp index 014c894..9a1af17 100644 --- a/SourceCode/arduino/src/main.cpp +++ b/SourceCode/arduino/src/main.cpp @@ -1,9 +1,8 @@ #include "theSecrets.h" #include "WiFi.h" -#include "esp32Firewall.hpp" +#include "esp32API.hpp" -const char *esp_ip_address; -esp32Firewall *firewall; +firewall::API *firewall_api; void setup_wifi() { @@ -17,17 +16,16 @@ void setup_wifi() delay(2000); log_d("Connecting... (%i/%i)", retries++, max_retries); } - esp_ip_address = WiFi.localIP().toString().c_str(); - log_i("Connected, IP Address: %s", esp_ip_address); + log_i("Connected, IP Address: %s", WiFi.localIP().toString().c_str()); } void setup() { setup_wifi(); - firewall = new esp32Firewall; + firewall_api = new firewall::API; } void loop() { - firewall->handle_firewall_api_clients(); + firewall_api->handle_clients(); } \ No newline at end of file