void check_error(int gai_error, int mmdb_error)
{
  if (gai_error) {
    caml_failwith((const char *)MMDB_strerror(gai_error));
  }
  if (mmdb_error) {
    caml_failwith((const char *)MMDB_strerror(mmdb_error));
  }
}
Example #2
0
vmod_geoip2__init(VRT_CTX, struct vmod_geoip2_geoip2 **vpp,
    const char *vcl_name, VCL_STRING filename)
{
	struct vmod_geoip2_geoip2 *vp;
	MMDB_s mmdb;
	int error;

	(void)vcl_name;

	CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
	AN(vpp);
	AZ(*vpp);

	VSL(SLT_Debug, 0, "geoip2.geoip2: Using maxminddb %s",
	    MMDB_lib_version());

	error = MMDB_open(filename, MMDB_MODE_MMAP, &mmdb);
	if (error != MMDB_SUCCESS) {
		VSL(SLT_Error, 0, "geoip2.geoip2: %s",
		    MMDB_strerror(error));
		return;
	}

	ALLOC_OBJ(vp, VMOD_GEOIP2_MAGIC);
	AN(vp);
	*vpp = vp;
	vp->mmdb = mmdb;
}
MMDB_entry_data_s data_ok(MMDB_lookup_result_s *result, uint32_t expect_type,
                          const char *description, ...)
{
    va_list keys;
    va_start(keys, description);

    MMDB_entry_data_s data;
    int status = MMDB_vget_value(&result->entry, &data, keys);

    va_end(keys);

    if (cmp_ok(status, "==", MMDB_SUCCESS,
               "no error from call to MMDB_vget_value - %s", description)) {

        if (!ok(data.type == expect_type, "got the expected data type - %s",
                description)) {

            diag("  data type value is %i but expected %i", data.type,
                 expect_type);
        }
    } else {
        diag("  error from MMDB_vget_value - %s", MMDB_strerror(status));
    }

    return data;
}
MMDB_s *open_ok(const char *db_file, int mode, const char *mode_desc)
{
    if (0 != access(db_file, R_OK)) {
        BAIL_OUT(
            "could not read the specified file - %s\nIf you are in a git checkout try running 'git submodule update --init'",
            db_file);
    }

    MMDB_s *mmdb = (MMDB_s *)calloc(1, sizeof(MMDB_s));

    if (NULL == mmdb) {
        BAIL_OUT("could not allocate memory for our MMDB_s struct");
    }

    int status = MMDB_open(db_file, mode, mmdb);

    int is_ok = ok(MMDB_SUCCESS == status, "open %s status is success - %s",
                   db_file, mode_desc);

    if (!is_ok) {
        diag("open status code = %d (%s)", status, MMDB_strerror(status));
        free(mmdb);
        return NULL;
    }

    is_ok = ok(NULL != mmdb, "returned mmdb struct is not null for %s - %s",
               db_file, mode_desc);

    if (!is_ok) {
        free(mmdb);
        return NULL;
    }

    return mmdb;
}
Example #5
0
lookup_res_t geoip2_lookup_ip(char *ip, int *status)
{
	int gai_error, mmdb_error;

	MMDB_lookup_result_s result = MMDB_lookup_string(&mmdb, ip, &gai_error,
		&mmdb_error);

	if (gai_error) {
		LM_ERR("getaddrinfo() error\n");
		goto error;
	}
	if (mmdb_error != MMDB_SUCCESS) {
		LM_ERR("libmaxminddb error: %s\n", MMDB_strerror(mmdb_error));
		goto error;
	}

	if (!result.found_entry) {
		LM_DBG("IP: %s not found\n", ip);
		goto error;
	}

	*status = 0;
	return result;

error:
	*status = -1;
	return result;
}
MMDB_lookup_result_s lookup_sockaddr_ok(MMDB_s *mmdb, const char *ip,
                                        const char *file, const char *mode_desc)
{
    int ai_flags = AI_NUMERICHOST;
    struct addrinfo hints = {
        .ai_socktype = SOCK_STREAM
    };
    struct addrinfo *addresses = NULL;

    if (ip[0] == ':') {
        hints.ai_flags = ai_flags;
#if defined AI_V4MAPPED && !defined __FreeBSD__
        hints.ai_flags |= AI_V4MAPPED;
#endif
        hints.ai_family = AF_INET6;
    } else {
        hints.ai_flags = ai_flags;
        hints.ai_family = AF_INET;
    }

    int gai_error = getaddrinfo(ip, NULL, &hints, &addresses);

    int mmdb_error = 0;
    MMDB_lookup_result_s result = { .found_entry = false };
    if (gai_error == 0) {
        result = MMDB_lookup_sockaddr(mmdb, addresses->ai_addr, &mmdb_error);
    }
    if (NULL != addresses) {
        freeaddrinfo(addresses);
    }

    test_lookup_errors(gai_error, mmdb_error, "MMDB_lookup_sockaddr", ip, file,
                       mode_desc);

    return result;
}

void test_lookup_errors(int gai_error, int mmdb_error,
                        const char *function, const char *ip,
                        const char *file, const char *mode_desc)
{

    int is_ok = ok(0 == gai_error,
                   "no getaddrinfo error in call to %s for %s - %s - %s",
                   function, ip, file, mode_desc);

    if (!is_ok) {
        diag("error from call to getaddrinfo for %s - %s",
             ip, gai_strerror(gai_error));
    }

    is_ok = ok(0 == mmdb_error,
               "no MMDB error in call to %s for %s - %s - %s",
               function, ip, file, mode_desc);

    if (!is_ok) {
        diag("MMDB error - %s", MMDB_strerror(mmdb_error));
    }
}
static char *
ngx_http_geoip2(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_http_geoip2_conf_t  *gcf = conf;
    ngx_str_t               *value;
    int                     status, nelts, i;
    ngx_http_geoip2_db_t    *database;
    char                    *rv;
    ngx_conf_t              save;

    value = cf->args->elts;

    if (gcf->databases == NULL) {
        gcf->databases = ngx_array_create(cf->pool, 2,
                                        sizeof(ngx_http_geoip2_db_t));
        if (gcf->databases == NULL) {
            return NGX_CONF_ERROR;
        }
    } else {
        nelts = (int) gcf->databases->nelts;
        database = gcf->databases->elts;

        for (i = 0; i < nelts; i++) {
            if (ngx_strcmp(value[1].data, database[i].mmdb.filename) == 0) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "Duplicate GeoIP2 mmdb - %V", &value[1]);
                return NGX_CONF_ERROR;
            }
        }
    }

    database = ngx_array_push(gcf->databases);
    if (database == NULL) {
        return NGX_CONF_ERROR;
    }

    status = MMDB_open((char *) value[1].data, MMDB_MODE_MMAP, &database->mmdb);

    if (status != MMDB_SUCCESS) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "MMDB_open(\"%V\") failed - %s", &value[1],
                           MMDB_strerror(status));
        return NGX_CONF_ERROR;
    }

#if (NGX_HAVE_INET6)
    ngx_memset(&database->address, 0, sizeof(database->address));
#else
    database->address = 0;
#endif

    save = *cf;
    cf->handler = ngx_http_geoip2_add_variable;
    cf->handler_conf = (void *) database;

    rv = ngx_conf_parse(cf, NULL);
    *cf = save;
    return rv;
}
Example #8
0
	bool Init( void ) {
		if ( handle ) {
			return true;
		}
		handle = new MMDB_s{};
		int status = -1;

		char fs_gameString[MAX_CVAR_VALUE_STRING];
		trap->Cvar_VariableStringBuffer( "fs_game", fs_gameString, sizeof(fs_gameString) );
		const char *sPath = va( "%s/GeoLite2-Country.mmdb", fs_gameString );

		trap->Print( "Loading %s\n", sPath );
		fileHandle_t f = NULL_FILE;
		unsigned int len = trap->FS_Open( sPath, &f, FS_READ );

		// no file
		if ( !f ) {
			return false;
		}

		// empty file
		if ( !len || len == -1 ) {
			trap->FS_Close( f );
			return false;
		}

		// alloc memory for buffer
		char *buf = (char *)malloc( len + 1 );
		if ( !buf ) {
			return false;
		}

		trap->FS_Read( buf, len, f );
		trap->FS_Close( f );
		buf[len] = '\0';

		// pass it off to the json reader
		char *tmpFilePath = nullptr;
		trap->Print( "writing to temporary file\n" );
		if ( WriteToTemporaryFile( buf, len, &tmpFilePath ) ) {
			trap->Print( "loading from temporary file %s\n", tmpFilePath );
			if ( (status = MMDB_open( tmpFilePath, MMDB_MODE_MMAP, handle ) ) != MMDB_SUCCESS ) {
				trap->Print( "Error occured while initialising MaxMind GeoIP: \"%s\"\n", MMDB_strerror( status ) );
				delete handle;
				handle = nullptr;
				return false;
			}
		}

		free( buf );

		return true;
	}
Example #9
0
void
mmdb_problem_to_error(const int _gai_error, const int _mmdb_error, gchar *where)
{
  if (0 != _gai_error)
    msg_error("Error from call to getaddrinfo",
              evt_tag_str("gai_error", gai_strerror(_gai_error)),
              evt_tag_str("where", where));

  if (MMDB_SUCCESS != _mmdb_error)
    msg_error("maxminddb_error",
              evt_tag_str("error", MMDB_strerror(_mmdb_error)),
              evt_tag_str("where", where));
}
Example #10
0
	void Worker( GeoIPData *data ) {
		int error = -1, gai_error = -1;
		MMDB_lookup_result_s result =  MMDB_lookup_string( handle, data->getIp().c_str(), &gai_error, &error );
		if ( error != MMDB_SUCCESS || gai_error != 0 ) {
			std::string *str = data->getData();
			*str = MMDB_strerror( error );
			data->setStatus( 0 ); // error
			return;
		}
		if ( result.found_entry ) {
			MMDB_entry_s entry = result.entry;
			MMDB_entry_data_s entry_data;
			if ( (error = MMDB_get_value( &entry, &entry_data, "names", "en", NULL )) != MMDB_SUCCESS ) {
				std::string *str = data->getData();
				*str = MMDB_strerror( error );
				data->setStatus( 0 ); // error
				return;
			}
			if ( entry_data.has_data ) {
				std::string *str = data->getData();
				*str = entry_data.utf8_string;
				data->setStatus( 1 );
				return;
			}
			else {
				*data->getData() = "Unknown";
				data->setStatus( 1 );
				return;
			}
		}
		else {
			*data->getData() = "Unknown";
			data->setStatus( 1 );
			return;
		}
	}
Example #11
0
static VALUE geoip2_compat_initialize(VALUE self, VALUE path)
{
  Check_Type(path, T_STRING);
  char* db = StringValuePtr(path);
  MMDB_s *mmdb;
  Data_Get_Struct(self, MMDB_s, mmdb);

  int status = MMDB_open(db, MMDB_MODE_MMAP, mmdb);

  if (status != MMDB_SUCCESS) {
    rb_raise(egeoip2_compat_Exception, "GeoIP2Compat - %s: %s",
      MMDB_strerror(status), db
    );
  }
  return self;
}
Example #12
0
// ------------------------------------------------------------------------------------------------
DbHnd::DbHnd(CSStr filepath, Uint32 flags)
    : mDb()
{
    // Validate the specified file path
    if (!filepath || *filepath == '\0')
    {
        STHROWF("Invalid database file path");
    }
    // Let's attempt to open the specified database
    const Int32 status = MMDB_open(filepath, flags, &mDb);
    // Validate the result of the operation
    if (status != MMDB_SUCCESS)
    {
        STHROWF("Unable to open the specified database [%s]", MMDB_strerror(status));
    }
}
Example #13
0
F_NONNULL
static void geoip2_list_xlate_recurse(geoip2_t* db, nlist_t* nl, struct in6_addr ip, unsigned depth, const uint32_t node_count, const uint32_t node_num) {
    dmn_assert(db); dmn_assert(nl);
    dmn_assert(depth < 129U);

    if(!depth) {
        log_err("plugin_geoip: map '%s': GeoIP2 database '%s': Error while traversing tree nodes: depth too low", db->map_name, db->pathname);
        siglongjmp(db->jbuf, 1);
    }

    // skip v4-like spaces other than canonical compat area
    if(
        (depth == 32 && (
               !memcmp(ip.s6_addr, start_v4mapped, 12U)
            || !memcmp(ip.s6_addr, start_siit, 12U)
            || !memcmp(ip.s6_addr, start_wkp, 12U)
        ))
        || (depth == 96U && !memcmp(ip.s6_addr, start_teredo, 4U))
        || (depth == 112U && !memcmp(ip.s6_addr, start_6to4, 2U))
    )
        return;

    MMDB_search_node_s node;
    int read_rv = MMDB_read_node(&db->mmdb, node_num, &node);
    if(read_rv != MMDB_SUCCESS) {
        log_err("plugin_geoip: map '%s': GeoIP2 database '%s': Error while traversing tree nodes: %s",
            db->map_name, db->pathname, MMDB_strerror(read_rv));
        siglongjmp(db->jbuf, 1);
    }

    const uint32_t zero_node_num = node.left_record;
    const uint32_t one_node_num = node.right_record;
    const unsigned new_depth = depth - 1U;
    const unsigned mask = 128U - new_depth;

    if(zero_node_num >= node_count)
        nlist_append(nl, ip.s6_addr, mask, geoip2_get_dclist_cached(db, zero_node_num - node_count));
    else
        geoip2_list_xlate_recurse(db, nl, ip, new_depth, node_count, zero_node_num);

    SETBIT_v6(ip.s6_addr, mask - 1U);

    if(one_node_num >= node_count)
        nlist_append(nl, ip.s6_addr, mask, geoip2_get_dclist_cached(db, one_node_num - node_count));
    else
        geoip2_list_xlate_recurse(db, nl, ip, new_depth, node_count, one_node_num);
}
// lookup an ip address using the maxmind db and return the value
// lookup_path described in this doc: http://maxmind.github.io/MaxMind-DB/
const char *
geo_lookup(MMDB_s *const mmdb_handle, const char *ipstr, const char **lookup_path)
{
    char *data = NULL;
    // Lookup IP in the DB
    int gai_error, mmdb_error;
    MMDB_lookup_result_s result =
        MMDB_lookup_string(mmdb_handle, ipstr, &gai_error, &mmdb_error);

    if (0 != gai_error) {
#if DEBUG
        fprintf(stderr,
            "[INFO] Error from getaddrinfo for %s - %s\n\n",
            ipstr, gai_strerror(gai_error));
#endif
        return NULL;
    }

    if (MMDB_SUCCESS != mmdb_error) {
#if DEBUG
        fprintf(stderr,
            "[ERROR] Got an error from libmaxminddb: %s\n\n",
            MMDB_strerror(mmdb_error));
#endif
        return NULL;
    }

    // Parse results
    MMDB_entry_data_s entry_data;
    int exit_code = 0;

    if (result.found_entry) {
        int status = MMDB_aget_value(&result.entry, &entry_data, lookup_path);

        if (MMDB_SUCCESS != status) {
#if DEBUG
            fprintf(
                stderr,
                    "[WARN] Got an error looking up the entry data. Make sure \
 the lookup_path is correct. %s\n",
                    MMDB_strerror(status));
#endif
            exit_code = 4;
            return NULL;
        }
Example #15
0
// ------------------------------------------------------------------------------------------------
Object LookupResult::GetEntryDataList()
{
    // See if there's an entry
    if (!m_Result.found_entry)
    {
        STHROWF("Result does not have an entry");
    }

    MMDB_entry_data_list_s * entry_data_list = nullptr;
    // Attempt to retrieve the entire entry data list at once
    const int status = MMDB_get_entry_data_list(&m_Result.entry, &entry_data_list);
    // Validate the status code
    if (status != MMDB_SUCCESS)
    {
        STHROWF("Unable to get entry data list [%s]", MMDB_strerror(status));
    }
    // Return the resulted list
    return Object(new EntryDataList(m_Handle, entry_data_list));
}
// Open the maxmind db file
int
open_mmdb(MMDB_s *mmdb_handle)
{
    int mmdb_baddb = MMDB_open(MMDB_CITY_PATH, MMDB_MODE_MMAP, mmdb_handle);
    if (mmdb_baddb != MMDB_SUCCESS) {
#if DEBUG
        fprintf(stderr, "[ERROR] open_mmdb: Can't open %s - %s\n",
            MMDB_CITY_PATH, MMDB_strerror(mmdb_baddb));
        if (MMDB_IO_ERROR == mmdb_baddb) {
            fprintf(stderr,
                "[ERROR] open_mmdb: IO error: %s\n",
                strerror(mmdb_baddb));
        }
#endif
        mmdb_handle = NULL;
        return 1;
    }
    return 0;
}
Example #17
0
LOCAL MMDB_s open_or_die(const char *fname)
{
    MMDB_s mmdb;
    int status = MMDB_open(fname, MMDB_MODE_MMAP, &mmdb);

    if (MMDB_SUCCESS != status) {
        fprintf(stderr, "\n  Can't open %s - %s\n", fname,
                MMDB_strerror(status));

        if (MMDB_IO_ERROR == status) {
            fprintf(stderr, "    IO error: %s\n", strerror(errno));
        }

        fprintf(stderr, "\n");

        exit(2);
    }

    return mmdb;
}
Example #18
0
static gboolean
_mmdb_load_entry_data_list(GeoIPParser *self, const gchar *input, MMDB_entry_data_list_s **entry_data_list)
{
  int _gai_error, mmdb_error;
  MMDB_lookup_result_s result =
    MMDB_lookup_string(self->database, input, &_gai_error, &mmdb_error);

  if (!result.found_entry)
    {
      mmdb_problem_to_error(_gai_error, mmdb_error, "lookup");
      return FALSE;
    }

  mmdb_error = MMDB_get_entry_data_list(&result.entry, entry_data_list);
  if (MMDB_SUCCESS != mmdb_error)
    {
      msg_debug("GeoIP2: MMDB_get_entry_data_list",
                evt_tag_str("error", MMDB_strerror(mmdb_error)));
      return FALSE;
    }
  return TRUE;
}
Example #19
0
static VALUE geoip2_compat_lookup(VALUE self, VALUE ip)
{
  int status, gai_error, mmdb_error;
  Check_Type(ip, T_STRING);

  char* ip_addr = StringValuePtr(ip);
  MMDB_s *mmdb;
  Data_Get_Struct(self, MMDB_s, mmdb);

  MMDB_lookup_result_s result =
    MMDB_lookup_string(mmdb, ip_addr, &gai_error, &mmdb_error);

  if (mmdb_error != MMDB_SUCCESS) {
    rb_raise(egeoip2_compat_Exception,
      "geoip2_compat - lookup failed: %s", MMDB_strerror(mmdb_error)
    );
  }

  if (gai_error != 0) {
    rb_raise(egeoip2_compat_Exception,
      "geoip2_compat - getaddrinfo failed: %s", gai_strerror(gai_error)
    );
  }

  if (!result.found_entry) return Qnil;

  VALUE hash = rb_hash_new();

  geoip2_compat_lookup_internal(&result, hash, geoip2_compat_COUNTRY_CODE, "country", "iso_code", NULL);
  geoip2_compat_lookup_internal(&result, hash, geoip2_compat_COUNTRY_NAME, "country", "names", "en", NULL);
  geoip2_compat_lookup_internal(&result, hash, geoip2_compat_REGION, "subdivisions", "0", "iso_code", NULL);
  geoip2_compat_lookup_internal(&result, hash, geoip2_compat_REGION_NAME, "subdivisions", "0", "names", "en", NULL);
  geoip2_compat_lookup_internal(&result, hash, geoip2_compat_CITY, "city", "names", "en", NULL);
  geoip2_compat_lookup_internal(&result, hash, geoip2_compat_POSTAL_CODE, "postal", "code", NULL);
  geoip2_compat_lookup_internal(&result, hash, geoip2_compat_LATITUDE, "location", "latitude", NULL);
  geoip2_compat_lookup_internal(&result, hash, geoip2_compat_LONGITUDE, "location", "longitude", NULL);

  return hash;
}
void test_lookup_errors(int gai_error, int mmdb_error,
                        const char *function, const char *ip,
                        const char *file, const char *mode_desc)
{

    int is_ok = ok(0 == gai_error,
                   "no getaddrinfo error in call to %s for %s - %s - %s",
                   function, ip, file, mode_desc);

    if (!is_ok) {
        diag("error from call to getaddrinfo for %s - %s",
             ip, gai_strerror(gai_error));
    }

    is_ok = ok(0 == mmdb_error,
               "no MMDB error in call to %s for %s - %s - %s",
               function, ip, file, mode_desc);

    if (!is_ok) {
        diag("MMDB error - %s", MMDB_strerror(mmdb_error));
    }
}
Example #21
0
static PyObject *Reader_get(PyObject *self, PyObject *args)
{
    char *ip_address = NULL;

    Reader_obj *mmdb_obj = (Reader_obj *)self;
    if (!PyArg_ParseTuple(args, "s", &ip_address)) {
        return NULL;
    }

    MMDB_s *mmdb = mmdb_obj->mmdb;

    if (NULL == mmdb) {
        PyErr_SetString(PyExc_ValueError,
                        "Attempt to read from a closed MaxMind DB.");
        return NULL;
    }

    int gai_error = 0;
    int mmdb_error = MMDB_SUCCESS;
    MMDB_lookup_result_s result =
        MMDB_lookup_string(mmdb, ip_address, &gai_error,
                           &mmdb_error);

    if (0 != gai_error) {
        PyErr_Format(PyExc_ValueError,
                     "'%s' does not appear to be an IPv4 or IPv6 address.",
                     ip_address);
        return NULL;
    }

    if (MMDB_SUCCESS != mmdb_error) {
        PyObject *exception;
        if (MMDB_IPV6_LOOKUP_IN_IPV4_DATABASE_ERROR == mmdb_error) {
            exception = PyExc_ValueError;
        } else {
            exception = MaxMindDB_error;
        }
        PyErr_Format(exception, "Error looking up %s. %s",
                     ip_address, MMDB_strerror(mmdb_error));
        return NULL;
    }

    if (!result.found_entry) {
        Py_RETURN_NONE;
    }

    MMDB_entry_data_list_s *entry_data_list = NULL;
    int status = MMDB_get_entry_data_list(&result.entry, &entry_data_list);
    if (MMDB_SUCCESS != status) {
        PyErr_Format(MaxMindDB_error,
                     "Error while looking up data for %s. %s",
                     ip_address, MMDB_strerror(status));
        MMDB_free_entry_data_list(entry_data_list);
        return NULL;
    }

    MMDB_entry_data_list_s *original_entry_data_list = entry_data_list;
    PyObject *py_obj = from_entry_data_list(&entry_data_list);
    MMDB_free_entry_data_list(original_entry_data_list);
    return py_obj;
}
Example #22
0
static void geoip2_dcmap_cb(void* data, char* lookup, const unsigned level) {
    dmn_assert(data);

    geoip2_dcmap_cb_data_t* state = data;

    // Explicit out-of-data set from below
    if(state->out_of_data)
        return;

    MMDB_entry_data_s val;

    if(!level) {
        mmdb_lookup_utf8_(GEOIP2_PATH_CONTINENT);
        return;
    }

    if(level == 1U) {
        mmdb_lookup_utf8_(GEOIP2_PATH_COUNTRY);
        // No further data for Country-level databases
        if(!state->db->is_city)
            state->out_of_data = true;
        return;
    }

    if(state->db->city_no_region) {
        mmdb_lookup_utf8_(GEOIP2_PATH_CITY);
        state->out_of_data = true;
        return;
    }

    // We only allow for up to 8-9 subdivision levels
    // (9 will function correctly, but then we won't bother
    //   matching city data after.  8 levels will fully function
    //   and do the city-level at the end if there's not a 9th
    //   level in the database).
    // If any country actually needs more, we'll have to change
    //   the simplistic '0' + subd_level magic below for lookup strings.
    if(level > 11U) {
        state->out_of_data = true;
        return;
    }

    // used to search/fetch subdivision array elements
    dmn_assert(level >= 2U && level <= 11U);
    const unsigned subd_level = level - 2U;
    const char idx[2] = { '0' + subd_level, '\0' };
    const char* path_subd[] = { "subdivisions", &idx[0], "iso_code", NULL };

    // fetch this level of subdivision data if possible
    int mmrv = MMDB_aget_value(&state->entry, &val, path_subd);
    if(mmrv == MMDB_SUCCESS && val.has_data && val.type == MMDB_DATA_TYPE_UTF8_STRING && val.utf8_string) {
        if(lookup) {
            memcpy(lookup, val.utf8_string, val.data_size);
            lookup[val.data_size] = '\0';
        }
    }
    else if(mmrv == MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR) {
        // no subdivision data left, or at all to begin with,
        //   switch to city and signal end of data depth
        mmdb_lookup_utf8_(GEOIP2_PATH_CITY);
        state->out_of_data = true;
    }
    else {
        dmn_log_err("plugin_geoip: map %s: Unexpected error fetching GeoIP2City subdivision data (%s)",
            state->db->map_name, MMDB_strerror(mmrv));
        siglongjmp(state->db->jbuf, 1);
    }
}
Example #23
0
static geoip2_t* geoip2_new(const char* pathname, const char* map_name, dclists_t* dclists, const dcmap_t* dcmap, const bool city_auto_mode, const bool city_no_region) {
    dmn_assert(pathname); dmn_assert(map_name); dmn_assert(dclists);

    geoip2_t* db = xcalloc(1, sizeof(*db));
    int status = MMDB_open(pathname, MMDB_MODE_MMAP, &db->mmdb);
    if(status != MMDB_SUCCESS) {
        dmn_log_err("plugin_geoip: map '%s': Failed to open GeoIP2 database '%s': %s",
            map_name, pathname, MMDB_strerror(status));
        free(db);
        return NULL;
    }

    MMDB_metadata_s* meta = &db->mmdb.metadata;
    if(!geoip2_mmdb_log_meta(meta, map_name, pathname)) {
        geoip2_destroy(db);
        return NULL;
    }

    // The database format spec indicates that minor version bumps
    //   should be backwards compatible, so we only need to check
    //   the major version here.
    if(meta->binary_format_major_version != 2U) {
        dmn_log_err("plugin_geoip: map '%s': GeoIP2 database '%s' has"
            " unsupported binfmt major version %" PRIu16,
            map_name, pathname, meta->binary_format_major_version
        );
        geoip2_destroy(db);
        return NULL;
    }

    // Both our own code and the current libmaxminddb seem to have
    //   built-in assumptions based on record_size of 32 or less,
    //   yet the spec allows for larger in the future.
    if(meta->record_size > 32U) {
        dmn_log_err("plugin_geoip: map '%s': GeoIP2 database '%s' has"
            " unsupported record_size %" PRIu16,
            map_name, pathname, meta->record_size
        );
        geoip2_destroy(db);
        return NULL;
    }

    if(meta->ip_version != 4U && meta->ip_version != 6U) {
        dmn_log_err("plugin_geoip: map '%s': GeoIP2 database '%s' has"
            " unsupported ip_version %" PRIu16,
            map_name, pathname, meta->ip_version
        );
        geoip2_destroy(db);
        return NULL;
    }

    // The check for /City/ is how the official Perl API detects
    //   the City-level data model, so it's probably a reliable bet.
    // We assume anything that didn't match /City/ is a Country-level
    //   database.  This will technically "work" for GeoIP2 if there is no
    //   Country-level info, but everything will default.  So, warn about the
    //   Country defaulting if the database_type does not match /Country/.
    db->is_city = !!strstr(meta->database_type, "City");

    if(!db->is_city) {
        if(city_auto_mode) {
            dmn_log_err("plugin_geoip: map '%s': GeoIP2 DB '%s' is not a City-level"
                " database and this map uses auto_dc_coords",
                map_name, pathname);
            geoip2_destroy(db);
            return NULL;
        }
        if(!strstr(meta->database_type, "Country"))
            dmn_log_warn("plugin_geoip: map '%s': Assuming GeoIP2 database '%s'"
                " has standard MaxMind Country data, but type is actually '%s'",
                map_name, pathname, meta->database_type
            );
    }

    db->is_v4 = meta->ip_version == 4U;
    db->city_auto_mode = city_auto_mode;
    db->city_no_region = city_no_region;
    db->pathname = strdup(pathname);
    db->map_name = strdup(map_name);
    db->dclists = dclists;
    db->dcmap = dcmap;
    return db;
}
Example #24
0
// ------------------------------------------------------------------------------------------------
SQInteger LookupResult::GetValue(HSQUIRRELVM vm)
{
    const Int32 top = sq_gettop(vm);
    // The lookup result instance
    LookupResult * lookup = nullptr;
    // Attempt to extract the lookup result instance
    try
    {
        lookup = Var< LookupResult * >(vm, 1).value;
    }
    catch (const Sqrat::Exception & e)
    {
        return sq_throwerror(vm, e.what());
    }
    // Do we have a valid lookup result instance?
    if (!lookup)
    {
        return sq_throwerror(vm, "Invalid lookup result instance");
    }
    // See if there's a handle
    else if (!lookup->m_Handle)
    {
        return sq_throwerror(vm, "Invalid Maxmind database reference");
    }
    // See if there's an entry
    else if (!(lookup->m_Result.found_entry))
    {
        return sq_throwerror(vm, "Result does not have an entry");
    }

    typedef std::vector< StackStrF > ArgList;
    // The list of extracted arguments
    ArgList arglist;
    // Extract each argument as a string
    for (SQInteger i = 2; i <= top; ++i)
    {
        arglist.emplace_back(vm, i, false);
        // Did we fail to extract the argument value?
        if (SQ_FAILED(arglist.back().mRes))
        {
            return arglist.back().mRes; // Propagate the error
        }
    }

    typedef std::vector< CSStr > PtrList;
    // The list of pointers to path segments
    PtrList ptrlist;
    // Grab the pointers to argument values
    for (const auto & a : arglist)
    {
        ptrlist.push_back(a.mPtr);
    }
    // Push null to specify the end of the list
    ptrlist.push_back(nullptr);

    MMDB_entry_data_s entry_data;
    // Attempt to retrieve the specified entry data
    const int status = MMDB_aget_value(&(lookup->m_Result.entry), &entry_data, ptrlist.data());
    // Validate the status code
    if (status != MMDB_SUCCESS)
    {
        return sq_throwerror(vm, ToStrF("Unable to get entry data [%s]", MMDB_strerror(status)));
    }
    // Push the resulted list object onto the stack
    try
    {
        ClassType< EntryData >::PushInstance(vm, new EntryData(lookup->m_Handle, entry_data));
    }
    catch (const Sqrat::Exception & e)
    {
        return sq_throwerror(vm, e.what());
    }
    // Specify that we returned a value
    return 1;
}
Example #25
0
vmod_geoip2_lookup(VRT_CTX, struct vmod_geoip2_geoip2 *vp,
    VCL_STRING path, VCL_IP addr)
{
	MMDB_lookup_result_s res;
	MMDB_entry_data_s data;
	const struct sockaddr *sa;
	socklen_t addrlen;
	const char **ap, *arrpath[COMPONENT_MAX];
	char buf[LOOKUP_PATH_MAX];
	char *p, *last;
	uint32_t i;
	int error;

	CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
	AN(addr);

	if (!vp) {
		VSLb(ctx->vsl, SLT_Error,
		    "geoip2.lookup: Database not open");
		return (NULL);
	}

	if (!path || !*path || strlen(path) >= sizeof(buf)) {
		VSLb(ctx->vsl, SLT_Error,
		    "geoip2.lookup: Invalid or missing path (%s)",
		    path ? path : "NULL");
		return (NULL);
	}

	sa = VSA_Get_Sockaddr(addr, &addrlen);
	AN(sa);

	res = MMDB_lookup_sockaddr(&vp->mmdb, sa, &error);
	if (error != MMDB_SUCCESS) {
		VSLb(ctx->vsl, SLT_Error,
		    "geoip2.lookup: MMDB_lookup_sockaddr: %s",
		    MMDB_strerror(error));
		return (NULL);
	}

	if (!res.found_entry) {
		VSLb(ctx->vsl, SLT_Debug,
		    "geoip2.lookup: No entry for this IP address (%s)",
		    VRT_IP_string(ctx, addr));
		return (NULL);
	}

	strncpy(buf, path, sizeof(buf));

	last = NULL;
	for (p = buf, ap = arrpath; ap < &arrpath[COMPONENT_MAX - 1] &&
	    (*ap = strtok_r(p, "/", &last)) != NULL; p = NULL) {
		if (**ap != '\0')
			ap++;
	}
	*ap = NULL;

	error = MMDB_aget_value(&res.entry, &data, arrpath);
	if (error != MMDB_SUCCESS &&
	    error != MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR) {
		VSLb(ctx->vsl, SLT_Error,
		    "geoip2.lookup: MMDB_aget_value: %s",
		    MMDB_strerror(error));
		return (NULL);
	}

	if (!data.has_data) {
		VSLb(ctx->vsl, SLT_Debug,
		    "geoip2.lookup: No data for this path (%s)",
		    path);
		return (NULL);
	}

	switch (data.type) {
	case MMDB_DATA_TYPE_BOOLEAN:
		p = WS_Printf(ctx->ws, "%s", data.boolean ?
		    "true" : "false");
		break;

	case MMDB_DATA_TYPE_BYTES:
		p = WS_Alloc(ctx->ws, data.data_size * 2 + 1);
		if (p)
			for (i = 0; i < data.data_size; i++)
				sprintf(&p[i * 2], "%02X", data.bytes[i]);
		break;

	case MMDB_DATA_TYPE_DOUBLE:
		p = WS_Printf(ctx->ws, "%f", data.double_value);
		break;

	case MMDB_DATA_TYPE_FLOAT:
		p = WS_Printf(ctx->ws, "%f", data.float_value);
		break;

	case MMDB_DATA_TYPE_INT32:
		p = WS_Printf(ctx->ws, "%i", data.int32);
		break;

	case MMDB_DATA_TYPE_UINT16:
		p = WS_Printf(ctx->ws, "%u", data.uint16);
		break;

	case MMDB_DATA_TYPE_UINT32:
		p = WS_Printf(ctx->ws, "%u", data.uint32);
		break;

	case MMDB_DATA_TYPE_UINT64:
		p = WS_Printf(ctx->ws, "%ju", (uintmax_t)data.uint64);
		break;

	case MMDB_DATA_TYPE_UTF8_STRING:
		p = WS_Alloc(ctx->ws, data.data_size + 1);
		if (p) {
			memcpy(p, data.utf8_string, data.data_size);
			p[data.data_size] = '\0';
		}
		break;

	default:
		VSLb(ctx->vsl, SLT_Error,
		    "geoip2.lookup: Unsupported data type (%d)",
		    data.type);
		return (NULL);
	}

	if (!p)
		VSLb(ctx->vsl, SLT_Error,
		    "geoip2.lookup: Out of workspace");

	return (p);
}
Example #26
0
void OnGeoipCommand()
{
	const auto cmd = CMD_ARGV(1);

	if (!strcmp(cmd, "version"))
	{
		if (!HandleDB.filename)
		{
			MF_PrintSrvConsole("\n  Database is not loaded.\n");
			return;
		}

		const auto meta_dump = "\n"
			"  Database metadata\n"
			"    Node count:    %i\n"
			"    Record size:   %i bits\n"
			"    IP version:    IPv%i\n"
			"    Binary format: %i.%i\n"
			"    Build epoch:   %llu (%s)\n"
			"    Type:          %s\n"
			"    Languages:     ";

		char date[40];
		strftime(date, sizeof date, "%Y-%m-%d %H:%M:%S UTC", gmtime(reinterpret_cast<const time_t *>(&HandleDB.metadata.build_epoch)));

		fprintf(stdout, meta_dump,
				HandleDB.metadata.node_count,
				HandleDB.metadata.record_size,
				HandleDB.metadata.ip_version,
				HandleDB.metadata.binary_format_major_version,
				HandleDB.metadata.binary_format_minor_version,
				HandleDB.metadata.build_epoch,
				date,
				HandleDB.metadata.database_type);

		for (size_t i = 0; i < HandleDB.metadata.languages.count; ++i)
		{
			fprintf(stdout, "%s", HandleDB.metadata.languages.names[i]);

			if (i < HandleDB.metadata.languages.count - 1)
			{
				fprintf(stdout, " ");
			}
		}

		fprintf(stdout, "\n");
		fprintf(stdout, "    Description:\n");

		for (size_t i = 0; i < HandleDB.metadata.description.count; ++i)
		{
			fprintf(stdout, "      %s:   %s\n",
					HandleDB.metadata.description.descriptions[i]->language,
					HandleDB.metadata.description.descriptions[i]->description);
		}
		fprintf(stdout, "\n");
	}
	else if (!strcmp(cmd, "dump"))
	{
		if (!HandleDB.filename)
		{
			MF_PrintSrvConsole("\n  Database is not loaded.\n\n");
			return;
		}

		const auto num_args = CMD_ARGC();

		if (num_args < 3)
		{
			MF_PrintSrvConsole("\n  An IP address must be provided.\n\n");
			return;
		}

		const auto ip = stripPort(const_cast<char *>(CMD_ARGV(2)));

		auto gai_error = 0;
		auto mmdb_error = 0;

		auto result = MMDB_lookup_string(&HandleDB, ip, &gai_error, &mmdb_error);

		if (gai_error != 0 || mmdb_error != MMDB_SUCCESS || !result.found_entry)
		{
			MF_PrintSrvConsole("\n  Either look up failed or no found result.\n\n");
			return;
		}

		MMDB_entry_data_list_s *entry_data_list = nullptr;
		int status;

		if ((status = MMDB_get_entry_data_list(&result.entry, &entry_data_list)) != MMDB_SUCCESS || entry_data_list == nullptr)
		{
			MF_PrintSrvConsole("\n  Could not retrieve data list - %s.\n\n", MMDB_strerror(status));
			return;
		}

		const char *file = nullptr;
		FILE *fp = nullptr;

		if (num_args > 3)
		{
			file = CMD_ARGV(3);
			fp = fopen(MF_BuildPathname("%s", file), "w");
		}

		if (!fp)
		{
			file = nullptr;
			fp = stdout;
		}

		fprintf(fp, "\n");
		MMDB_dump_entry_data_list(fp, entry_data_list, 2);
		fprintf(fp, "\n");

		if (file)
		{
			fclose(fp);
		}

		MMDB_free_entry_data_list(entry_data_list);
	}
	else if (!strcmp(cmd, "reload"))
	{
		const auto isDatabaseLoaded = HandleDB.filename != nullptr;

		if (isDatabaseLoaded)
		{
			MMDB_close(&HandleDB);
		}

		if (loadDatabase() && !NativesRegistered)
		{
			MF_AddNatives(GeoipNatives);

			NativesRegistered = true;
		}
	}
	else
	{
		MF_PrintSrvConsole("\n");
		MF_PrintSrvConsole("  Usage: geoip <command> [argument]\n");
		MF_PrintSrvConsole("  Commands:\n");
		MF_PrintSrvConsole("     version                 - display geoip database metadata\n");
		MF_PrintSrvConsole("     reload                  - reload geoip database\n");
		MF_PrintSrvConsole("     dump <ip> [output file] - dump all data from an IP address formatted in a JSON-ish fashion.\n");
		MF_PrintSrvConsole("                               An output file is mod-based and if not provided, it will print in the console.\n");
		MF_PrintSrvConsole("\n");
	}
}
Example #27
0
bool loadDatabase()
{
	const auto isDatabaseLoaded = HandleDB.filename != nullptr;

	if (isDatabaseLoaded)
	{
		return true;
	}

	const char *databases[] =
	{
		"City",
		"Country" // Is the default shipped database with AMXX.
	};

	const auto modName = MF_GetModname();
	const auto dataDir = MF_GetLocalInfo("amxx_datadir", "addons/amxmodx/data");

	char file[260];
	auto status = -1;

	for (auto& database : databases)
	{
		// MF_BuildPathname not used because backslash
		// makes CreateFileMapping failing under windows.

		ke::SafeSprintf(file, sizeof file, "%s/%s/GeoLite2-%s.mmdb", modName, dataDir, database);

		status = MMDB_open(file, MMDB_MODE_MMAP, &HandleDB);

		if (status == MMDB_SUCCESS)
		{
			break;
		}

		if (status != MMDB_FILE_OPEN_ERROR)
		{
			MF_Log("Could not open %s - %s", file, MMDB_strerror(status));

			if (status == MMDB_IO_ERROR)
			{
				MF_Log("    IO error: %s", strerror(errno));
			}
		}
	}

	if (status != MMDB_SUCCESS)
	{
		MF_Log("Could not find GeoIP2 databases. Disabled natives.");
		return false;
	}

	MF_Log("Database info: %s %i.%i",
		   HandleDB.metadata.description.descriptions[0]->description,
		   HandleDB.metadata.binary_format_major_version,
		   HandleDB.metadata.binary_format_minor_version);

	// Retrieve supported languages.
	for (size_t i = 0; i < HandleDB.metadata.languages.count; i++)
	{
		LangList.append(ke::AString(HandleDB.metadata.languages.names[i]));
	}

	return true;
}
void check_status(int status)
{
  if (MMDB_SUCCESS != status) {
    caml_invalid_argument((const char *)MMDB_strerror(status));
  }
}
Example #29
0
	bool Init( void ) {
		if ( handle ) {
			return true;
		}
		handle = new MMDB_s{};
		int status = -1;

		const char *sPath = "GeoLite2-Country.mmdb";
		trap->Print( "Loading %s\n", sPath );
		fileHandle_t f = NULL_FILE;
		unsigned int len = trap->FS_Open( sPath, &f, FS_READ );

		// no file
		if ( !f ) {
			return false;
		}

		// empty file
		if ( !len || len == -1 ) {
			trap->FS_Close( f );
			return false;
		}

		// alloc memory for buffer
		char *buf = (char *)malloc( len + 1 );
		if ( !buf ) {
			return false;
		}

		trap->FS_Read( buf, len, f );
		trap->FS_Close( f );
		buf[len] = '\0';

		const char *extension = nullptr;
		for ( const char *p = sPath + strlen(sPath); p != sPath; p-- ) {
			if ( *p == '.' ) {
				extension = p;
				break;
			}
		}
		char *tmpFilePath = nullptr;
		if ( WriteToTemporaryFile( buf, len, &tmpFilePath, extension ) ) {
			trap->Print( "Failed to create temporary file\n" );
			free( buf );
			return false;
		}

		trap->Print( "loading from temporary file %s\n", tmpFilePath );
		status = MMDB_open( tmpFilePath, MMDB_MODE_MMAP, handle );
		if ( status != MMDB_SUCCESS ) {
			trap->Print( "Error occured while initialising MaxMind GeoIP: \"%s\"\n", MMDB_strerror( status ) );
			delete handle;
			handle = nullptr;

			free( tmpFilePath );
			free( buf );
			return false;
		}

		free( tmpFilePath );
		free( buf );
		return true;
	}