From f0ec64b629396c5c8fbc6ec643554c793d544795 Mon Sep 17 00:00:00 2001 From: Lorenz Stechauner Date: Tue, 29 Dec 2020 16:26:53 +0100 Subject: [PATCH] GeoIP Info implemented --- Makefile | 4 +-- src/client.c | 52 +++++++++++++++++++++++++++++++++--- src/fastcgi.c | 3 +++ src/necronda-server.c | 53 +++++++++++++++++++++++++++++-------- src/necronda-server.h | 7 ++++- src/utils.c | 61 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 163 insertions(+), 17 deletions(-) diff --git a/Makefile b/Makefile index 61f809b..00d4005 100644 --- a/Makefile +++ b/Makefile @@ -7,11 +7,11 @@ packages: compile: @mkdir -p bin - gcc src/necronda-server.c -o bin/necronda-server -std=c11 -lssl -lcrypto -lmagic -lz + gcc src/necronda-server.c -o bin/necronda-server -std=c11 -lssl -lcrypto -lmagic -lz -lmaxminddb compile-debian: @mkdir -p bin - gcc src/necronda-server.c -o bin/necronda-server -std=c11 -lssl -lcrypto -lmagic -lz \ + gcc src/necronda-server.c -o bin/necronda-server -std=c11 -lssl -lcrypto -lmagic -lz -lmaxminddb \ -D MAGIC_FILE="\"/usr/share/file/magic.mgc\"" \ -D PHP_FPM_SOCKET="\"/var/run/php/php7.3-fpm.sock\"" diff --git a/src/client.c b/src/client.c index 8cda78a..0abe399 100644 --- a/src/client.c +++ b/src/client.c @@ -15,7 +15,7 @@ int server_keep_alive = 1; char *client_addr_str, *client_addr_str_ptr, *server_addr_str, *server_addr_str_ptr, *log_client_prefix, *log_conn_prefix, *log_req_prefix, - *client_host_str; + *client_host_str, *client_geoip; struct timeval client_timeout = {.tv_sec = CLIENT_TIMEOUT, .tv_usec = 0}; @@ -460,10 +460,56 @@ int client_connection_handler(sock *client, unsigned long client_num) { client_host_str = NULL; } - // TODO get geoip data for ip address + client_geoip = malloc(GEOIP_MAX_SIZE); + long str_off = 0; + for (int i = 0; i < MAX_MMDB && mmdbs[i].filename != NULL; i++) { + int gai_error, mmdb_res; + MMDB_lookup_result_s result = MMDB_lookup_string(&mmdbs[i], "62.47.28.246", &gai_error, &mmdb_res); + if (mmdb_res != MMDB_SUCCESS) { + print(ERR_STR "Unable to lookup geoip info: %s" CLR_STR "\n", MMDB_strerror(mmdb_res)); + continue; + } else if (gai_error != 0) { + print(ERR_STR "Unable to lookup geoip info" CLR_STR "\n"); + continue; + } else if (!result.found_entry) { + continue; + } + + MMDB_entry_data_list_s *list; + mmdb_res = MMDB_get_entry_data_list(&result.entry, &list); + if (mmdb_res != MMDB_SUCCESS) { + print(ERR_STR "Unable to lookup geoip info: %s" CLR_STR "\n", MMDB_strerror(mmdb_res)); + continue; + } + + long prev = str_off; + if (str_off != 0) { + str_off--; + } + mmdb_json(list, client_geoip, &str_off, GEOIP_MAX_SIZE); + if (prev != 0) { + client_geoip[prev - 1] = ','; + } + + MMDB_free_entry_data_list(list); + } + + char client_cc[3]; + client_cc[0] = 0; + if (str_off == 0) { + free(client_geoip); + client_geoip = NULL; + } else { + char *pos = strstr(client_geoip, "\"iso_code\":\""); + if (pos != NULL) { + pos += 12; + strncpy(client_cc, pos, 2); + } + } print("Connection accepted from %s %s%s%s[%s]", client_addr_str, client_host_str != NULL ? "(" : "", - client_host_str != NULL ? client_host_str : "", client_host_str != NULL ? ") " : "", "N/A"); + client_host_str != NULL ? client_host_str : "", client_host_str != NULL ? ") " : "", + client_cc[0] != 0 ? client_cc : "N/A"); client_timeout.tv_sec = CLIENT_TIMEOUT; client_timeout.tv_usec = 0; diff --git a/src/fastcgi.c b/src/fastcgi.c index 61ac8e1..702a59c 100644 --- a/src/fastcgi.c +++ b/src/fastcgi.c @@ -142,6 +142,9 @@ int fastcgi_init(fastcgi_conn *conn, unsigned int client_num, unsigned int req_n param_ptr = fastcgi_add_param(param_ptr, "CONTENT_LENGTH", content_length != NULL ? content_length : ""); char *content_type = http_get_header_field(&req->hdr, "Content-Type"); param_ptr = fastcgi_add_param(param_ptr, "CONTENT_TYPE", content_type != NULL ? content_type : ""); + if (client_geoip != NULL) { + param_ptr = fastcgi_add_param(param_ptr, "REMOTE_INFO", client_geoip); + } for (int i = 0; i < req->hdr.field_num; i++) { char *ptr = buf0; diff --git a/src/necronda-server.c b/src/necronda-server.c index 7157df3..ad3c02d 100644 --- a/src/necronda-server.c +++ b/src/necronda-server.c @@ -172,6 +172,10 @@ int main(int argc, const char *argv[]) { struct sockaddr_in6 client_addr; unsigned int client_addr_len = sizeof(client_addr); + memset(sockets, 0, sizeof(sockets)); + memset(children, 0, sizeof(children)); + memset(mmdbs, 0, sizeof(mmdbs)); + struct timeval timeout; const struct sockaddr_in6 addresses[2] = { @@ -189,12 +193,12 @@ int main(int argc, const char *argv[]) { const char *arg = argv[i]; unsigned long len = strlen(arg); if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) { - printf("Usage: necronda-server [-h] -w -c -p [-g ] [-d ]\n" + printf("Usage: necronda-server [-h] -w -c -p [-g ] [-d ]\n" "\n" "Options:\n" " -c, --cert path to the full chain certificate file\n" " -d, --dns ip address or hostname of a DNS server for dig\n" - " -g, --geoip path to a Maxmind GeoIP Database file\n" + " -g, --geoip path to a Maxmind GeoIP Database file\n" " -h, --help print this dialogue\n" " -p, --privkey path to the private key file\n" " -w, --webroot path to the web root directory\n"); @@ -219,10 +223,10 @@ int main(int argc, const char *argv[]) { key_file = argv[++i]; } else if (strcmp(arg, "-g") == 0 || strcmp(arg, "--geoip") == 0) { if (i == argc - 1) { - fprintf(stderr, ERR_STR "Unable to parse argument %s, usage: --geoip " CLR_STR "\n", arg); + fprintf(stderr, ERR_STR "Unable to parse argument %s, usage: --geoip " CLR_STR "\n", arg); return 1; } - geoip_file = argv[++i]; + geoip_dir = argv[++i]; } else if (strcmp(arg, "-d") == 0 || strcmp(arg, "--dns") == 0) { if (i == argc - 1) { fprintf(stderr, ERR_STR "Unable to parse argument %s, usage: --dns " CLR_STR "\n", arg); @@ -274,15 +278,35 @@ int main(int argc, const char *argv[]) { signal(SIGINT, terminate); signal(SIGTERM, terminate); - ret = cache_init(); - if (ret < 0) { - return 1; - } else if (ret != 0) { - return 0; + if (geoip_dir != NULL) { + DIR *geoip = opendir(geoip_dir); + if (geoip == NULL) { + fprintf(stderr, ERR_STR "Unable to open GeoIP dir: %s" CLR_STR "\n", strerror(errno)); + return 1; + } + struct dirent *dir; + int i = 0; + while ((dir = readdir(geoip)) != NULL) { + if (strcmp(dir->d_name + strlen(dir->d_name) - 5, ".mmdb") != 0) continue; + if (i >= MAX_MMDB) { + fprintf(stderr, ERR_STR "Too many .mmdb files" CLR_STR "\n"); + return 1; + } + sprintf(buf, "%s/%s", geoip_dir, dir->d_name); + ret = MMDB_open(buf, 0, &mmdbs[i]); + if (ret != MMDB_SUCCESS) { + fprintf(stderr, ERR_STR "Unable to open .mmdb file: %s" CLR_STR "\n", MMDB_strerror(ret)); + return 1; + } + i++; + } + if (i == 0) { + fprintf(stderr, ERR_STR "No .mmdb files found in %s" CLR_STR "\n", geoip_dir); + return 1; + } + closedir(geoip); } - // TODO init geoip database - openssl_init(); client.buf = NULL; @@ -322,6 +346,13 @@ int main(int argc, const char *argv[]) { } } + ret = cache_init(); + if (ret < 0) { + return 1; + } else if (ret != 0) { + return 0; + } + fprintf(stderr, "Ready to accept connections\n"); while (active) { diff --git a/src/necronda-server.h b/src/necronda-server.h index 26eeeca..daaad13 100644 --- a/src/necronda-server.h +++ b/src/necronda-server.h @@ -25,10 +25,13 @@ #include #include #include +#include +#include #define NUM_SOCKETS 2 #define MAX_CHILDREN 1024 +#define MAX_MMDB 3 #define LISTEN_BACKLOG 16 #define REQ_PER_CONNECTION 100 #define CLIENT_TIMEOUT 3600 @@ -37,6 +40,7 @@ #define CLIENT_MAX_HEADER_SIZE 8192 #define FILE_CACHE_SIZE 1024 #define SHM_KEY 255641 +#define GEOIP_MAX_SIZE 8192 #define ERR_STR "\x1B[1;31m" #define CLR_STR "\x1B[0m" @@ -67,8 +71,9 @@ int sockets[NUM_SOCKETS]; pid_t children[MAX_CHILDREN]; +MMDB_s mmdbs[MAX_MMDB]; -const char *cert_file, *key_file, *webroot_base, *geoip_file, *dns_server; +const char *cert_file, *key_file, *webroot_base, *geoip_dir, *dns_server; typedef struct { unsigned int enc:1; diff --git a/src/utils.c b/src/utils.c index 12386e9..2488b5b 100644 --- a/src/utils.c +++ b/src/utils.c @@ -94,3 +94,64 @@ int url_decode(const char *str, char *dec, ssize_t *size) { *size = ptr - dec; return 0; } + +MMDB_entry_data_list_s *mmdb_json(MMDB_entry_data_list_s *list, char *str, long *str_off, long str_len) { + switch (list->entry_data.type) { + case MMDB_DATA_TYPE_MAP: + *str_off += sprintf(str + *str_off, "{"); + break; + case MMDB_DATA_TYPE_ARRAY: + *str_off += sprintf(str + *str_off, "["); + break; + case MMDB_DATA_TYPE_UTF8_STRING: + *str_off += sprintf(str + *str_off, "\"%.*s\"", list->entry_data.data_size, list->entry_data.utf8_string); + break; + case MMDB_DATA_TYPE_UINT16: + *str_off += sprintf(str + *str_off, "%u", list->entry_data.uint16); + break; + case MMDB_DATA_TYPE_UINT32: + *str_off += sprintf(str + *str_off, "%u", list->entry_data.uint32); + break; + case MMDB_DATA_TYPE_UINT64: + *str_off += sprintf(str + *str_off, "%lu", list->entry_data.uint64); + break; + case MMDB_DATA_TYPE_UINT128: + *str_off += sprintf(str + *str_off, "%llu", list->entry_data.uint128); + break; + case MMDB_DATA_TYPE_INT32: + *str_off += sprintf(str + *str_off, "%i", list->entry_data.uint32); + break; + case MMDB_DATA_TYPE_BOOLEAN: + *str_off += sprintf(str + *str_off, "%s", list->entry_data.boolean ? "true" : "false"); + break; + case MMDB_DATA_TYPE_FLOAT: + *str_off += sprintf(str + *str_off, "%f", list->entry_data.float_value); + break; + case MMDB_DATA_TYPE_DOUBLE: + *str_off += sprintf(str + *str_off, "%f", list->entry_data.double_value); + break; + } + if (list->entry_data.type != MMDB_DATA_TYPE_MAP && list->entry_data.type != MMDB_DATA_TYPE_ARRAY) { + return list->next; + } + MMDB_entry_data_list_s *next = list->next; + int stat = 0; + for (int i = 0; i < list->entry_data.data_size; i++) { + next = mmdb_json(next, str, str_off, str_len); + if (list->entry_data.type == MMDB_DATA_TYPE_MAP) { + stat = !stat; + if (stat) { + i--; + *str_off += sprintf(str + *str_off, ":"); + continue; + } + } + if (i != list->entry_data.data_size - 1) *str_off += sprintf(str + *str_off, ","); + } + if (list->entry_data.type == MMDB_DATA_TYPE_MAP) { + *str_off += sprintf(str + *str_off, "}"); + } else { + *str_off += sprintf(str + *str_off, "]"); + } + return next; +}