GeoIP Info implemented

This commit is contained in:
2020-12-29 16:26:53 +01:00
parent 0db781e823
commit f0ec64b629
6 changed files with 163 additions and 17 deletions

View File

@ -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\""

View File

@ -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;

View File

@ -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;

View File

@ -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 <PATH> -c <CERT-FILE> -p <KEY-FILE> [-g <DB-FILE>] [-d <DNS-SERVER>]\n"
printf("Usage: necronda-server [-h] -w <PATH> -c <CERT-FILE> -p <KEY-FILE> [-g <DB-DIR>] [-d <DNS-SERVER>]\n"
"\n"
"Options:\n"
" -c, --cert <CERT-FILE> path to the full chain certificate file\n"
" -d, --dns <DNS-SERVER> ip address or hostname of a DNS server for dig\n"
" -g, --geoip <DB-FILE> path to a Maxmind GeoIP Database file\n"
" -g, --geoip <DB-DIR> path to a Maxmind GeoIP Database file\n"
" -h, --help print this dialogue\n"
" -p, --privkey <KEY-FILE> path to the private key file\n"
" -w, --webroot <PATH> 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 <DB-FILE>" CLR_STR "\n", arg);
fprintf(stderr, ERR_STR "Unable to parse argument %s, usage: --geoip <DB-DIR>" 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 <DNS-SERVER>" 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) {

View File

@ -25,10 +25,13 @@
#include <openssl/conf.h>
#include <openssl/engine.h>
#include <openssl/dh.h>
#include <maxminddb.h>
#include <dirent.h>
#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;

View File

@ -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;
}