Merge branch '7-network-analysieren' into 'main'

Resolve "Network analysieren"

Closes #7

See merge request toheer/iot-security-tools!6
This commit is contained in:
Florian Hoss 2022-07-19 08:16:08 +00:00
commit aeb2189197
13 changed files with 366 additions and 391 deletions

36
ESPFirewall/app.py Normal file
View file

@ -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:])

View file

@ -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"
}
}

View file

@ -2,10 +2,11 @@
namespace fw 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->firewall = firewall;
this->server_port = port; this->api_ip = WiFi.localIP().toString();
this->api_port = port;
if (this->setup_auth(username, password) == ERROR) if (this->setup_auth(username, password) == ERROR)
endless_loop(); endless_loop();
#ifdef ESP32 #ifdef ESP32
@ -32,9 +33,9 @@ namespace fw
String API::get_url_base() String API::get_url_base()
{ {
#ifdef ESP32 #ifdef ESP32
return "http://" + this->server_ip + ":" + this->server_port; return "http://" + this->api_ip + ":" + this->api_port;
#elif defined(ESP8266) #elif defined(ESP8266)
return "https://" + this->server_ip + ":" + this->server_port; return "https://" + this->api_ip + ":" + this->api_port;
#endif #endif
} }
@ -63,7 +64,7 @@ namespace fw
} }
else else
{ {
this->json_message_response("please provide username and password", 403); this->json_message_response("unauthorised", 403);
return DENIED; return DENIED;
} }
} }
@ -74,23 +75,20 @@ namespace fw
this->server->getServer().setRSACert(new BearSSL::X509List(cert), new BearSSL::PrivateKey(key)); this->server->getServer().setRSACert(new BearSSL::X509List(cert), new BearSSL::PrivateKey(key));
this->server->getServer().setCache(serverCache); this->server->getServer().setCache(serverCache);
#endif #endif
this->server->on("/firewall", HTTP_GET, std::bind(&API::get_firewall_rules_handler, this)); this->server->on("/api/firewall/rules", HTTP_GET, std::bind(&API::get_firewall_rules_handler, this));
add_api_endpoint("/firewall", "GET", "Get all Firewall Rules"); 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("/firewall/([0-9]+)"), HTTP_GET, std::bind(&API::get_firewall_rule_handler, this)); this->server->on(UriRegex("/api/firewall/rules/([0-9]+)"), HTTP_DELETE, std::bind(&API::delete_firewall_handler, this));
add_api_endpoint("/firewall/1", "GET", "Get Firewall Rule by key"); this->server->on("/api", HTTP_GET, std::bind(&API::get_endpoint_list_handler, this));
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->onNotFound(std::bind(&API::not_found_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/<key>", "GET", "Get Firewall Rule by key");
add_endpoint_to_list("/api/firewall/rules", "POST", "Create Firewall Rule");
add_endpoint_to_list("/api/firewall/rules/<key>", "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; api_endpoint_t *temp;
const String url = get_url_base() + uri; const String url = get_url_base() + uri;
@ -123,9 +121,9 @@ namespace fw
404); 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() void API::get_firewall_rule_handler()
@ -134,7 +132,7 @@ namespace fw
return; return;
String param = this->server->pathArg(0); String param = this->server->pathArg(0);
int rule_number = atoi(param.c_str()); 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) if (rule_ptr == NULL)
this->json_message_response("rule does not exist", 404); this->json_message_response("rule does not exist", 404);
else else
@ -145,21 +143,22 @@ namespace fw
{ {
if (this->check_auth() == DENIED) if (this->check_auth() == DENIED)
return; return;
this->json_generic_response(this->construct_json_firewall(), 200); this->json_array_response(this->construct_json_firewall(), 200);
} }
void API::post_firewall_handler() void API::post_firewall_handler()
{ {
if (this->check_auth() == DENIED) if (this->check_auth() == DENIED)
return; return;
if (request_has_firewall_parameter()) if (request_has_all_firewall_parameter())
{ {
firewall_rule_t *rule_ptr = add_rule_to_firewall( String args[IPV4ADDRESS_LENGTH] = {};
this->server->arg("source"), for (uint8_t i = 0; i < firewall_fields_amount; i++)
this->server->arg("destination"), {
this->server->arg("protocol"), args[i] = this->server->arg(firewall_fields[i]);
this->server->arg("target")); }
this->json_generic_response(this->construct_json_firewall_rule(rule_ptr), 200); firewall_rule_t *rule_ptr = firewall->add_rule_to_firewall(args);
this->json_generic_response(this->construct_json_firewall_rule(rule_ptr), 201);
} }
else else
{ {
@ -173,22 +172,24 @@ namespace fw
return; return;
String param = this->server->pathArg(0); String param = this->server->pathArg(0);
int rule_number = atoi(param.c_str()); 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); this->json_message_response("firewall rule deleted", 200);
else else
this->json_message_response("cannot delete firewall rule", 500); 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()) if (!this->server->args())
return false; return false;
else else
{ {
return this->server->hasArg("source") || for (uint8_t i = 0; i < firewall_fields_amount; i++)
this->server->hasArg("destination") || {
this->server->hasArg("protocol") || if (i != KEY && !this->server->hasArg(firewall_fields[i]))
this->server->hasArg("target"); return false;
}
return true;
} }
} }
@ -201,42 +202,45 @@ namespace fw
return json_string; 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); return json_new_attribute(key, String(value), last);
} }
void API::json_generic_response(String serialized_string, const uint16_t response_code) void API::json_generic_response(String serialized_string, const uint16_t response_code)
{ {
this->server->send( this->server->send(response_code, json_response_type, serialized_string);
response_code, }
"application/json; charset=utf-8",
construct_json_begin(response_code) + "\"result\": [" + 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) 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 += json_new_attribute("message", message, true);
serialized_string += "}"; 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 API::construct_json_firewall_rule(firewall_rule_t *rule_ptr)
{ {
String serialized_string = "{"; String serialized_string = "{";
serialized_string += json_new_attribute("key", rule_ptr->key); serialized_string += json_new_attribute(firewall_fields[KEY], rule_ptr->key);
serialized_string += json_new_attribute("source", rule_ptr->source); serialized_string += json_new_attribute(firewall_fields[IP], rule_ptr->ip);
serialized_string += json_new_attribute("destination", rule_ptr->destination); serialized_string += json_new_attribute(firewall_fields[PORT_FROM], rule_ptr->port_from);
serialized_string += json_new_attribute("protocol", protocol_to_string(rule_ptr->protocol)); serialized_string += json_new_attribute(firewall_fields[PORT_TO], rule_ptr->port_to);
serialized_string += json_new_attribute("target", target_to_string(rule_ptr->target), true); 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 += "}"; serialized_string += "}";
return serialized_string; return serialized_string;
} }
String API::construct_json_firewall() String API::construct_json_firewall()
{ {
firewall_rule_t *rule_ptr = rule_head; firewall_rule_t *rule_ptr = firewall->get_rule_head();
String serialized_string; String serialized_string;
while (rule_ptr != NULL) while (rule_ptr != NULL)
{ {
@ -271,11 +275,4 @@ namespace fw
} }
return serialized_string; 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;
}
} }

View file

@ -8,22 +8,18 @@
#endif #endif
#include "uri/UriRegex.h" #include "uri/UriRegex.h"
#include "Firewall.hpp"
#include "Rules.hpp"
#include "Utils.hpp" #include "Utils.hpp"
namespace fw namespace fw
{ {
typedef struct api_endpoints class API
{ {
char uri[40]; public:
char method[7]; API(Firewall *, const char *cert, const char *key, const char *username, const char *password, const uint16_t port = 8080);
char description[30]; ~API();
struct api_endpoints *next; void handle_client();
} api_endpoint_t;
class API : public Rules
{
private: private:
#ifdef ESP32 #ifdef ESP32
WebServer *server; WebServer *server;
@ -31,41 +27,37 @@ namespace fw
BearSSL::ESP8266WebServerSecure *server; BearSSL::ESP8266WebServerSecure *server;
BearSSL::ServerSessions *serverCache; BearSSL::ServerSessions *serverCache;
#endif #endif
Firewall *firewall;
credential_t credentials; credential_t credentials;
api_endpoint_t *endpoint_head = NULL; 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); ok_t setup_auth(const char *username, const char *password);
auth_t check_auth(); auth_t check_auth();
void setup_routing(const char *cert, const char *key); 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_rule_handler();
void get_firewall_rules_handler(); void get_firewall_rules_handler();
void post_firewall_handler(); void post_firewall_handler();
void delete_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, 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_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); 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_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_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();
}; };
} }

View file

@ -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);
}
}

View file

@ -1,26 +1,31 @@
#ifndef FIREWALL_HPP #ifndef ESP32_FIREWALL_HPP
#define FIREWALL_HPP #define ESP32_FIREWALL_HPP
#include "API.hpp" #include "Utils.hpp"
#include "Storage.hpp"
#include "WiFiClient.h"
namespace fw namespace fw
{ {
class Firewall : public API class Firewall : public Storage
{ {
private:
public: public:
Firewall(const char *, const char *, const char *, const char *, const String ip, const uint16_t = 8080); Firewall();
~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) firewall_rule_t *get_rule_head();
: API(cert, key, username, password, ip, port) {} void add_rule_to_firewall(firewall_rule_t *rule_ptr, const bool save_in_eeprom = true);
Firewall::~Firewall() {} firewall_rule_t *add_rule_to_firewall(String *args);
void Firewall::handle_api_client() firewall_rule_t *get_rule_from_firewall(const uint8_t key);
{ ok_t delete_rule_from_firewall(const uint8_t key);
handle_client();
} 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 #endif

View file

@ -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;
}
}

View file

@ -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

View file

@ -4,11 +4,12 @@ namespace fw
{ {
Storage::Storage() Storage::Storage()
{ {
#ifdef ESP32 #if defined(ESP8266)
if (this->mount_spiffs() == ERROR) this->max_rules = 15;
endless_loop(); this->eeprom_amount_of_rules = 0;
#elif defined(ESP8266) this->eeprom_rules_head = 1;
this->setup_eeprom(); this->eeprom_size = this->max_rules * sizeof(firewall_rule_t) + eeprom_rules_head;
EEPROM.begin(this->eeprom_size);
#endif #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) uint16_t Storage::eeprom_rule_position(uint8_t key)
{ {
#ifdef ESP8266 #ifdef ESP32
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)
return 0; return 0;
#elif defined(ESP8266)
return eeprom_rules_head + (key - 1) * sizeof(firewall_rule_t);
#endif #endif
} }
uint8_t Storage::retrieve_settings_value(const char *key) uint8_t Storage::retrieve_amount_of_rules()
{ {
#ifdef ESP32 #ifdef ESP32
uint8_t value;
this->memory.begin("settings", true); this->memory.begin("settings", true);
value = memory.getUChar(key, 0); const uint8_t value = memory.getUChar("amount_of_rules", 0);
this->memory.end(); this->memory.end();
return value; return value;
#elif defined(ESP8266) #elif defined(ESP8266)
if (strncmp("amount_of_rules", key, 16) == 0) const uint8_t amount_of_rules = EEPROM.read(this->eeprom_amount_of_rules);
{
uint8_t security_number = EEPROM.read(this->eeprom_settings_head);
uint8_t amount_of_rules = EEPROM.read(this->eeprom_amout_of_rules_head);
if (amount_of_rules > 50 || security_number != this->security_number) if (amount_of_rules > this->max_rules)
return 0; return 0;
return amount_of_rules; return amount_of_rules;
}
return 0;
#endif #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 #ifdef ESP32
this->memory.begin("settings", false); this->memory.begin("settings", false);
this->memory.putUChar(key, new_amount); this->memory.putUChar("amount_of_rules", new_amount);
this->memory.end(); this->memory.end();
#elif defined(ESP8266) #elif defined(ESP8266)
if (strncmp("amount_of_rules", key, 16) == 0) EEPROM.put(this->eeprom_amount_of_rules, new_amount);
{ EEPROM.commit();
EEPROM.write(this->eeprom_settings_head, this->security_number);
EEPROM.write(this->eeprom_amout_of_rules_head, new_amount);
EEPROM.commit();
}
#endif #endif
} }
@ -105,29 +64,21 @@ namespace fw
sprintf(rulename, "fwRule%i", key); sprintf(rulename, "fwRule%i", key);
this->memory.begin(rulename, true); 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->ip, this->memory.getString(firewall_fields[IP], "0.0.0.0").c_str(), sizeof(rule_ptr->ip));
strncpy(rule_ptr->destination, this->memory.getString("destination", "0.0.0.0").c_str(), sizeof(rule_ptr->source)); rule_ptr->port_from = this->memory.getULong(firewall_fields[PORT_FROM], 0);
rule_ptr->protocol = static_cast<firewall_protocol_t>(this->memory.getUChar("protocol", PROTOCOL_ALL)); rule_ptr->port_to = this->memory.getULong(firewall_fields[PORT_TO], 0);
rule_ptr->target = static_cast<firewall_target_t>(this->memory.getUChar("target", TARGET_REJECT)); rule_ptr->protocol = static_cast<firewall_protocol_t>(this->memory.getUChar(firewall_fields[PROTOCOL], PROTOCOL_ALL));
rule_ptr->target = static_cast<firewall_target_t>(this->memory.getUChar(firewall_fields[TARGET], TARGET_REJECT));
this->memory.end(); this->memory.end();
#elif defined(ESP8266) #elif defined(ESP8266)
uint16_t eespom_position = eeprom_rule_position(key); uint16_t eespom_position = eeprom_rule_position(key);
const char source[IPV4ADDRESS_LENGTH] = "";
const char destination[IPV4ADDRESS_LENGTH] = "";
EEPROM.get(eespom_position, source); EEPROM.get(eespom_position, rule_ptr->ip);
strncpy(rule_ptr->source, source, sizeof(rule_ptr->source)); EEPROM.get(eespom_position += sizeof(rule_ptr->ip), rule_ptr->port_from);
eespom_position += sizeof(rule_ptr->source); 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, destination); EEPROM.get(eespom_position += sizeof(rule_ptr->protocol), rule_ptr->target);
strncpy(rule_ptr->destination, destination, sizeof(rule_ptr->destination));
eespom_position += sizeof(rule_ptr->destination);
rule_ptr->protocol = static_cast<firewall_protocol_t>(EEPROM.read(eespom_position));
eespom_position += sizeof(rule_ptr->protocol);
rule_ptr->target = static_cast<firewall_target_t>(EEPROM.read(eespom_position));
#endif #endif
return rule_ptr; return rule_ptr;
} }
@ -151,22 +102,21 @@ namespace fw
sprintf(rulename, "fwRule%i", rule_ptr->key); sprintf(rulename, "fwRule%i", rule_ptr->key);
this->memory.begin(rulename, false); this->memory.begin(rulename, false);
this->memory.putString("source", rule_ptr->source); this->memory.putString(firewall_fields[IP], rule_ptr->ip);
this->memory.putString("destination", rule_ptr->destination); this->memory.putULong(firewall_fields[PORT_FROM], rule_ptr->port_from);
this->memory.putUChar("protocol", rule_ptr->protocol); this->memory.putULong(firewall_fields[PORT_TO], rule_ptr->port_to);
this->memory.putUChar("target", rule_ptr->target); this->memory.putUChar(firewall_fields[PROTOCOL], rule_ptr->protocol);
this->memory.putUChar(firewall_fields[TARGET], rule_ptr->target);
this->memory.end(); this->memory.end();
#elif defined(ESP8266) #elif defined(ESP8266)
uint16_t eespom_position = eeprom_rule_position(rule_ptr->key); uint16_t eespom_position = eeprom_rule_position(rule_ptr->key);
EEPROM.put(eespom_position, rule_ptr->source); EEPROM.put(eespom_position, rule_ptr->ip);
eespom_position += sizeof(rule_ptr->source); EEPROM.put(eespom_position += sizeof(rule_ptr->ip), rule_ptr->port_from);
EEPROM.put(eespom_position, rule_ptr->destination); EEPROM.put(eespom_position += sizeof(rule_ptr->port_from), rule_ptr->port_to);
eespom_position += sizeof(rule_ptr->destination); EEPROM.put(eespom_position += sizeof(rule_ptr->port_to), rule_ptr->protocol);
EEPROM.put(eespom_position, rule_ptr->protocol); EEPROM.put(eespom_position += sizeof(rule_ptr->protocol), rule_ptr->target);
eespom_position += sizeof(rule_ptr->protocol);
EEPROM.put(eespom_position, rule_ptr->target);
EEPROM.commit(); EEPROM.commit();
#endif #endif

View file

@ -3,7 +3,6 @@
#ifdef ESP32 #ifdef ESP32
#include "Preferences.h" #include "Preferences.h"
#include "SPIFFS.h"
#elif defined(ESP8266) #elif defined(ESP8266)
#include "EEPROM.h" #include "EEPROM.h"
#endif #endif
@ -14,34 +13,28 @@ namespace fw
{ {
class Storage class Storage
{ {
public:
Storage();
~Storage();
private: private:
#ifdef ESP32 #ifdef ESP32
Preferences memory; Preferences memory;
#elif defined(ESP8266) #elif defined(ESP8266)
// Storage per firewall rule is 34 Byte uint8_t max_rules;
// Space for 15 Rules is 510 Byte uint16_t eeprom_size;
// plus 10 byte for settings uint16_t eeprom_amount_of_rules;
const uint16_t eeprom_size = 520; uint16_t eeprom_rules_head;
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;
#endif #endif
ok_t mount_spiffs(); uint16_t eeprom_rule_position(uint8_t key);
void setup_eeprom();
uint16_t eeprom_rule_position(uint8_t);
protected: protected:
uint8_t retrieve_settings_value(const char *); uint8_t retrieve_amount_of_rules();
void store_settings_value(const char *, const uint8_t); void store_amount_of_rules(const uint8_t new_amount);
firewall_rule_t *retrieve_firewall_rule(const uint8_t key);
firewall_rule_t *retrieve_firewall_rule(const uint8_t); void store_all_firewall_rules(firewall_rule_t *rule_head);
void store_all_firewall_rules(firewall_rule_t *); void store_firewall_rule(firewall_rule_t *rule_ptr);
void store_firewall_rule(firewall_rule_t *);
public:
Storage();
~Storage();
}; };
} }

View file

@ -48,27 +48,15 @@ namespace fw
return TARGET_ACCEPT; 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() void endless_loop()
{ {
Serial.printf("Something went wrong. Running endless loop until fixed..."); Serial.printf("Something went wrong. Running endless loop until fixed...");
while (true) while (true)
delay(500); delay(500);
} }
bool is_in_range(const uint32_t number, const uint32_t lower, const uint32_t upper)
{
return lower <= number && number <= upper;
}
} }

View file

@ -6,9 +6,6 @@
namespace fw namespace fw
{ {
static const uint8_t IPV4ADDRESS_LENGTH = 16;
static const uint8_t CREDENTIALS_LENGTH = 32;
typedef enum firewall_targets : uint8_t typedef enum firewall_targets : uint8_t
{ {
TARGET_REJECT = 0, TARGET_REJECT = 0,
@ -36,28 +33,52 @@ namespace fw
DENIED = 1, DENIED = 1,
} auth_t; } auth_t;
static const uint8_t IPV4ADDRESS_LENGTH = 16;
typedef struct firewall_rules typedef struct firewall_rules
{ {
uint8_t key; uint8_t key;
char source[IPV4ADDRESS_LENGTH]; char ip[IPV4ADDRESS_LENGTH];
char destination[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_protocol_t protocol;
firewall_target_t target; firewall_target_t target;
struct firewall_rules *next; struct firewall_rules *next;
} firewall_rule_t; } 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 typedef struct credentials
{ {
char password[CREDENTIALS_LENGTH]; char password[CREDENTIALS_LENGTH];
char username[CREDENTIALS_LENGTH]; char username[CREDENTIALS_LENGTH];
} credential_t; } 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); String protocol_to_string(firewall_protocol_t &protocol);
firewall_protocol_t string_to_protocol(String &protocol); firewall_protocol_t string_to_protocol(String &protocol);
String target_to_string(firewall_target_t &target); String target_to_string(firewall_target_t &target);
firewall_target_t string_to_target(String &target); firewall_target_t string_to_target(String &target);
String response_code_to_string(const uint16_t response_code); String response_code_to_string(const uint16_t response_code);
void endless_loop(); void endless_loop();
bool is_in_range(const uint32_t number, const uint32_t lower, const uint32_t upper);
} }
#endif #endif

View file

@ -8,9 +8,12 @@
#endif #endif
#include "Firewall.hpp" #include "Firewall.hpp"
#include "API.hpp"
fw::Firewall *firewall; fw::Firewall *firewall;
String ip = "0.0.0.0"; fw::API *firewallApi;
WiFiServer wifiServer(80);
void setup_wifi() void setup_wifi()
{ {
@ -25,17 +28,27 @@ void setup_wifi()
} }
Serial.println(); Serial.println();
Serial.print("IP Address: "); Serial.print("IP Address: ");
ip = WiFi.localIP().toString(); Serial.println(WiFi.localIP());
Serial.println(ip); wifiServer.begin();
} }
void setup() void setup()
{ {
setup_wifi(); 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() 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();
}
} }