diff --git a/ESPFirewall/app.py b/ESPFirewall/app.py new file mode 100644 index 0000000..021383d --- /dev/null +++ b/ESPFirewall/app.py @@ -0,0 +1,36 @@ +import socket +import sys +import getopt +import argparse + + +def main(argv): + parser = argparse.ArgumentParser( + description='Send socket message to ip and port.') + parser.add_argument('-i', '--ip', + default='localhost', + dest='ip', + help='Provide destination ip. Defaults to localhost', + type=str + ) + parser.add_argument('-p', '--port', + default=80, + dest='port', + help='Provide destination port. Defaults to 80', + type=int + ) + + args = parser.parse_args() + print(f'Sending message to {args.ip}:{args.port}') + sock = socket.socket() + try: + sock.connect((args.ip, args.port)) + sock.send("test".encode()) + print("Message sent.") + sock.close() + except: + print("Cannot send message...") + + +if __name__ == "__main__": + main(sys.argv[1:]) diff --git a/ESPFirewall/lib/Firewall/library.json b/ESPFirewall/lib/Firewall/library.json deleted file mode 100644 index bec6af0..0000000 --- a/ESPFirewall/lib/Firewall/library.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "name": "firewall", - "license": "MIT", - "version": "0.0.1", - "frameworks": "arduino", - "platforms": ["espressif32"], - "dependencies": { - "bblanchon/ArduinoJson": "^6.19.4", - "external-repo": "https://github.com/fhessel/esp32_https_server/pull/91" - } -} diff --git a/ESPFirewall/lib/Firewall/src/API.cpp b/ESPFirewall/lib/Firewall/src/API.cpp index aa6ab10..5fefc17 100644 --- a/ESPFirewall/lib/Firewall/src/API.cpp +++ b/ESPFirewall/lib/Firewall/src/API.cpp @@ -2,10 +2,11 @@ namespace fw { - API::API(const char *cert, const char *key, const char *username, const char *password, const String ip, const uint16_t port) + API::API(fw::Firewall *firewall, const char *cert, const char *key, const char *username, const char *password, const uint16_t port) { - this->server_ip = ip; - this->server_port = port; + this->firewall = firewall; + this->api_ip = WiFi.localIP().toString(); + this->api_port = port; if (this->setup_auth(username, password) == ERROR) endless_loop(); #ifdef ESP32 @@ -32,9 +33,9 @@ namespace fw String API::get_url_base() { #ifdef ESP32 - return "http://" + this->server_ip + ":" + this->server_port; + return "http://" + this->api_ip + ":" + this->api_port; #elif defined(ESP8266) - return "https://" + this->server_ip + ":" + this->server_port; + return "https://" + this->api_ip + ":" + this->api_port; #endif } @@ -63,7 +64,7 @@ namespace fw } else { - this->json_message_response("please provide username and password", 403); + this->json_message_response("unauthorised", 403); return DENIED; } } @@ -74,23 +75,20 @@ namespace fw this->server->getServer().setRSACert(new BearSSL::X509List(cert), new BearSSL::PrivateKey(key)); this->server->getServer().setCache(serverCache); #endif - this->server->on("/firewall", HTTP_GET, std::bind(&API::get_firewall_rules_handler, this)); - add_api_endpoint("/firewall", "GET", "Get all Firewall Rules"); - - this->server->on(UriRegex("/firewall/([0-9]+)"), HTTP_GET, std::bind(&API::get_firewall_rule_handler, this)); - add_api_endpoint("/firewall/1", "GET", "Get Firewall Rule by key"); - - this->server->on("/firewall", HTTP_POST, std::bind(&API::post_firewall_handler, this)); - add_api_endpoint("/firewall", "POST", "Create Firewall Rule"); - - this->server->on(UriRegex("/firewall/([0-9]+)"), HTTP_DELETE, std::bind(&API::delete_firewall_handler, this)); - add_api_endpoint("/firewall/1", "DELETE", "Delete Firewall Rule by key"); - - this->server->on("/api", HTTP_GET, std::bind(&API::api_endpoints_handler, this)); + this->server->on("/api/firewall/rules", HTTP_GET, std::bind(&API::get_firewall_rules_handler, this)); + this->server->on(UriRegex("/api/firewall/rules/([0-9]+)"), HTTP_GET, std::bind(&API::get_firewall_rule_handler, this)); + this->server->on("/api/firewall/rules", HTTP_POST, std::bind(&API::post_firewall_handler, this)); + this->server->on(UriRegex("/api/firewall/rules/([0-9]+)"), HTTP_DELETE, std::bind(&API::delete_firewall_handler, this)); + this->server->on("/api", HTTP_GET, std::bind(&API::get_endpoint_list_handler, this)); this->server->onNotFound(std::bind(&API::not_found_handler, this)); + + add_endpoint_to_list("/api/firewall/rules", "GET", "Get all Firewall Rules"); + add_endpoint_to_list("/api/firewall/rules/", "GET", "Get Firewall Rule by key"); + add_endpoint_to_list("/api/firewall/rules", "POST", "Create Firewall Rule"); + add_endpoint_to_list("/api/firewall/rules/", "DELETE", "Delete Firewall Rule by key"); } - void API::add_api_endpoint(const String uri, const char *method, const char *description) + void API::add_endpoint_to_list(const String uri, const char *method, const char *description) { api_endpoint_t *temp; const String url = get_url_base() + uri; @@ -123,9 +121,9 @@ namespace fw 404); } - void API::api_endpoints_handler() + void API::get_endpoint_list_handler() { - this->json_generic_response(this->construct_json_api(), 200); + this->json_array_response(this->construct_json_api(), 200); } void API::get_firewall_rule_handler() @@ -134,7 +132,7 @@ namespace fw return; String param = this->server->pathArg(0); int rule_number = atoi(param.c_str()); - firewall_rule_t *rule_ptr = get_rule_from_firewall(rule_number); + firewall_rule_t *rule_ptr = firewall->get_rule_from_firewall(rule_number); if (rule_ptr == NULL) this->json_message_response("rule does not exist", 404); else @@ -145,21 +143,22 @@ namespace fw { if (this->check_auth() == DENIED) return; - this->json_generic_response(this->construct_json_firewall(), 200); + this->json_array_response(this->construct_json_firewall(), 200); } void API::post_firewall_handler() { if (this->check_auth() == DENIED) return; - if (request_has_firewall_parameter()) + if (request_has_all_firewall_parameter()) { - firewall_rule_t *rule_ptr = add_rule_to_firewall( - this->server->arg("source"), - this->server->arg("destination"), - this->server->arg("protocol"), - this->server->arg("target")); - this->json_generic_response(this->construct_json_firewall_rule(rule_ptr), 200); + String args[IPV4ADDRESS_LENGTH] = {}; + for (uint8_t i = 0; i < firewall_fields_amount; i++) + { + args[i] = this->server->arg(firewall_fields[i]); + } + firewall_rule_t *rule_ptr = firewall->add_rule_to_firewall(args); + this->json_generic_response(this->construct_json_firewall_rule(rule_ptr), 201); } else { @@ -173,22 +172,24 @@ namespace fw return; String param = this->server->pathArg(0); int rule_number = atoi(param.c_str()); - if (delete_rule_from_firewall(rule_number) == SUCCESS) + if (firewall->delete_rule_from_firewall(rule_number) == SUCCESS) this->json_message_response("firewall rule deleted", 200); else this->json_message_response("cannot delete firewall rule", 500); } - bool API::request_has_firewall_parameter() + bool API::request_has_all_firewall_parameter() { if (!this->server->args()) return false; else { - return this->server->hasArg("source") || - this->server->hasArg("destination") || - this->server->hasArg("protocol") || - this->server->hasArg("target"); + for (uint8_t i = 0; i < firewall_fields_amount; i++) + { + if (i != KEY && !this->server->hasArg(firewall_fields[i])) + return false; + } + return true; } } @@ -201,42 +202,45 @@ namespace fw return json_string; } - String API::json_new_attribute(String key, uint8_t value, bool last) + String API::json_new_attribute(String key, uint32_t value, bool last) { return json_new_attribute(key, String(value), last); } void API::json_generic_response(String serialized_string, const uint16_t response_code) { - this->server->send( - response_code, - "application/json; charset=utf-8", - construct_json_begin(response_code) + "\"result\": [" + serialized_string + "]}"); + this->server->send(response_code, json_response_type, serialized_string); + } + + void API::json_array_response(String serialized_string, const uint16_t response_code) + { + this->server->send(response_code, json_response_type, "[" + serialized_string + "]"); } void API::json_message_response(String message, const uint16_t response_code) { - String serialized_string = construct_json_begin(response_code); + String serialized_string = "{"; serialized_string += json_new_attribute("message", message, true); serialized_string += "}"; - this->server->send(response_code, "application/json; charset=utf-8", serialized_string); + this->server->send(response_code, json_response_type, serialized_string); } String API::construct_json_firewall_rule(firewall_rule_t *rule_ptr) { String serialized_string = "{"; - serialized_string += json_new_attribute("key", rule_ptr->key); - serialized_string += json_new_attribute("source", rule_ptr->source); - serialized_string += json_new_attribute("destination", rule_ptr->destination); - serialized_string += json_new_attribute("protocol", protocol_to_string(rule_ptr->protocol)); - serialized_string += json_new_attribute("target", target_to_string(rule_ptr->target), true); + serialized_string += json_new_attribute(firewall_fields[KEY], rule_ptr->key); + serialized_string += json_new_attribute(firewall_fields[IP], rule_ptr->ip); + serialized_string += json_new_attribute(firewall_fields[PORT_FROM], rule_ptr->port_from); + serialized_string += json_new_attribute(firewall_fields[PORT_TO], rule_ptr->port_to); + serialized_string += json_new_attribute(firewall_fields[PROTOCOL], protocol_to_string(rule_ptr->protocol)); + serialized_string += json_new_attribute(firewall_fields[TARGET], target_to_string(rule_ptr->target), true); serialized_string += "}"; return serialized_string; } String API::construct_json_firewall() { - firewall_rule_t *rule_ptr = rule_head; + firewall_rule_t *rule_ptr = firewall->get_rule_head(); String serialized_string; while (rule_ptr != NULL) { @@ -271,11 +275,4 @@ namespace fw } return serialized_string; } - - String API::construct_json_begin(const uint16_t response_code) - { - String serialized_string = "{"; - serialized_string += json_new_attribute("status", response_code_to_string(response_code)); - return serialized_string; - } } diff --git a/ESPFirewall/lib/Firewall/src/API.hpp b/ESPFirewall/lib/Firewall/src/API.hpp index effac7d..ee50ed2 100644 --- a/ESPFirewall/lib/Firewall/src/API.hpp +++ b/ESPFirewall/lib/Firewall/src/API.hpp @@ -8,22 +8,18 @@ #endif #include "uri/UriRegex.h" - -#include "Rules.hpp" +#include "Firewall.hpp" #include "Utils.hpp" namespace fw { - typedef struct api_endpoints + class API { - char uri[40]; - char method[7]; - char description[30]; - struct api_endpoints *next; - } api_endpoint_t; + public: + API(Firewall *, const char *cert, const char *key, const char *username, const char *password, const uint16_t port = 8080); + ~API(); + void handle_client(); - class API : public Rules - { private: #ifdef ESP32 WebServer *server; @@ -31,41 +27,37 @@ namespace fw BearSSL::ESP8266WebServerSecure *server; BearSSL::ServerSessions *serverCache; #endif + Firewall *firewall; credential_t credentials; api_endpoint_t *endpoint_head = NULL; + String api_ip = "0.0.0.0"; + uint16_t api_port; + String json_response_type = "application/json; charset=utf-8"; + String get_url_base(); ok_t setup_auth(const char *username, const char *password); auth_t check_auth(); void setup_routing(const char *cert, const char *key); - void add_api_endpoint(const String uri, const char *method, const char *description); + void add_endpoint_to_list(const String uri, const char *method, const char *description); + void not_found_handler(); + void get_endpoint_list_handler(); void get_firewall_rule_handler(); void get_firewall_rules_handler(); void post_firewall_handler(); void delete_firewall_handler(); - void not_found_handler(); - void api_endpoints_handler(); - bool request_has_firewall_parameter(); + bool request_has_all_firewall_parameter(); String json_new_attribute(String key, String value, bool last = false); - String json_new_attribute(String key, uint8_t value, bool last = false); + String json_new_attribute(String key, uint32_t value, bool last = false); void json_generic_response(String serialized_string, const uint16_t response_code); + void json_array_response(String serialized_string, const uint16_t response_code); void json_message_response(String message, const uint16_t response_code); - String construct_json_firewall_rule(firewall_rule_t *); + + String construct_json_firewall_rule(firewall_rule_t *rule_ptr); String construct_json_firewall(); - String construct_json_api_endpoint(api_endpoint_t *); + String construct_json_api_endpoint(api_endpoint_t *api_ptr); String construct_json_api(); - String construct_json_begin(const uint16_t response_code); - - protected: - String server_ip; - uint16_t server_port; - void handle_client(); - String get_url_base(); - - public: - API(const char *cert, const char *key, const char *username, const char *password, const String ip, const uint16_t port); - ~API(); }; } diff --git a/ESPFirewall/lib/Firewall/src/Firewall.cpp b/ESPFirewall/lib/Firewall/src/Firewall.cpp new file mode 100644 index 0000000..45c6bf1 --- /dev/null +++ b/ESPFirewall/lib/Firewall/src/Firewall.cpp @@ -0,0 +1,133 @@ +#include "Firewall.hpp" + +namespace fw +{ + Firewall::Firewall() + { + this->amount_of_rules = retrieve_amount_of_rules(); + for (uint8_t i = 1; i <= this->amount_of_rules; i++) + { + firewall_rule_t *rule_ptr = retrieve_firewall_rule(i); + this->add_rule_to_firewall(rule_ptr, false); + } + } + + Firewall::~Firewall() + { + } + + firewall_rule_t *Firewall::get_rule_head() + { + return this->rule_head; + } + + void Firewall::add_rule_to_firewall(firewall_rule_t *rule_ptr, const bool save_in_eeprom) + { + store_amount_of_rules(this->amount_of_rules); + if (save_in_eeprom) + Storage::store_firewall_rule(rule_ptr); + if (this->rule_head == NULL) + { + this->rule_head = rule_ptr; + rule_ptr->next = NULL; + return; + } + firewall_rule_t *current_rule; + current_rule = this->rule_head; + while (current_rule->next != NULL) + current_rule = current_rule->next; + current_rule->next = rule_ptr; + rule_ptr->next = NULL; + } + + firewall_rule_t *Firewall::add_rule_to_firewall(String *args) + { + firewall_rule_t *rule_ptr = (firewall_rule_t *)malloc(sizeof(firewall_rule_t)); + rule_ptr->key = ++this->amount_of_rules; + + strncpy(rule_ptr->ip, args[IP].c_str(), sizeof(rule_ptr->ip)); + rule_ptr->port_from = args[PORT_FROM].toInt(); + rule_ptr->port_to = args[PORT_TO].toInt(); + rule_ptr->protocol = string_to_protocol(args[PROTOCOL]); + rule_ptr->target = string_to_target(args[TARGET]); + + add_rule_to_firewall(rule_ptr); + return rule_ptr; + } + + firewall_rule_t *Firewall::get_rule_from_firewall(const uint8_t key) + { + firewall_rule_t *rule_ptr = this->rule_head; + if (this->rule_head == NULL) + return NULL; + while (rule_ptr->key != key) + { + if (rule_ptr->next == NULL) + return NULL; + else + rule_ptr = rule_ptr->next; + } + return rule_ptr; + } + + ok_t Firewall::delete_rule_from_firewall(const uint8_t key) + { + if (this->rule_head == NULL) + return NO_ACTION; + firewall_rule_t *current_rule = this->rule_head; + firewall_rule_t *previous_rule = NULL; + firewall_rule_t *temp = NULL; + while (current_rule->key != key) + { + if (current_rule->next == NULL) + return NO_ACTION; + else + { + previous_rule = current_rule; + current_rule = current_rule->next; + } + } + if (current_rule == this->rule_head) + { + this->rule_head = rule_head->next; + temp = this->rule_head; + } + else + { + previous_rule->next = current_rule->next; + temp = previous_rule->next; + } + while (temp != NULL) + { + temp->key--; + temp = temp->next; + } + free(current_rule); + this->amount_of_rules--; + Storage::store_amount_of_rules(this->amount_of_rules); + if (this->amount_of_rules != 0) + Storage::store_all_firewall_rules(rule_head); + return SUCCESS; + } + + bool Firewall::is_included_in_firewall(String &ip, const uint32_t &port) + { + firewall_rule_t *rule_ptr = this->rule_head; + while (rule_ptr != NULL) + { + if (ip == String(rule_ptr->ip) && + is_in_range(port, rule_ptr->port_from, rule_ptr->port_to) && + rule_ptr->target != TARGET_ACCEPT) + return true; + rule_ptr = rule_ptr->next; + } + return false; + } + + bool Firewall::is_client_allowed(WiFiClient client) + { + String ip = client.remoteIP().toString(); + const uint32_t port = client.remotePort(); + return !is_included_in_firewall(ip, port); + } +} diff --git a/ESPFirewall/lib/Firewall/src/Firewall.hpp b/ESPFirewall/lib/Firewall/src/Firewall.hpp index bbd3b8f..47cc64d 100644 --- a/ESPFirewall/lib/Firewall/src/Firewall.hpp +++ b/ESPFirewall/lib/Firewall/src/Firewall.hpp @@ -1,26 +1,31 @@ -#ifndef FIREWALL_HPP -#define FIREWALL_HPP +#ifndef ESP32_FIREWALL_HPP +#define ESP32_FIREWALL_HPP -#include "API.hpp" +#include "Utils.hpp" +#include "Storage.hpp" +#include "WiFiClient.h" namespace fw { - class Firewall : public API + class Firewall : public Storage { - private: public: - Firewall(const char *, const char *, const char *, const char *, const String ip, const uint16_t = 8080); + Firewall(); ~Firewall(); - void handle_api_client(); - }; - Firewall::Firewall(const char *cert, const char *key, const char *username, const char *password, const String ip, const uint16_t port) - : API(cert, key, username, password, ip, port) {} - Firewall::~Firewall() {} - void Firewall::handle_api_client() - { - handle_client(); - } + firewall_rule_t *get_rule_head(); + void add_rule_to_firewall(firewall_rule_t *rule_ptr, const bool save_in_eeprom = true); + firewall_rule_t *add_rule_to_firewall(String *args); + firewall_rule_t *get_rule_from_firewall(const uint8_t key); + ok_t delete_rule_from_firewall(const uint8_t key); + + bool is_included_in_firewall(String &ip, const uint32_t &port); + bool is_client_allowed(WiFiClient client); + + protected: + uint8_t amount_of_rules = 0; + firewall_rule_t *rule_head = NULL; + }; } #endif diff --git a/ESPFirewall/lib/Firewall/src/Rules.cpp b/ESPFirewall/lib/Firewall/src/Rules.cpp deleted file mode 100644 index e2f804e..0000000 --- a/ESPFirewall/lib/Firewall/src/Rules.cpp +++ /dev/null @@ -1,116 +0,0 @@ -#include "Rules.hpp" - -namespace fw -{ - Rules::Rules() - { - this->amount_of_rules = retrieve_settings_value("amount_of_rules"); - Serial.print("Available Firewall Rules: "); - Serial.println(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); - } - } - - Rules::~Rules() - { - } - - void Rules::add_rule_to_firewall(firewall_rule_t *rule_ptr) - { - store_settings_value("amount_of_rules", this->amount_of_rules); - store_firewall_rule(rule_ptr); - firewall_rule_t *temp; - if (this->rule_head == NULL) - { - this->rule_head = rule_ptr; - rule_ptr->next = NULL; - return; - } - temp = this->rule_head; - while (temp->next != NULL) - { - temp = temp->next; - } - temp->next = rule_ptr; - rule_ptr->next = NULL; - } - - firewall_rule_t *Rules::add_rule_to_firewall(String source, String destination, String protocol, String target) - { - firewall_rule_t *rule_ptr = (firewall_rule_t *)malloc(sizeof(firewall_rule_t)); - rule_ptr->key = ++amount_of_rules; - - strncpy(rule_ptr->source, source.c_str(), sizeof(rule_ptr->source)); - strncpy(rule_ptr->destination, destination.c_str(), sizeof(rule_ptr->destination)); - - rule_ptr->protocol = string_to_protocol(protocol); - rule_ptr->target = string_to_target(target); - - add_rule_to_firewall(rule_ptr); - return rule_ptr; - } - - firewall_rule_t *Rules::get_rule_from_firewall(uint8_t key) - { - firewall_rule_t *rule_ptr = this->rule_head; - if (this->rule_head == NULL) - { - return NULL; - } - while (rule_ptr->key != key) - { - if (rule_ptr->next == NULL) - { - return NULL; - } - else - { - rule_ptr = rule_ptr->next; - } - } - return rule_ptr; - } - - ok_t Rules::delete_rule_from_firewall(uint8_t key) - { - if (this->rule_head == NULL) - return NO_ACTION; - firewall_rule_t *current_rule_ptr = this->rule_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 NO_ACTION; - else - { - previous_rule_ptr = current_rule_ptr; - current_rule_ptr = current_rule_ptr->next; - } - } - if (current_rule_ptr == this->rule_head) - { - this->rule_head = rule_head->next; - temp = this->rule_head; - } - else - { - 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(rule_head); - return SUCCESS; - } -} diff --git a/ESPFirewall/lib/Firewall/src/Rules.hpp b/ESPFirewall/lib/Firewall/src/Rules.hpp deleted file mode 100644 index 1656573..0000000 --- a/ESPFirewall/lib/Firewall/src/Rules.hpp +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef ESP32_FIREWALL_HPP -#define ESP32_FIREWALL_HPP - -#include "Utils.hpp" -#include "Storage.hpp" - -namespace fw -{ - class Rules : public Storage - { - protected: - uint8_t amount_of_rules = 0; - firewall_rule_t *rule_head = NULL; - - void add_rule_to_firewall(firewall_rule_t *); - firewall_rule_t *add_rule_to_firewall(String source, String destination, String protocol, String target); - firewall_rule_t *get_rule_from_firewall(uint8_t); - ok_t delete_rule_from_firewall(uint8_t); - - public: - Rules(); - ~Rules(); - }; -} - -#endif diff --git a/ESPFirewall/lib/Firewall/src/Storage.cpp b/ESPFirewall/lib/Firewall/src/Storage.cpp index 99fea25..4504ae4 100644 --- a/ESPFirewall/lib/Firewall/src/Storage.cpp +++ b/ESPFirewall/lib/Firewall/src/Storage.cpp @@ -4,11 +4,12 @@ namespace fw { Storage::Storage() { -#ifdef ESP32 - if (this->mount_spiffs() == ERROR) - endless_loop(); -#elif defined(ESP8266) - this->setup_eeprom(); +#if defined(ESP8266) + this->max_rules = 15; + this->eeprom_amount_of_rules = 0; + this->eeprom_rules_head = 1; + this->eeprom_size = this->max_rules * sizeof(firewall_rule_t) + eeprom_rules_head; + EEPROM.begin(this->eeprom_size); #endif } @@ -16,83 +17,41 @@ namespace fw { } - ok_t Storage::mount_spiffs() - { -#ifdef ESP32 - if (!SPIFFS.begin(false)) - { - if (!SPIFFS.begin(true)) - { - Serial.println("SPIFFS cannot be mounted"); - return ERROR; - }; - } - return SUCCESS; -#elif defined(ESP8266) - return NO_ACTION; -#endif - } - - void Storage::setup_eeprom() - { -#ifdef ESP8266 - EEPROM.begin(this->eeprom_size); -#endif - } - uint16_t Storage::eeprom_rule_position(uint8_t key) { -#ifdef ESP8266 - firewall_rule_t rule; - uint8_t total_space_needed = 0; - total_space_needed += sizeof(rule.source); - total_space_needed += sizeof(rule.destination); - total_space_needed += sizeof(rule.target); - total_space_needed += sizeof(rule.protocol); - // key-1 because key will be in range 1-255, but we need 1 less for multiplication - return eeprom_rules_head + (key - 1) * total_space_needed; -#elif defined(ESP32) +#ifdef ESP32 return 0; +#elif defined(ESP8266) + return eeprom_rules_head + (key - 1) * sizeof(firewall_rule_t); #endif } - uint8_t Storage::retrieve_settings_value(const char *key) + uint8_t Storage::retrieve_amount_of_rules() { #ifdef ESP32 - uint8_t value; - this->memory.begin("settings", true); - value = memory.getUChar(key, 0); + const uint8_t value = memory.getUChar("amount_of_rules", 0); this->memory.end(); return value; #elif defined(ESP8266) - if (strncmp("amount_of_rules", key, 16) == 0) - { - uint8_t security_number = EEPROM.read(this->eeprom_settings_head); - uint8_t amount_of_rules = EEPROM.read(this->eeprom_amout_of_rules_head); + const uint8_t amount_of_rules = EEPROM.read(this->eeprom_amount_of_rules); - if (amount_of_rules > 50 || security_number != this->security_number) - return 0; - return amount_of_rules; - } - return 0; + if (amount_of_rules > this->max_rules) + return 0; + return amount_of_rules; #endif } - void Storage::store_settings_value(const char *key, const uint8_t new_amount) + void Storage::store_amount_of_rules(const uint8_t new_amount) { #ifdef ESP32 this->memory.begin("settings", false); - this->memory.putUChar(key, new_amount); + this->memory.putUChar("amount_of_rules", new_amount); this->memory.end(); #elif defined(ESP8266) - if (strncmp("amount_of_rules", key, 16) == 0) - { - EEPROM.write(this->eeprom_settings_head, this->security_number); - EEPROM.write(this->eeprom_amout_of_rules_head, new_amount); - EEPROM.commit(); - } + EEPROM.put(this->eeprom_amount_of_rules, new_amount); + EEPROM.commit(); #endif } @@ -105,29 +64,21 @@ namespace fw sprintf(rulename, "fwRule%i", key); this->memory.begin(rulename, true); - strncpy(rule_ptr->source, this->memory.getString("source", "0.0.0.0").c_str(), sizeof(rule_ptr->source)); - strncpy(rule_ptr->destination, this->memory.getString("destination", "0.0.0.0").c_str(), sizeof(rule_ptr->source)); - rule_ptr->protocol = static_cast(this->memory.getUChar("protocol", PROTOCOL_ALL)); - rule_ptr->target = static_cast(this->memory.getUChar("target", TARGET_REJECT)); + strncpy(rule_ptr->ip, this->memory.getString(firewall_fields[IP], "0.0.0.0").c_str(), sizeof(rule_ptr->ip)); + rule_ptr->port_from = this->memory.getULong(firewall_fields[PORT_FROM], 0); + rule_ptr->port_to = this->memory.getULong(firewall_fields[PORT_TO], 0); + rule_ptr->protocol = static_cast(this->memory.getUChar(firewall_fields[PROTOCOL], PROTOCOL_ALL)); + rule_ptr->target = static_cast(this->memory.getUChar(firewall_fields[TARGET], TARGET_REJECT)); this->memory.end(); #elif defined(ESP8266) uint16_t eespom_position = eeprom_rule_position(key); - const char source[IPV4ADDRESS_LENGTH] = ""; - const char destination[IPV4ADDRESS_LENGTH] = ""; - EEPROM.get(eespom_position, source); - strncpy(rule_ptr->source, source, sizeof(rule_ptr->source)); - eespom_position += sizeof(rule_ptr->source); - - EEPROM.get(eespom_position, destination); - strncpy(rule_ptr->destination, destination, sizeof(rule_ptr->destination)); - eespom_position += sizeof(rule_ptr->destination); - - rule_ptr->protocol = static_cast(EEPROM.read(eespom_position)); - eespom_position += sizeof(rule_ptr->protocol); - - rule_ptr->target = static_cast(EEPROM.read(eespom_position)); + EEPROM.get(eespom_position, rule_ptr->ip); + EEPROM.get(eespom_position += sizeof(rule_ptr->ip), rule_ptr->port_from); + EEPROM.get(eespom_position += sizeof(rule_ptr->port_from), rule_ptr->port_to); + EEPROM.get(eespom_position += sizeof(rule_ptr->port_to), rule_ptr->protocol); + EEPROM.get(eespom_position += sizeof(rule_ptr->protocol), rule_ptr->target); #endif return rule_ptr; } @@ -151,22 +102,21 @@ namespace fw 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.putString(firewall_fields[IP], rule_ptr->ip); + this->memory.putULong(firewall_fields[PORT_FROM], rule_ptr->port_from); + this->memory.putULong(firewall_fields[PORT_TO], rule_ptr->port_to); + this->memory.putUChar(firewall_fields[PROTOCOL], rule_ptr->protocol); + this->memory.putUChar(firewall_fields[TARGET], rule_ptr->target); this->memory.end(); #elif defined(ESP8266) uint16_t eespom_position = eeprom_rule_position(rule_ptr->key); - EEPROM.put(eespom_position, rule_ptr->source); - eespom_position += sizeof(rule_ptr->source); - EEPROM.put(eespom_position, rule_ptr->destination); - eespom_position += sizeof(rule_ptr->destination); - EEPROM.put(eespom_position, rule_ptr->protocol); - eespom_position += sizeof(rule_ptr->protocol); - EEPROM.put(eespom_position, rule_ptr->target); + EEPROM.put(eespom_position, rule_ptr->ip); + EEPROM.put(eespom_position += sizeof(rule_ptr->ip), rule_ptr->port_from); + EEPROM.put(eespom_position += sizeof(rule_ptr->port_from), rule_ptr->port_to); + EEPROM.put(eespom_position += sizeof(rule_ptr->port_to), rule_ptr->protocol); + EEPROM.put(eespom_position += sizeof(rule_ptr->protocol), rule_ptr->target); EEPROM.commit(); #endif diff --git a/ESPFirewall/lib/Firewall/src/Storage.hpp b/ESPFirewall/lib/Firewall/src/Storage.hpp index e5996ab..ec69548 100644 --- a/ESPFirewall/lib/Firewall/src/Storage.hpp +++ b/ESPFirewall/lib/Firewall/src/Storage.hpp @@ -3,7 +3,6 @@ #ifdef ESP32 #include "Preferences.h" -#include "SPIFFS.h" #elif defined(ESP8266) #include "EEPROM.h" #endif @@ -14,34 +13,28 @@ namespace fw { class Storage { + public: + Storage(); + ~Storage(); + private: #ifdef ESP32 Preferences memory; #elif defined(ESP8266) - // Storage per firewall rule is 34 Byte - // Space for 15 Rules is 510 Byte - // plus 10 byte for settings - const uint16_t eeprom_size = 520; - const uint8_t security_number = 93; - const uint16_t eeprom_settings_head = 0; - const uint16_t eeprom_amout_of_rules_head = eeprom_settings_head + 1; - const uint16_t eeprom_rules_head = 10; + uint8_t max_rules; + uint16_t eeprom_size; + uint16_t eeprom_amount_of_rules; + uint16_t eeprom_rules_head; + #endif - ok_t mount_spiffs(); - void setup_eeprom(); - uint16_t eeprom_rule_position(uint8_t); + uint16_t eeprom_rule_position(uint8_t key); 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 *); - - public: - Storage(); - ~Storage(); + uint8_t retrieve_amount_of_rules(); + void store_amount_of_rules(const uint8_t new_amount); + firewall_rule_t *retrieve_firewall_rule(const uint8_t key); + void store_all_firewall_rules(firewall_rule_t *rule_head); + void store_firewall_rule(firewall_rule_t *rule_ptr); }; } diff --git a/ESPFirewall/lib/Firewall/src/Utils.cpp b/ESPFirewall/lib/Firewall/src/Utils.cpp index 4eeeaac..9be85ba 100644 --- a/ESPFirewall/lib/Firewall/src/Utils.cpp +++ b/ESPFirewall/lib/Firewall/src/Utils.cpp @@ -48,27 +48,15 @@ namespace fw return TARGET_ACCEPT; } - String response_code_to_string(const uint16_t response_code) - { - switch (response_code) - { - case 200: - return "success"; - case 403: - return "unauthorized"; - case 404: - return "not found"; - case 500: - return "server error"; - default: - return "unknown error"; - } - } - void endless_loop() { Serial.printf("Something went wrong. Running endless loop until fixed..."); while (true) delay(500); } + + bool is_in_range(const uint32_t number, const uint32_t lower, const uint32_t upper) + { + return lower <= number && number <= upper; + } } diff --git a/ESPFirewall/lib/Firewall/src/Utils.hpp b/ESPFirewall/lib/Firewall/src/Utils.hpp index c2e6d03..db8e5d5 100644 --- a/ESPFirewall/lib/Firewall/src/Utils.hpp +++ b/ESPFirewall/lib/Firewall/src/Utils.hpp @@ -6,9 +6,6 @@ namespace fw { - static const uint8_t IPV4ADDRESS_LENGTH = 16; - static const uint8_t CREDENTIALS_LENGTH = 32; - typedef enum firewall_targets : uint8_t { TARGET_REJECT = 0, @@ -36,28 +33,52 @@ namespace fw DENIED = 1, } auth_t; + static const uint8_t IPV4ADDRESS_LENGTH = 16; typedef struct firewall_rules { uint8_t key; - char source[IPV4ADDRESS_LENGTH]; - char destination[IPV4ADDRESS_LENGTH]; + char ip[IPV4ADDRESS_LENGTH]; + uint32_t port_from; // port can be max 65565 + uint32_t port_to; // range of uint16_t: 0 to 65535 firewall_protocol_t protocol; firewall_target_t target; struct firewall_rules *next; } firewall_rule_t; + static const uint8_t firewall_fields_amount = 6; + const char firewall_fields[firewall_fields_amount][10] = {"key", "ip", "port_from", "port_to", "protocol", "target"}; + typedef enum firewall_fields : uint8_t + { + KEY, + IP, + PORT_FROM, + PORT_TO, + PROTOCOL, + TARGET, + } firewall_fields_t; + + static const uint8_t CREDENTIALS_LENGTH = 32; typedef struct credentials { char password[CREDENTIALS_LENGTH]; char username[CREDENTIALS_LENGTH]; } credential_t; + typedef struct api_endpoints + { + char uri[60]; + char method[7]; + char description[30]; + struct api_endpoints *next; + } api_endpoint_t; + String protocol_to_string(firewall_protocol_t &protocol); firewall_protocol_t string_to_protocol(String &protocol); String target_to_string(firewall_target_t &target); firewall_target_t string_to_target(String &target); String response_code_to_string(const uint16_t response_code); void endless_loop(); + bool is_in_range(const uint32_t number, const uint32_t lower, const uint32_t upper); } #endif diff --git a/ESPFirewall/src/main.cpp b/ESPFirewall/src/main.cpp index 0d0d349..2e5e9c3 100644 --- a/ESPFirewall/src/main.cpp +++ b/ESPFirewall/src/main.cpp @@ -8,9 +8,12 @@ #endif #include "Firewall.hpp" +#include "API.hpp" fw::Firewall *firewall; -String ip = "0.0.0.0"; +fw::API *firewallApi; + +WiFiServer wifiServer(80); void setup_wifi() { @@ -25,17 +28,27 @@ void setup_wifi() } Serial.println(); Serial.print("IP Address: "); - ip = WiFi.localIP().toString(); - Serial.println(ip); + Serial.println(WiFi.localIP()); + wifiServer.begin(); } void setup() { setup_wifi(); - firewall = new fw::Firewall(cert, key, username, password, ip, 8080); + firewall = new fw::Firewall(); + firewallApi = new fw::API(firewall, cert, key, username, password); } void loop() { - firewall->handle_api_client(); + firewallApi->handle_client(); + WiFiClient client = wifiServer.available(); + if (client) + { + if (firewall->is_client_allowed(client)) + Serial.println("allowed"); + else + Serial.println("rejected"); + client.stop(); + } } \ No newline at end of file