summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar moon <moon@coffin.ir> 2025-09-13 00:51:54 +0330
committerGravatar moon <moon@coffin.ir> 2025-09-13 00:51:54 +0330
commit59a134f2d68a6b27e8bd4e2c31794bd8f2dad6e8 (patch)
tree07a85376425a0393ce2557e87adb6a7dd0aa4a02
parentbug fixes (diff)
new things
-rw-r--r--client.c20
-rw-r--r--common.c26
-rw-r--r--firehose.c2
-rw-r--r--omen.c226
-rw-r--r--packet_storage.c2
-rw-r--r--ratelimit.c108
-rw-r--r--security.c4
-rw-r--r--server.c79
8 files changed, 370 insertions, 97 deletions
diff --git a/client.c b/client.c
index f8f3c93..5270204 100644
--- a/client.c
+++ b/client.c
@@ -118,26 +118,6 @@ struct data_packet run_pow(struct data_packet packet, byte leading_zeros) {
return packet;
}
-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;
- size_t resp_len = 0;
- bool success;
-
- int ret = study(ip, port, data, sizeof(data), &response, &resp_len);
- if (ret != 0) {
- printf("error: study returned %i\n", ret);
- if (response) free(response);
- return (struct relay_info) { 0 };
- }
-
- struct relay_info info = s2relay_info(resp_len - 1, response + 1, &success);
- if (!success) { printf("error: failed to deserialize relay_info\n"); }
-
- free(response);
- return info;
-}
-
struct relay_neighbor* get_server_neighbors(const char* ip, int port, byte count) {
byte data[ 8 ] = { get_neighbors, count, 0, 0, 0, 0, 0, 0 };
byte* response = NULL;
diff --git a/common.c b/common.c
index 183cfb2..27f2734 100644
--- a/common.c
+++ b/common.c
@@ -6,6 +6,8 @@
#include <stdio.h>
#include <string.h>
#include <time.h>
+//
+#include "omen.c"
#define likely(A) __builtin_expect(A, 1)
#define unlikely(A) __builtin_expect(A, 0)
@@ -421,4 +423,26 @@ static inline uint16_t read_u16_le(const byte *b) {
static inline void write_u16_le(byte *b, uint16_t v) {
b[ 0 ] = v & 0xFF;
b[ 1 ] = (v >> 8) & 0xFF;
-} \ No newline at end of file
+}
+
+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;
+ size_t resp_len = 0;
+ bool success;
+
+ int ret = study(ip, port, data, sizeof(data), &response, &resp_len);
+ if (ret != 0) {
+ printf("error: study returned %i\n", ret);
+ if (response) free(response);
+ return (struct relay_info) { 0 };
+ }
+
+ struct relay_info info = s2relay_info(resp_len - 1, response + 1, &success);
+ if (!success) { printf("error: failed to deserialize relay_info\n"); }
+
+ free(response);
+ return info;
+}
+
+pthread_mutex_t packet_storage_mutex = PTHREAD_MUTEX_INITIALIZER; \ No newline at end of file
diff --git a/firehose.c b/firehose.c
index 67d62c8..b2931a7 100644
--- a/firehose.c
+++ b/firehose.c
@@ -62,8 +62,6 @@ void firehose_push(hash new_hash, uint64_t storage_index) {
uint16_t firehose_get_count() { return firehose_buffer.count; }
uint64_t firehose_get_total_packets() { return firehose_buffer.total_packets; }
-pthread_mutex_t packet_storage_mutex;
-
uint16_t firehose_get_packets(uint64_t offset, uint16_t count, water_splash* output_entries) {
pthread_mutex_lock(&firehose_buffer.mutex);
diff --git a/omen.c b/omen.c
index 2f60a8c..98da86a 100644
--- a/omen.c
+++ b/omen.c
@@ -14,29 +14,30 @@
#include <unistd.h>
//
#include "common.c"
+#include "ratelimit.c"
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 Task {
- int fd;
- struct Task *next;
+struct server_task {
+ int fd;
+ struct server_task *next;
};
#define MAX_BUFFER 1 << 18
-#define MAX_BODY 1 << 17
+#define MAX_BODY 1 << 22
#define MAX_CONNECTIONS 2048
// vars
-int worker_count = 16;
+int worker_count = 64;
-pthread_mutex_t queue_mutex = PTHREAD_MUTEX_INITIALIZER;
-pthread_cond_t queue_cond = PTHREAD_COND_INITIALIZER;
-struct Task *head = NULL;
-struct 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;
+struct server_task *head = NULL;
+struct server_task *tail = NULL;
+size_t queue_size = 0;
+tome_ptr global_handler = NULL;
// utils
@@ -56,11 +57,15 @@ static ssize_t write_all(int fd, const void *buf, size_t len) {
}
static int read_until_headers(int fd, char **out_buf, size_t *out_len) {
+ size_t total_tries = 0;
+
size_t cap = 4096;
size_t len = 0;
char *buf = malloc(cap);
if (!buf) return -1;
while (1) {
+ if (total_tries++ > 128) break;
+
if (cap - len < 1024) {
size_t ncap = cap * 2;
char *n = realloc(buf, ncap);
@@ -81,7 +86,18 @@ static int read_until_headers(int fd, char **out_buf, size_t *out_len) {
break;
}
len += (size_t) r;
- if (len >= 4 && memmem(buf, len, "\r\n\r\n", 4) != NULL) break;
+ if (len >= 4 && memmem(buf, len, "\r\n\r\n", 4) != NULL) {
+ if (len >= 19 && memmem(buf, len, "Transfer-Encoding: chunked", 19) != NULL) {
+ const char *err = "HTTP/1.1 501 Not Implemented\r\n"
+ "Content-Length: 31\r\n"
+ "Connection: close\r\n\r\n"
+ "chunked encoding not supported";
+ write_all(fd, err, strlen(err));
+ free(buf);
+ return -1;
+ }
+ break;
+ }
if (len > MAX_BUFFER) break;
}
*out_buf = buf;
@@ -153,14 +169,14 @@ 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_in client_addr;
- socklen_t client_addr_len = sizeof(client_addr);
+ int client_fd = -1;
+ struct sockaddr_storage client_addr;
+ socklen_t client_addr_len = sizeof(client_addr);
pthread_mutex_lock(&queue_mutex);
while (head == NULL) { pthread_cond_wait(&queue_cond, &queue_mutex); }
- struct Task *task = head;
- head = head->next;
+ struct server_task *task = head;
+ head = head->next;
if (head == NULL) tail = NULL;
queue_size--;
client_fd = task->fd;
@@ -172,9 +188,36 @@ void *omen_bound(void *arg) {
free(task);
pthread_mutex_unlock(&queue_mutex);
- char client_ip[ INET_ADDRSTRLEN ] = { 0 };
- if (client_addr.sin_family == AF_INET) {
- inet_ntop(AF_INET, &client_addr.sin_addr, client_ip, INET_ADDRSTRLEN);
+ 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 };
@@ -264,19 +307,39 @@ int omen(int port, tome_ptr handler) {
global_handler = handler;
signal(SIGPIPE, SIG_IGN);
- int server_fd = socket(AF_INET, SOCK_STREAM, 0);
- if (server_fd < 0) return -1;
+ int server_fd = socket(AF_INET6, SOCK_STREAM, 0);
+ if (server_fd < 0) {
+ perror("failed to create IPv6 socket");
+ return -1;
+ }
+
+ int opt = 0;
+ if (setsockopt(server_fd, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt)) < 0) {
+ perror("failed to disable IPV6_V6ONLY");
+ close(server_fd);
+ return -1;
+ }
+
+ opt = 1;
+ if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
+ perror("failed to set SO_REUSEADDR");
+ close(server_fd);
+ return -1;
+ }
- int opt = 1;
- setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
+ struct sockaddr_in6 addr = { 0 };
+ addr.sin6_family = AF_INET6;
+ addr.sin6_addr = in6addr_any;
+ addr.sin6_port = htons(port);
- struct sockaddr_in addr = { 0 };
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = INADDR_ANY;
- addr.sin_port = htons(port);
+ if (bind(server_fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ perror("bind failed");
+ close(server_fd);
+ return -1;
+ }
- if (bind(server_fd, (struct sockaddr *) &addr, sizeof(addr)) < 0
- || listen(server_fd, MAX_CONNECTIONS) < 0) {
+ if (listen(server_fd, MAX_CONNECTIONS) < 0) {
+ perror("Listen failed");
close(server_fd);
return -1;
}
@@ -290,33 +353,37 @@ int omen(int port, tome_ptr handler) {
for (int i = 0; i < worker_count; i++) {
if (pthread_create(&threads[ i ], NULL, omen_bound, NULL) != 0) {
perror("pthread_create failed");
- } else {
- pthread_detach(threads[ i ]);
+ free(threads);
+ close(server_fd);
+ return -1;
}
+ pthread_detach(threads[ i ]);
}
while (1) {
- struct sockaddr_in client_addr;
- socklen_t len = sizeof(client_addr);
- int client_fd = accept(server_fd, (struct sockaddr *) &client_addr, &len);
- if (client_fd < 0) continue;
+ struct sockaddr_storage client_addr;
+ 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"); }
+ continue;
+ }
+
+ printf("request\n");
pthread_mutex_lock(&queue_mutex);
if (queue_size >= (size_t) MAX_CONNECTIONS) {
- // note: The server converts into a teapot if the number of concurrent connections
- // reaches the max amount. this can be mitigated by disconnecting some clients,
- // which will turn the teapot back to an actual server.
char err_resp[] = "HTTP/1.1 418 I'm a teapot\r\n"
"Content-Length: 24\r\n"
"Connection: close\r\n\r\n"
"Max connections reached";
- write_all(client_fd, err_resp, 92);
+ write_all(client_fd, err_resp, strlen(err_resp));
close(client_fd);
pthread_mutex_unlock(&queue_mutex);
continue;
}
- struct Task *new_task = malloc(sizeof(struct Task));
+ struct server_task *new_task = malloc(sizeof(struct server_task));
if (!new_task) {
close(client_fd);
pthread_mutex_unlock(&queue_mutex);
@@ -333,6 +400,7 @@ int omen(int port, tome_ptr handler) {
pthread_mutex_unlock(&queue_mutex);
}
+ free(threads);
close(server_fd);
return 0;
}
@@ -346,41 +414,82 @@ int study(
size_t data_len,
byte **response,
size_t *resp_len) {
- int sock = socket(AF_INET, SOCK_STREAM, 0);
- if (sock < 0) return -1;
+ 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);
- struct sockaddr_in addr = { 0 };
- addr.sin_family = AF_INET;
- if (inet_pton(AF_INET, ip, &addr.sin_addr) != 1) {
+ int sock = socket(domain, SOCK_STREAM, 0);
+ if (sock < 0) {
+ printf("Socket creation failed: %s\n", strerror(errno));
+ return -1;
+ }
+
+ struct sockaddr_storage addr = { 0 };
+ addr.ss_family = domain;
+ void *addr_ptr = NULL;
+ size_t addr_len = 0;
+ if (domain == AF_INET) {
+ struct sockaddr_in *addr4 = (struct sockaddr_in *) &addr;
+ addr_ptr = &addr4->sin_addr;
+ addr_len = sizeof(struct sockaddr_in);
+ addr4->sin_port = htons(port);
+ } else {
+ struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) &addr;
+ addr_ptr = &addr6->sin6_addr;
+ addr_len = sizeof(struct sockaddr_in6);
+ addr6->sin6_port = htons(port);
+ }
+
+ if (inet_pton(domain, ip, addr_ptr) != 1) {
+ printf("Invalid %s address: %s\n", is_ipv6 ? "IPv6" : "IPv4", ip);
close(sock);
return -1;
}
- addr.sin_port = htons(port);
struct timeval timeout = { 5, 0 };
- setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
- setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
+ 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));
+ close(sock);
+ return -1;
+ }
- if (connect(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ printf("Connecting to %s:%d\n", ip, port);
+ if (connect(sock, (struct sockaddr *) &addr, addr_len) < 0) {
+ printf("Connect failed: %s\n", strerror(errno));
close(sock);
return -1;
}
if (data_len > MAX_BODY) data_len = MAX_BODY;
char req_hdr[ 256 ];
- int hdr_n = snprintf(
- req_hdr,
- sizeof(req_hdr),
- "POST /data HTTP/1.1\r\nHost: %s\r\nContent-Length: %zu\r\nConnection: close\r\n\r\n",
- ip,
- data_len);
+ // Use [ ] for IPv6 in Host header
+ int hdr_n;
+ if (is_ipv6) {
+ hdr_n = snprintf(
+ req_hdr,
+ sizeof(req_hdr),
+ "POST /data HTTP/1.1\r\nHost: [%s]\r\nContent-Length: %zu\r\nConnection: close\r\n\r\n",
+ ip,
+ data_len);
+ } else {
+ hdr_n = snprintf(
+ req_hdr,
+ sizeof(req_hdr),
+ "POST /data HTTP/1.1\r\nHost: %s\r\nContent-Length: %zu\r\nConnection: close\r\n\r\n",
+ ip,
+ data_len);
+ }
if (hdr_n < 0 || (size_t) hdr_n >= sizeof(req_hdr)) {
+ printf("Failed to format HTTP header\n");
close(sock);
return -1;
}
+ 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));
close(sock);
return -1;
}
@@ -388,12 +497,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));
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");
close(sock);
free(hdr_buf);
return -2;
@@ -410,6 +521,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");
free(hdr_buf);
close(sock);
return -1;
@@ -422,6 +534,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));
free(body);
free(hdr_buf);
close(sock);
@@ -463,5 +576,6 @@ int study(
*resp_len = 0;
free(body);
}
+ printf("Response received, length: %zu\n", body_len);
return 0;
} \ No newline at end of file
diff --git a/packet_storage.c b/packet_storage.c
index 8dd0b16..30e047f 100644
--- a/packet_storage.c
+++ b/packet_storage.c
@@ -29,8 +29,6 @@ struct data_packet_entry {
// TODO: yes, i know it's weird, but this has to be zero
#define minus_one (uint64_t) 0
-pthread_mutex_t packet_storage_mutex = PTHREAD_MUTEX_INITIALIZER;
-
struct data_packet* load_packet(const hash packet_hash) {
char filename[ 128 ];
sprintf(filename, "packets/" hash_fmt ".bin", hash_ref(packet_hash));
diff --git a/ratelimit.c b/ratelimit.c
new file mode 100644
index 0000000..38f756e
--- /dev/null
+++ b/ratelimit.c
@@ -0,0 +1,108 @@
+#include <pthread.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#define TABLE_SIZE 2048
+#define MAX_KEY_LEN 46
+#define STALE_SECONDS 30
+
+struct rl_entry {
+ char ip[ MAX_KEY_LEN ];
+ time_t last_request;
+ int count;
+ int in_use;
+};
+
+struct rl_table {
+ struct rl_entry entries[ TABLE_SIZE ];
+ pthread_mutex_t mutex;
+};
+
+struct rl_table* global_ratelimit = NULL;
+
+void ratelimit_init() {
+ if (global_ratelimit != NULL) return;
+
+ struct rl_table* table = malloc(sizeof(struct rl_table));
+ if (!table) {
+ perror("failed to alloc ratelimit table");
+ exit(1);
+ }
+ memset(table->entries, 0, sizeof(table->entries));
+ pthread_mutex_init(&table->mutex, NULL);
+
+ global_ratelimit = table;
+}
+
+static uint32_t hash_ip(const char* ip) {
+ uint32_t hash = 5381;
+ while (*ip) hash = (hash << 5) + hash + *ip++;
+ return hash % TABLE_SIZE;
+}
+
+int ratelimit_check(const char* ip) {
+ ratelimit_init();
+ pthread_mutex_lock(&global_ratelimit->mutex);
+
+ time_t now = time(NULL);
+ uint32_t index = hash_ip(ip);
+ uint32_t probes = 0;
+
+ while (probes < TABLE_SIZE) {
+ struct rl_entry* entry = &global_ratelimit->entries[ index ];
+
+ if (!entry->in_use) {
+ strncpy(entry->ip, ip, MAX_KEY_LEN - 1);
+ entry->ip[ MAX_KEY_LEN - 1 ] = '\0';
+ entry->last_request = now;
+ entry->count = 1;
+ entry->in_use = 1;
+ pthread_mutex_unlock(&global_ratelimit->mutex);
+ return 1;
+ }
+
+ if (strcmp(entry->ip, ip) == 0) {
+ if (now > entry->last_request) {
+ entry->last_request = now;
+ entry->count = 1;
+ } else if (entry->count >= 4) {
+ pthread_mutex_unlock(&global_ratelimit->mutex);
+ return 0;
+ } else {
+ entry->count++;
+ }
+ pthread_mutex_unlock(&global_ratelimit->mutex);
+ return 1;
+ }
+
+ if (entry->in_use && (now - entry->last_request) > STALE_SECONDS) {
+ entry->in_use = 0;
+ entry->count = 0;
+ entry->last_request = 0;
+ entry->ip[ 0 ] = '\0';
+ strncpy(entry->ip, ip, MAX_KEY_LEN - 1);
+ entry->ip[ MAX_KEY_LEN - 1 ] = '\0';
+ entry->last_request = now;
+ entry->count = 1;
+ entry->in_use = 1;
+ pthread_mutex_unlock(&global_ratelimit->mutex);
+ return 1;
+ }
+
+ index = (index + 1) % TABLE_SIZE;
+ probes++;
+ }
+
+ pthread_mutex_unlock(&global_ratelimit->mutex);
+ return 0;
+}
+
+void ratelimit_free(struct rl_table* table) {
+ if (table) {
+ pthread_mutex_destroy(&table->mutex);
+ free(table);
+ }
+} \ No newline at end of file
diff --git a/security.c b/security.c
index 79dd2c2..35f2a81 100644
--- a/security.c
+++ b/security.c
@@ -100,7 +100,7 @@ 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_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;
@@ -125,7 +125,7 @@ plain_payload decrypt(secure_payload input, keypair target_keys, public_key auth
input.encrypted_data,
sizeof(input.encrypted_data),
input.nonce,
- target_keys.encryption_pub,
+ author_public,
target_keys.encryption_priv)
!= 0) {
fprintf(stderr, "sodium decryption failed\n");
diff --git a/server.c b/server.c
index 9715467..a88b6f8 100644
--- a/server.c
+++ b/server.c
@@ -45,7 +45,7 @@ struct {
.minor_version = 1,
.motd = "A moonpaste server.", // minecraft much?
.retention_hours = 168, // 1 week
- .leading_zeros = 10, // the moon guarantee
+ .leading_zeros = 12, // the moon guarantee
.accepts_plain = true, // probably legal
};
@@ -145,9 +145,9 @@ void* propagate_packet(void* _packet) {
void save_packet(const struct data_packet packet);
-#define reply(__len, __stream) \
+#define reply(__len, ...) \
({ \
- *out = (byte*) __stream; \
+ *out = (byte*) __VA_ARGS__; \
*out_len = __len; \
})
@@ -363,6 +363,14 @@ void paste_server(
return;
}
+ if (current_time - packet.contents.created_time_ms
+ > server_stats.retention_hours * (60 * 60 * 1000)) {
+ log(_warn, "expired\n");
+ 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");
output_data[ 1 ] = false;
@@ -433,6 +441,14 @@ void paste_server(
bool success;
req = s2firehose_request(in_len - 1, in + 1, &success);
+ if (!success) {
+ byte* output_data = calloc(1 + 14, sizeof(byte));
+ output_data[ 0 ] = error;
+ memcpy(output_data + 1, "invalid request", 14);
+ reply(15, output_data);
+ return;
+ }
+
if (unlikely(req.count > 64)) req.count = 64; // clamp
log(_info,
@@ -442,14 +458,6 @@ void paste_server(
req.count,
req.offset);
- if (!success) {
- byte* output_data = calloc(1 + 14, sizeof(byte));
- output_data[ 0 ] = error;
- memcpy(output_data + 1, "invalid request", 14);
- reply(15, output_data);
- return;
- }
-
water_splash entries[ req.count ];
uint16_t copied_count = firehose_get_packets(req.offset, req.count, entries);
@@ -481,9 +489,48 @@ void paste_server(
}
case register_neighbor: {
- // TODO
- }
- // break;
+ bool success;
+ struct relay_neighbor neighbor = s2relay_neighbor(in_len - 1, in + 1, &success);
+
+ if (!success) {
+ byte* output_data = calloc(1 + 14, sizeof(byte));
+ output_data[ 0 ] = error;
+ memcpy(output_data + 1, "invalid request", 14);
+ reply(15, output_data);
+ return;
+ }
+
+ log(_info, "<%.*s> request type: neighbor registration\n", (int) ip_size, ip_addr);
+
+ char ip_string[ INET6_ADDRSTRLEN ];
+
+ if (neighbor.has_ipv4) {
+ sprintf(
+ ip_string,
+ "%d.%d.%d.%d",
+ neighbor.v4_addr[ 0 ],
+ neighbor.v4_addr[ 1 ],
+ neighbor.v4_addr[ 2 ],
+ neighbor.v4_addr[ 3 ]);
+ } else if (neighbor.has_ipv6) {
+ int offset = 0;
+ for (int j = 0; j < 8; j++) {
+ uint16_t word
+ = (neighbor.v6_addr[ j * 2 ] << 8) | neighbor.v6_addr[ j * 2 + 1 ];
+ offset += sprintf(ip_string + offset, "%x%s", word, (j < 7) ? ":" : "");
+ }
+ }
+
+ struct relay_info audit_result = run_server_audit(ip_string, default_port);
+ if (!audit_result.capabilities.can_store && audit_result.major_version == 0
+ && audit_result.minor_version == 0) {
+ // invalid
+ reply(2, (byte[ 2 ]) { error, 0 });
+ break;
+ }
+
+ reply(2, (byte[ 2 ]) { register_neighbor_result, add_neighbor(neighbor) });
+ } break;
default: {
log(_info, "<%.*s> request type: invalid method\n", (int) ip_size, ip_addr);
@@ -643,6 +690,10 @@ void* cleanup_packets(void* arg) {
pthread_mutex_unlock(&packet_storage_mutex);
}
+ // external cleanup
+ system("find packets/ -mtime +7 -delete");
+
+ // disk cleanup, tho not sure this is needed
DIR* dir = opendir("packets");
if (dir) {
struct dirent* entry;