414 lines
14 KiB
C
414 lines
14 KiB
C
/*
|
|
* ==================================================================================
|
|
* Common Header - Shared definitions and utilities for ISA ICMP Covert Channel
|
|
*
|
|
* ISA Project
|
|
* Author: Roman Necas (xnecasr00)
|
|
* Date: 13. October 2025
|
|
*
|
|
* PURPOSE:
|
|
* This header file serves as the central repository for all common definitions,
|
|
* constants, macros, and data structures used throughout the application. It is
|
|
* included by virtually every module in the project.
|
|
*
|
|
* CONTENTS:
|
|
* - System and POSIX includes
|
|
* - Network-related includes (BSD sockets, ICMP)
|
|
* - Application-wide constants and limits
|
|
* - Common data structures (config_t)
|
|
* - Utility macros (SAFE_FREE, SAFE_CLOSE, etc.)
|
|
* - Global variable declarations
|
|
* - Function prototypes for utility functions
|
|
* ==================================================================================
|
|
*/
|
|
|
|
#ifndef COMMON_H
|
|
#define COMMON_H
|
|
|
|
/*
|
|
* ==================================================================================
|
|
* SYSTEM INCLUDES
|
|
* ==================================================================================
|
|
*/
|
|
|
|
/* Enable GNU extensions and POSIX features */
|
|
#define _GNU_SOURCE
|
|
|
|
/* Standard C library headers */
|
|
#include <stdio.h> /* Standard I/O (printf, fprintf, FILE) */
|
|
#include <stdlib.h> /* Memory allocation (malloc, free), exit codes */
|
|
#include <string.h> /* String operations (memcpy, strlen, strcmp) */
|
|
#include <unistd.h> /* POSIX API (getuid, access, close) */
|
|
#include <getopt.h> /* Command-line argument parsing (getopt) */
|
|
#include <errno.h> /* Error number definitions (errno) */
|
|
#include <signal.h> /* Signal handling (not currently used but available) */
|
|
#include <time.h> /* Time functions (time, localtime, strftime) */
|
|
#include <ctype.h> /* Character type checking (isalnum, isdigit) */
|
|
|
|
/* POSIX socket and system headers */
|
|
#include <sys/socket.h> /* Socket API (socket, bind, sendto, recvfrom) */
|
|
#include <sys/types.h> /* Data types (size_t, ssize_t, pid_t) */
|
|
#include <sys/time.h> /* Time structures (timeval for socket timeouts) */
|
|
#include <sys/stat.h> /* File status (stat, access) */
|
|
#include <fcntl.h> /* File control (open flags, fcntl for non-blocking) */
|
|
|
|
/* Network protocol headers - BSD sockets */
|
|
#include <netinet/in.h> /* Internet address structures (sockaddr_in, sockaddr_in6) */
|
|
#include <netinet/ip.h> /* IPv4 header structure (struct iphdr) */
|
|
#include <netinet/ip_icmp.h> /* ICMPv4 structures (struct icmphdr, ICMP_ECHO, ICMP_ECHOREPLY) */
|
|
#include <netinet/ip6.h> /* IPv6 header structure (struct ip6_hdr) */
|
|
#include <netinet/icmp6.h> /* ICMPv6 structures (struct icmp6_hdr, ICMP6_ECHO_REQUEST, ICMP6_ECHO_REPLY) */
|
|
#include <arpa/inet.h> /* Internet operations (inet_pton, inet_ntop, htons, ntohs) */
|
|
#include <netdb.h> /* Network database (getaddrinfo for hostname resolution) */
|
|
|
|
/*
|
|
* ==================================================================================
|
|
* APPLICATION CONSTANTS
|
|
* ==================================================================================
|
|
*/
|
|
|
|
/* Application identification */
|
|
#define APP_NAME "secret" /* Application binary name */
|
|
|
|
/*
|
|
* BUFFER AND SIZE LIMITS
|
|
* ----------------------
|
|
* These constants define the maximum sizes for various buffers and data structures.
|
|
* They are carefully chosen to balance functionality with security and memory usage.
|
|
*/
|
|
|
|
/* Maximum ICMP payload size (1400 bytes)
|
|
* This is chosen to stay well within the typical MTU (1500 bytes) while leaving
|
|
* room for IP header (20 bytes IPv4/40 bytes IPv6) and ICMP header (8 bytes).
|
|
* Formula: 1500 (MTU) - 20 (IP) - 8 (ICMP) - 48 (IFTP header) = 1424 bytes safe
|
|
* We use 1400 for additional safety margin. */
|
|
#define MAX_PAYLOAD_SIZE 1400
|
|
|
|
/* Maximum filename length (255 bytes)
|
|
* Matches the typical filesystem limit for filename components. This does not
|
|
* include the directory path, only the filename itself. */
|
|
#define MAX_FILENAME_LEN 255
|
|
|
|
/* General-purpose buffer size (2048 bytes)
|
|
* Used for temporary operations like packet reception, string formatting, etc.
|
|
* Large enough to hold any ICMP packet including IP header and payload. */
|
|
#define MAX_BUFFER_SIZE 2048
|
|
|
|
/* Maximum path length (4096 bytes)
|
|
* Matches Linux PATH_MAX constant. Used for validating file paths provided
|
|
* by the user on the command line. */
|
|
#define MAX_PATH_LEN 4096
|
|
|
|
/*
|
|
* NETWORK CONFIGURATION
|
|
* ---------------------
|
|
* Timeout and retry parameters for reliable communication over ICMP.
|
|
*/
|
|
|
|
/* Maximum number of retry attempts for failed transmissions
|
|
* After this many retries, the operation is considered failed. */
|
|
#define MAX_RETRIES 5
|
|
|
|
/* Initial timeout value in seconds
|
|
* Time to wait for ACK response before retrying. This value increases
|
|
* exponentially with each retry (exponential backoff). */
|
|
#define INITIAL_TIMEOUT 2
|
|
|
|
/* Maximum timeout value in seconds
|
|
* Upper limit for exponential backoff. Prevents waiting too long. */
|
|
#define MAX_TIMEOUT 30
|
|
|
|
/*
|
|
* ==================================================================================
|
|
* APPLICATION MODE ENUMERATION
|
|
* ==================================================================================
|
|
*/
|
|
|
|
/*
|
|
* app_mode_t - Operating mode of the application
|
|
*
|
|
* The application can run in one of two modes:
|
|
* - CLIENT: Sends a file to a remote server via ICMP
|
|
* - SERVER: Listens for incoming ICMP packets and receives files
|
|
*
|
|
* The mode is determined by command-line arguments:
|
|
* - Client requires: -r <file> -s <destination>
|
|
* - Server requires: -l
|
|
*/
|
|
typedef enum {
|
|
MODE_CLIENT = 0, /* Client mode: transmit file via ICMP Echo Request */
|
|
MODE_SERVER = 1 /* Server mode: listen for ICMP Echo Request and save file */
|
|
} app_mode_t;
|
|
|
|
/*
|
|
* ==================================================================================
|
|
* UTILITY MACROS
|
|
* ==================================================================================
|
|
*/
|
|
|
|
/* Get the number of elements in an array
|
|
* Usage: ARRAY_SIZE(my_array) returns the element count
|
|
* Note: Only works with arrays, not pointers */
|
|
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
|
|
|
/* Return the maximum of two values */
|
|
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
|
|
|
/* Return the minimum of two values */
|
|
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
|
|
|
/*
|
|
* SAFE MEMORY AND RESOURCE MANAGEMENT MACROS
|
|
* -------------------------------------------
|
|
* These macros provide safe wrappers around common operations that prevent
|
|
* common bugs like double-free and resource leaks.
|
|
*/
|
|
|
|
/*
|
|
* SAFE_FREE - Safely free memory and set pointer to NULL
|
|
*
|
|
* This macro prevents double-free bugs by:
|
|
* 1. Checking if the pointer is non-NULL
|
|
* 2. Calling free()
|
|
* 3. Setting the pointer to NULL
|
|
*
|
|
* After SAFE_FREE(ptr), the pointer is guaranteed to be NULL, making
|
|
* subsequent SAFE_FREE calls safe (they become no-ops).
|
|
*
|
|
* Usage:
|
|
* char *buffer = malloc(100);
|
|
* SAFE_FREE(buffer); // buffer is now NULL
|
|
* SAFE_FREE(buffer); // safe - does nothing
|
|
*/
|
|
#define SAFE_FREE(ptr) do { \
|
|
if (ptr) { \
|
|
free(ptr); \
|
|
ptr = NULL; \
|
|
} \
|
|
} while(0)
|
|
|
|
/*
|
|
* SAFE_CLOSE - Safely close file descriptor and set to -1
|
|
*
|
|
* This macro prevents double-close bugs and resource leaks by:
|
|
* 1. Checking if the file descriptor is valid (>= 0)
|
|
* 2. Calling close()
|
|
* 3. Setting the descriptor to -1
|
|
*
|
|
* After SAFE_CLOSE(fd), the descriptor is -1, making subsequent
|
|
* SAFE_CLOSE calls safe (they become no-ops).
|
|
*
|
|
* Usage:
|
|
* int sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
|
|
* SAFE_CLOSE(sockfd); // sockfd is now -1
|
|
* SAFE_CLOSE(sockfd); // safe - does nothing
|
|
*/
|
|
#define SAFE_CLOSE(fd) do { \
|
|
if (fd >= 0) { \
|
|
close(fd); \
|
|
fd = -1; \
|
|
} \
|
|
} while(0)
|
|
|
|
/*
|
|
* ==================================================================================
|
|
* APPLICATION CONFIGURATION STRUCTURE
|
|
* ==================================================================================
|
|
*/
|
|
|
|
/*
|
|
* config_t - Application runtime configuration
|
|
*
|
|
* This structure holds all configuration parameters parsed from command-line
|
|
* arguments. It is populated by parse_arguments() and passed to client_run()
|
|
* or server_run() to control application behavior.
|
|
*
|
|
* LIFECYCLE:
|
|
* 1. Initialized (zeroed) in main()
|
|
* 2. Populated by parse_arguments()
|
|
* 3. Used by client_run() or server_run()
|
|
* 4. Cleaned up by cleanup_config()
|
|
*
|
|
* MEMORY MANAGEMENT:
|
|
* Fields marked with (*) are dynamically allocated and must be freed.
|
|
* Use cleanup_config() to properly release all resources.
|
|
*/
|
|
typedef struct {
|
|
/* Source file path for transfer (CLIENT MODE ONLY)
|
|
* (*) Dynamically allocated - freed by cleanup_config()
|
|
* Example: "/home/user/document.pdf" */
|
|
char *source_file;
|
|
|
|
/* Destination IP address or hostname (CLIENT MODE ONLY)
|
|
* (*) Dynamically allocated - freed by cleanup_config()
|
|
* Examples: "192.168.1.100", "::1", "hostname.example.com" */
|
|
char *dest_address;
|
|
|
|
/* Operating mode - CLIENT or SERVER */
|
|
app_mode_t mode;
|
|
|
|
/* Listen mode flag (1 = server mode, 0 = client mode)
|
|
* This is redundant with 'mode' field but kept for backward compatibility */
|
|
int listen_mode;
|
|
|
|
/* Timeout in seconds for network operations
|
|
* Default: INITIAL_TIMEOUT (2 seconds)
|
|
* Range: 1-300 seconds (validated by argument parser) */
|
|
int timeout_seconds;
|
|
|
|
/* Maximum retry attempts for failed operations
|
|
* Default: MAX_RETRIES (5 attempts) */
|
|
int max_retries;
|
|
} config_t;
|
|
|
|
/*
|
|
* ==================================================================================
|
|
* GLOBAL VARIABLES
|
|
* ==================================================================================
|
|
*/
|
|
|
|
/*
|
|
* login - User's login name used as encryption password
|
|
*
|
|
* SECURITY NOTE:
|
|
* This global variable holds the login name which is used as the password
|
|
* for PBKDF2 key derivation. In this implementation, it is hardcoded to
|
|
* "xnecasr00" as required by the assignment specification.
|
|
*
|
|
* USAGE:
|
|
* - Set in argument_parser.c during initialization
|
|
* - Used by crypto_engine.c for AES-256 key derivation via PBKDF2
|
|
* - Both client and server must use the same login for successful decryption
|
|
*
|
|
* REQUIREMENT:
|
|
* According to the assignment specification, the login name must be used
|
|
* as the encryption key. This creates a shared secret between client and
|
|
* server running under the same username.
|
|
*/
|
|
extern char *login;
|
|
|
|
/*
|
|
* ==================================================================================
|
|
* FUNCTION DECLARATIONS
|
|
* ==================================================================================
|
|
*/
|
|
|
|
/*
|
|
* Command-line argument parsing
|
|
* ------------------------------
|
|
*/
|
|
|
|
/*
|
|
* parse_arguments - Parse and validate command-line arguments
|
|
*
|
|
* Processes command-line arguments and populates the config structure.
|
|
* Performs comprehensive validation of all inputs including:
|
|
* - File existence and readability (client mode)
|
|
* - IP address/hostname format validation
|
|
* - Timeout range validation
|
|
* - Root privilege verification
|
|
*
|
|
* @param argc: Argument count from main()
|
|
* @param argv: Argument vector from main()
|
|
* @param config: Configuration structure to populate (output parameter)
|
|
*
|
|
* @return:
|
|
* >0 : Help was displayed (normal exit)
|
|
* 0 : Arguments parsed successfully
|
|
* -1 : Error occurred (details in error context)
|
|
*/
|
|
int parse_arguments(int argc, char *argv[], config_t *config);
|
|
|
|
/*
|
|
* print_usage - Display usage information to stderr
|
|
*
|
|
* Prints comprehensive help text including:
|
|
* - Syntax and options
|
|
* - Usage examples for client and server modes
|
|
* - Security notes and requirements
|
|
*
|
|
* @param progname: Name of the program (typically argv[0])
|
|
*/
|
|
void print_usage(const char *progname);
|
|
|
|
/*
|
|
* print_error - Print error message to stderr
|
|
*
|
|
* Convenience function that outputs an error message to stderr
|
|
* and logs it to the error handling system.
|
|
*
|
|
* @param message: Error message to display
|
|
*/
|
|
void print_error(const char *message);
|
|
|
|
/*
|
|
* cleanup_config - Free resources allocated in config structure
|
|
*
|
|
* Releases all dynamically allocated memory in the config_t structure.
|
|
* Safe to call multiple times (uses SAFE_FREE internally).
|
|
*
|
|
* @param config: Configuration structure to clean up
|
|
*/
|
|
void cleanup_config(config_t *config);
|
|
|
|
/*
|
|
* Filename validation and security
|
|
* ---------------------------------
|
|
*/
|
|
|
|
/*
|
|
* validate_filename - Validate filename for security
|
|
*
|
|
* Performs security checks on a filename to prevent:
|
|
* - Path traversal attacks (.. sequences)
|
|
* - Absolute path abuse
|
|
* - Invalid characters
|
|
* - Control characters
|
|
*
|
|
* This is critical for server-side security when receiving filenames
|
|
* from untrusted clients.
|
|
*
|
|
* @param filename: Filename to validate
|
|
* @return: 0 on success, -1 if filename is invalid
|
|
*/
|
|
int validate_filename(const char *filename);
|
|
|
|
/*
|
|
* get_safe_filename - Extract safe filename from path
|
|
*
|
|
* Extracts the basename from a path and ensures the resulting filename
|
|
* is safe to use. If a file with that name already exists, appends a
|
|
* numeric suffix (_1, _2, etc.) to avoid overwriting.
|
|
*
|
|
* SECURITY:
|
|
* This function strips all directory components from the input path,
|
|
* preventing directory traversal attacks.
|
|
*
|
|
* @param original_filename: Input filename (may include path)
|
|
* @param safe_filename: Output buffer for safe filename
|
|
* @param max_len: Maximum length of output buffer
|
|
* @return: 0 on success, -1 on error
|
|
*/
|
|
int get_safe_filename(const char *original_filename, char *safe_filename, size_t max_len);
|
|
|
|
/*
|
|
* Session management
|
|
* ------------------
|
|
*/
|
|
|
|
/*
|
|
* generate_secure_session_id - Generate cryptographically secure session ID
|
|
*
|
|
* Creates a random 16-bit session identifier using OpenSSL's RAND_bytes()
|
|
* for cryptographic quality randomness. This ensures session IDs are
|
|
* unpredictable and unique.
|
|
*
|
|
* SECURITY:
|
|
* Uses RAND_bytes() from OpenSSL for cryptographic randomness. Falls back
|
|
* to less secure rand() only if RAND_bytes() fails (extremely rare).
|
|
*
|
|
* @return: 16-bit session ID (never returns 0)
|
|
*/
|
|
uint16_t generate_secure_session_id(void);
|
|
|
|
#endif /* COMMON_H */
|