diff options
| -rw-r--r-- | Makefile | 15 | ||||
| -rwxr-xr-x | all-in-one.sh | 4 | ||||
| -rw-r--r-- | plugin_example/plugin_example.c | 35 | ||||
| -rw-r--r-- | src/client.c (renamed from client.c) | 15 | ||||
| -rw-r--r-- | src/common.c (renamed from common.c) | 23 | ||||
| -rw-r--r-- | src/config.c | 99 | ||||
| -rw-r--r-- | src/external.h | 124 | ||||
| -rw-r--r-- | src/firehose.c (renamed from firehose.c) | 12 | ||||
| -rw-r--r-- | src/omen.c (renamed from omen.c) | 150 | ||||
| -rw-r--r-- | src/packet_storage.c (renamed from packet_storage.c) | 52 | ||||
| -rw-r--r-- | src/plugin.c | 163 | ||||
| -rw-r--r-- | src/ratelimit.c (renamed from ratelimit.c) | 4 | ||||
| -rw-r--r-- | src/security.c (renamed from security.c) | 12 | ||||
| -rw-r--r-- | src/server.c (renamed from server.c) | 251 | ||||
| -rw-r--r-- | src/sha256.c (renamed from sha256.c) | 10 |
15 files changed, 749 insertions, 220 deletions
@@ -2,18 +2,21 @@ clean: rm -rf bin/* mkdir bin 2> /dev/null || true +sample_plugin: + clang plugin_example/plugin_example.c -shared -fPIC -o bin/plugin_example.so + client: - clang client.c -o bin/client -lsodium -O3 -g + clang src/client.c -o bin/client -lsodium -lz -O3 -g server: - clang server.c -o bin/server -lsodium -O3 -g + clang src/server.c -o bin/server -lsodium -lz -O3 -g release: clean - clang client.c -o bin/client -O3 - clang server.c -o bin/server -O3 + clang src/client.c -o bin/client -O3 + clang src/server.c -o bin/server -O3 crun: bin/client -srun: - bin/server
\ No newline at end of file +srun: sample_plugin + bin/server plugin=bin/plugin_example.so log=debug
\ No newline at end of file diff --git a/all-in-one.sh b/all-in-one.sh new file mode 100755 index 0000000..8ea9762 --- /dev/null +++ b/all-in-one.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env sh +find . -type f -name "*.c" -exec sh -c 'echo "{}:"; echo "\"\"\""; cat "{}"; echo " +\"\"\" +"' \; > bin/compressed.txt
\ No newline at end of file diff --git a/plugin_example/plugin_example.c b/plugin_example/plugin_example.c new file mode 100644 index 0000000..45a2131 --- /dev/null +++ b/plugin_example/plugin_example.c @@ -0,0 +1,35 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +// +#include "../src/external.h" + +static void log_to_file(const char *message) { + FILE *log_file = fopen("bin/server_logs.log", "a"); + if (log_file) { + fprintf(log_file, "%s\n", message); + fclose(log_file); + } +} + +void MP_init_plugin() { // say hello to the user! + printf("hello from a plugin!\n"); +} + +void MP_modify_server_stats(struct relay_info *server_stats) { + // return a random number as motd each time + char str[] = "hello! random number: X"; + str[ sizeof(str) - 2 ] = (rand() % 10) + '0'; + memcpy(server_stats->motd, str, sizeof(str)); +} + +void MP_custom_log(int level, const char *msg) { + // log stuff to a file + char log_msg[ 512 ]; + snprintf(log_msg, sizeof(log_msg), "[level %d] %s", level, msg); + log_to_file(log_msg); +} + +void MP_on_server_shutdown() { // goodbye! + printf("bye!\n"); +}
\ No newline at end of file @@ -356,16 +356,13 @@ int main() { printf(" Neighbors: %u\n", info.statistics.neighbors); printf(" Held Packets: %lu\n", info.statistics.held_packets); - FILE* temp_file = fopen("test_packet.txt", "w"); - if (temp_file) { - fprintf(temp_file, "this is a test message from the moonpaste client."); - fclose(temp_file); - } - keypair author = generate_keypair(); - struct data_packet new_packet = create_packet("test_packet.txt", author, 0, NULL); - new_packet = run_pow(new_packet, info.capabilities.leading_zeros); + const char input[] = "this is a test message from the moonpaste client."; + + struct data_packet new_packet + = create_packet_from_bytes((byte*) input, sizeof(input), 0, NULL, author); + new_packet = run_pow(new_packet, info.capabilities.leading_zeros); printf("hash: " hash_fmt "\n", hash_ref(new_packet.hash)); printf("pushing new packet to server...\n"); @@ -428,8 +425,6 @@ int main() { printf("\nstarting firehose stream. Press Ctrl+C to exit.\n"); get_firehose_stream("127.0.0.1", 8040, 0, 10); - remove("test_packet.txt"); - return 0; } @@ -388,7 +388,7 @@ bool check_leading_zeros(const hash _hash, byte required_zeros) { return true; } -uint64_t get_current_time_ms() { +uint64_t get_current_time_ms(void) { struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); return (uint64_t) ts.tv_sec * 1000 + (uint64_t) ts.tv_nsec / 1000000; @@ -425,9 +425,9 @@ static inline void write_u16_le(byte *b, uint16_t v) { b[ 1 ] = (v >> 8) & 0xFF; } -struct relay_info run_server_audit(const char* ip, int port) { +struct relay_info run_server_audit(const char *ip, int port) { byte data[] = { audit_server, 0, 0, 0, 0, 0, 0, 0 }; - byte* response = NULL; + byte *response = NULL; size_t resp_len = 0; bool success; @@ -445,4 +445,19 @@ struct relay_info run_server_audit(const char* ip, int port) { return info; } -pthread_mutex_t packet_storage_mutex = PTHREAD_MUTEX_INITIALIZER;
\ No newline at end of file +pthread_mutex_t packet_storage_mutex = PTHREAD_MUTEX_INITIALIZER; + +pthread_mutex_t log_io_mutex = PTHREAD_MUTEX_INITIALIZER; + +enum { _debug = 1, _info = 2, _warn = 3, _error = 4 } log_level = _error; // error only by default +const char* log_level_names[] = { "debug", "info", "warn", "error" }; +#define log(__level, fmt, ...) \ + ({ \ + char msg[ 4096 ]; \ + snprintf(msg, sizeof(msg), fmt __VA_OPT__(, ) __VA_ARGS__); \ + pthread_mutex_lock(&log_io_mutex); \ + if (__level >= log_level) \ + fprintf(stderr, "[%s] %s\n", log_level_names[ __level - 1 ], msg); \ + if (custom_log_func) custom_log_func(__level, msg); \ + pthread_mutex_unlock(&log_io_mutex); \ + }) diff --git a/src/config.c b/src/config.c new file mode 100644 index 0000000..ef55387 --- /dev/null +++ b/src/config.c @@ -0,0 +1,99 @@ +#include <ctype.h> +#include <pthread.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +// + +// . +// . +// warning: slices are not NULL-terminated, and should not be modified! +// strdup them if you need to make modifications. +typedef struct slice { + char* ref; + size_t len; +} slice_t; + +typedef struct pair { + slice_t key; + slice_t value; +} pair_t; + +pair_t* global_arg_table = NULL; +size_t args_count = 0; + +void parse_arguments(int argc, char** argv) { + if (argc <= 1) return; + + global_arg_table = calloc(argc - 1, sizeof(pair_t)); + + for (int i = 1; i < argc; i++) { + char* current = argv[ i ]; + char* eq_sign = strchr(current, '='); + if (eq_sign == NULL) { + printf( + "argument error: " + "moonpaste expects named arguments with values. example: 'foo=bar'\n" + " in '%s'", + current); + exit(1); + } + + // key + size_t key_len = eq_sign - current; + size_t key_start = 0; + while (key_start < key_len && isspace(current[ key_start ])) { // trim start + key_start++; + key_len--; + } + while (key_len > 0 && isspace(current[ key_start + key_len - 1 ])) { // trim end + key_len--; + } + + if (key_len == 0) { + printf( + "argument error: empty key\n" + " in '%s'\n", + current); + exit(1); + } + + // value + size_t value_start = eq_sign - current + 1; + size_t value_len = strlen(current) - value_start; + while (value_start < strlen(current) && isspace(current[ value_start ])) { // trim start + value_start++; + value_len--; + } + while (value_len > 0 && isspace(current[ value_start + value_len - 1 ])) { // trim end + value_len--; + } + + // store + global_arg_table[ args_count ].key.ref = current + key_start; + global_arg_table[ args_count ].key.len = key_len; + global_arg_table[ args_count ].value.ref = current + value_start; + global_arg_table[ args_count ].value.len = value_len; + args_count++; + } +} + +// get a config option's value from argv. +// if mandatory == true -> program errors +char* get_config(char* key, bool mandatory) { + size_t len = strlen(key); + for (int i = 0; i < args_count; i++) { + if (global_arg_table[ i ].key.len != len) continue; + if (strncmp(key, global_arg_table[ i ].key.ref, len) != 0) continue; + char* new_str = malloc(global_arg_table[ i ].value.len); + memcpy(new_str, global_arg_table[ i ].value.ref, global_arg_table[ i ].value.len); + return new_str; // free me! + } + + if (!mandatory) return NULL; + fprintf(stderr, "program expected argument %s but did not receive it.\n", key); + // __builtin_unreachable(); + return NULL; +}
\ No newline at end of file diff --git a/src/external.h b/src/external.h new file mode 100644 index 0000000..e145f91 --- /dev/null +++ b/src/external.h @@ -0,0 +1,124 @@ +#pragma once +// +#include <stddef.h> +#include <stdint.h> +#include <stdbool.h> +// + +typedef uint8_t byte; + +typedef byte ipv4[ 4 ]; +typedef byte ipv6[ 16 ]; + +typedef byte hash[ 32 ]; +typedef byte public_key[ 32 ]; +typedef byte private_key[ 32 ]; +typedef byte signature[ 64 ]; + +const uint16_t default_port = 8040; + +enum client_input { + // ask server for its information (responds with audit_response) + audit_server = 0x9a, + + // ask server for a random set of neighbors + // (input uint8_t neighbor_count, responds with neighbors_info) + get_neighbors = 0x20, + + // monitor incoming packets + // (input struct firehose_request, responds with firehose_reply) + firehose = 0xf1, + + // give a packet to the relay + // (input struct data_packet, responds with push_packet_result) + push_packet = 0x88, + + // get a packet from the server + // (input hash, responds with get_packet_result) + get_packet = 0x87, + + // register a new neighbor relay to this server + // (input struct relay_neighbor, responds with register_neighbor_result) + register_neighbor = 0x73, +}; + +enum server_reply { + // pretty self-explanatory. + error = 0x1, + + // type `struct relay_info` + audit_response = 0xaf, + // type `struct relay_neighbor[ neighbor_count ]` + neighbors_info = 0x43, + // type `uint64_t new_offset, struct data_packet[ count ]` + firehose_reply = 0x6c, + // type `bool result_code` + push_packet_result = 0x4a, + // type `struct data_packet` + get_packet_result = 0x42, + // type `bool result_code` + register_neighbor_result = 0x6e, +}; + +typedef uint8_t get_neighbors_request; + +struct firehose_request { + uint8_t count; + uint64_t offset; +}; + +typedef uint64_t firehose_reply_new_offset; + +struct relay_neighbor { + bool active; // set to 0 to indicate empty quick connect slot + + bool has_ipv4; // whether the neighbor supports ipv4 connection + bool has_ipv6; // whether the neighbor supports ipv6 connection + ipv4 v4_addr; // ipv4 address of the neighbor (if supported) + ipv6 v6_addr; // ipv6 address of the neighbor (if supported) +}; + +struct relay_info { + // -- version info -- + byte major_version; + byte minor_version; + // -- motd -- + byte motd[ 128 ]; + // -- capabilities -- + struct { + uint16_t retention_hours; // how many hours packets will be retained for + bool can_store; // whether or not the relay is accepting new packets + byte leading_zeros; // relay challenge level + bool accepts_plain; // whether or not the relay accepts unencrypted packets + } capabilities; + // -- statistics -- + struct { + uint16_t neighbors; // current neighboring relay count for this relay + uint64_t held_packets; // how many packets the relay is holding + struct relay_neighbor quick_connect[ 4 ]; // four best neighbors for quick connection + } statistics; +}; + +// do not change +#define MAX_RECIPIENTS 32 + +struct data_packet { + // nonce + hash for PoW + uint32_t nonce; + hash hash; + + // content inside to be nonce + hashed + struct { + bool encrypted; // whether the contents is encrypted or plaintext + uint64_t created_time_ms; // unix timestamp for creation time in milliseconds + public_key author; // message author + public_key author_signing_pub; // message signing pubkey + uint8_t recipient_count; // number of recipients. leave as 0 for public. + public_key recipients[ 32 ]; // up to 32 recipients for packet + byte data[ 65536 ]; // packet data + signature signature; // data signature + } contents; +}; + +const size_t CONTENTS_SIZE = 1 + 8 + 32 + 32 + 1 + (32 * MAX_RECIPIENTS) + 65536 + 64; +const size_t PACKET_SIZE = 4 + 32 + (CONTENTS_SIZE);
\ No newline at end of file diff --git a/firehose.c b/src/firehose.c index b2931a7..6a4a134 100644 --- a/firehose.c +++ b/src/firehose.c @@ -24,13 +24,13 @@ typedef struct { static fire_buffer firehose_buffer; -void firehose_init(); +void firehose_init(void); void firehose_push(hash new_hash, uint64_t storage_index); -uint16_t firehose_get_count(); -uint64_t firehose_get_total_packets(); +uint16_t firehose_get_count(void); +uint64_t firehose_get_total_packets(void); uint16_t firehose_get_packets(uint64_t offset, uint16_t count, water_splash* output_entries); -void firehose_init() { +void firehose_init(void) { memset(firehose_buffer.entries, 0, sizeof(firehose_buffer.entries)); firehose_buffer.head = 0; firehose_buffer.tail = 0; @@ -59,8 +59,8 @@ void firehose_push(hash new_hash, uint64_t storage_index) { pthread_mutex_unlock(&firehose_buffer.mutex); } -uint16_t firehose_get_count() { return firehose_buffer.count; } -uint64_t firehose_get_total_packets() { return firehose_buffer.total_packets; } +uint16_t firehose_get_count(void) { return firehose_buffer.count; } +uint64_t firehose_get_total_packets(void) { return firehose_buffer.total_packets; } uint16_t firehose_get_packets(uint64_t offset, uint16_t count, water_splash* output_entries) { pthread_mutex_lock(&firehose_buffer.mutex); @@ -19,10 +19,6 @@ typedef uint8_t byte; typedef void (*tome_ptr)( char *ip_addr, size_t addr_size, byte *in, size_t in_len, byte **out, size_t *out_len); -struct server_task { - int fd; - struct server_task *next; -}; #define MAX_BUFFER 1 << 18 #define MAX_BODY 1 << 22 @@ -32,12 +28,16 @@ struct server_task { int worker_count = 64; -pthread_mutex_t queue_mutex = PTHREAD_MUTEX_INITIALIZER; -pthread_cond_t queue_cond = PTHREAD_COND_INITIALIZER; -struct server_task *head = NULL; -struct server_task *tail = NULL; -size_t queue_size = 0; -tome_ptr global_handler = NULL; +pthread_mutex_t queue_mutex = PTHREAD_MUTEX_INITIALIZER; +pthread_cond_t queue_cond = PTHREAD_COND_INITIALIZER; + +static int ring_fds[ MAX_CONNECTIONS ]; +static char ring_ips[ MAX_CONNECTIONS ][ INET6_ADDRSTRLEN ]; +static size_t ring_head = 0; +static size_t ring_tail = 0; +size_t queue_size = 0; + +tome_ptr global_handler = NULL; // utils @@ -82,7 +82,8 @@ static int read_until_headers(int fd, char **out_buf, size_t *out_len) { free(buf); return -1; } else if (r == 0) { - len = len; + // TODO: why? + // len = len; break; } len += (size_t) r; @@ -169,57 +170,19 @@ static int send_http_response(int fd, const byte *payload, size_t payload_len) { void *omen_bound(void *arg) { (void) arg; while (1) { - int client_fd = -1; - struct sockaddr_storage client_addr; - socklen_t client_addr_len = sizeof(client_addr); + int client_fd = -1; + char client_ip[ INET6_ADDRSTRLEN ] = { 0 }; pthread_mutex_lock(&queue_mutex); - while (head == NULL) { pthread_cond_wait(&queue_cond, &queue_mutex); } - struct server_task *task = head; - head = head->next; - if (head == NULL) tail = NULL; - queue_size--; - client_fd = task->fd; + while (queue_size == 0) { pthread_cond_wait(&queue_cond, &queue_mutex); } - if (getpeername(client_fd, (struct sockaddr *) &client_addr, &client_addr_len) < 0) { - memset(&client_addr, 0, sizeof(client_addr)); - } - - free(task); + client_fd = ring_fds[ ring_head ]; + strncpy(client_ip, ring_ips[ ring_head ], INET6_ADDRSTRLEN - 1); + client_ip[ INET6_ADDRSTRLEN - 1 ] = '\0'; + ring_head = (ring_head + 1) % MAX_CONNECTIONS; + queue_size--; pthread_mutex_unlock(&queue_mutex); - char client_ip[ INET6_ADDRSTRLEN ] = { 0 }; - if (client_addr.ss_family == AF_INET) { - struct sockaddr_in *addr4 = (struct sockaddr_in *) &client_addr; - inet_ntop(AF_INET, &addr4->sin_addr, client_ip, INET_ADDRSTRLEN); - } else if (client_addr.ss_family == AF_INET6) { - struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) &client_addr; - inet_ntop(AF_INET6, &addr6->sin6_addr, client_ip, INET6_ADDRSTRLEN); - } - - if (!ratelimit_check(client_ip)) { - usleep(250 * 1000); - - struct server_task *new_task = malloc(sizeof(struct server_task)); - if (new_task) { - new_task->fd = client_fd; - new_task->next = NULL; - - pthread_mutex_lock(&queue_mutex); - if (tail) tail->next = new_task; - else - head = new_task; - tail = new_task; - queue_size++; - pthread_cond_signal(&queue_cond); - pthread_mutex_unlock(&queue_mutex); - } else { - close(client_fd); - } - - continue; - } - struct timeval timeout = { 5, 0 }; setsockopt(client_fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); @@ -339,7 +302,7 @@ int omen(int port, tome_ptr handler) { } if (listen(server_fd, MAX_CONNECTIONS) < 0) { - perror("Listen failed"); + perror("listen failed"); close(server_fd); return -1; } @@ -365,11 +328,29 @@ int omen(int port, tome_ptr handler) { socklen_t len = sizeof(client_addr); int client_fd = accept(server_fd, (struct sockaddr *) &client_addr, &len); if (client_fd < 0) { - if (errno != EINTR) { perror("Accept failed"); } + if (errno != EINTR) { perror("accept failed"); } continue; } - printf("request\n"); + char client_ip[ INET6_ADDRSTRLEN ] = { 0 }; + if (client_addr.ss_family == AF_INET) { + struct sockaddr_in *addr4 = (struct sockaddr_in *) &client_addr; + inet_ntop(AF_INET, &addr4->sin_addr, client_ip, sizeof(client_ip)); + } else if (client_addr.ss_family == AF_INET6) { + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) &client_addr; + if (IN6_IS_ADDR_V4MAPPED(&addr6->sin6_addr)) { + struct in_addr v4; + memcpy(&v4.s_addr, &addr6->sin6_addr.s6_addr[ 12 ], sizeof(v4.s_addr)); + inet_ntop(AF_INET, &v4, client_ip, sizeof(client_ip)); + } else { + inet_ntop(AF_INET6, &addr6->sin6_addr, client_ip, sizeof(client_ip)); + } + } else { + strncpy(client_ip, "0.0.0.0", sizeof(client_ip) - 1); + client_ip[ sizeof(client_ip) - 1 ] = '\0'; + } + + if (!ratelimit_check(client_ip)) { usleep(250 * 1000); } pthread_mutex_lock(&queue_mutex); if (queue_size >= (size_t) MAX_CONNECTIONS) { @@ -383,18 +364,10 @@ int omen(int port, tome_ptr handler) { continue; } - struct server_task *new_task = malloc(sizeof(struct server_task)); - if (!new_task) { - close(client_fd); - pthread_mutex_unlock(&queue_mutex); - continue; - } - new_task->fd = client_fd; - new_task->next = NULL; - if (tail) tail->next = new_task; - else - head = new_task; - tail = new_task; + ring_fds[ ring_tail ] = client_fd; + strncpy(ring_ips[ ring_tail ], client_ip, INET6_ADDRSTRLEN - 1); + ring_ips[ ring_tail ][ INET6_ADDRSTRLEN - 1 ] = '\0'; + ring_tail = (ring_tail + 1) % MAX_CONNECTIONS; queue_size++; pthread_cond_signal(&queue_cond); pthread_mutex_unlock(&queue_mutex); @@ -416,11 +389,11 @@ int study( size_t *resp_len) { bool is_ipv6 = strchr(ip, ':') != NULL; int domain = is_ipv6 ? AF_INET6 : AF_INET; - printf("Attempting %s connection to %s:%d\n", is_ipv6 ? "IPv6" : "IPv4", ip, port); + // printf("attempting %s connection to %s:%d\n", is_ipv6 ? "ipv6" : "ipv4", ip, port); int sock = socket(domain, SOCK_STREAM, 0); if (sock < 0) { - printf("Socket creation failed: %s\n", strerror(errno)); + printf("socket creation failed: %s\n", strerror(errno)); return -1; } @@ -441,7 +414,7 @@ int study( } if (inet_pton(domain, ip, addr_ptr) != 1) { - printf("Invalid %s address: %s\n", is_ipv6 ? "IPv6" : "IPv4", ip); + printf("invalid %s address: %s\n", is_ipv6 ? "ipv6" : "ipv4", ip); close(sock); return -1; } @@ -449,22 +422,21 @@ int study( struct timeval timeout = { 5, 0 }; if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0 || setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)) < 0) { - printf("Setsockopt failed: %s\n", strerror(errno)); + printf("setsockopt failed: %s\n", strerror(errno)); close(sock); return -1; } - printf("Connecting to %s:%d\n", ip, port); + // printf("connecting to %s:%d\n", ip, port); if (connect(sock, (struct sockaddr *) &addr, addr_len) < 0) { - printf("Connect failed: %s\n", strerror(errno)); + printf("connect failed: %s\n", strerror(errno)); close(sock); return -1; } if (data_len > MAX_BODY) data_len = MAX_BODY; char req_hdr[ 256 ]; - // Use [ ] for IPv6 in Host header - int hdr_n; + int hdr_n; if (is_ipv6) { hdr_n = snprintf( req_hdr, @@ -481,15 +453,15 @@ int study( data_len); } if (hdr_n < 0 || (size_t) hdr_n >= sizeof(req_hdr)) { - printf("Failed to format HTTP header\n"); + printf("failed to format HTTP header\n"); close(sock); return -1; } - printf("Sending request: %.*s\n", hdr_n, req_hdr); + // printf("sending request: %.*s\n", hdr_n, req_hdr); if (write_all(sock, req_hdr, (size_t) hdr_n) < 0 || (data_len > 0 && write_all(sock, data, data_len) < 0)) { - printf("Write failed: %s\n", strerror(errno)); + printf("write failed: %s\n", strerror(errno)); close(sock); return -1; } @@ -497,14 +469,14 @@ int study( char *hdr_buf = NULL; size_t hdr_len = 0; if (read_until_headers(sock, &hdr_buf, &hdr_len) < 0) { - printf("Failed to read headers: %s\n", strerror(errno)); + printf("failed to read headers: %s\n", strerror(errno)); close(sock); free(hdr_buf); return -1; } if (memmem(hdr_buf, hdr_len, "HTTP/1.1 418 I'm a teapot", 34) != NULL) { - printf("Server responded with 418 I'm a teapot\n"); + // printf("server responded with 418 I'm a teapot\n"); close(sock); free(hdr_buf); return -2; @@ -521,7 +493,7 @@ int study( if ((size_t) cl > MAX_BODY) cl = MAX_BODY; body = malloc((size_t) cl); if (!body) { - printf("Failed to allocate body buffer\n"); + printf("failed to allocate body buffer\n"); free(hdr_buf); close(sock); return -1; @@ -534,7 +506,7 @@ int study( } if ((size_t) body_len < (size_t) cl) { if (read_exact(sock, body + body_len, (size_t) cl - body_len) < 0) { - printf("Failed to read body: %s\n", strerror(errno)); + printf("failed to read body: %s\n", strerror(errno)); free(body); free(hdr_buf); close(sock); @@ -576,6 +548,6 @@ int study( *resp_len = 0; free(body); } - printf("Response received, length: %zu\n", body_len); + // printf("response received, length: %zu\n", body_len); return 0; -}
\ No newline at end of file +} diff --git a/packet_storage.c b/src/packet_storage.c index 30e047f..1094afd 100644 --- a/packet_storage.c +++ b/src/packet_storage.c @@ -1,6 +1,8 @@ #include <pthread.h> #include <stdint.h> #include <stdlib.h> +// dependency: zlib +#include <zlib.h> // #include "common.c" @@ -27,45 +29,37 @@ struct data_packet_entry { }* packet_storage; // TODO: yes, i know it's weird, but this has to be zero -#define minus_one (uint64_t) 0 +#define minus_one ((uint64_t) 0) -struct data_packet* load_packet(const hash packet_hash) { - char filename[ 128 ]; - sprintf(filename, "packets/" hash_fmt ".bin", hash_ref(packet_hash)); - - FILE* file = fopen(filename, "rb"); +struct data_packet* load_packet(FILE* file) { if (!file) { return NULL; } fseek(file, 0, SEEK_END); size_t file_size = ftell(file); fseek(file, 0, SEEK_SET); - if (file_size != PACKET_SIZE) { + if (file_size == 0) { fclose(file); return NULL; } - byte* buffer = malloc(file_size); - if (!buffer) { - fclose(file); - return NULL; - } + byte comp_buf[ file_size ]; - size_t r = fread(buffer, 1, file_size, file); + size_t r = fread(comp_buf, 1, file_size, file); fclose(file); - if (r != file_size) { - free(buffer); - return NULL; - } + if (r != file_size) { return NULL; } + + byte buffer[ PACKET_SIZE ]; + + uLongf dest_len = (uLongf) PACKET_SIZE; + int unres = uncompress(buffer, &dest_len, comp_buf, (uLongf) file_size); + + if (unres != Z_OK || dest_len != (uLongf) PACKET_SIZE) { return NULL; } bool success; struct data_packet* packet = malloc(sizeof(struct data_packet)); - if (!packet) { - free(buffer); - return NULL; - } - *packet = s2data_packet(file_size, buffer, &success); - free(buffer); + if (!packet) { return NULL; } + *packet = s2data_packet(PACKET_SIZE, buffer, &success); if (!success) { free(packet); @@ -77,7 +71,7 @@ struct data_packet* load_packet(const hash packet_hash) { uint64_t set_data_packet(struct data_packet* new_packet); -struct data_packet_entry* get_data_packet(hash _hash) { +struct data_packet_entry* get_data_packet(const hash _hash) { uint64_t hash_val; memcpy(&hash_val, _hash, sizeof(uint64_t)); uint64_t cur_index = hash_val % max_storage; @@ -97,7 +91,11 @@ struct data_packet_entry* get_data_packet(hash _hash) { } pthread_mutex_unlock(&packet_storage_mutex); - struct data_packet* packet = load_packet(_hash); + char filename[ 128 ]; + sprintf(filename, "packets/" hash_fmt ".bin", hash_ref(_hash)); + FILE* file = fopen(filename, "rb"); + + struct data_packet* packet = load_packet(file); if (packet) { uint64_t add_idx = set_data_packet(packet); @@ -105,7 +103,7 @@ struct data_packet_entry* get_data_packet(hash _hash) { free(packet); return &packet_storage[ add_idx ]; } else { - __thread static struct data_packet_entry temp_entry; + static __thread struct data_packet_entry temp_entry; temp_entry.packet = *packet; free(packet); return &temp_entry; @@ -232,4 +230,4 @@ bool _delete_at_index(uint64_t index) { current_entry->prev = minus_one; return true; -}
\ No newline at end of file +} diff --git a/src/plugin.c b/src/plugin.c new file mode 100644 index 0000000..cfee5d4 --- /dev/null +++ b/src/plugin.c @@ -0,0 +1,163 @@ +#pragma once + +#include <dlfcn.h> +#include <pthread.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +// +#include "common.c" + +typedef uint8_t byte; + +// contracts + +void __init_plugin_func(void); +typedef typeof(__init_plugin_func) init_plugin; + +struct relay_info; +struct relay_neighbor; +struct data_packet; + +// runs when the server wants to respond to a server audit request +void __modify_server_stats_func(struct relay_info *server_stats); +typedef typeof(__modify_server_stats_func) modify_server_stats; + +// runs when the server wants to decide whether to add a neighbor by request or not +bool __decide_neighbor_registry_func(struct relay_neighbor new_neighbor); +typedef typeof(__decide_neighbor_registry_func) decide_neighbor_registry; + +// runs when the server wants to decide whether to propagate +bool __decide_packet_propogation_func(struct data_packet packet); +typedef typeof(__decide_packet_propogation_func) decide_packet_propogation; + +// runs before the paste_server function performs any logic +void __paste_server_start_func( + char **ip_addr_ref, + size_t *ip_size_ref, + byte **in_ref, + size_t *in_len_ref, + byte ***out_ref, + size_t **out_len_ref); +typedef typeof(__paste_server_start_func) paste_server_start; + +// runs when the server wants to decide whether to save the packet to disk +bool __decide_packet_save_to_disk_func(struct data_packet packet); +typedef typeof(__decide_packet_save_to_disk_func) decide_packet_save_to_disk; + +// runs when the server wants a plugin to modify a packet (e.g., keepalive, run PoW, etc) +void __modify_packet_func(struct data_packet *packet); +typedef typeof(__modify_packet_func) modify_packet; + +// runs when the server wants to decide whether to wipe a packet +bool __decide_packet_cleanup_func(struct data_packet packet); +typedef typeof(__decide_packet_cleanup_func) decide_packet_cleanup; + +// runs when the server logs a message +void __custom_log_func(int level, const char *msg); +typedef typeof(__custom_log_func) custom_log; + +// runs when the server is shutting down +void __on_server_shutdown_func(void); +typedef typeof(__on_server_shutdown_func) on_server_shutdown; + +// data + +enum plugin_handler_code_types { + code_modify_server_stats = 1, + code_decide_neighbor_registry = 2, + code_decide_packet_propogation = 3, + code_paste_server_start = 4, + code_decide_packet_save_to_disk = 5, + code_modify_packet = 6, + code_decide_packet_cleanup = 7, + code_on_server_shutdown = 8, + code_custom_log = 9 +}; + +void *plugin_handle = NULL; +init_plugin *init_plugin_func = NULL; +modify_server_stats *modify_server_stats_func = NULL; +decide_neighbor_registry *decide_neighbor_registry_func = NULL; +decide_packet_propogation *decide_packet_propogation_func = NULL; +paste_server_start *paste_server_start_func = NULL; +decide_packet_save_to_disk *decide_packet_save_to_disk_func = NULL; +modify_packet *modify_packet_func = NULL; +decide_packet_cleanup *decide_packet_cleanup_func = NULL; +custom_log *custom_log_func = NULL; +on_server_shutdown *on_server_shutdown_func = NULL; // unused for now + +pthread_mutex_t plugin_mutex = PTHREAD_MUTEX_INITIALIZER; + +// implementation + +void load_plugins(const char *plugin_path) { + pthread_mutex_lock(&plugin_mutex); + if (plugin_handle) { + dlclose(plugin_handle); + plugin_handle = NULL; + init_plugin_func = NULL; + modify_server_stats_func = NULL; + decide_neighbor_registry_func = NULL; + decide_packet_propogation_func = NULL; + paste_server_start_func = NULL; + decide_packet_save_to_disk_func = NULL; + modify_packet_func = NULL; + decide_packet_cleanup_func = NULL; + custom_log_func = NULL; + on_server_shutdown_func = NULL; + } + + plugin_handle = dlopen(plugin_path, RTLD_NOW); + if (!plugin_handle) { + fprintf(stderr, "%s\n", dlerror()); + pthread_mutex_unlock(&plugin_mutex); + return; + } + + if (init_plugin_func) { + init_plugin_func(); + log(_info, "loaded %s\n", plugin_path); + } else { + log(_error, "%s has no MP_init_plugin", plugin_path); + dlclose(plugin_handle); + plugin_handle = NULL; + pthread_mutex_unlock(&plugin_mutex); + return; + } + + init_plugin_func = dlsym(plugin_handle, "MP_init_plugin"); + modify_server_stats_func = dlsym(plugin_handle, "MP_modify_server_stats"); + decide_neighbor_registry_func = dlsym(plugin_handle, "MP_decide_neighbor_registry"); + decide_packet_propogation_func = dlsym(plugin_handle, "MP_decide_packet_propogation"); + paste_server_start_func = dlsym(plugin_handle, "MP_paste_server_start"); + decide_packet_save_to_disk_func = dlsym(plugin_handle, "MP_decide_packet_save_to_disk"); + modify_packet_func = dlsym(plugin_handle, "MP_modify_packet"); + decide_packet_cleanup_func = dlsym(plugin_handle, "MP_decide_packet_cleanup"); + custom_log_func = dlsym(plugin_handle, "MP_custom_log"); + on_server_shutdown_func = dlsym(plugin_handle, "MP_on_server_shutdown"); + + pthread_mutex_unlock(&plugin_mutex); +} + +void cleanup_plugins(void) { + pthread_mutex_lock(&plugin_mutex); + if (plugin_handle) { + if (on_server_shutdown_func) { on_server_shutdown_func(); } + dlclose(plugin_handle); + plugin_handle = NULL; + init_plugin_func = NULL; + modify_server_stats_func = NULL; + decide_neighbor_registry_func = NULL; + decide_packet_propogation_func = NULL; + paste_server_start_func = NULL; + decide_packet_save_to_disk_func = NULL; + modify_packet_func = NULL; + decide_packet_cleanup_func = NULL; + custom_log_func = NULL; + on_server_shutdown_func = NULL; + } + pthread_mutex_unlock(&plugin_mutex); +} diff --git a/ratelimit.c b/src/ratelimit.c index 38f756e..c6f0e01 100644 --- a/ratelimit.c +++ b/src/ratelimit.c @@ -23,7 +23,7 @@ struct rl_table { struct rl_table* global_ratelimit = NULL; -void ratelimit_init() { +void ratelimit_init(void) { if (global_ratelimit != NULL) return; struct rl_table* table = malloc(sizeof(struct rl_table)); @@ -105,4 +105,4 @@ void ratelimit_free(struct rl_table* table) { pthread_mutex_destroy(&table->mutex); free(table); } -}
\ No newline at end of file +} diff --git a/security.c b/src/security.c index 35f2a81..7afdb27 100644 --- a/security.c +++ b/src/security.c @@ -42,7 +42,7 @@ typedef struct { bool has_called_sodium_init = false; -void init_sec() { +void init_sec(void) { if (unlikely(!has_called_sodium_init)) { if (sodium_init() == -1) { fprintf(stderr, "sodium init failed\n"); @@ -52,7 +52,7 @@ void init_sec() { } } -keypair generate_keypair() { +keypair generate_keypair(void) { init_sec(); keypair new; crypto_box_keypair(new.encryption_pub, new.encryption_priv); @@ -100,7 +100,11 @@ encrypt_and_sign(plain_payload input, keypair author_keys, public_key target_enc return output; } -plain_payload decrypt(secure_payload input, keypair target_keys, public_key author_public, public_key author_signing_public) { +plain_payload decrypt( + secure_payload input, + keypair target_keys, + public_key author_public, + public_key author_signing_public) { init_sec(); plain_payload output; @@ -158,4 +162,4 @@ bool verify_raw_signature( init_sec(); if (msg == NULL || signature == NULL || author_signing_public == NULL) return false; return crypto_sign_verify_detached(signature, msg, msg_len, author_signing_public) == 0; -}
\ No newline at end of file +} @@ -1,28 +1,21 @@ #include <dirent.h> #include <fcntl.h> +#include <pthread.h> #include <sys/mman.h> #include <sys/stat.h> #include <unistd.h> +// dependency: zlib +#include <zlib.h> // #include "common.c" +#include "config.c" +#include "firehose.c" #include "omen.c" +#include "packet_storage.c" +#include "plugin.c" #include "security.c" #include "sha256.c" // -#include "firehose.c" -#include "packet_storage.c" - -pthread_mutex_t log_io_mutex = PTHREAD_MUTEX_INITIALIZER; - -enum { _debug = 1, _info = 2, _warn = 3, _error = 4 } log_level = _debug; -const char* log_level_names[] = { "debug", "info", "warn", "error" }; -#define log(__level, fmt, ...) \ - ({ \ - pthread_mutex_lock(&log_io_mutex); \ - if (__level >= log_level) \ - fprintf(stderr, "[%s] " fmt, (#__level) + 1 __VA_OPT__(, ) __VA_ARGS__); \ - pthread_mutex_unlock(&log_io_mutex); \ - }) const uint64_t max_neighbors = 1 << 10; // probably more than enough for a lot of folks @@ -32,7 +25,7 @@ struct relay_neighbor* neighbor_storage; bool* empty_neighbor_slots; pthread_mutex_t neighbor_storage_mutex = PTHREAD_MUTEX_INITIALIZER; -struct { +struct server_stats { byte major_version; byte minor_version; byte motd[ 128 ]; @@ -50,7 +43,11 @@ struct { }; bool add_neighbor(struct relay_neighbor new_neighbor) { - log(_info, "adding neighbor\n"); + if (decide_neighbor_registry_func) { + if (!decide_neighbor_registry_func(new_neighbor)) return false; + } + + log(_info, "adding neighbor"); pthread_mutex_lock(&neighbor_storage_mutex); if (neighbor_count >= max_neighbors) { @@ -91,11 +88,16 @@ bool add_neighbor(struct relay_neighbor new_neighbor) { void* propagate_packet(void* _packet) { struct data_packet packet = *(struct data_packet*) _packet; - log(_debug, "propagating packet " hash_fmt "\n", hash_ref(packet.hash)); - size_t send_len = 1 + sizeof(struct data_packet); - byte* send_data = calloc(send_len, sizeof(byte)); - send_data[ 0 ] = push_packet; + if (decide_packet_propogation_func) { + if (!decide_packet_propogation_func(packet)) return NULL; + } + + log(_debug, "propagating packet " hash_fmt, hash_ref(packet.hash)); + + size_t send_len = 1 + sizeof(struct data_packet); + byte send_data[ send_len * sizeof(byte) ]; + send_data[ 0 ] = push_packet; data_packet2s(packet, send_data + 1); pthread_mutex_lock(&neighbor_storage_mutex); @@ -131,14 +133,13 @@ void* propagate_packet(void* _packet) { ip_string, default_port, send_data, send_len, &response_data, &response_len); } - if (result != 0) { fprintf(stderr, "failed to send packet to neighbor\n"); } + if (result != 0) { log(_error, "failed to send packet to neighbor"); } if (response_data) { free(response_data); } } } pthread_mutex_unlock(&neighbor_storage_mutex); - free(send_data); free(_packet); return NULL; } @@ -153,7 +154,14 @@ void save_packet(const struct data_packet packet); void paste_server( char* ip_addr, size_t ip_size, byte* in, size_t in_len, byte** out, size_t* out_len) { - log(_info, "<%.*s> incoming request with size %li\n", (int) ip_size, ip_addr, in_len); + log(_info, "<%.*s> incoming request with size %li", (int) ip_size, ip_addr, in_len); + + if (paste_server_start_func) { + paste_server_start_func(&ip_addr, &ip_size, &in, &in_len, &out, &out_len); + } + + // tip: if you want the server to not mandate the 8 bytes minimum, modify in_len using the + // plugin. if (in_len < 8) { // server mandates 8 bytes minimum. pad it if you don't need it! reply(17, strdup("\x01input too small")); @@ -164,7 +172,7 @@ void paste_server( switch (input_type) { case audit_server: { - log(_info, "<%.*s> request type: audit\n", (int) ip_size, ip_addr); + log(_info, "<%.*s> request type: audit", (int) ip_size, ip_addr); byte* output_data = calloc(1 + 237, sizeof(byte)); if (!output_data) { @@ -198,11 +206,13 @@ void paste_server( info.statistics.quick_connect[ i ] = neighbor_storage[ i ]; } + memcpy(info.motd, server_stats.motd, 128); + + if (modify_server_stats_func) { modify_server_stats_func(&info); } + pthread_mutex_unlock(&packet_storage_mutex); pthread_mutex_unlock(&neighbor_storage_mutex); - memcpy(info.motd, server_stats.motd, 128); - relay_info2s(info, output_data + 1); reply(1 + 237, output_data); @@ -212,7 +222,7 @@ void paste_server( case get_neighbors: { byte count = in[ 1 ]; log(_info, - "<%.*s> request type: get neighbors, count %i\n", + "<%.*s> request type: get neighbors, count %i", (int) ip_size, ip_addr, count); @@ -257,7 +267,7 @@ void paste_server( s2hash(32, in + 1, &success, packet_hash); log(_info, - "<%.*s> request type: get packet with hash " hash_fmt "\n", + "<%.*s> request type: get packet with hash " hash_fmt, (int) ip_size, ip_addr, hash_ref(packet_hash)); @@ -305,7 +315,7 @@ void paste_server( struct data_packet packet = s2data_packet(in_len - 1, in + 1, &success); log(_info, - "<%.*s> request type: push packet with hash " hash_fmt "\n", + "<%.*s> request type: push packet with hash " hash_fmt, (int) ip_size, ip_addr, hash_ref(packet.hash)); @@ -316,14 +326,23 @@ void paste_server( output_data[ 0 ] = push_packet_result; if (!success) { - log(_warn, "<%.*s> malformed data\n", (int) ip_size, ip_addr); + log(_warn, "<%.*s> malformed data", (int) ip_size, ip_addr); output_data[ 1 ] = false; reply(output_len, output_data); return; } + if (modify_packet_func) { + // things you can do here: + // - prefer certain packet authors + // - run PoW + // - increase leading zeroes + // - recompute the hash + modify_packet_func(&packet); + } + if (!check_leading_zeros(packet.hash, server_stats.leading_zeros)) { - log(_warn, "bad leads\n"); + log(_warn, "bad leads"); output_data[ 1 ] = false; reply(output_len, output_data); return; @@ -347,7 +366,7 @@ void paste_server( struct sha256 calculated_hash_struct = sha256_hash(hash_input_buffer, hash_input_len); if (memcmp(calculated_hash_struct.hash, packet.hash, sizeof(hash)) != 0) { log(_warn, - "bad hash " hash_fmt " vs " hash_fmt "\n", + "bad hash " hash_fmt " vs " hash_fmt, hash_ref(calculated_hash_struct.hash), hash_ref(packet.hash)); output_data[ 1 ] = false; @@ -357,7 +376,7 @@ void paste_server( uint64_t current_time = get_current_time_ms(); if (packet.contents.created_time_ms > current_time) { - log(_warn, "future\n"); + log(_warn, "packet timestamp is in the future"); output_data[ 1 ] = false; reply(output_len, output_data); return; @@ -365,14 +384,14 @@ void paste_server( if (current_time - packet.contents.created_time_ms > server_stats.retention_hours * (60 * 60 * 1000)) { - log(_warn, "expired\n"); + log(_warn, "packet expired"); output_data[ 1 ] = false; reply(output_len, output_data); return; } if (!packet.contents.encrypted && !server_stats.accepts_plain) { - log(_warn, "plaintext not accepted by server\n"); + log(_warn, "plaintext not accepted by server"); output_data[ 1 ] = false; reply(output_len, output_data); return; @@ -398,7 +417,7 @@ void paste_server( } if (!sig_ok) { - log(_warn, "bad signature\n"); + log(_warn, "bad signature"); output_data[ 1 ] = false; reply(output_len, output_data); return; @@ -452,7 +471,7 @@ void paste_server( if (unlikely(req.count > 64)) req.count = 64; // clamp log(_info, - "<%.*s> request type: firehose count %i offset %li\n", + "<%.*s> request type: firehose count %i offset %li", (int) ip_size, ip_addr, req.count, @@ -500,7 +519,7 @@ void paste_server( return; } - log(_info, "<%.*s> request type: neighbor registration\n", (int) ip_size, ip_addr); + log(_info, "<%.*s> request type: neighbor registration", (int) ip_size, ip_addr); char ip_string[ INET6_ADDRSTRLEN ]; @@ -533,7 +552,7 @@ void paste_server( } break; default: { - log(_info, "<%.*s> request type: invalid method\n", (int) ip_size, ip_addr); + log(_info, "<%.*s> request type: invalid method", (int) ip_size, ip_addr); byte* output_data = calloc(1 + 14, sizeof(byte)); output_data[ 0 ] = error; @@ -562,7 +581,7 @@ void* alloc_map(uint64_t size) { alloc = mmap(NULL, size, RW, PA, -1, 0); if (alloc != MAP_FAILED) { // hugepages failed, remove flag - printf("[note] no hugepages support present\n"); + printf("[note] no hugepages support present"); try_hugepages = false; } } @@ -580,30 +599,60 @@ volatile bool disk_persistence_thread_running = true; bool file_exists(const char* filename) { return access(filename, F_OK) == 0; } void save_packet(const struct data_packet packet) { - log(_debug, "saving packet " hash_fmt " to disk\n", hash_ref(packet.hash)); + if (decide_packet_save_to_disk_func) { + if (!decide_packet_save_to_disk_func(packet)) return; + } + + log(_debug, "saving packet " hash_fmt " to disk", hash_ref(packet.hash)); mkdir("packets", 0755); - char filename[ 128 ]; - sprintf(filename, "packets/" hash_fmt ".bin", hash_ref(packet.hash)); + char filename_tmp[ 256 ]; + char filename_final[ 256 ]; + snprintf( + filename_tmp, sizeof(filename_tmp), "packets/" hash_fmt ".bin.tmp", hash_ref(packet.hash)); + snprintf( + filename_final, sizeof(filename_final), "packets/" hash_fmt ".bin", hash_ref(packet.hash)); - FILE* file = fopen(filename, "wb"); - if (!file) { - perror("failed to save packet"); + /* serialize packet into buffer */ + byte buffer[ PACKET_SIZE ]; + data_packet2s(packet, buffer); + + /* compress */ + uLongf comp_bound = compressBound(PACKET_SIZE); + byte comp_buf[ comp_bound ]; + + uLongf comp_len = comp_bound; + int zres = compress2(comp_buf, &comp_len, buffer, PACKET_SIZE, Z_BEST_COMPRESSION); + if (zres != Z_OK) { + log(_error, "save_packet: compress2 failed (%d)", zres); return; } - byte* buffer = malloc(PACKET_SIZE); - if (!buffer) { - fclose(file); + FILE* f = fopen(filename_tmp, "wb"); + if (!f) { + perror("save_packet: fopen tmp"); return; } - data_packet2s(packet, buffer); - size_t written = fwrite(buffer, 1, PACKET_SIZE, file); - if (written != PACKET_SIZE) { perror("failed to write full packet to disk"); } - free(buffer); - fclose(file); + if (fwrite(comp_buf, 1, comp_len, f) != comp_len) { + perror("save_packet: write failed"); + fclose(f); + unlink(filename_tmp); + return; + } + + fflush(f); +#if defined(__unix__) || defined(__APPLE__) + int fd = fileno(f); + if (fd >= 0) fsync(fd); +#endif + fclose(f); + + if (rename(filename_tmp, filename_final) != 0) { + perror("save_packet: rename failed"); + unlink(filename_tmp); + } } void save_neighbors() { @@ -645,13 +694,13 @@ void load_neighbors() { } fclose(file); - log(_info, "loaded %li neighbors\n", count); + log(_info, "loaded %li neighbors", count); } void* fs_persistence(void* arg) { while (disk_persistence_thread_running) { sleep(2 * 60); // 2m - log(_info, "saving neighbors...\n"); + log(_info, "saving neighbors..."); save_neighbors(); } @@ -662,18 +711,29 @@ void* cleanup_packets(void* arg) { while (packet_cleanup_thread_running) { sleep(30 * 60); // 30m - log(_warn, "running cleanup\n"); + log(_warn, "running cleanup"); uint64_t current_time_ms = get_current_time_ms(); uint64_t retention_ms = (uint64_t) server_stats.retention_hours * 60 * 60 * 1000; // memory for (uint64_t i = 0; i < max_storage; i++) { pthread_mutex_lock(&packet_storage_mutex); - if (packet_storage[ i ].is_full - && current_time_ms - packet_storage[ i ].packet.contents.created_time_ms - > retention_ms) { + + if (!packet_storage[ i ].is_full) { + pthread_mutex_unlock(&packet_storage_mutex); + continue; + } + + bool result + = decide_packet_cleanup_func + ? decide_packet_cleanup_func(packet_storage[ i ].packet) // delegate to user + : ( // do it natively + current_time_ms - packet_storage[ i ].packet.contents.created_time_ms + > retention_ms); + + if (result) { log(_debug, - "cleaning up old packet hashed " hash_fmt "\n", + "cleaning up old packet hashed " hash_fmt, hash_ref(packet_storage[ i ].packet.hash)); char filename[ 128 ]; @@ -682,11 +742,12 @@ void* cleanup_packets(void* arg) { "packets/" hash_fmt ".bin", hash_ref(packet_storage[ i ].packet.hash)); - if (remove(filename) != 0) log(_error, "failed to delete packet %s\n", filename); + if (remove(filename) != 0) log(_error, "failed to delete packet %s", filename); packet_storage[ i ].is_full = false; packet_count--; } + pthread_mutex_unlock(&packet_storage_mutex); } @@ -701,10 +762,25 @@ void* cleanup_packets(void* arg) { if (entry->d_type == DT_REG) { char filepath[ 256 ]; snprintf(filepath, sizeof(filepath), "packets/%s", entry->d_name); + + FILE* fd = decide_packet_cleanup_func ? fopen(filepath, "rb") : NULL; + struct data_packet* new = decide_packet_cleanup_func ? load_packet(fd) : NULL; + struct stat st; - if (stat(filepath, &st) == 0 - && current_time_ms - (uint64_t) st.st_mtime * 1000 > retention_ms) { - if (remove(filepath) != 0) log(_error, "failed to delete %s\n", filepath); + bool result = decide_packet_cleanup_func + ? decide_packet_cleanup_func(*new) // delegate to user + : ( // do it natively + stat(filepath, &st) == 0 + && current_time_ms - (uint64_t) st.st_mtime * 1000 + > retention_ms); + + if (decide_packet_cleanup_func) { + fclose(fd); + free(new); + } + + if (result) { + if (remove(filepath) != 0) log(_error, "failed to delete %s", filepath); } } } @@ -767,7 +843,7 @@ void* check_neighbors(void* arg) { if (result != 0 || response_data[ 0 ] != audit_response) { empty_neighbor_slots[ i ] = true; neighbor_count--; - log(_warn, "removed dead neighbor\n"); + log(_warn, "removed dead neighbor"); } if (response_data) { free(response_data); } @@ -780,7 +856,41 @@ void* check_neighbors(void* arg) { return NULL; } -int main() { +int main(int argc, char** argv) { + parse_arguments(argc, argv); + + char* __log_level = get_config("log", false); + if (__log_level) { + if (isdigit(*__log_level)) { + int _log_level = atoi(__log_level); + if (_log_level < 1 || _log_level > 4) { + fprintf( + stderr, + "invalid log level %d (1 = debug, 2 = info, 3 = warn, 4 = error)\n", + _log_level); + exit(1); + } + log_level = _log_level; + } else { + if (strcmp(__log_level, "debug") == 0) log_level = 1; + else if (strcmp(__log_level, "info") == 0) + log_level = 2; + else if (strcmp(__log_level, "warn") == 0) + log_level = 3; + else if (strcmp(__log_level, "error") == 0) + log_level = 4; + else { + fprintf( + stderr, + "invalid log level %s (1 = debug, 2 = info, 3 = warn, 4 = error)\n", + __log_level); + exit(1); + } + } + + free(__log_level); + } + fprintf( stderr, "-- moonpaste server v%i.%i --\n" @@ -820,6 +930,13 @@ int main() { firehose_init(); + // load the plugins! + char* plugin_path = get_config("plugin", false); + if (plugin_path) { + load_plugins(plugin_path); + free(plugin_path); + } + omen(default_port, paste_server); packet_cleanup_thread_running = false; @@ -30,7 +30,7 @@ static const uint32_t K[ 64 ] = { 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 }; -static void compress(uint32_t state[ 8 ], const byte block[ 64 ]) { +static void sha256_compress(uint32_t state[ 8 ], const byte block[ 64 ]) { uint32_t w[ 64 ]; int i; for (i = 0; i < 16; i++) { @@ -72,7 +72,7 @@ struct sha256 { uint32_t state[ 8 ] = { 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 }; size_t off = 0; - for (; off + 64 <= in_len; off += 64) { compress(state, in + off); } + for (; off + 64 <= in_len; off += 64) { sha256_compress(state, in + off); } byte pad[ 128 ]; memset(pad, 0, sizeof(pad)); size_t rem = in_len - off; @@ -91,8 +91,8 @@ struct sha256 { pad[ pad_len - 6 ] = (bit_len >> 40) & 0xff; pad[ pad_len - 7 ] = (bit_len >> 48) & 0xff; pad[ pad_len - 8 ] = (bit_len >> 56) & 0xff; - compress(state, pad); - if (use_two_blocks) { compress(state, pad + 64); } + sha256_compress(state, pad); + if (use_two_blocks) { sha256_compress(state, pad + 64); } for (int i = 0; i < 8; i++) { out.hash[ 4 * i ] = (state[ i ] >> 24) & 0xff; out.hash[ 4 * i + 1 ] = (state[ i ] >> 16) & 0xff; @@ -101,4 +101,4 @@ struct sha256 { } return out; -}
\ No newline at end of file +} |
