telize

High performance JSON IP and GeoIP REST API (IP Geolocation)
Log | Files | Refs | README | LICENSE

utils.c (2810B)


      1 /*
      2  * Telize 3.1.0
      3  * Copyright (c) 2013-2021, Frederic Cambus
      4  * https://www.telize.com
      5  *
      6  * Created:      2013-08-15
      7  * Last Updated: 2021-04-04
      8  *
      9  * Telize is released under the BSD 2-Clause license.
     10  * See LICENSE file for details.
     11  *
     12  * SPDX-License-Identifier: BSD-2-Clause
     13  */
     14 
     15 #include "telize.h"
     16 
     17 MMDB_s telize_asn;
     18 MMDB_s telize_city;
     19 
     20 int
     21 telize_init(int state)
     22 {
     23 	if (state == KORE_MODULE_UNLOAD) {
     24 		MMDB_close(&telize_city);
     25 		MMDB_close(&telize_asn);
     26 		return (KORE_RESULT_OK);
     27 	}
     28 
     29 	if (MMDB_open(GEOIP2DIR GEOIP2DB_CITY,
     30 	    MMDB_MODE_MMAP, &telize_city) != MMDB_SUCCESS)
     31 		fatalx("can't open GeoLite2 City database: %s", errno_s);
     32 
     33 	if (MMDB_open(GEOIP2DIR GEOIP2DB_ASN,
     34 	    MMDB_MODE_MMAP, &telize_asn) != MMDB_SUCCESS)
     35 		fatalx("can't open GeoLite2 ASN database: %s", errno_s);
     36 
     37 	return (KORE_RESULT_OK);
     38 }
     39 
     40 void
     41 telize_getdata(struct kore_buf *json, MMDB_lookup_result_s *lookup,
     42     MMDB_entry_data_s *entry_data, char *field, int type, ...)
     43 {
     44 	va_list keys;
     45 	va_start(keys, type);
     46 
     47 	MMDB_vget_value(&lookup->entry, entry_data, keys);
     48 
     49 	if (entry_data->has_data) {
     50 		switch(type) {
     51 		case ENTRY_TYPE_UINT32:
     52 			kore_buf_appendf(json, ",\"%s\":%d",
     53 			    field, entry_data->uint32);
     54 			break;
     55 		case ENTRY_TYPE_STRING:
     56 			kore_buf_appendf(json, ",\"%s\":\"%.*s\"",
     57 			    field, entry_data->data_size,
     58 			    entry_data->utf8_string);
     59 			break;
     60 		case ENTRY_TYPE_DOUBLE:
     61 			kore_buf_appendf(json, ",\"%s\":%.4f",
     62 			    field, entry_data->double_value);
     63 			break;
     64 		case ENTRY_TYPE_BOOLEAN:
     65 			kore_buf_appendf(json, ",\"%s\":%s",
     66 			    field, entry_data->boolean ? "true" : "false");
     67 			break;
     68 		}
     69 	}
     70 
     71 	va_end(keys);
     72 }
     73 
     74 int
     75 telize_request_ip(struct http_request *req, char *buf, size_t len)
     76 {
     77 	char		*ptr;
     78 	void		*addr;
     79 	size_t		hdr_len;
     80 	const char	*hdr_ip;
     81 
     82 	switch (req->owner->family) {
     83 	case AF_INET:
     84 		addr = &req->owner->addr.ipv4.sin_addr;
     85 		break;
     86 	case AF_INET6:
     87 		addr = &req->owner->addr.ipv6.sin6_addr;
     88 		break;
     89 	default:
     90 		kore_log(LOG_ERR, "unsupported family %d", req->owner->family);
     91 		return (KORE_RESULT_ERROR);
     92 	}
     93 
     94 	if (inet_ntop(req->owner->family, addr, buf, len) == NULL) {
     95 		kore_log(LOG_ERR, "inet_ntop failed (%s)", errno_s);
     96 		return (KORE_RESULT_ERROR);
     97 	}
     98 
     99 	if (!http_request_header(req, "x-forwarded-for", &hdr_ip))
    100 		return (KORE_RESULT_OK);
    101 
    102 	if ((ptr = strchr(hdr_ip, ',')) != NULL) {
    103 		hdr_len = ptr - hdr_ip;
    104 	} else {
    105 		hdr_len = strlen(hdr_ip);
    106 	}
    107 
    108 	if (hdr_len > len - 1) {
    109 		kore_log(LOG_ERR, "IP in X-Forwarded-For too large");
    110 		return (KORE_RESULT_ERROR);
    111 	}
    112 
    113 	memcpy(buf, hdr_ip, hdr_len);
    114 	buf[hdr_len] = '\0';
    115 
    116 	if (inet_pton(AF_INET, buf, addr) == -1) {
    117 		if (inet_pton(AF_INET6, buf, &req->owner->addr) == -1) {
    118 			kore_log(LOG_ERR, "Malformed IP in X-Forwarded-For");
    119 			return (KORE_RESULT_ERROR);
    120 		}
    121 	}
    122 
    123 	return (KORE_RESULT_OK);
    124 }