140 lines
2.7 KiB
C
140 lines
2.7 KiB
C
#include <stdbool.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#include <netdb.h>
|
|
|
|
#include <glib.h>
|
|
#include <sodium.h>
|
|
|
|
#include "floof_int.h"
|
|
#include "floof_db.h"
|
|
|
|
typedef struct {
|
|
floof_db_t *db;
|
|
GThreadPool *thpool;
|
|
bool (*filter_packets)(unsigned char *data, size_t datalen);
|
|
} floof_node_t;
|
|
|
|
typedef struct {
|
|
floof_node_t * node;
|
|
int sock;
|
|
} floof_conn_t;
|
|
|
|
typedef struct {
|
|
unsigned char pubkey[crypto_sign_PUBLICKEYBYTES];
|
|
unsigned char sig[crypto_sign_BYTES];
|
|
unsigned char *data;
|
|
size_t datalen;
|
|
} floof_worker_task_t;
|
|
|
|
/** internal **/
|
|
|
|
static void floof_free_task(void * data) {
|
|
floof_worker_task_t * task = (floof_worker_task_t*) data;
|
|
|
|
free(task->data);
|
|
free(task);
|
|
}
|
|
|
|
static void floof_worker(void * data, void * user_data) {
|
|
floof_worker_task_t * task = (floof_worker_task_t*) data;
|
|
floof_node_t * node = (floof_node_t*) user_data;
|
|
|
|
if(0 != crypto_sign_verify_detached(task->sig, task->data, task->datalen, task->pubkey)) {
|
|
// signature check failed, drop packet
|
|
goto drop;
|
|
}
|
|
|
|
if(!node->filter_packets(task->data, task->datalen)) {
|
|
// drop packet
|
|
goto drop;
|
|
}
|
|
|
|
// forward packet
|
|
floof_db_insert_packet(node->db, task);
|
|
goto cleanup;
|
|
|
|
drop:
|
|
|
|
cleanup:
|
|
floof_free_task(data);
|
|
}
|
|
|
|
/** external **/
|
|
|
|
floof_node_t * floof_new_node(const char * spooldir) {
|
|
floof_node_t * ret = calloc(sizeof(floof_node_t), 1);
|
|
if(!ret) return 0;
|
|
|
|
const unsigned int cpu_count = floof_get_cpu_count();
|
|
ret->thpool = g_thread_pool_new(
|
|
floof_worker,
|
|
(void*) ret,
|
|
g_get_num_processors(),
|
|
FALSE,
|
|
0);
|
|
|
|
if(floof_db_open(&ret->db, spooldir) == -1)
|
|
goto error;
|
|
|
|
return ret;
|
|
|
|
error:
|
|
floof_destroy_node(ret);
|
|
return 0;
|
|
}
|
|
|
|
floof_conn_t * floof_socket(floof_node_t * node, int domain) {
|
|
floof_conn_t * ret = calloc(sizeof(floof_conn_t), 1);
|
|
if(!ret) return 0;
|
|
|
|
ret->node = node;
|
|
|
|
if(-1 == (ret->sock = socket(domain, SOCK_SEQPACKET, IPPROTO_TCP))) {
|
|
free(ret);
|
|
return 0;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int floof_bind_listen(floof_conn_t * conn, struct sockaddr *addr, socklen_t addrlen) {
|
|
if(bind(conn->sock, addr, addrlen) < 0)
|
|
return -1;
|
|
|
|
if(listen(conn->sock, 10) < 0)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int floof_connect(floof_node_t * conn, struct sockaddr *remotename, socklen_t addrlen) {
|
|
if(connect(conn->sock, remotename, addrlen) < 0)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void floof_close(floof_conn_t * conn) {
|
|
if(!conn) return;
|
|
if(conn->sock != -1)
|
|
close(conn->sock);
|
|
free(conn);
|
|
}
|
|
|
|
void floof_destroy_node(floof_node_t * node) {
|
|
if(!node) return;
|
|
|
|
if(node->thpool)
|
|
g_thread_pool_free(node->thpool, TRUE, TRUE);
|
|
|
|
floof_db_close(&node->db);
|
|
|
|
free(node);
|
|
}
|