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:
commit
aeb2189197
13 changed files with 366 additions and 391 deletions
36
ESPFirewall/app.py
Normal file
36
ESPFirewall/app.py
Normal 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:])
|
|
@ -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"
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
}
|
||||
|
||||
|
|
133
ESPFirewall/lib/Firewall/src/Firewall.cpp
Normal file
133
ESPFirewall/lib/Firewall/src/Firewall.cpp
Normal 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);
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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<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
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
Reference in a new issue