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
{
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/<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;
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;
}
}

View file

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

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

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()
{
#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)
if (amount_of_rules > this->max_rules)
return 0;
return amount_of_rules;
}
return 0;
#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.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<firewall_protocol_t>(this->memory.getUChar("protocol", PROTOCOL_ALL));
rule_ptr->target = static_cast<firewall_target_t>(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<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();
#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<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));
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

View file

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

View file

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

View file

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

View file

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