diff --git a/.github/workflows/cross-compile.yml b/.github/workflows/cross-compile.yml index fa60252cbe0269a0f5030f148b473abbbb44046b..80785a5a2d94eccc6966f15ce9f1e03132f12327 100644 --- a/.github/workflows/cross-compile.yml +++ b/.github/workflows/cross-compile.yml @@ -12,6 +12,8 @@ jobs: - name: Checkout repository uses: actions/checkout@v3 + with: + submodules: recursive - name: Install Python packages run: pip install -r $GITHUB_WORKSPACE/requirements.txt diff --git a/.github/workflows/full-test.yml b/.github/workflows/full-test.yml index a09c010b61e0519355724b52312192fe4d202b59..79bf5dce6a44d019146c27bfba3febcefc37dc32 100644 --- a/.github/workflows/full-test.yml +++ b/.github/workflows/full-test.yml @@ -11,6 +11,8 @@ jobs: - name: Checkout repository uses: actions/checkout@v3 + with: + submodules: recursive - name: Install required packages run: sudo $GITHUB_WORKSPACE/.ci_scripts/full-test/install_packages.sh diff --git a/.github/workflows/publish-docs.yml b/.github/workflows/publish-docs.yml index a08272dc806816175b5d6673db17009f5ddc39b0..7126e9344cf3c31712379dcea7f72fe4836e7f17 100644 --- a/.github/workflows/publish-docs.yml +++ b/.github/workflows/publish-docs.yml @@ -19,7 +19,7 @@ jobs: - name: Checkout repository uses: actions/checkout@v3 with: - submodules: "true" + submodules: recursive - name: Install required packages run: sudo $GITHUB_WORKSPACE/.ci_scripts/publish-docs/install_packages.sh diff --git a/include/dns_map.h b/include/dns_map.h deleted file mode 100644 index 77de135f0ae3e5d6490073effb3b0ab349347028..0000000000000000000000000000000000000000 --- a/include/dns_map.h +++ /dev/null @@ -1,132 +0,0 @@ -/** - * @file include/dns_map.h - * @brief Implementation of a DNS domain name to IP addresses mapping, using Joshua J Baker's hashmap.c (https://github.com/tidwall/hashmap.c) - * @date 2022-09-06 - * - * @copyright Copyright (c) 2022 - * - */ - -#ifndef _IOTFIREWALL_DNS_MAP_ -#define _IOTFIREWALL_DNS_MAP_ - -#include <stdlib.h> -#include <stdint.h> -#include <stdbool.h> -#include <string.h> -#include "hashmap.h" -#include "packet_utils.h" - -// Initial size of the DNS table -// If set to 0, the default size will be 16 -#define DNS_MAP_INIT_SIZE 0 - - -////////// TYPE DEFINITIONS ////////// - -/** - * List of IP addresses - */ -typedef struct ip_list { - uint8_t ip_count; // Number of IP addresses - ip_addr_t *ip_addresses; // List of IP addresses -} ip_list_t; - -/** - * DNS table entry: - * mapping between domain name and a list of IP addresses. - */ -typedef struct dns_entry { - char *domain_name; // Domain name - ip_list_t ip_list; // List of IP addresses -} dns_entry_t; - -/** - * Alias for the hashmap structure. - */ -typedef struct hashmap dns_map_t; - - -////////// FUNCTIONS ////////// - -/** - * @brief Initialize an ip_list_t structure. - * - * Creates an empty list of IP addresses. - * The `ip_count` field is set to 0, - * and the `ip_addresses` field is set to NULL. - * - * @return ip_list_t newly initialized structure - */ -ip_list_t ip_list_init(); - -/** - * @brief Checks if a dns_entry_t structure contains a given IP address. - * - * @param dns_entry pointer to the DNS entry to process - * @param ip_address IP address to check the presence of - * @return true if the IP address is present in the DNS entry, false otherwise - */ -bool dns_entry_contains(dns_entry_t *dns_entry, ip_addr_t ip_address); - -/** - * Create a new DNS table. - * - * @return the newly created DNS table - */ -dns_map_t* dns_map_create(); - -/** - * Destroy (free) a DNS table. - * - * @param table the DNS table to free - */ -void dns_map_free(dns_map_t *table); - -/** - * Add IP addresses corresponding to a given domain name in the DNS table. - * If the domain name was already present, its IP addresses will be replaced by the new ones. - * - * @param table the DNS table to add the entry to - * @param domain_name the domain name of the entry - * @param ip_list an ip_list_t structure containing the list of IP addresses - */ -void dns_map_add(dns_map_t *table, char *domain_name, ip_list_t ip_list); - -/** - * Remove a domain name (and its corresponding IP addresses) from the DNS table. - * - * @param table the DNS table to remove the entry from - * @param domain_name the domain name of the entry to remove - */ -void dns_map_remove(dns_map_t *table, char *domain_name); - -/** - * Retrieve the IP addresses corresponding to a given domain name in the DNS table. - * - * @param table the DNS table to retrieve the entry from - * @param domain_name the domain name of the entry to retrieve - * @return a pointer to a dns_entry structure containing the IP addresses corresponding to the domain name, - * or NULL if the domain name was not found in the DNS table - */ -dns_entry_t* dns_map_get(dns_map_t *table, char *domain_name); - -/** - * Retrieve the IP addresses corresponding to a given domain name, - * and remove the domain name from the DNS table. - * - * @param table the DNS table to retrieve the entry from - * @param domain_name the domain name of the entry to retrieve - * @return a pointer to a dns_entry structure containing the IP addresses corresponding to the domain name, - * or NULL if the domain name was not found in the DNS table - */ -dns_entry_t* dns_map_pop(dns_map_t *table, char *domain_name); - -/** - * @brief Print a DNS table entry. - * - * @param dns_entry the DNS table entry to print - */ -void dns_entry_print(dns_entry_t *dns_entry); - -#endif /* _IOTFIREWALL_DNS_MAP_ */ diff --git a/include/packet_utils.h b/include/packet_utils.h deleted file mode 100644 index 9f383ae9f83c36d4eb9e3983b117960fe9880c0b..0000000000000000000000000000000000000000 --- a/include/packet_utils.h +++ /dev/null @@ -1,184 +0,0 @@ -/** - * @file include/packet_utils.h - * @brief Utilitaries for payload manipulation and display - * @date 2022-09-09 - * - * @copyright Copyright (c) 2022 - * - */ - -#ifndef _IOTFIREWALL_PACKET_UTILS_ -#define _IOTFIREWALL_PACKET_UTILS_ - -#include <stdlib.h> -#include <stdio.h> -#include <stdint.h> -#include <stdbool.h> -#include <string.h> -#include <arpa/inet.h> -#include "sha256.h" - -#define MAC_ADDR_LENGTH 6 -#define MAC_ADDR_STRLEN 18 -#define IPV4_ADDR_LENGTH 4 -#define IPV6_ADDR_LENGTH 16 - -/** - * @brief IP (v4 or v6) address value - */ -typedef union { - uint32_t ipv4; // IPv4 address, as a 32-bit unsigned integer in network byte order - uint8_t ipv6[IPV6_ADDR_LENGTH]; // IPv6 address, as a 16-byte array -} ip_val_t; - -/** - * @brief IP (v4 or v6) address - */ -typedef struct { - uint8_t version; // IP version (4 or 6, 0 if not set) - ip_val_t value; // IP address value (0 if not set) -} ip_addr_t; - -/** - * Print a packet payload. - * - * @param length length of the payload in bytes - * @param data pointer to the start of the payload - */ -void print_payload(int length, uint8_t *data); - -/** - * Converts a hexstring payload to a data buffer. - * - * @param hexstring the hexstring to convert - * @param payload a double pointer to the payload, which will be set to the start of the payload - * @return the length of the payload in bytes - */ -size_t hexstr_to_payload(char *hexstring, uint8_t **payload); - -/** - * Converts a MAC address from its hexadecimal representation - * to its string representation. - * - * @param mac_hex MAC address in hexadecimal representation - * @return the same MAC address in string representation - */ -char *mac_hex_to_str(uint8_t mac_hex[]); - -/** - * Converts a MAC address from its string representation - * to its hexadecimal representation. - * - * @param mac_str MAC address in string representation - * @return the same MAC address in hexadecimal representation - */ -uint8_t *mac_str_to_hex(char *mac_str); - -/** - * Converts an IPv4 address from its network order numerical representation - * to its string representation. - * (Wrapper arount inet_ntoa) - * - * @param ipv4_net IPv4 address in hexadecimal representation - * @return the same IPv4 address in string representation - */ -char* ipv4_net_to_str(uint32_t ipv4_net); - -/** - * Converts an IPv4 address from its string representation - * to its network order numerical representation. - * (Wrapper arount inet_aton) - * - * @param ipv4_str IPv4 address in string representation - * @return the same IPv4 address in network order numerical representation - */ -uint32_t ipv4_str_to_net(char *ipv4_str); - -/** - * Converts an IPv4 addres from its hexadecimal representation - * to its string representation. - * - * @param ipv4_hex IPv4 address in hexadecimal representation - * @return the same IPv4 address in string representation - */ -char* ipv4_hex_to_str(char *ipv4_hex); - -/** - * Converts an IPv4 address from its string representation - * to its hexadecimal representation. - * - * @param ipv4_str IPv4 address in string representation - * @return the same IPv4 address in hexadecimal representation - */ -char* ipv4_str_to_hex(char *ipv4_str); - -/** - * @brief Converts an IPv6 address to its string representation. - * - * @param ipv6 the IPv6 address - * @return the same IPv6 address in string representation - */ -char* ipv6_net_to_str(uint8_t ipv6[]); - -/** - * Converts an IPv6 address from its string representation - * to its network representation (a 16-byte array). - * - * @param ipv6_str IPv6 address in string representation - * @return the same IPv6 address as a 16-byte array - */ -uint8_t* ipv6_str_to_net(char *ipv6_str); - -/** - * @brief Converts an IP (v4 or v6) address to its string representation. - * - * @param ip_addr the IP address, as an ip_addr_t struct - * @return the same IP address in string representation - */ -char* ip_net_to_str(ip_addr_t ip_addr); - -/** - * Converts an IP (v4 or v6) address from its string representation - * to an ip_addr_t struct. - * - * @param ip_str IP (v4 or v6) address in string representation - * @return the same IP address as a ip_addr_t struct - */ -ip_addr_t ip_str_to_net(char *ip_str, uint8_t version); - -/** - * @brief Compare two IPv6 addresses. - * - * @param ipv6_1 first IPv6 address - * @param ipv6_2 second IPv6 address - * @return true if the two addresses are equal, false otherwise - */ -bool compare_ipv6(uint8_t *ipv6_1, uint8_t *ipv6_2); - -/** - * @brief Compare two IP (v4 or v6) addresses. - * - * @param ip_1 first IP address - * @param ip_2 second IP address - * @return true if the two addresses are equal, false otherwise - */ -bool compare_ip(ip_addr_t ip_1, ip_addr_t ip_2); - -/** - * @brief Compute SHA256 hash of a given payload. - * - * @param payload Payload to hash - * @param payload_len Payload length, including padding (in bytes) - * @return uint8_t* SHA256 hash of the payload - */ -uint8_t* compute_hash(uint8_t *payload, int payload_len); - -/** - * @brief Print a SHA256 hash. - * - * @param hash SHA256 hash to print - */ -void print_hash(uint8_t *hash); - - -#endif /* _IOTFIREWALL_PACKET_UTILS_ */ diff --git a/include/parsers/coap.h b/include/parsers/coap.h deleted file mode 100644 index f0fec91667729c12176d6097d6ee0dd568903d23..0000000000000000000000000000000000000000 --- a/include/parsers/coap.h +++ /dev/null @@ -1,87 +0,0 @@ -/** - * @file include/parsers/coap.h - * @brief CoAP message parser - * @date 2022-11-30 - * - * @copyright Copyright (c) 2022 - * - */ - -#ifndef _IOTFIREWALL_COAP_ -#define _IOTFIREWALL_COAP_ - -#include <stdlib.h> -#include <stdio.h> -#include <stdint.h> -#include <string.h> -#include <arpa/inet.h> -#include "parsers/http.h" - - -/** - * @brief CoAP message type - */ -typedef enum -{ - COAP_CON = 0, - COAP_NON = 1, - COAP_ACK = 2, - COAP_RST = 3 -} coap_type_t; - -/** - * @brief CoAP Option number - */ -typedef enum -{ - COAP_URI_PATH = 11, - COAP_URI_QUERY = 15 -} coap_option_t; - -/** - * @brief Abstraction of a CoAP message - */ -typedef struct coap_message -{ - coap_type_t type; // CoAP message type - http_method_t method; // CoAP method, analogous to HTTP - char *uri; // Message URI - uint16_t uri_len; // URI length -} coap_message_t; - - -////////// FUNCTIONS ////////// - -///// PARSING ///// - -/** - * @brief Parse a CoAP message. - * - * @param data pointer to the start of the CoAP message - * @param length length of the CoAP message, in bytes - * @return the parsed CoAP message - */ -coap_message_t coap_parse_message(uint8_t *data, uint16_t length); - - -///// DESTROY ///// - -/** - * @brief Free the memory allocated for a CoAP message. - * - * @param message the CoAP message to free - */ -void coap_free_message(coap_message_t message); - - -///// PRINTING ///// - -/** - * @brief Print a CoAP message. - * - * @param message the CoAP message to print - */ -void coap_print_message(coap_message_t message); - - -#endif /* _IOTFIREWALL_COAP_ */ diff --git a/include/parsers/dhcp.h b/include/parsers/dhcp.h deleted file mode 100644 index 9a1c386cbb3cbab19bf17d5d701e54c9d26b4260..0000000000000000000000000000000000000000 --- a/include/parsers/dhcp.h +++ /dev/null @@ -1,174 +0,0 @@ -/** - * @file include/parsers/dhcp.h - * @brief DHCP message parser - * @date 2022-09-12 - * - * @copyright Copyright (c) 2022 - * - */ - -#ifndef _IOTFIREWALL_DHCP_ -#define _IOTFIREWALL_DHCP_ - -#include <stdlib.h> -#include <stdio.h> -#include <stdint.h> -#include <string.h> -#include <arpa/inet.h> - -#define MAX_HW_LEN 16 -#define DHCP_HEADER_LEN 236 -#define DHCP_MAX_OPTION_COUNT 20 -#define DHCP_MAGIC_COOKIE 0x63825363 - - -////////// TYPE DEFINITIONS ////////// - -/** - * DHCP opcode - */ -typedef enum -{ - DHCP_BOOTREQUEST = 1, - DHCP_BOOTREPLY = 2 -} dhcp_opcode_t; - -/** - * Useful DHCP option codes - */ -typedef enum -{ - DHCP_PAD = 0, - DHCP_MESSAGE_TYPE = 53, - DHCP_END = 255 -} dhcp_option_code_t; - -/** - * DHCP message type - */ -typedef enum -{ - DHCP_DISCOVER = 1, - DHCP_OFFER = 2, - DHCP_REQUEST = 3, - DHCP_DECLINE = 4, - DHCP_ACK = 5, - DHCP_NAK = 6, - DHCP_RELEASE = 7, - DHCP_INFORM = 8 -} dhcp_message_type_t; - -/** - * DHCP Option - */ -typedef struct dhcp_option { - dhcp_option_code_t code; - uint8_t length; - uint8_t *value; -} dhcp_option_t; - -/** - * DHCP Options - */ -typedef struct dhcp_options { - uint8_t count; // Number of options - dhcp_message_type_t message_type; // DHCP Message type (stored for convenience) - dhcp_option_t *options; // List of options -} dhcp_options_t; - -/** - * DHCP Message - */ -typedef struct dhcp_message { - dhcp_opcode_t op; // DHCP opcode - uint8_t htype; // Hardware address type - uint8_t hlen; // Hardware address length - uint8_t hops; // Number of hops - uint32_t xid; // Transaction ID - uint16_t secs; // Seconds elapsed since client began address acquisition or renewal process - uint16_t flags; // DHCP flags - uint32_t ciaddr; // Client IP address - uint32_t yiaddr; // Your (client) IP address - uint32_t siaddr; // Next server IP address - uint32_t giaddr; // Relay agent IP address - uint8_t chaddr[16]; // Client hardware address - uint8_t sname[64]; // Optional server host name - uint8_t file[128]; // Boot file name - dhcp_options_t options; // DHCP options -} dhcp_message_t; - - -////////// FUNCTIONS ////////// - -///// PARSING ///// - -/** - * @brief Parse the header of a DHCP message (not including options) - * - * @param data a pointer to the start of the DHCP message - * @return the parsed DHCP message with the header fields filled in - */ -dhcp_message_t dhcp_parse_header(uint8_t *data); - -/** - * @brief Parse a DHCP option - * - * @param data a pointer to the start of the DHCP option - * @param offset a pointer to the current offset inside the DHCP message - * Its value will be updated to point to the next option - * @return the parsed DHCP option - */ -dhcp_option_t dhcp_parse_option(uint8_t *data, uint16_t *offset); - -/** - * @brief Parse DHCP options - * - * @param data a pointer to the start of the DHCP options list - * @return a pointer to the start of the parsed DHCP options - */ -dhcp_options_t dhcp_parse_options(uint8_t *data); - -/** - * @brief Parse a DHCP message - * - * @param data a pointer to the start of the DHCP message - * @return the parsed DHCP message - */ -dhcp_message_t dhcp_parse_message(uint8_t *data); - - -///// DESTROY ////// - -/** - * @brief Free the memory allocated for a DHCP message. - * - * @param message the DHCP message to free - */ -void dhcp_free_message(dhcp_message_t message); - - -///// PRINTING ///// - -/** - * @brief Print the header of a DHCP message - * - * @param message the DHCP message to print the header of - */ -void dhcp_print_header(dhcp_message_t message); - -/** - * @brief Print a DHCP option - * - * @param option the DHCP option to print - */ -void dhcp_print_option(dhcp_option_t option); - -/** - * @brief Print a DHCP message - * - * @param message the DHCP message to print - */ -void dhcp_print_message(dhcp_message_t message); - - -#endif /* _IOTFIREWALL_DHCP_ */ diff --git a/include/parsers/dns.h b/include/parsers/dns.h deleted file mode 100644 index 7b6f76b613d1bf76a9df4d5edde95bf4a1cc93bc..0000000000000000000000000000000000000000 --- a/include/parsers/dns.h +++ /dev/null @@ -1,271 +0,0 @@ -/** - * @file include/parsers/dns.h - * @brief DNS message parser - * @date 2022-09-09 - * - * @copyright Copyright (c) 2022 - * - */ - -#ifndef _IOTFIREWALL_DNS_ -#define _IOTFIREWALL_DNS_ - -#include <stdlib.h> -#include <stdio.h> -#include <stdint.h> -#include <stdbool.h> -#include <string.h> -#include <arpa/inet.h> -#include "packet_utils.h" -#include "dns_map.h" - -#define DNS_HEADER_SIZE 12 -#define DNS_MAX_DOMAIN_NAME_LENGTH 100 -#define DNS_QR_FLAG_MASK 0x8000 -#define DNS_CLASS_MASK 0x7fff -#define DNS_COMPRESSION_MASK 0x3fff - - -////////// TYPE DEFINITIONS ////////// - -/** - * DNS types - */ -typedef enum { - A = 1, - NS = 2, - MD = 3, - MF = 4, - CNAME = 5, - SOA = 6, - MB = 7, - MG = 8, - MR = 9, - NULL_ = 10, - WKS = 11, - PTR = 12, - HINFO = 13, - MINFO = 14, - MX = 15, - TXT = 16, - AAAA = 28, - OPT = 41, // Used to specify extensions - ANY = 255 // Used to query any type -} dns_rr_type_t; - -/** - * DNS Header - */ -typedef struct dns_header { - uint16_t id; - uint16_t flags; - bool qr; // 0 if the message is a query, 1 if it is a response - uint16_t qdcount; // Number of entries in Question section - uint16_t ancount; // Number of Resource Records in Answer section - uint16_t nscount; // Number of Resource Records in Authority section - uint16_t arcount; // Number of Resource Records in Additional section -} dns_header_t; - -/** - * DNS Question - */ -typedef struct dns_question { - char *qname; - dns_rr_type_t qtype; - uint16_t qclass; -} dns_question_t; - -/** - * RDATA field of a DNS Resource Record - */ -typedef union { - char *domain_name; // Domain name, character string - ip_addr_t ip; // IP (v4 or v6) address - uint8_t *data; // Generic data, series of bytes -} rdata_t; - -/** - * DNS Resource Record - */ -typedef struct dns_resource_record { - char *name; - dns_rr_type_t rtype; - uint16_t rclass; - uint32_t ttl; - uint16_t rdlength; - rdata_t rdata; -} dns_resource_record_t; - -/** - * DNS Message - */ -typedef struct dns_message { - dns_header_t header; - dns_question_t *questions; - dns_resource_record_t *answers; - dns_resource_record_t *authorities; - dns_resource_record_t *additionals; -} dns_message_t; - - -////////// FUNCTIONS ////////// - -///// PARSING ///// - -/** - * Parse a DNS header. - * A DNS header is always 12 bytes. - * - * @param data a pointer pointing to the start of the DNS message - * @param offset a pointer to the current parsing offset - * @return the parsed header - */ -dns_header_t dns_parse_header(uint8_t *data, uint16_t *offset); - -/** - * Parse a DNS question section. - * - * @param qdcount the number of questions present in the question section - * @param data a pointer pointing to the start of the DNS message - * @param offset a pointer to the current parsing offset - * @return the parsed question section - */ -dns_question_t* dns_parse_questions(uint16_t qdcount, uint8_t *data, uint16_t *offset); - -/** - * Parse a DNS resource record list. - * - * @param count the number of resource records present in the section - * @param data a pointer pointing to the start of the DNS message - * @param offset a pointer to the current parsing offset - * @return the parsed resource records list - */ -dns_resource_record_t* dns_parse_rrs(uint16_t count, uint8_t *data, uint16_t *offset); - -/** - * Parse a DNS message. - * - * @param data a pointer to the start of the DNS message - * @return the parsed DNS message - */ -dns_message_t dns_parse_message(uint8_t *data); - - -///// LOOKUP ///// - -/** - * @brief Check if a given DNS Questions list contains a domain name which has a given suffix. - * - * @param questions DNS Questions list - * @param qdcount number of Questions in the list - * @param suffix the domain name suffix to search for - * @param suffix_length the length of the domain name suffix - * @return true if a domain name with the given suffix is found is found in the Questions list, - * false otherwise - */ -bool dns_contains_suffix_domain_name(dns_question_t *questions, uint16_t qdcount, char *suffix, uint16_t suffix_length); - -/** - * @brief Check if a given domain name is fully contained in a DNS Questions list. - * - * @param questions DNS Questions list - * @param qdcount number of Questions in the list - * @param domain_name the domain name to search for - * @return true if the full domain name is found in the Questions list, false otherwise - */ -bool dns_contains_full_domain_name(dns_question_t *questions, uint16_t qdcount, char *domain_name); - -/** - * @brief Search for a specific domain name in a DNS Questions list. - * - * @param questions DNS Questions list - * @param qdcount number of Suestions in the list - * @param domain_name the domain name to search for - * @return the DNS Question related to the given domain name, or NULL if not found - */ -dns_question_t* dns_get_question(dns_question_t *questions, uint16_t qdcount, char *domain_name); - -/** - * @brief Retrieve the IP addresses corresponding to a given domain name in a DNS Answers list. - * - * Searches a DNS Answer list for a specific domain name and returns the corresponding IP address. - * Processes each Answer recursively if the Answer Type is a CNAME. - * - * @param answers DNS Answers list to search in - * @param ancount number of Answers in the list - * @param domain_name domain name to search for - * @return struct ip_list representing the list of corresponding IP addresses - */ -ip_list_t dns_get_ip_from_name(dns_resource_record_t *answers, uint16_t ancount, char *domain_name); - - -///// DESTROY ///// - -/** - * Free the memory allocated for a DNS message. - * - * @param question the DNS message to free - */ -void dns_free_message(dns_message_t message); - - -///// PRINTING ///// - -/** - * Print a DNS header. - * - * @param message the DNS header - */ -void dns_print_header(dns_header_t header); - -/** - * Print a DNS Question - * - * @param question the DNS Question - */ -void dns_print_question(dns_question_t question); - -/** - * Print a DNS Question section. - * - * @param qdcount the number of Questions in the Question section - * @param questions the list of DNS Questions - */ -void dns_print_questions(uint16_t qdcount, dns_question_t *questions); - -/** - * Return a string representation of the given RDATA value. - * - * @param rtype the type corresponding to the RDATA value - * @param rdlength the length, in bytes, of the RDATA value - * @param rdata the RDATA value, stored as a union type - * @return a string representation of the RDATA value - */ -char* dns_rdata_to_str(dns_rr_type_t rtype, uint16_t rdlength, rdata_t rdata); - -/** - * Print a DNS Resource Record. - * - * @param section_name the name of the Resource Record section - * @param rr the DNS Resource Record - */ -void dns_print_rr(char* section_name, dns_resource_record_t rr); - -/** - * Print a DNS Resource Records section. - * - * @param section_name the name of the Resource Record section - * @param count the number of Resource Records in the section - * @param rrs the list of DNS Resource Records - */ -void dns_print_rrs(char* section_name, uint16_t count, dns_resource_record_t *rrs); - -/** - * Print a DNS message. - * - * @param message the DNS message - */ -void dns_print_message(dns_message_t message); - - -#endif /* _IOTFIREWALL_DNS_ */ diff --git a/include/parsers/header.h b/include/parsers/header.h deleted file mode 100644 index d7a010552b15e762a2ee603b9c47f0b42d8132d1..0000000000000000000000000000000000000000 --- a/include/parsers/header.h +++ /dev/null @@ -1,140 +0,0 @@ -/** - * @file include/parsers/header.h - * @brief Parser for layer 3 and 4 headers (currently only IP, UDP and TCP) - * - * Parser for layer 3 and 4 headers. - * Currently supported protocols: - * - Layer 3: - * - IP - * - Layer 4: - * - UDP - * - TCP - * - * @date 2022-09-09 - * - * @copyright Copyright (c) 2022 - * - */ - -#ifndef _IOTFIREWALL_HEADER_ -#define _IOTFIREWALL_HEADER_ - -#include <stdlib.h> -#include <stdio.h> -#include <stdint.h> -#include <string.h> -#include <arpa/inet.h> -#include "packet_utils.h" - -#define IPV6_HEADER_LENGTH 40 -#define UDP_HEADER_LENGTH 8 - - -/** - * IP protocols assigned to their protocol number - */ -typedef enum { - ICMP = 1, - IGMP = 2, - TCP = 6, - UDP = 17 -} ip_protocol_t; - -/** - * Retrieve the length of a packet's IPv4 header. - * - * @param data a pointer to the start of the packet's IPv4 header - * @return the size, in bytes, of the IPv4 header - */ -size_t get_ipv4_header_length(uint8_t *data); - -/** - * Retrieve the length of a packet's IPv6 header. - * - * @param data a pointer to the start of the packet's IPv6 header - * @return the size, in bytes, of the IPv6 header - */ -size_t get_ipv6_header_length(uint8_t *data); - -/** - * Retrieve the length of a packet's UDP header. - * - * @param data a pointer to the start of the packet's UDP (layer 4) header - * @return the size, in bytes, of the UDP header - */ -size_t get_udp_header_length(uint8_t *data); - -/** - * Retrieve the length of a packet's TCP header. - * - * @param data a pointer to the start of the packet's TCP (layer 4) header - * @return the size, in bytes, of the UDP header - */ -size_t get_tcp_header_length(uint8_t *data); - -/** - * Retrieve the length of a packet's layer 3 header (IPv4 or IPv6). - * - * @param data a pointer to the start of the packet's layer 3 header - * @return the size, in bytes, of the layer 3 header - */ -size_t get_l3_header_length(uint8_t *data); - -/** - * Retrieve the length of a packet's layer-3 and layer-4 headers. - * - * @param data a pointer to the start of the packet's layer-3 header - * @return the size, in bytes, of the UDP header - */ -size_t get_headers_length(uint8_t* data); - -/** - * @brief Retrieve the length of a UDP payload. - * - * @param data pointer to the start of the UDP header - * @return length of the UDP payload, in bytes - */ -uint16_t get_udp_payload_length(uint8_t *data); - -/** - * @brief Retrieve the source port from a layer 4 header. - * - * @param data pointer to the start of the layer 4 header - * @return destination port - */ -uint16_t get_dst_port(uint8_t* data); - -/** - * @brief Retrieve the source address from an IPv4 header. - * - * @param data pointer to the start of the IPv4 header - * @return source IPv4 address, in network byte order - */ -uint32_t get_ipv4_src_addr(uint8_t *data); - -/** - * @brief Retrieve the destination address from an IPv4 header. - * - * @param data pointer to the start of the IPv4 header - * @return destination IPv4 address, in network byte order - */ -uint32_t get_ipv4_dst_addr(uint8_t *data); - -/** - * @brief Retrieve the source address from an IPv6 header. - * - * @param data pointer to the start of the IPv6 header - * @return source IPv6 address, as a 16-byte array - */ -uint8_t* get_ipv6_src_addr(uint8_t *data); - -/** - * @brief Retrieve the destination address from an IPv6 header. - * - * @param data pointer to the start of the IPv6 header - * @return destination IPv6 address, as a 16-byte array - */ -uint8_t* get_ipv6_dst_addr(uint8_t *data); - - -#endif /* _IOTFIREWALL_HEADER_ */ diff --git a/include/parsers/http.h b/include/parsers/http.h deleted file mode 100644 index 28d4d6e95038ec42f280b25e941387127f3d1668..0000000000000000000000000000000000000000 --- a/include/parsers/http.h +++ /dev/null @@ -1,101 +0,0 @@ -/** - * @file include/parsers/http.h - * @brief HTTP message parser - * @date 2022-09-09 - * - * @copyright Copyright (c) 2022 - * - */ - -#ifndef _IOTFIREWALL_HTTP_ -#define _IOTFIREWALL_HTTP_ - -#include <stdlib.h> -#include <stdio.h> -#include <stdint.h> -#include <stdbool.h> - -#define HTTP_MESSAGE_MIN_LEN 16 // Minimum length of a HTTP message -#define HTTP_METHOD_MAX_LEN 7 // Maximum length of a HTTP method -#define HTTP_URI_DEFAULT_LEN 100 // Default length of a HTTP URI - - -/** - * HTTP methods - */ -typedef enum -{ - HTTP_GET, - HTTP_HEAD, - HTTP_POST, - HTTP_PUT, - HTTP_DELETE, - HTTP_CONNECT, - HTTP_OPTIONS, - HTTP_TRACE, - HTTP_UNKNOWN -} http_method_t; - -/** - * Abstraction of a HTTP message - */ -typedef struct http_message { - bool is_request; // True if the message is a request, false if it is a response - http_method_t method; // HTTP method (GET, POST, etc.) - char *uri; // Message URI -} http_message_t; - - -////////// FUNCTIONS ////////// - -///// PARSING ///// - -/** - * @brief Check if a TCP message is a HTTP message. - * - * @param data pointer to the start of the TCP payload - * @param dst_port TCP destination port - * @return true if the message is a HTTP message - * @return false if the message is not a HTTP message - */ -bool is_http(uint8_t *data); - -/** - * @brief Parse the method and URI of HTTP message. - * - * @param data pointer to the start of the HTTP message - * @param src_port TCP destination port - * @return the parsed HTTP message - */ -http_message_t http_parse_message(uint8_t *data, uint16_t dst_port); - - -///// DESTROY ///// - -/** - * @brief Free the memory allocated for a HTTP message. - * - * @param message the HTTP message to free - */ -void http_free_message(http_message_t message); - - -///// PRINTING ///// - -/** - * @brief Converts a HTTP method from enum value to character string. - * - * @param method the HTTP method in enum value - * @return the same HTTP method as a character string - */ -char* http_method_to_str(http_method_t method); - -/** - * @brief Print an HTTP message. - * - * @param message the HTTP message to print - */ -void http_print_message(http_message_t message); - - -#endif /* _IOTFIREWALL_HTTP_ */ diff --git a/include/parsers/igmp.h b/include/parsers/igmp.h deleted file mode 100644 index 4a541fff8c830aa7695a3ab1c003f74b73966d85..0000000000000000000000000000000000000000 --- a/include/parsers/igmp.h +++ /dev/null @@ -1,121 +0,0 @@ -/** - * @file include/parsers/igmp.h - * @brief IGMP message parser - * @date 2022-10-05 - * - * IGMP message parser. - * Supports v1 and v2, and v3 Membership Report messages. - * TODO: support v3 Membership Query messages. - * - * @copyright Copyright (c) 2022 - * - */ - -#ifndef _IOTFIREWALL_IGMP_ -#define _IOTFIREWALL_IGMP_ - -#include <stdio.h> -#include <stdint.h> -#include "packet_utils.h" - - -/** - * @brief IGMP message types - */ -typedef enum { - MEMBERSHIP_QUERY = 0x11, - V1_MEMBERSHIP_REPORT = 0x12, - V2_MEMBERSHIP_REPORT = 0x16, - LEAVE_GROUP = 0x17, - V3_MEMBERSHIP_REPORT = 0x22 -} igmp_message_type_t; - -/** - * @brief IGMPv2 message - */ -typedef struct { - uint8_t max_resp_time; - uint16_t checksum; - uint32_t group_address; // IPv4 group address, in network byte order -} igmp_v2_message_t; - -/** - * @brief IGMPv3 membership query - */ -typedef struct { - uint8_t max_resp_code; - uint16_t checksum; - uint32_t group_address; // IPv4 group address, in network byte order - uint8_t flags; // Resv, S, QRV - uint8_t qqic; - uint16_t num_sources; - uint32_t *sources; // Array of IPv4 addresses, in network byte order -} igmp_v3_membership_query_t; - -/** - * @brief IGMPv3 Group Record - */ -typedef struct { - uint8_t type; - uint8_t aux_data_len; - uint16_t num_sources; - uint32_t group_address; // IPv4 group address, in network byte order - uint32_t *sources; // Array of IPv4 addresses, in network byte order -} igmp_v3_group_record_t; - -/** - * @brief IGMPv3 membership report - */ -typedef struct { - uint16_t checksum; - uint16_t num_groups; - igmp_v3_group_record_t *groups; // Array of group records -} igmp_v3_membership_report_t; - -/** - * @brief IGMP message body. - */ -typedef union -{ - igmp_v2_message_t v2_message; - igmp_v3_membership_query_t v3_membership_query; - igmp_v3_membership_report_t v3_membership_report; -} igmp_message_body_t; - -/** - * @brief Generic IGMP message - */ -typedef struct -{ - uint8_t version; - igmp_message_type_t type; - igmp_message_body_t body; -} igmp_message_t; - - -////////// FUNCTIONS ////////// - -/** - * @brief Parse an IGMP message. - * - * @param data pointer to the start of the IGMP message - * @return the parsed IGMP message - */ -igmp_message_t igmp_parse_message(uint8_t *data); - -/** - * @brief Free the memory allocated for an IGMP message. - * - * @param message the IGMP message to free - */ -void igmp_free_message(igmp_message_t message); - -/** - * @brief Print an IGMP message. - * - * @param message the IGMP message to print - */ -void igmp_print_message(igmp_message_t message); - - -#endif /* _IOTFIREWALL_IGMP_ */ diff --git a/include/parsers/ssdp.h b/include/parsers/ssdp.h deleted file mode 100644 index 689e2519a6b17bb18c2b510f4f13a395499bb427..0000000000000000000000000000000000000000 --- a/include/parsers/ssdp.h +++ /dev/null @@ -1,73 +0,0 @@ -/** - * @file include/parsers/ssdp.h - * @brief SSDP message parser - * @date 2022-11-24 - * - * @copyright Copyright (c) 2022 - * - */ - -#ifndef _IOTFIREWALL_SSDP_ -#define _IOTFIREWALL_SSDP_ - -#include <stdlib.h> -#include <stdio.h> -#include <stdint.h> -#include <stdbool.h> -#include <arpa/inet.h> -#include "packet_utils.h" - -#define SSDP_METHOD_MAX_LEN 8 // Maximum length of a SSDP method -#define SSDP_MULTICAST_ADDR "239.255.255.250" // SSDP multicast group address - -/** - * SSDP methods - */ -typedef enum { - SSDP_M_SEARCH, - SSDP_NOTIFY, - SSDP_UNKNOWN -} ssdp_method_t; - -/** - * Abstraction of an SSDP message - */ -typedef struct ssdp_message { - bool is_request; // True if the message is a request, false if it is a response - ssdp_method_t method; // SSDP method (M-SEARCH or NOTIFY) -} ssdp_message_t; - - -////////// FUNCTIONS ////////// - -///// PARSING ///// - -/** - * @brief Parse the method and URI of SSDP message. - * - * @param data pointer to the start of the SSDP message - * @param dst_addr IPv4 destination address, in network byte order - * @return the parsed SSDP message - */ -ssdp_message_t ssdp_parse_message(uint8_t *data, uint32_t dst_addr); - - -///// PRINTING ///// - -/** - * @brief Converts a SSDP method from enum value to character string. - * - * @param method the SSDP method in enum value - * @return the same SSDP method as a character string - */ -char *ssdp_method_to_str(ssdp_method_t method); - -/** - * @brief Print the method and URI of a SSDP message. - * - * @param message the message to print - */ -void ssdp_print_message(ssdp_message_t message); - - -#endif /* _IOTFIREWALL_SSDP_ */ diff --git a/include/sha256.h b/include/sha256.h deleted file mode 100644 index 7123a30dd49628d6ca15345c33968c50ca328cb7..0000000000000000000000000000000000000000 --- a/include/sha256.h +++ /dev/null @@ -1,34 +0,0 @@ -/********************************************************************* -* Filename: sha256.h -* Author: Brad Conte (brad AT bradconte.com) -* Copyright: -* Disclaimer: This code is presented "as is" without any guarantees. -* Details: Defines the API for the corresponding SHA1 implementation. -*********************************************************************/ - -#ifndef SHA256_H -#define SHA256_H - -/*************************** HEADER FILES ***************************/ -#include <stddef.h> - -/****************************** MACROS ******************************/ -#define SHA256_BLOCK_SIZE 32 // SHA256 outputs a 32 byte digest - -/**************************** DATA TYPES ****************************/ -typedef unsigned char BYTE; // 8-bit byte -typedef unsigned int WORD; // 32-bit word, change to "long" for 16-bit machines - -typedef struct { - BYTE data[64]; - WORD datalen; - unsigned long long bitlen; - WORD state[8]; -} SHA256_CTX; - -/*********************** FUNCTION DECLARATIONS **********************/ -void sha256_init(SHA256_CTX *ctx); -void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len); -void sha256_final(SHA256_CTX *ctx, BYTE hash[]); - -#endif // SHA256_H diff --git a/src/dns_map.c b/src/dns_map.c deleted file mode 100644 index b5406b8f17adec239c60ae6bf716cb803870aec1..0000000000000000000000000000000000000000 --- a/src/dns_map.c +++ /dev/null @@ -1,203 +0,0 @@ -/** - * @file src/dns_map.c - * @brief Implementation of a DNS domain name to IP addresses mapping, using Joshua J Baker's hashmap.c (https://github.com/tidwall/hashmap.c) - * @date 2022-09-06 - * - * @copyright Copyright (c) 2022 - * - */ - -#include "dns_map.h" - - -/*** Static functions for hashmap ****/ - -/** - * Hash function for the DNS table. - * - * @param item DNS table entry to hash - * @param seed0 first seed - * @param seed1 second seed - * @return hash value for the given DNS table entry - */ -static uint64_t dns_hash(const void *item, uint64_t seed0, uint64_t seed1) { - const dns_entry_t *entry = (dns_entry_t *) item; - return hashmap_sip(entry->domain_name, strlen(entry->domain_name), seed0, seed1); -} - -/** - * Compare function for the DNS table. - * - * @param a first DNS table entry to compare - * @param a second DNS table entry to compare - * @param udata user data, unused - * @return an integer which takes the following value: - * - 0 if a and b are equal - * - less than 0 if a is smaller than b - * - greater than 0 if a is greater than b - */ -static int dns_compare(const void *a, const void *b, void *udata) { - const dns_entry_t *entry1 = (dns_entry_t *) a; - const dns_entry_t *entry2 = (dns_entry_t *) b; - return strcmp(entry1->domain_name, entry2->domain_name); -} - -/** - * Free an entry of the DNS table. - * - * @param item the entry to free - */ -static void dns_free(void *item) { - free(((dns_entry_t *) item)->ip_list.ip_addresses); -} - - -/*** Visible functions ***/ - -/** - * @brief Initialize an ip_list_t structure. - * - * Creates an empty list of IP addresses. - * The `ip_count` field is set to 0, - * and the `ip_addresses` field is set to NULL. - * - * @return ip_list_t newly initialized structure - */ -ip_list_t ip_list_init() { - ip_list_t ip_list; - ip_list.ip_count = 0; - ip_list.ip_addresses = NULL; - return ip_list; -} - -/** - * @brief Checks if a dns_entry_t structure contains a given IP address. - * - * @param dns_entry pointer to the DNS entry to process - * @param ip_address IP address to check the presence of - * @return true if the IP address is present in the DNS entry, false otherwise - */ -bool dns_entry_contains(dns_entry_t *dns_entry, ip_addr_t ip_address) { - if (dns_entry == NULL || dns_entry->ip_list.ip_addresses == NULL) { - // DNS entry or IP address list is NULL - return false; - } - - // Not NULL, search for the IP address - for (uint8_t i = 0; i < dns_entry->ip_list.ip_count; i++) { - if (compare_ip(*(dns_entry->ip_list.ip_addresses + i), ip_address)) { - // IP address found - return true; - } - } - - // IP address not found - return false; -} - -/** - * Create a new DNS table. - * Uses random seeds for the hash function. - * - * @return the newly created DNS table, or NULL if creation failed - */ -dns_map_t* dns_map_create() { - return hashmap_new( - sizeof(dns_entry_t), // Size of one entry - DNS_MAP_INIT_SIZE, // Hashmap initial size - rand(), // Optional seed 1 - rand(), // Optional seed 2 - &dns_hash, // Hash function - &dns_compare, // Compare function - &dns_free, // Element free function - NULL // User data, unused - ); -} - -/** - * Free the memory allocated for a DNS table. - * - * @param table the DNS table to free - */ -void dns_map_free(dns_map_t *table) { - hashmap_free(table); -} - -/** - * Add IP addresses corresponding to a given domain name in the DNS table. - * If the domain name was already present, its IP addresses will be replaced by the new ones. - * - * @param table the DNS table to add the entry to - * @param domain_name the domain name of the entry - * @param ip_list an ip_list_t structure containing the list of IP addresses - */ -void dns_map_add(dns_map_t *table, char *domain_name, ip_list_t ip_list) { - dns_entry_t *dns_entry = dns_map_get(table, domain_name); - if (dns_entry != NULL) { - // Domain name already present, add given IP addresses to the already existing ones - ip_list_t old_ip_list = dns_entry->ip_list; - ip_list_t new_ip_list; - new_ip_list.ip_count = old_ip_list.ip_count + ip_list.ip_count; - new_ip_list.ip_addresses = (ip_addr_t *) malloc(new_ip_list.ip_count * sizeof(ip_addr_t)); - memcpy(new_ip_list.ip_addresses, old_ip_list.ip_addresses, old_ip_list.ip_count * sizeof(ip_addr_t)); - memcpy(new_ip_list.ip_addresses + old_ip_list.ip_count, ip_list.ip_addresses, ip_list.ip_count * sizeof(ip_addr_t)); - dns_entry->ip_list = new_ip_list; - free(old_ip_list.ip_addresses); - free(ip_list.ip_addresses); - } else { - // Domain name not present, create a new entry with given IP addresses - hashmap_set(table, &(dns_entry_t){.domain_name = domain_name, .ip_list = ip_list}); - } -} - -/** - * Remove a domain name, and its corresponding IP addresses, from the DNS table. - * - * @param table the DNS table to remove the entry from - * @param domain_name the domain name of the entry to remove - */ -void dns_map_remove(dns_map_t *table, char *domain_name) { - dns_entry_t *entry = hashmap_delete(table, &(dns_entry_t){ .domain_name = domain_name }); - if (entry != NULL) - dns_free(entry); -} - -/** - * Retrieve the IP addresses corresponding to a given domain name in the DNS table. - * - * @param table the DNS table to retrieve the entry from - * @param domain_name the domain name of the entry to retrieve - * @return a pointer to a dns_entry structure containing the IP addresses corresponding to the domain name, - * or NULL if the domain name was not found in the DNS table - */ -dns_entry_t* dns_map_get(dns_map_t *table, char *domain_name) { - return (dns_entry_t *) hashmap_get(table, &(dns_entry_t){ .domain_name = domain_name }); -} - -/** - * Retrieve the IP addresses corresponding to a given domain name, - * and remove the domain name from the DNS table. - * - * @param table the DNS table to retrieve the entry from - * @param domain_name the domain name of the entry to retrieve - * @return a pointer to a dns_entry structure containing the IP addresses corresponding to the domain name, - * or NULL if the domain name was not found in the DNS table - */ -dns_entry_t* dns_map_pop(dns_map_t *table, char *domain_name) { - return (dns_entry_t *) hashmap_delete(table, &(dns_entry_t){ .domain_name = domain_name }); -} - -/** - * @brief Print a DNS table entry. - * - * @param dns_entry the DNS table entry to print - */ -void dns_entry_print(dns_entry_t *dns_entry) { - if (dns_entry != NULL) { - printf("Domain name: %s\n", dns_entry->domain_name); - printf("IP addresses:\n"); - for (uint8_t i = 0; i < dns_entry->ip_list.ip_count; i++) { - printf(" %s\n", ip_net_to_str(*(dns_entry->ip_list.ip_addresses + i))); - } - } -} diff --git a/src/packet_utils.c b/src/packet_utils.c deleted file mode 100644 index 8b0aec2358ec417e898759dfdd46ec602b86f90c..0000000000000000000000000000000000000000 --- a/src/packet_utils.c +++ /dev/null @@ -1,294 +0,0 @@ -/** - * @file src/packet_utils.c - * @brief Utilitaries for payload manipulation and display - * @date 2022-09-09 - * - * @copyright Copyright (c) 2022 - * - */ - -#include "packet_utils.h" - - -/** - * Print a packet payload. - * - * @param length length of the payload in bytes - * @param data pointer to the start of the payload - */ -void print_payload(int length, uint8_t *data) { - char trailing = ' '; - // Iterate on the whole payload - for (int i = 0; i < length; i++) { - if (i == length - 1) { - // Insert newline after last byte - trailing = '\n'; - } - - uint8_t c = *(data + i); - if (c == 0) { - printf("0x00%c", trailing); - } else { - printf("%#.2x%c", c, trailing); - } - } -} - -/** - * Converts a hexstring payload to a data buffer. - * - * @param hexstring the hexstring to convert - * @param payload a double pointer to the payload, which will be set to the start of the payload - * @return the length of the payload in bytes - */ -size_t hexstr_to_payload(char *hexstring, uint8_t **payload) { - size_t length = strlen(hexstring) / 2; // Size of the payload in bytes, one byte is two characters - *payload = (uint8_t *) malloc(length * sizeof(uint8_t)); // Allocate memory for the payload - - // WARNING: no sanitization or error-checking whatsoever - for (size_t count = 0; count < length; count++) { - sscanf(hexstring + 2*count, "%2hhx", (*payload) + count); // Convert two characters to one byte - } - - return length; -} - -/** - * Converts a MAC address from its hexadecimal representation - * to its string representation. - * - * @param mac_hex MAC address in hexadecimal representation - * @return the same MAC address in string representation - */ -char *mac_hex_to_str(uint8_t mac_hex[]) -{ - char *mac_str = (char *) malloc(MAC_ADDR_STRLEN * sizeof(char)); // A string representation of a MAC address is 17 characters long + null terminator - int ret = snprintf(mac_str, MAC_ADDR_STRLEN, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", mac_hex[0], mac_hex[1], mac_hex[2], mac_hex[3], mac_hex[4], mac_hex[5]); - // Error handling - if (ret != MAC_ADDR_STRLEN - 1) - { - free(mac_str); - fprintf(stderr, "Error converting MAC address \\x%2x\\x%2x\\x%2x\\x%2x\\x%2x\\x%2x to string representation.\n", mac_hex[0], mac_hex[1], mac_hex[2], mac_hex[3], mac_hex[4], mac_hex[5]); - return NULL; - } - return mac_str; -} - -/** - * Converts a MAC address from its string representation - * to its hexadecimal representation. - * - * @param mac_str MAC address in string representation - * @return the same MAC address in hexadecimal representation - */ -uint8_t *mac_str_to_hex(char *mac_str) -{ - uint8_t *mac_hex = (uint8_t *) malloc(MAC_ADDR_LENGTH * sizeof(uint8_t)); // A MAC address is 6 bytes long - int ret = sscanf(mac_str, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", mac_hex, mac_hex + 1, mac_hex + 2, mac_hex + 3, mac_hex + 4, mac_hex + 5); - // Error handling - if (ret != MAC_ADDR_LENGTH) - { - free(mac_hex); - fprintf(stderr, "Error converting MAC address %s to hexadecimal representation.\n", mac_str); - return NULL; - } - return mac_hex; -} - -/** - * Converts an IPv4 address from its network order numerical representation - * to its string representation. - * (Wrapper arount inet_ntoa) - * - * @param ipv4_net IPv4 address in hexadecimal representation - * @return the same IPv4 address in string representation - */ -char* ipv4_net_to_str(uint32_t ipv4_net) { - return inet_ntoa((struct in_addr) {ipv4_net}); -} - -/** - * Converts an IPv4 address from its string representation - * to its network order numerical representation. - * (Wrapper arount inet_aton) - * - * @param ipv4_str IPv4 address in string representation - * @return the same IPv4 address in network order numerical representation - */ -uint32_t ipv4_str_to_net(char *ipv4_str) { - struct in_addr ipv4_addr; - inet_aton(ipv4_str, &ipv4_addr); - return ipv4_addr.s_addr; -} - -/** - * Converts an IPv4 addres from its hexadecimal representation - * to its string representation. - * - * @param ipv4_hex IPv4 address in hexadecimal representation - * @return the same IPv4 address in string representation - */ -char* ipv4_hex_to_str(char *ipv4_hex) { - char* ipv4_str = (char *) malloc(INET_ADDRSTRLEN * sizeof(char)); // A string representation of an IPv4 address is at most 15 characters long + null terminator - int ret = snprintf(ipv4_str, INET_ADDRSTRLEN, "%hhu.%hhu.%hhu.%hhu", *ipv4_hex, *(ipv4_hex + 1), *(ipv4_hex + 2), *(ipv4_hex + 3)); - // Error handling - if (ret < 0) { - free(ipv4_str); - fprintf(stderr, "Error converting IPv4 address \\x%2x\\x%2x\\x%2x\\x%2x to string representation.\n", *ipv4_hex, *(ipv4_hex + 1), *(ipv4_hex + 2), *(ipv4_hex + 3)); - return NULL; - } - return ipv4_str; -} - -/** - * Converts an IPv4 address from its string representation - * to its hexadecimal representation. - * - * @param ipv4_str IPv4 address in string representation - * @return the same IPv4 address in hexadecimal representation - */ -char* ipv4_str_to_hex(char *ipv4_str) { - char* ipv4_hex = (char *) malloc(4 * sizeof(char)); // An IPv4 address is 4 bytes long - int ret = sscanf(ipv4_str, "%hhu.%hhu.%hhu.%hhu", ipv4_hex, ipv4_hex + 1, ipv4_hex + 2, ipv4_hex + 3); - // Error handling - if (ret != 4) { - free(ipv4_hex); - fprintf(stderr, "Error converting IPv4 address %s to hexadecimal representation.\n", ipv4_str); - return NULL; - } - return ipv4_hex; -} - -/** - * @brief Converts an IPv6 to its string representation. - * - * @param ipv6 the IPv6 address - * @return the same IPv6 address in string representation - */ -char* ipv6_net_to_str(uint8_t ipv6[]) { - char *ipv6_str = (char *) malloc(INET6_ADDRSTRLEN * sizeof(char)); - const char *ret = inet_ntop(AF_INET6, ipv6, ipv6_str, INET6_ADDRSTRLEN); - // Error handling - if (ret == NULL) { - fprintf(stderr, "Error converting IPv6 address \\x%2x\\x%2x\\x%2x\\x%2x\\x%2x\\x%2x\\x%2x\\x%2x\\x%2x\\x%2x\\x%2x\\x%2x\\x%2x\\x%2x\\x%2x\\x%2x to its string representation.\n", ipv6[0], ipv6[1], ipv6[2], ipv6[3], ipv6[4], ipv6[5], ipv6[6], ipv6[7], ipv6[8], ipv6[9], ipv6[10], ipv6[11], ipv6[12], ipv6[13], ipv6[14], ipv6[15]); - } - return ipv6_str; -} - -/** - * Converts an IPv6 address from its string representation - * to its network representation (a 16-byte array). - * - * @param ipv6_str IPv6 address in string representation - * @return the same IPv6 address as a 16-byte array - */ -uint8_t *ipv6_str_to_net(char *ipv6_str) { - uint8_t *ipv6 = (uint8_t *) malloc(IPV6_ADDR_LENGTH * sizeof(uint8_t)); // An IPv6 address is 16 bytes long - int err = inet_pton(AF_INET6, ipv6_str, ipv6); - // Error handling - if (err != 1) { - fprintf(stderr, "Error converting IPv6 address %s to its network representation.\n", ipv6_str); - return NULL; - } - return ipv6; -} - -/** - * @brief Converts an IP (v4 or v6) address to its string representation. - * - * Converts an IP (v4 or v6) address to its string representation. - * If it is an IPv6 address, it must be freed after use. - * - * @param ip_addr the IP address, as an ip_addr_t struct - * @return the same IP address in string representation - */ -char* ip_net_to_str(ip_addr_t ip_addr) { - switch (ip_addr.version) { - case 4: - return ipv4_net_to_str(ip_addr.value.ipv4); - break; - case 6: - return ipv6_net_to_str(ip_addr.value.ipv6); - break; - default: - fprintf(stderr, "Unknown IP version: %hhu.\n", ip_addr.version); - return ""; - } -} - -/** - * Converts an IP (v4 or v6) address from its string representation - * to an ip_addr_t struct. - * - * @param ip_str IP (v4 or v6) address in string representation - * @return the same IP address as a ip_addr_t struct - */ -ip_addr_t ip_str_to_net(char *ip_str, uint8_t version) { - ip_addr_t ip_addr; - ip_addr.version = version; - if (version == 4) { - ip_addr.value.ipv4 = ipv4_str_to_net(ip_str); - } else if (version == 6) { - uint8_t *ipv6_net = ipv6_str_to_net(ip_str); - memcpy(ip_addr.value.ipv6, ipv6_net, IPV6_ADDR_LENGTH); - free(ipv6_net); - } else { - fprintf(stderr, "Error converting address %s to ip_addr_t.\n", ip_str); - } - return ip_addr; -} - -/** - * @brief Compare two IPv6 addresses. - * - * @param ipv6_1 first IPv6 address - * @param ipv6_2 second IPv6 address - * @return true if the two addresses are equal, false otherwise - */ -bool compare_ipv6(uint8_t *ipv6_1, uint8_t *ipv6_2) { - return memcmp(ipv6_1, ipv6_2, 16) == 0; -} - -/** - * @brief Compare two IP (v4 or v6) addresses. - * - * @param ip_1 first IP address - * @param ip_2 second IP address - * @return true if the two addresses are equal, false otherwise - */ -bool compare_ip(ip_addr_t ip_1, ip_addr_t ip_2) { - if (ip_1.version == 4 && ip_2.version == 4) { - return ip_1.value.ipv4 == ip_2.value.ipv4; - } else if (ip_1.version == 6 && ip_2.version == 6) { - return compare_ipv6(ip_1.value.ipv6, ip_2.value.ipv6); - } else { - return false; - } -} - -/** - * @brief Compute SHA256 hash of a given payload. - * - * @param payload Payload to hash - * @param payload_len Payload length, including padding (in bytes) - * @return uint8_t* SHA256 hash of the payload - */ -uint8_t* compute_hash(uint8_t *payload, int payload_len) { - uint8_t *hash = (uint8_t *) malloc(SHA256_BLOCK_SIZE * sizeof(uint8_t)); - SHA256_CTX ctx; - sha256_init(&ctx); - sha256_update(&ctx, payload, payload_len); - sha256_final(&ctx, hash); - return hash; -} - -/** - * @brief Print a SHA256 hash. - * - * @param hash SHA256 hash to print - */ -void print_hash(uint8_t *hash) { - for (uint16_t i = 0; i < SHA256_BLOCK_SIZE; i++) { - printf("%02x", *(hash + i)); - } -} diff --git a/src/parsers/CMakeLists.txt b/src/parsers/CMakeLists.txt deleted file mode 100644 index 95c212e9e6ec1a031f837603f4d1c161b330c2d0..0000000000000000000000000000000000000000 --- a/src/parsers/CMakeLists.txt +++ /dev/null @@ -1,31 +0,0 @@ -# Minimum required CMake version -cmake_minimum_required(VERSION 3.20) - -set(INCLUDE_PARSERS_DIR ${INCLUDE_DIR}/parsers) - -# Header parser -add_library(header STATIC ${INCLUDE_PARSERS_DIR}/header.h header.c) -target_include_directories(header PRIVATE ${INCLUDE_DIR} ${INCLUDE_PARSERS_DIR}) -target_link_libraries(header packet_utils) -# DNS parser -add_library(dns STATIC ${INCLUDE_PARSERS_DIR}/dns.h dns.c) -target_include_directories(dns PRIVATE ${INCLUDE_DIR} ${INCLUDE_PARSERS_DIR}) -target_link_libraries(dns packet_utils dns_map) -# DHCP parser -add_library(dhcp STATIC ${INCLUDE_PARSERS_DIR}/dhcp.h dhcp.c) -target_include_directories(dhcp PRIVATE ${INCLUDE_DIR} ${INCLUDE_PARSERS_DIR}) -# HTTP parser -add_library(http STATIC ${INCLUDE_PARSERS_DIR}/http.h http.c) -target_include_directories(http PRIVATE ${INCLUDE_DIR} ${INCLUDE_PARSERS_DIR}) -# IGMP parser -add_library(igmp STATIC ${INCLUDE_PARSERS_DIR}/igmp.h igmp.c) -target_include_directories(igmp PRIVATE ${INCLUDE_DIR} ${INCLUDE_PARSERS_DIR}) -# SSDP parser -add_library(ssdp STATIC ${INCLUDE_PARSERS_DIR}/ssdp.h ssdp.c) -target_include_directories(ssdp PRIVATE ${INCLUDE_DIR} ${INCLUDE_PARSERS_DIR}) -# CoAP parser -add_library(coap STATIC ${INCLUDE_PARSERS_DIR}/coap.h coap.c) -target_include_directories(coap PRIVATE ${INCLUDE_DIR} ${INCLUDE_PARSERS_DIR}) -target_link_libraries(coap http) -# Installation -install(TARGETS ${PARSERS} DESTINATION ${LIB_DIR}) diff --git a/src/parsers/coap.c b/src/parsers/coap.c deleted file mode 100644 index d4ac043cb0d914a1d97daf3af63998ba7b2fa1a3..0000000000000000000000000000000000000000 --- a/src/parsers/coap.c +++ /dev/null @@ -1,201 +0,0 @@ -/** - * @file src/parsers/coap.c - * @brief CoAP message parser - * @date 2022-11-30 - * - * @copyright Copyright (c) 2022 - * - */ - -#include "coap.h" - - -///// PARSING ///// - -/** - * @brief Parse the method of a CoAP message. - * - * @param code byte which encodes the CoAP method - * @return CoAP method - */ -static http_method_t coap_parse_method(uint8_t code) { - switch (code) { - case 1: - return HTTP_GET; - break; - case 2: - return HTTP_POST; - break; - case 3: - return HTTP_PUT; - break; - case 4: - return HTTP_DELETE; - break; - default: - // CoAP responses and all other codes are not supported - return HTTP_UNKNOWN; - } -} - -/** - * @brief Parse an URI option (Uri-Path or Uri-Query) of a CoAP message. - * - * @param message pointer to the CoAP message, which will be updated - * @param option CoAP option number (11 for Uri-Path, 15 for Uri-Query) - * @param length CoAP option length - * @param data pointer to the start of the URI option - */ -static void coap_parse_uri_option(coap_message_t *message, coap_option_t option_num, uint16_t length, uint8_t *data) { - char prefix = (option_num == COAP_URI_PATH) ? '/' : '?'; - if (message->uri == NULL) { - message->uri = malloc(length + 2); - } else { - message->uri = realloc(message->uri, message->uri_len + length + 2); - } - *(message->uri + message->uri_len) = prefix; - memcpy(message->uri + message->uri_len + 1, data, length); - message->uri_len += length + 1; - *(message->uri + message->uri_len) = '\0'; -} - -/** - * @brief Parse CoAP options. - * - * @param message pointer to the currently parsed CoAP message, which will be updated - * @param data pointer to the start of the options section of a CoAP message - * @param msg_length length of the rest of the CoAP message (after the header) - */ -static void coap_parse_options(coap_message_t *message, uint8_t *data, uint16_t msg_length) { - uint16_t option_num = 0; - uint16_t bytes_read = 0; - while (bytes_read < msg_length && *data != 0b11111111) - { - // Parse option delta - uint16_t delta = (*data) >> 4; - uint8_t delta_len = 0; // Length of the extended delta field - switch (delta) { - case 13: - delta = (*(data + 1)) + 13; - delta_len = 1; - break; - case 14: - delta = ntohs(*((uint16_t*) (data + 1))) + 269; - delta_len = 2; - break; - case 15: - continue; - break; - default: - break; - } - // Compute option number - option_num += delta; - - // Parse option length - uint16_t option_length = (*data) & 0b00001111; - uint8_t length_len = 0; // Length of the extended length field - switch (option_length) - { - case 13: - option_length = (*(data + 1 + delta_len)) + 13; - length_len = 1; - break; - case 14: - option_length = ntohs(*((uint16_t *)(data + 1 + delta_len))) + 269; - length_len = 2; - break; - case 15: - continue; - break; - default: - break; - } - - // Parse option value - data += 1 + delta_len + length_len; - if (option_num == COAP_URI_PATH || option_num == COAP_URI_QUERY) - { - // Option Uri-Path or Uri-Query - coap_parse_uri_option(message, option_num, option_length, data); - } - data += option_length; - bytes_read += 1 + delta_len + length_len + option_length; - // Other options are not supported (yet) - } -} - -/** - * @brief Parse a CoAP message. - * - * @param data pointer to the start of the CoAP message - * @param length length of the CoAP message, in bytes - * @return the parsed CoAP message - */ -coap_message_t coap_parse_message(uint8_t *data, uint16_t length) -{ - coap_message_t message; - message.type = (coap_type_t) (((*data) & 0b00110000) >> 4); // CoAP type is encoded in bits 2-3 - message.method = coap_parse_method(*(data + 1)); // CoAP method is encoded in byte 1 - uint8_t token_length = (*data) & 0b00001111; // CoAP token length is encoded in bits 4-7 - uint8_t header_length = 4 + token_length; // Length of the CoAP header - data += header_length; // Skip the header - message.uri = NULL; // Initialize the URI to NULL - message.uri_len = 0; - coap_parse_options(&message, data, length - header_length); // Parse CoAP options - return message; -} - - -///// DESTROY ///// - -/** - * @brief Free the memory allocated for a CoAP message. - * - * @param message the CoAP message to free - */ -void coap_free_message(coap_message_t message) { - if (message.uri != NULL) - free(message.uri); -} - - -///// PRINTING ///// - -/** - * @brief Converts a CoAP message type to its string representation. - * - * @param type CoAP message type - * @return string representation of the CoAP message type - */ -static char* coap_type_to_str(coap_type_t type) { - switch (type) { - case COAP_CON: - return "Confirmable"; - break; - case COAP_NON: - return "Non-Confirmable"; - break; - case COAP_ACK: - return "Acknowledgement"; - break; - case COAP_RST: - return "Reset"; - break; - default: - return "Unknown"; - } -} - -/** - * @brief Print a CoAP message. - * - * @param message the CoAP message to print - */ -void coap_print_message(coap_message_t message) -{ - printf("CoAP message:\n"); - printf(" Type: %s\n", coap_type_to_str(message.type)); - printf(" Method: %s\n", http_method_to_str(message.method)); - printf(" URI: %s\n", message.uri); -} diff --git a/src/parsers/dhcp.c b/src/parsers/dhcp.c deleted file mode 100644 index 6ef14eb6d94f8bd5676afcde137eda2ab833476f..0000000000000000000000000000000000000000 --- a/src/parsers/dhcp.c +++ /dev/null @@ -1,245 +0,0 @@ -/** - * @file src/parsers/dhcp.c - * @brief DHCP message parser - * @date 2022-09-12 - * - * @copyright Copyright (c) 2022 - * - */ - -#include "parsers/dhcp.h" - - -///// PARSING ///// - -/** - * @brief Parse the header of a DHCP message (not including options). - * - * @param data a pointer to the start of the DHCP message - * @return the parsed DHCP message with the header fields filled in - */ -dhcp_message_t dhcp_parse_header(uint8_t *data) { - dhcp_message_t message; - // Opcode: 1 byte - message.op = *data; - // htype: 1 byte - message.htype = *(data + 1); - // hlen: 1 byte - message.hlen = *(data + 2); - // hops: 1 byte - message.hops = *(data + 3); - // xid: 4 bytes - message.xid = ntohl(*((uint32_t *) (data + 4))); - // secs: 2 bytes - message.secs = ntohs(*((uint16_t *) (data + 8))); - // flags: 2 bytes - message.flags = ntohs(*((uint16_t *) (data + 10))); - // The IP addresses are left in network byte order - // ciaddr: 4 bytes - message.ciaddr = *((uint32_t *) (data + 12)); - // yiaddr: 4 bytes - message.yiaddr = *((uint32_t *) (data + 16)); - // siaddr: 4 bytes - message.siaddr = *((uint32_t *) (data + 20)); - // giaddr: 4 bytes - message.giaddr = *((uint32_t *) (data + 24)); - // chaddr: 16 bytes - memcpy(message.chaddr, data + 28, sizeof(uint8_t) * 16); - // sname: 64 bytes - memcpy(message.sname, data + 44, sizeof(uint8_t) * 64); - // file: 128 bytes - memcpy(message.file, data + 108, sizeof(uint8_t) * 128); - return message; -} - -/** - * @brief Parse a DHCP option. - * - * @param data a pointer to the start of the DHCP option - * @param offset a pointer to the current offset inside the DHCP message - * Its value will be updated to point to the next option - * @return the parsed DHCP option - */ -dhcp_option_t dhcp_parse_option(uint8_t *data, uint16_t *offset) { - dhcp_option_t option; - option.code = *(data + *offset); - if (option.code == DHCP_PAD || option.code == DHCP_END) - { - option.length = 0; - option.value = NULL; - *offset += 1; - } - else - { - option.length = *(data + *offset + 1); - option.value = (uint8_t *) malloc(sizeof(uint8_t) * option.length); - memcpy(option.value, data + *offset + 2, option.length * sizeof(uint8_t)); - *offset += 2 + option.length; - } - return option; -} - -/** - * @brief Parse DHCP options. - * - * @param data a pointer to the start of the DHCP options list - * @return a pointer to the start of the parsed DHCP options - */ -dhcp_options_t dhcp_parse_options(uint8_t *data) { - // Init - uint8_t max_option_count = DHCP_MAX_OPTION_COUNT; - dhcp_options_t options; - options.count = 0; - // Check magic cookie is equal to 0x63825363 - uint32_t magic_cookie = ntohl(*((uint32_t *) data)); - if (magic_cookie != DHCP_MAGIC_COOKIE) { - fprintf(stderr, "Error: DHCP magic cookie is %#x, which is not equal to %#x\n", magic_cookie, DHCP_MAGIC_COOKIE); - return options; - } - // Parse options - options.options = (dhcp_option_t *) malloc(sizeof(dhcp_option_t) * max_option_count); - uint16_t offset = 4; - uint8_t code; - do { - if (options.count == max_option_count) { - // Realloc memory if too many options - max_option_count *= 2; - options.options = (dhcp_option_t *) realloc(options.options, sizeof(dhcp_option_t) * max_option_count); - } - dhcp_option_t option = dhcp_parse_option(data, &offset); - code = option.code; - if (code == DHCP_MESSAGE_TYPE) { - // Store DHCP message type - options.message_type = *option.value; - } - *(options.options + (options.count++)) = option; - } while (code != DHCP_END); - // Shrink allocated memory to the actual number of options, if needed - if (options.count < max_option_count) { - options.options = (dhcp_option_t *) realloc(options.options, sizeof(dhcp_option_t) * options.count); - } - return options; -} - -/** - * @brief Parse a DHCP message. - * - * @param data a pointer to the start of the DHCP message - * @return the parsed DHCP message - */ -dhcp_message_t dhcp_parse_message(uint8_t *data) { - // Parse constant fields - dhcp_message_t message = dhcp_parse_header(data); - // Parse DHCP options - message.options = dhcp_parse_options(data + DHCP_HEADER_LEN); - // Return - return message; -} - - -///// DESTROY ////// - -/** - * @brief Free the memory allocated for a DHCP message. - * - * @param message the DHCP message to free - */ -void dhcp_free_message(dhcp_message_t message) { - if (message.options.count > 0) { - for (uint8_t i = 0; i < message.options.count; i++) { - dhcp_option_t option = *(message.options.options + i); - if (option.length > 0) { - free(option.value); - } - } - free(message.options.options); - } -} - - -///// PRINTING ///// - -/** - * @brief Print a hardware address. - * - * @param htype hardware type - * @param chaddr the hardware address to print - */ -static void dhcp_print_chaddr(uint8_t htype, uint8_t chaddr[]) { - printf(" Client hardware address: "); - uint8_t length = (htype == 1) ? 6 : 16; - printf("%02hhx", chaddr[0]); - for (uint8_t i = 1; i < length; i++) { - printf(":%02hhx", chaddr[i]); - } - printf("\n"); -} - -/** - * @brief Print the header of a DHCP message. - * - * @param message the DHCP message to print the header of - */ -void dhcp_print_header(dhcp_message_t message) { - // Opcode - printf(" Opcode: %hhu\n", message.op); - // htype - printf(" Hardware type: %hhu\n", message.htype); - // hlen - printf(" Hardware address length: %hhu\n", message.hlen); - // hops - printf(" Hops: %hhu\n", message.hops); - // xid - printf(" Transaction ID: %#x\n", message.xid); - // secs - printf(" Seconds elapsed: %hu\n", message.secs); - // flags - printf(" Flags: 0x%04x\n", message.flags); - // ciaddr - printf(" Client IP address: %s\n", inet_ntoa((struct in_addr) {message.ciaddr})); - // yiaddr - printf(" Your IP address: %s\n", inet_ntoa((struct in_addr) {message.yiaddr})); - // siaddr - printf(" Server IP address: %s\n", inet_ntoa((struct in_addr) {message.siaddr})); - // giaddr - printf(" Gateway IP address: %s\n", inet_ntoa((struct in_addr) {message.giaddr})); - // chaddr - dhcp_print_chaddr(message.htype, message.chaddr); - // sname - if (strlen((char *) message.sname) > 0) { - printf(" Server name: %s\n", message.sname); - } - // file - if (strlen((char *) message.file) > 0) { - printf(" Boot file name: %s\n", message.file); - } -} - -/** - * @brief Print a DHCP option. - * - * @param option the DHCP option to print - */ -void dhcp_print_option(dhcp_option_t option) { - printf(" Code: %hhu; Length: %hhu; Value: ", option.code, option.length); - for (uint8_t i = 0; i < option.length; i++) { - printf("%02hhx ", *(option.value + i)); - } - printf("\n"); -} - -/** - * @brief Print a DHCP message. - * - * @param message the DHCP message to print - */ -void dhcp_print_message(dhcp_message_t message) { - printf("DHCP message\n"); - // Print header fields - dhcp_print_header(message); - // Print DHCP options - printf(" DHCP options:\n"); - for (uint8_t i = 0; i < message.options.count; i++) { - dhcp_print_option(*(message.options.options + i)); - } -} diff --git a/src/parsers/dns.c b/src/parsers/dns.c deleted file mode 100644 index 0f0fb9db2068034fbe5c9949f0bf62a74b5f3c25..0000000000000000000000000000000000000000 --- a/src/parsers/dns.c +++ /dev/null @@ -1,584 +0,0 @@ -/** - * @file src/parsers/dns.c - * @brief DNS message parser - * @date 2022-09-09 - * - * @copyright Copyright (c) 2022 - * - */ - -#include "dns.h" - - -///// PARSING ///// - -/** - * Parse a DNS header. - * A DNS header is always 12 bytes. - * - * @param data a pointer pointing to the start of the DNS message - * @param offset a pointer to the current parsing offset - * @return the parsed header - */ -dns_header_t dns_parse_header(uint8_t *data, uint16_t *offset) { - // Init - dns_header_t header; - // Parse fields - header.id = ntohs(*((uint16_t *) (data + *offset))); - header.flags = ntohs(*((uint16_t *) (data + *offset + 2))); - header.qr = (header.flags & DNS_QR_FLAG_MASK); - header.qdcount = ntohs(*((uint16_t *) (data + *offset + 4))); - header.ancount = ntohs(*((uint16_t *) (data + *offset + 6))); - header.nscount = ntohs(*((uint16_t *) (data + *offset + 8))); - header.arcount = ntohs(*((uint16_t *) (data + *offset + 10))); - // Update offset to point after header - *offset += DNS_HEADER_SIZE; - - return header; -} - -/** - * Parse a DNS Domain Name. - * - * @param data a pointer pointing to the start of the DNS message - * @param offset a pointer to the current parsing offset - * @return the parsed domain name - */ -static char* dns_parse_domain_name(uint8_t *data, uint16_t *offset) { - if (*(data + *offset) == '\0') { - // Domain name is ROOT - (*offset)++; - return ""; - } - uint16_t current_length = 0; - uint16_t max_length = DNS_MAX_DOMAIN_NAME_LENGTH; - char* domain_name = (char *) malloc(sizeof(char) * max_length); - bool compression = false; - uint16_t domain_name_offset = *offset; // Other offset, might be useful for domain name compression - while (*(data + domain_name_offset) != '\0') { - uint8_t length_byte = *((uint8_t *) (data + domain_name_offset)); - if (length_byte >> 6 == 3) { // Length byte starts with 0b11 - // Domain name compression - // Advance offset by 2 bytes, and do not update it again - if(!compression) { - *offset += 2; - } - compression = true; - // Retrieve new offset to parse domain name from - domain_name_offset = ntohs(*((uint16_t *) (data + domain_name_offset))) & DNS_COMPRESSION_MASK; - } else { - // Fully written label, parse it - for (int i = 1; i <= length_byte; i++) { - if (current_length == max_length) { - // Realloc buffer - max_length *= 2; - void *realloc_ptr = realloc(domain_name, sizeof(char) * max_length); - if (realloc_ptr == NULL) { - // Handle realloc error - fprintf(stderr, "Error reallocating memory for domain name %s\n", domain_name); - free(domain_name); - return NULL; - } else { - domain_name = (char*) realloc_ptr; - } - } - char c = *(data + domain_name_offset + i); - *(domain_name + (current_length++)) = c; - } - *(domain_name + (current_length++)) = '.'; - domain_name_offset += length_byte + 1; - if (!compression) { - *offset = domain_name_offset; - } - } - } - // Domain name was fully parsed - // Overwrite last '.' written with NULL byte - *(domain_name + (--current_length)) = '\0'; - // Shrink allocated memory to fit domain name, if needed - if (current_length + 1 < max_length) { - void* realloc_ptr = realloc(domain_name, sizeof(char) * (current_length + 1)); - if (realloc_ptr == NULL) { - fprintf(stderr, "Error shrinking memory for domain name %s\n", domain_name); - } else { - domain_name = (char*) realloc_ptr; - } - } - // Advance offset after NULL terminator, if domain name compression was not used - if (!compression) { - (*offset)++; - } - return domain_name; -} - -/** - * Parse a DNS Question section. - * - * @param qdcount the number of questions present in the question section - * @param data a pointer pointing to the start of the DNS message - * @param offset a pointer to the current parsing offset - * @return the parsed question section - */ -dns_question_t* dns_parse_questions(uint16_t qdcount, uint8_t *data, uint16_t *offset) { - // Init - dns_question_t *questions = (dns_question_t *) malloc(qdcount * sizeof(dns_question_t)); - // Iterate over all questions - for (uint16_t i = 0; i < qdcount; i++) { - // Parse domain name - (questions + i)->qname = dns_parse_domain_name(data, offset); - // Parse rtype and rclass - (questions + i)->qtype = ntohs(*((uint16_t *) (data + *offset))); - (questions + i)->qclass = ntohs(*((uint16_t *) (data + *offset + 2))) & DNS_CLASS_MASK; - *offset += 4; - } - return questions; -} - -/** - * Parse a DNS Resource Record RDATA field. - * - * @param rdlength the length, in bytes, of the RDATA field - * @param data a pointer pointing to the start of the DNS message - * @param offset a pointer to the current parsing offset - * @return the parsed RDATA field - */ -static rdata_t dns_parse_rdata(dns_rr_type_t rtype, uint16_t rdlength, uint8_t *data, uint16_t *offset) { - rdata_t rdata; - if (rdlength == 0) { - // RDATA field is empty - rdata.data = NULL; - } else { - // RDATA field is not empty - switch (rtype) { - case A: - // RDATA contains an IPv4 address - rdata.ip.version = 4; - rdata.ip.value.ipv4 = *((uint32_t *) (data + *offset)); // Stored in network byte order - *offset += rdlength; - break; - case AAAA: - // RDATA contains an IPv6 address - rdata.ip.version = 6; - memcpy(rdata.ip.value.ipv6, data + *offset, rdlength); - *offset += rdlength; - break; - case NS: - case CNAME: - case PTR: - // RDATA contains is a domain name - rdata.domain_name = dns_parse_domain_name(data, offset); - break; - default: - // RDATA contains is generic data - rdata.data = (uint8_t *) malloc(sizeof(char) * rdlength); - memcpy(rdata.data, data + *offset, rdlength); - *offset += rdlength; - } - } - return rdata; -} - -/** - * Parse a DNS Resource Record list. - * @param count the number of resource records present in the section - * @param data a pointer pointing to the start of the DNS message - * @param offset a pointer to the current parsing offset - * @return the parsed resource records list - */ -dns_resource_record_t* dns_parse_rrs(uint16_t count, uint8_t *data, uint16_t *offset) { - dns_resource_record_t *rrs = (dns_resource_record_t *) malloc(count * sizeof(dns_resource_record_t)); - for (uint16_t i = 0; i < count; i++) { - // Parse domain name - (rrs + i)->name = dns_parse_domain_name(data, offset); - // Parse rtype, rclass and TTL - dns_rr_type_t rtype = ntohs(*((uint16_t *) (data + *offset))); - (rrs + i)->rtype = rtype; - (rrs + i)->rclass = ntohs(*((uint16_t *) (data + *offset + 2))) & DNS_CLASS_MASK; - (rrs + i)->ttl = ntohl(*((uint32_t *) (data + *offset + 4))); - // Parse rdata - uint16_t rdlength = ntohs(*((uint16_t *) (data + *offset + 8))); - (rrs + i)->rdlength = rdlength; - *offset += 10; - (rrs + i)->rdata = dns_parse_rdata(rtype, rdlength, data, offset); - } - return rrs; -} - -/** - * Parse a DNS message. - * - * @param data a pointer to the start of the DNS message - * @return the parsed DNS message - */ -dns_message_t dns_parse_message(uint8_t *data) { - // Init - dns_message_t message; - uint16_t offset = 0; - message.questions = NULL; - message.answers = NULL; - message.authorities = NULL; - message.additionals = NULL; - - // Parse DNS header - message.header = dns_parse_header(data, &offset); - // If present, parse DNS Question section - if (message.header.qdcount > 0) - { - message.questions = dns_parse_questions(message.header.qdcount, data, &offset); - } - // If message is a response and section is present, parse DNS Answer section - if (message.header.qr == 1 && message.header.ancount > 0) - { - message.answers = dns_parse_rrs(message.header.ancount, data, &offset); - } - - /* Parsing other sections is not necessary for this project - - // If message is a response and section is present, parse DNS Authority section - if (message.header.qr == 1 && message.header.nscount > 0) - { - message.authorities = dns_parse_rrs(message.header.nscount, data, &offset); - } - // If message is a response and section is present, parse DNS Additional section - if (message.header.qr == 1 && message.header.arcount > 0) - { - message.additionals = dns_parse_rrs(message.header.arcount, data, &offset); - } - - */ - - return message; -} - - -///// LOOKUP ///// - -/** - * @brief Check if a given string ends with a given suffix. - * - * @param str the string to check - * @param suffix the suffix to search for - * @param suffix_length the length of the suffix - * @return true if the string ends with the suffix - * @return false if the string does not end with the suffix - */ -static bool ends_with(char* str, char* suffix, uint16_t suffix_length) { - uint16_t str_length = strlen(str); - if (str_length < suffix_length) { - return false; - } - return strncmp(str + str_length - suffix_length, suffix, suffix_length) == 0; -} - -/** - * @brief Check if a given DNS Questions list contains a domain name which has a given suffix. - * - * @param questions DNS Questions list - * @param qdcount number of Questions in the list - * @param suffix the domain name suffix to search for - * @param suffix_length the length of the domain name suffix - * @return true if a domain name with the given suffix is found is found in the Questions list, - * false otherwise - */ -bool dns_contains_suffix_domain_name(dns_question_t *questions, uint16_t qdcount, char *suffix, uint16_t suffix_length) { - for (uint16_t i = 0; i < qdcount; i++) { - if (ends_with((questions + i)-> qname, suffix, suffix_length)) { - return true; - } - } - return false; -} - -/** - * @brief Check if a given domain name is fully contained in a DNS Questions list. - * - * @param questions DNS Questions list - * @param qdcount number of Questions in the list - * @param domain_name the domain name to search for - * @return true if the full domain name is found in the Questions list, false otherwise - */ -bool dns_contains_full_domain_name(dns_question_t *questions, uint16_t qdcount, char *domain_name) -{ - for (uint16_t i = 0; i < qdcount; i++) { - if (strcmp((questions + i)->qname, domain_name) == 0) { - return true; - } - } - return false; -} - -/** - * @brief Search for a specific domain name in a DNS Questions list. - * - * @param questions DNS Questions list - * @param qdcount number of Suestions in the list - * @param domain_name the domain name to search for - * @return the DNS Question related to the given domain name, or NULL if not found - */ -dns_question_t* dns_get_question(dns_question_t *questions, uint16_t qdcount, char *domain_name) { - for (uint16_t i = 0; i < qdcount; i++) { - if (strcmp((questions + i)->qname, domain_name) == 0) { - return questions + i; - } - } - return NULL; -} - -/** - * @brief Retrieve the IP addresses corresponding to a given domain name in a DNS Answers list. - * - * Searches a DNS Answer list for a specific domain name and returns the corresponding IP address. - * Processes each Answer recursively if the Answer Type is a CNAME. - * - * @param answers DNS Answers list to search in - * @param ancount number of Answers in the list - * @param domain_name domain name to search for - * @return struct ip_list representing the list of corresponding IP addresses - */ -ip_list_t dns_get_ip_from_name(dns_resource_record_t *answers, uint16_t ancount, char *domain_name) { - ip_list_t ip_list; - ip_list.ip_count = 0; - ip_list.ip_addresses = NULL; - char *cname = domain_name; - for (uint16_t i = 0; i < ancount; i++) { - if (strcmp((answers + i)->name, cname) == 0) { - dns_rr_type_t rtype = (answers + i)->rtype; - if (rtype == A || rtype == AAAA) - { - // Handle IP list length - if (ip_list.ip_addresses == NULL) { - ip_list.ip_addresses = (ip_addr_t *) malloc(sizeof(ip_addr_t)); - } else { - void *realloc_ptr = realloc(ip_list.ip_addresses, (ip_list.ip_count + 1) * sizeof(ip_addr_t)); - if (realloc_ptr == NULL) { - // Handle realloc error - free(ip_list.ip_addresses); - fprintf(stderr, "Error reallocating memory for IP list.\n"); - ip_list.ip_count = 0; - ip_list.ip_addresses = NULL; - return ip_list; - } else { - ip_list.ip_addresses = (ip_addr_t*) realloc_ptr; - } - } - // Handle IP version and value - *(ip_list.ip_addresses + ip_list.ip_count) = (answers + i)->rdata.ip; - ip_list.ip_count++; - } - else if ((answers + i)->rtype == CNAME) - { - cname = (answers + i)->rdata.domain_name; - } - } - } - return ip_list; -} - - -///// DESTROY ///// - -/** - * @brief Free the memory allocated for a DNS RDATA field. - * - * @param rdata the DNS RDATA field to free - * @param rtype the DNS Resource Record Type of the RDATA field - */ -static void dns_free_rdata(rdata_t rdata, dns_rr_type_t rtype) { - switch (rtype) { - case A: - case AAAA: - break; // Nothing to free for IP addresses - case NS: - case CNAME: - case PTR: - free(rdata.domain_name); - break; - default: - free(rdata.data); - } -} - -/** - * @brief Free the memory allocated for a list of DNS Resource Records. - * - * @param rr the list of DNS Resource Records to free - * @param count the number of Resource Records in the list - */ -static void dns_free_rrs(dns_resource_record_t *rrs, uint16_t count) { - if (rrs != NULL && count > 0) { - for (uint16_t i = 0; i < count; i++) { - dns_resource_record_t rr = *(rrs + i); - if (rr.rdlength > 0) { - free(rr.name); - dns_free_rdata(rr.rdata, rr.rtype); - } - } - free(rrs); - } -} - -/** - * Free the memory allocated for a DNS message. - * - * @param question the DNS message to free - */ -void dns_free_message(dns_message_t message) { - // Free DNS Questions - if (message.header.qdcount > 0) { - for (uint16_t i = 0; i < message.header.qdcount; i++) { - free((message.questions + i)->qname); - } - free(message.questions); - } - - // Free DNS Answers - dns_free_rrs(message.answers, message.header.ancount); - - /* Other sections are not used in this project - - // Free DNS Authorities - dns_free_rrs(message.authorities, message.header.nscount); - // Free DNS Additionals - dns_free_rrs(message.additionals, message.header.arcount); - - */ -} - - -///// PRINTING ///// - -/** - * Print a DNS header. - * - * @param message the DNS header - */ -void dns_print_header(dns_header_t header) { - printf("DNS Header:\n"); - printf(" ID: %#hx\n", header.id); - printf(" Flags: %#hx\n", header.flags); - printf(" QR: %d\n", header.qr); - printf(" Questions count: %hd\n", header.qdcount); - printf(" Answers count: %hd\n", header.ancount); - printf(" Authority name servers count: %hd\n", header.nscount); - printf(" Additional records count: %hd\n", header.arcount); -} - -/** - * Print a DNS Question - * - * @param question the DNS Question - */ -void dns_print_question(dns_question_t question) { - printf(" Question:\n"); - printf(" Domain name: %s\n", question.qname); - printf(" Type: %hd\n", question.qtype); - printf(" Class: %hd\n", question.qclass); -} - -/** - * Print a DNS Question section. - * - * @param qdcount the number of Questions in the Question section - * @param questions the list of DNS Questions - */ -void dns_print_questions(uint16_t qdcount, dns_question_t *questions) { - printf("DNS Question section:\n"); - for (uint16_t i = 0; i < qdcount; i++) { - dns_question_t *question = questions + i; - if (question != NULL) { - dns_print_question(*question); - } - } -} - -/** - * Return a string representation of the given RDATA value. - * - * @param rtype the type corresponding to the RDATA value - * @param rdlength the length, in bytes, of the RDATA value - * @param rdata the RDATA value, stored as a union type - * @return a string representation of the RDATA value - */ -char* dns_rdata_to_str(dns_rr_type_t rtype, uint16_t rdlength, rdata_t rdata) { - if (rdlength == 0) { - // RDATA is empty - return ""; - } - switch (rtype) { - case A: - case AAAA: - // RDATA is an IP (v4 or v6) address - return ip_net_to_str(rdata.ip); - break; - case NS: - case CNAME: - case PTR: - // RDATA is a domain name - return rdata.domain_name; - break; - default: ; - // Generic RDATA - char *buffer = (char *) malloc(rdlength * 4 + 1); // Allocate memory for each byte (4 characters) + the NULL terminator - for (uint8_t i = 0; i < rdlength; i++) { - snprintf(buffer + (i * 4), 5, "\\x%02x", *(rdata.data + i)); - } - return buffer; - } -} - -/** - * Print a DNS Resource Record. - * - * @param section_name the name of the Resource Record section - * @param rr the DNS Resource Record - */ -void dns_print_rr(char* section_name, dns_resource_record_t rr) { - printf(" %s RR:\n", section_name); - printf(" Name: %s\n", rr.name); - printf(" Type: %hd\n", rr.rtype); - printf(" Class: %hd\n", rr.rclass); - printf(" TTL [s]: %d\n", rr.ttl); - printf(" Data length: %hd\n", rr.rdlength); - printf(" RDATA: %s\n", dns_rdata_to_str(rr.rtype, rr.rdlength, rr.rdata)); -} - -/** - * Print a DNS Resource Records section. - * - * @param section_name the name of the Resource Record section - * @param count the number of Resource Records in the section - * @param rrs the list of DNS Resource Records - */ -void dns_print_rrs(char* section_name, uint16_t count, dns_resource_record_t *rrs) { - printf("%s RRs:\n", section_name); - for (uint16_t i = 0; i < count; i++) { - dns_resource_record_t *rr = rrs + i; - if (rr != NULL) - dns_print_rr(section_name, *rr); - } -} - -/** - * Print a DNS message. - * - * @param message the DNS message - */ -void dns_print_message(dns_message_t message) { - // Print DNS Header - dns_print_header(message.header); - - // Print DNS Questions, if any - if (message.header.qdcount > 0) - dns_print_questions(message.header.qdcount, message.questions); - - // Print DNS Answers, if message is a response and has answers - if (message.header.qr == 1 && message.header.ancount > 0) - dns_print_rrs("Answer", message.header.ancount, message.answers); - - /* Other sections are not used in this project - - dns_print_rrs("Authority", message.header.nscount, message.authorities); - dns_print_rrs("Additional", message.header.arcount, message.additionals); - - */ -} diff --git a/src/parsers/header.c b/src/parsers/header.c deleted file mode 100644 index f33228cf175bb0b2a6824c140390354cad7bfc09..0000000000000000000000000000000000000000 --- a/src/parsers/header.c +++ /dev/null @@ -1,204 +0,0 @@ -/** - * @file src/parsers/header.c - * @brief Parser for layer 3 and 4 headers (currently only IPv4, IPv6, UDP and TCP) - * - * Parser for layer 3 and 4 headers. - * Currently supported protocols: - * - Layer 3: - * - IPv4 - * - IPv6 - * - Layer 4: - * - UDP - * - TCP - * - * @date 2022-09-09 - * - * @copyright Copyright (c) 2022 - * - */ - -#include "header.h" - - -/** - * Retrieve the length of a packet's IPv4 header. - * - * @param data a pointer to the start of the packet's IPv4 header - * @return the size, in bytes, of the IPv4 header - */ -size_t get_ipv4_header_length(uint8_t *data) { - // 4-bit IPv4 header length is encoded in the last 4 bits of byte 0. - // It indicates the number of 32-bit words. - // It must be multiplied by 4 to obtain the header size in bytes. - uint8_t length = (*data & 0x0f) * 4; - return length; -} - -/** - * Retrieve the length of a packet's IPv6 header. - * - * @param data a pointer to the start of the packet's IPv6 header - * @return the size, in bytes, of the IPv6 header - */ -size_t get_ipv6_header_length(uint8_t *data) { - // An IPv6 header has a fixed length of 40 bytes - return IPV6_HEADER_LENGTH; -} - -/** - * Retrieve the length of a packet's UDP header. - * - * @param data a pointer to the start of the packet's UDP (layer 4) header - * @return the size, in bytes, of the UDP header - */ -size_t get_udp_header_length(uint8_t *data) { - // A UDP header has a fixed length of 8 bytes - return UDP_HEADER_LENGTH; -} - -/** - * Retrieve the length of a packet's TCP header. - * - * @param data a pointer to the start of the packet's TCP (layer 4) header - * @return the size, in bytes, of the UDP header - */ -size_t get_tcp_header_length(uint8_t *data) { - // 4-bit TCP header data offset is encoded in the first 4 bits of byte 12. - // It indicates the number of 32-bit words. - // It must be multiplied by 4 to obtain the header size in bytes. - uint8_t length = (*((data) + 12) >> 4) * 4; - return length; -} - -/** - * Retrieve the length of a packet's layer 3 header (IPv4 or IPv6). - * - * @param data a pointer to the start of the packet's layer 3 header - * @return the size, in bytes, of the layer 3 header - */ -size_t get_l3_header_length(uint8_t *data) { - uint8_t ip_version = (*data) >> 4; - switch (ip_version) { - case 4: - return get_ipv4_header_length(data); - break; - case 6: - return get_ipv6_header_length(data); - break; - default: - return 0; - break; - } -} - -/** - * Retrieve the length of a packet's layer-3 and layer-4 headers. - * - * @param data a pointer to the start of the packet's layer-3 header - * @return the size, in bytes, of the UDP header - */ -size_t get_headers_length(uint8_t* data) { - size_t length = 0; - - // Layer 3: Network - // Retrieve the IP version, which is encoded in the first 4 bits of byte 0 - uint8_t ip_version = (*data) >> 4; - ip_protocol_t protocol = 0; - switch (ip_version) { - case 4: - length += get_ipv4_header_length(data); - protocol = *((data) + 9); // In IPv4, the protocol number is encoded in byte 9 - break; - case 6: - length += get_ipv6_header_length(data); - protocol = *((data) + 6); // In IPv6, the protocol number is encoded in byte 6 - break; - default: - break; - } - - // Layer 4: Transport - switch (protocol) { - case TCP: - length += get_tcp_header_length(data + length); - break; - case UDP: - length += get_udp_header_length(data + length); - break; - default: - break; - } - return length; -} - -/** - * @brief Retrieve the length of a UDP payload. - * - * @param data pointer to the start of the UDP header - * @return length of the UDP payload, in bytes - */ -uint16_t get_udp_payload_length(uint8_t *data) -{ - // The 16-bit length of the complete UDP datagram is encoded in bytes 4 and 5 of the UDP header. - // The length of the UDP header (8 bytes) must then be subtracted to obtain the length of the UDP payload. - return ntohs(*((uint16_t *) (data + 4))) - UDP_HEADER_LENGTH; -} - -/** - * @brief Retrieve the source port from a layer 4 header. - * - * @param data pointer to the start of the layer 4 header - * @return destination port - */ -uint16_t get_dst_port(uint8_t *data) { - // Source port is encoded in bytes 2 and 3 - return ntohs(*((uint16_t*) (data + 2))); -} - -/** - * @brief Retrieve the source address from an IPv4 header. - * - * @param data pointer to the start of the IPv4 header - * @return source IPv4 address, in network byte order - */ -uint32_t get_ipv4_src_addr(uint8_t *data) { - // Source address is encoded in bytes 12 to 15 - return *((uint32_t*) (data + 12)); -} - -/** - * @brief Retrieve the destination address from an IPv4 header. - * - * @param data pointer to the start of the IPv4 header - * @return destination IPv4 address, in network byte order - */ -uint32_t get_ipv4_dst_addr(uint8_t* data) { - // Destination address is encoded in bytes 16 to 19 - return *((uint32_t*) (data + 16)); -} - -/** - * @brief Retrieve the source address from an IPv6 header. - * - * @param data pointer to the start of the IPv6 header - * @return source IPv6 address, as a 16-byte array - */ -uint8_t* get_ipv6_src_addr(uint8_t *data) { - // Source address is encoded in bytes 8 to 23 - uint8_t *addr = (uint8_t *) malloc(IPV6_ADDR_LENGTH); - memcpy(addr, data + 8, IPV6_ADDR_LENGTH); - return addr; -} - -/** - * @brief Retrieve the destination address from an IPv6 header. - * - * @param data pointer to the start of the IPv6 header - * @return destination IPv6 address, as a 16-byte array - */ -uint8_t* get_ipv6_dst_addr(uint8_t *data) { - // Source address is encoded in bytes 24 to 39 - uint8_t *addr = (uint8_t *) malloc(IPV6_ADDR_LENGTH); - memcpy(addr, data + 24, IPV6_ADDR_LENGTH); - return addr; -} diff --git a/src/parsers/http.c b/src/parsers/http.c deleted file mode 100644 index 5f583247fa88004e9ee22e811f23d08c9850027a..0000000000000000000000000000000000000000 --- a/src/parsers/http.c +++ /dev/null @@ -1,229 +0,0 @@ -/** - * @file src/parsers/http.c - * @brief HTTP message parser - * @date 2022-09-19 - * - * @copyright Copyright (c) 2022 - * - */ - -#include "http.h" - - -///// PARSING ///// - -/** - * @brief Parse the method of an HTTP message. - * - * Parse a HTTP message to retrieve its method, - * and convert it to a http_message_t. - * Only the two first characters need to be parsed. - * Advances the offset value after parsing. - * - * @param data pointer to the start of the HTTP message - * @param offset current offset in the message - * @return parsed HTTP method - */ -static http_method_t http_parse_method(uint8_t *data, uint16_t *offset) { - switch (*(data + *offset)) { - case 'G': - // Method is GET - *offset += 4; - return HTTP_GET; - break; - case 'H': - // Method is HEAD - *offset += 5; - return HTTP_HEAD; - break; - case 'P': - // Method is POST or PUT - switch (*(data + *offset + 1)) { - case 'O': - // Method is POST - *offset += 5; - return HTTP_POST; - break; - case 'U': - // Method is PUT - *offset += 4; - return HTTP_PUT; - break; - default: - // Unknown method - return HTTP_UNKNOWN; - } - case 'D': - // Method is DELETE - *offset += 7; - return HTTP_DELETE; - break; - case 'C': - // Method is CONNECT - *offset += 8; - return HTTP_CONNECT; - break; - case 'O': - // Method is OPTIONS - *offset += 8; - return HTTP_OPTIONS; - break; - case 'T': - // Method is TRACE - *offset += 6; - return HTTP_TRACE; - break; - default: - // Unknown method - return HTTP_UNKNOWN; - } -} - -/** - * @brief Check if a TCP message is a HTTP message. - * - * @param data pointer to the start of the TCP payload - * @param dst_port TCP destination port - * @return true if the message is a HTTP message - * @return false if the message is not a HTTP message - */ -bool is_http(uint8_t *data) -{ - uint16_t offset = 0; - return http_parse_method(data, &offset) != HTTP_UNKNOWN; -} - -/** - * @brief Parse an URI in an HTTP message. - * - * Parse a HTTP message to retrieve its URI, - * and convert it to a character string. - * Advances the offset value after parsing. - * - * @param data pointer to the start of the HTTP message - * @param offset current offset in the message - * @return parsed URI - */ -static char* http_parse_uri(uint8_t *data, uint16_t *offset) { - uint16_t length = 1; - uint16_t max_length = HTTP_METHOD_MAX_LEN; - char *uri = (char *) malloc(sizeof(char) * max_length); - while (*(data + *offset) != ' ') { - if (length == max_length) { - // URI is too long, increase buffer size - max_length *= 2; - void* realloc_ptr = realloc(uri, sizeof(char) * max_length); - if (realloc_ptr == NULL) { - // Handle realloc error - fprintf(stderr, "Error reallocating memory for URI %s\n", uri); - free(uri); - return NULL; - } else { - uri = (char*) realloc_ptr; - } - } - *(uri + (length - 1)) = *(data + (*offset)++); - length++; - } - if (length < max_length) { - // URI is shorter than allocated buffer, shrink buffer - void *realloc_ptr = realloc(uri, sizeof(char) * length); - if (realloc_ptr == NULL) { - fprintf(stderr, "Error shrinking memory for URI %s\n", uri); - } else { - uri = (char*) realloc_ptr; - } - } - // Add NULL terminating character - *(uri + length - 1) = '\0'; - return uri; -} - -/** - * @brief Parse the method and URI of HTTP message. - * - * @param data pointer to the start of the HTTP message - * @param dst_port TCP destination port - * @return the parsed HTTP message - */ -http_message_t http_parse_message(uint8_t *data, uint16_t dst_port) { - http_message_t message; - uint16_t offset = 0; - http_method_t http_method = http_parse_method(data, &offset); - message.is_request = dst_port == 80 && http_method != HTTP_UNKNOWN; - if (message.is_request) { - message.method = http_method; - message.uri = http_parse_uri(data, &offset); - } else { - message.method = HTTP_UNKNOWN; - message.uri = NULL; - } - return message; -} - - -///// DESTROY ///// - -/** - * @brief Free the memory allocated for a HTTP message. - * - * @param message the HTTP message to free - */ -void http_free_message(http_message_t message) { - if (message.uri != NULL) - free(message.uri); -} - - -///// PRINTING ///// - -/** - * @brief Converts a HTTP method from enum value to character string. - * - * @param method the HTTP method in enum value - * @return the same HTTP method as a character string - */ -char* http_method_to_str(http_method_t method) { - switch (method) { - case HTTP_GET: - return "GET"; - break; - case HTTP_HEAD: - return "HEAD"; - break; - case HTTP_POST: - return "POST"; - break; - case HTTP_PUT: - return "PUT"; - break; - case HTTP_DELETE: - return "DELETE"; - break; - case HTTP_CONNECT: - return "CONNECT"; - break; - case HTTP_OPTIONS: - return "OPTIONS"; - break; - case HTTP_TRACE: - return "TRACE"; - break; - default: - return "UNKNOWN"; - } -} - -/** - * @brief Print the method and URI of a HTTP message. - * - * @param message the message to print - */ -void http_print_message(http_message_t message) { - printf("HTTP message:\n"); - printf(" is request ?: %d\n", message.is_request); - if (message.is_request) { - printf(" Method: %s\n", http_method_to_str(message.method)); - printf(" URI: %s\n", message.uri); - } -} diff --git a/src/parsers/igmp.c b/src/parsers/igmp.c deleted file mode 100644 index e02889a7e8a2a4d5c5da261a062d33e698c18174..0000000000000000000000000000000000000000 --- a/src/parsers/igmp.c +++ /dev/null @@ -1,177 +0,0 @@ -/** - * @file src/parsers/igmp.c - * @brief IGMP message parser - * @date 2022-10-05 - * - * IGMP message parser. - * Supports v1 and v2, and v3 Membership Report messages. - * TODO: support v3 Membership Query messages. - * - * @copyright Copyright (c) 2022 - * - */ - -#include "igmp.h" - - -///// PARSING ///// - -/** - * @brief Parse an IGMPv2 message. - * - * @param data pointer to the start of the IGMPv2 message - * @return the parsed IGMPv2 message - */ -static igmp_v2_message_t igmp_v2_parse_message(uint8_t *data) { - igmp_v2_message_t message; - message.max_resp_time = *(data + 1); - message.checksum = ntohs(*((uint16_t *)(data + 2))); - message.group_address = *((uint32_t *)(data + 4)); // Stored in network byte order - return message; -} - -/** - * @brief Parse an array of IGMPv3 group records. - * - * @param num_groups number of group records - * @param data pointer to the start of the group records - * @return pointer to the array of parsed group records - */ -static igmp_v3_group_record_t* igmp_v3_parse_groups(uint16_t num_groups, uint8_t *data) { - // If num_groups is 0, group list is NULL - if (num_groups == 0) - return NULL; - - // num_groups is greater than 0 - igmp_v3_group_record_t *groups = malloc(num_groups * sizeof(igmp_v3_group_record_t)); - for (uint16_t i = 0; i < num_groups; i++) { - igmp_v3_group_record_t *group = groups + i; - group->type = *data; - group->aux_data_len = *(data + 1); - group->num_sources = ntohs(*((uint16_t *)(data + 2))); - group->group_address = *((uint32_t *)(data + 4)); // Stored in network byte order - if (group->num_sources > 0) { - group->sources = malloc(group->num_sources * sizeof(uint32_t)); - for (uint16_t j = 0; j < group->num_sources; j++) { - *((group->sources) + j) = *((uint32_t *)(data + 8 + j * 4)); // Stored in network byte order - } - } else { - group->sources = NULL; - } - data += 8 + group->num_sources * 4; - } - return groups; -} - -/** - * @brief Parse an IGMPv3 Membership Report message. - * - * @param data pointer to the start of the IGMPv3 Membership Report message - * @return the parsed IGMPv3 Membership Report message - */ -static igmp_v3_membership_report_t igmp_v3_parse_membership_report(uint8_t *data) { - igmp_v3_membership_report_t message; - message.checksum = ntohs(*((uint16_t *)(data + 2))); - message.num_groups = ntohs(*((uint16_t *)(data + 6))); - message.groups = igmp_v3_parse_groups(message.num_groups, data + 8); - return message; -} - -/** - * @brief Parse an IGMP message. - * - * @param data pointer to the start of the IGMP message - * @return the parsed IGMP message - */ -igmp_message_t igmp_parse_message(uint8_t *data) { - igmp_message_t message; - message.type = (igmp_message_type_t) *data; - // Dispatch on IGMP message type - switch (message.type) { - case MEMBERSHIP_QUERY: - case V1_MEMBERSHIP_REPORT: - case V2_MEMBERSHIP_REPORT: - case LEAVE_GROUP: - message.version = 2; - message.body.v2_message = igmp_v2_parse_message(data); - break; - case V3_MEMBERSHIP_REPORT: - message.version = 3; - message.body.v3_membership_report = igmp_v3_parse_membership_report(data); - break; - default: - break; - } - return message; -} - -/** - * @brief Free the memory allocated for an IGMP message. - * - * @param message the IGMP message to free - */ -void igmp_free_message(igmp_message_t message) { - if (message.version == 3 && message.body.v3_membership_report.num_groups > 0) { - for (uint16_t i = 0; i < message.body.v3_membership_report.num_groups; i++) - { - igmp_v3_group_record_t group = *(message.body.v3_membership_report.groups + i); - if (group.num_sources > 0) - free(group.sources); - } - free(message.body.v3_membership_report.groups); - } -} - - -///// PRINTING ///// - -/** - * @brief Print an IGMPv2 message. - * - * @param v2_message the IGMPv2 message to print - */ -static void igmp_v2_print_message(igmp_v2_message_t v2_message) { - printf(" Max resp time: %hhu\n", v2_message.max_resp_time); - printf(" Checksum: %#hx\n", v2_message.checksum); - printf(" Group address: %s\n", ipv4_net_to_str(v2_message.group_address)); -} - -/** - * @brief Print an IGMPv3 Membership Report message. - * - * @param group the IGMPv3 Membership Report message to print - */ -static void igmp_v3_print_membership_report(igmp_v3_membership_report_t v3_message) { - printf(" Checksum: %#hx\n", v3_message.checksum); - printf(" Number of groups: %hu\n", v3_message.num_groups); - for (uint16_t i = 0; i < v3_message.num_groups; i++) { - igmp_v3_group_record_t group = *(v3_message.groups + i); - printf(" Group %d:\n", i); - printf(" Type: %#hhx\n", group.type); - printf(" Aux data len: %hhu\n", group.aux_data_len); - printf(" Number of sources: %hu\n", group.num_sources); - printf(" Group address: %s\n", ipv4_net_to_str(group.group_address)); - for (uint16_t j = 0; j < group.num_sources; j++) { - printf(" Source %d: %s\n", j, ipv4_net_to_str(*(group.sources + j))); - } - } -} - -/** - * @brief Print an IGMP message. - * - * @param message the IGMP message to print - */ -void igmp_print_message(igmp_message_t message) { - printf("IGMP message:\n"); - printf(" Version: %hhu\n", message.version); - printf(" Type: %#hhx\n", message.type); - switch (message.version) { - case 2: - igmp_v2_print_message(message.body.v2_message); - break; - case 3: - igmp_v3_print_membership_report(message.body.v3_membership_report); - break; - } -} diff --git a/src/parsers/ssdp.c b/src/parsers/ssdp.c deleted file mode 100644 index b82a6cd6d0a1ff659be236058efd7378328d523f..0000000000000000000000000000000000000000 --- a/src/parsers/ssdp.c +++ /dev/null @@ -1,91 +0,0 @@ -/** - * @file src/parsers/ssdp.c - * @brief SSDP message parser - * @date 2022-11-24 - * - * @copyright Copyright (c) 2022 - * - */ - -#include "ssdp.h" - - -///// PARSING ///// - -/** - * @brief Parse the method of an SSDP message. - * - * Parse a SSDP message to retrieve its method, - * and convert it to a ssdp_message_t. - * Only the two first characters need to be parsed. - * Advances the offset value after parsing. - * - * @param data pointer to the start of the SSDP message - * @param offset current offset in the message - * @return parsed SSDP method - */ -static ssdp_method_t ssdp_parse_method(uint8_t *data, uint16_t *offset) { - switch (*(data + *offset)) { - case 'M': - // Method is M-SEARCH - *offset += 9; - return SSDP_M_SEARCH; - break; - case 'N': - // Method is NOTIFY - *offset += 7; - return SSDP_NOTIFY; - break; - default: - // Unknown method - return SSDP_UNKNOWN; - } -} - -/** - * @brief Parse the method and URI of SSDP message. - * - * @param data pointer to the start of the SSDP message - * @param dst_addr IPv4 destination address, in network byte order - * @return the parsed SSDP message - */ -ssdp_message_t ssdp_parse_message(uint8_t *data, uint32_t dst_addr) { - ssdp_message_t message; - message.is_request = dst_addr == ipv4_str_to_net(SSDP_MULTICAST_ADDR); - uint16_t offset = 0; - message.method = ssdp_parse_method(data, &offset); - return message; -} - - -///// PRINTING ///// - -/** - * @brief Converts a SSDP method from enum value to character string. - * - * @param method the SSDP method in enum value - * @return the same SSDP method as a character string - */ -char *ssdp_method_to_str(ssdp_method_t method) { - switch (method) { - case SSDP_M_SEARCH: - return "M-SEARCH"; - break; - case SSDP_NOTIFY: - return "NOTIFY"; - break; - default: - return "UNKNOWN"; - } -} - -/** - * @brief Print the method and URI of a SSDP message. - * - * @param message the message to print - */ -void ssdp_print_message(ssdp_message_t message) { - printf("SSDP message:\n"); - printf(" is request ?: %d\n", message.is_request); - printf(" Method: %s\n", ssdp_method_to_str(message.method)); -} diff --git a/src/sha256.c b/src/sha256.c deleted file mode 100644 index eb9c5c0733e7a6234998e1dff49300c4b58e7d71..0000000000000000000000000000000000000000 --- a/src/sha256.c +++ /dev/null @@ -1,158 +0,0 @@ -/********************************************************************* -* Filename: sha256.c -* Author: Brad Conte (brad AT bradconte.com) -* Copyright: -* Disclaimer: This code is presented "as is" without any guarantees. -* Details: Implementation of the SHA-256 hashing algorithm. - SHA-256 is one of the three algorithms in the SHA2 - specification. The others, SHA-384 and SHA-512, are not - offered in this implementation. - Algorithm specification can be found here: - * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf - This implementation uses little endian byte order. -*********************************************************************/ - -/*************************** HEADER FILES ***************************/ -#include <stdlib.h> -#include <memory.h> -#include "sha256.h" - -/****************************** MACROS ******************************/ -#define ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b)))) -#define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b)))) - -#define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z))) -#define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) -#define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22)) -#define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25)) -#define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3)) -#define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10)) - -/**************************** VARIABLES *****************************/ -static const WORD k[64] = { - 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5, - 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174, - 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da, - 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967, - 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85, - 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070, - 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3, - 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 -}; - -/*********************** FUNCTION DEFINITIONS ***********************/ -void sha256_transform(SHA256_CTX *ctx, const BYTE data[]) -{ - WORD a, b, c, d, e, f, g, h, i, j, t1, t2, m[64]; - - for (i = 0, j = 0; i < 16; ++i, j += 4) - m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | (data[j + 3]); - for ( ; i < 64; ++i) - m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16]; - - a = ctx->state[0]; - b = ctx->state[1]; - c = ctx->state[2]; - d = ctx->state[3]; - e = ctx->state[4]; - f = ctx->state[5]; - g = ctx->state[6]; - h = ctx->state[7]; - - for (i = 0; i < 64; ++i) { - t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i]; - t2 = EP0(a) + MAJ(a,b,c); - h = g; - g = f; - f = e; - e = d + t1; - d = c; - c = b; - b = a; - a = t1 + t2; - } - - ctx->state[0] += a; - ctx->state[1] += b; - ctx->state[2] += c; - ctx->state[3] += d; - ctx->state[4] += e; - ctx->state[5] += f; - ctx->state[6] += g; - ctx->state[7] += h; -} - -void sha256_init(SHA256_CTX *ctx) -{ - ctx->datalen = 0; - ctx->bitlen = 0; - ctx->state[0] = 0x6a09e667; - ctx->state[1] = 0xbb67ae85; - ctx->state[2] = 0x3c6ef372; - ctx->state[3] = 0xa54ff53a; - ctx->state[4] = 0x510e527f; - ctx->state[5] = 0x9b05688c; - ctx->state[6] = 0x1f83d9ab; - ctx->state[7] = 0x5be0cd19; -} - -void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len) -{ - WORD i; - - for (i = 0; i < len; ++i) { - ctx->data[ctx->datalen] = data[i]; - ctx->datalen++; - if (ctx->datalen == 64) { - sha256_transform(ctx, ctx->data); - ctx->bitlen += 512; - ctx->datalen = 0; - } - } -} - -void sha256_final(SHA256_CTX *ctx, BYTE hash[]) -{ - WORD i; - - i = ctx->datalen; - - // Pad whatever data is left in the buffer. - if (ctx->datalen < 56) { - ctx->data[i++] = 0x80; - while (i < 56) - ctx->data[i++] = 0x00; - } - else { - ctx->data[i++] = 0x80; - while (i < 64) - ctx->data[i++] = 0x00; - sha256_transform(ctx, ctx->data); - memset(ctx->data, 0, 56); - } - - // Append to the padding the total message's length in bits and transform. - ctx->bitlen += ctx->datalen * 8; - ctx->data[63] = ctx->bitlen; - ctx->data[62] = ctx->bitlen >> 8; - ctx->data[61] = ctx->bitlen >> 16; - ctx->data[60] = ctx->bitlen >> 24; - ctx->data[59] = ctx->bitlen >> 32; - ctx->data[58] = ctx->bitlen >> 40; - ctx->data[57] = ctx->bitlen >> 48; - ctx->data[56] = ctx->bitlen >> 56; - sha256_transform(ctx, ctx->data); - - // Since this implementation uses little endian byte ordering and SHA uses big endian, - // reverse all the bytes when copying the final state to the output hash. - for (i = 0; i < 4; ++i) { - hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff; - hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff; - hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff; - hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff; - hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff; - hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff; - hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff; - hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff; - } -}