/** * Lookup the IP address in the GeoIP database * * @param[in] ib IronBee engine * @param[in] tx Transaction * @param[in] event Event * @param[in] data callback data (Module configuration) */ static ib_status_t geoip_lookup( ib_engine_t *ib, ib_tx_t *tx, ib_state_event_type_t event, void *data ) { assert(ib != NULL); assert(event == handle_context_tx_event); assert(data != NULL); const char *ip = tx->er_ipstr; const module_data_t *mod_data = (const module_data_t *)data; if (ip == NULL) { ib_log_alert_tx(tx, "Trying to lookup NULL IP in GEOIP"); return IB_EINVAL; } #ifdef GEOIP_HAVE_VERSION /** * Some configurations exist as single characters and must be converted to * a string. This is simply a place to assemble that string before * it is passed into ip_data_add_nulstr. * This is only needed if we have support confidence items. WAM */ char one_char_str[2] = { '\0', '\0' }; #endif /* GEOIP_HAVE_VERSION */ ib_status_t rc; /* Declare and initialize the GeoIP property list. * Regardless of if we find a record or not, we want to create the list * artifact so that later modules know we ran and did [not] find a * record. */ ib_field_t *geoip_lst = NULL; ib_field_t *tmp_field = NULL; /* Id of geo ip record to read. */ int geoip_id; ib_log_debug_tx(tx, "GeoIP Lookup '%s'", ip); /* Build a new list. */ rc = ib_var_source_initialize( mod_data->geoip_source, &geoip_lst, tx->var_store, IB_FTYPE_LIST ); /* NOTICE: Called before GeoIP_record_by_addr allocates a * GeoIPRecord. */ if (rc != IB_OK) { ib_log_alert_tx(tx, "Unable to add GEOIP var."); return IB_EINVAL; } if (mod_data->geoip_db == NULL) { ib_log_alert_tx(tx, "GeoIP database was never opened. Perhaps the " "configuration file needs a GeoIPDatabaseFile " "\"/usr/share/geoip/GeoLite.dat\" line?"); return IB_EINVAL; } geoip_id = GeoIP_id_by_addr(mod_data->geoip_db, ip); if (geoip_id > 0) { const char *tmp_str; ib_log_debug_tx(tx, "GeoIP record found."); /* Add integers. */ tmp_field = NULL; tmp_str = GeoIP_code_by_id(geoip_id); if (tmp_str) { ib_field_create(&tmp_field, tx->mp, IB_FIELD_NAME("country_code"), IB_FTYPE_NULSTR, ib_ftype_nulstr_in(tmp_str)); ib_field_list_add(geoip_lst, tmp_field); } tmp_str = GeoIP_code3_by_id(geoip_id); if (tmp_str) { ib_field_create(&tmp_field, tx->mp, IB_FIELD_NAME("country_code3"), IB_FTYPE_NULSTR, ib_ftype_nulstr_in(tmp_str)); ib_field_list_add(geoip_lst, tmp_field); } tmp_str = GeoIP_country_name_by_id(mod_data->geoip_db, geoip_id); if (tmp_str) { ib_field_create(&tmp_field, tx->mp, IB_FIELD_NAME("country_name"), IB_FTYPE_NULSTR, ib_ftype_nulstr_in(tmp_str)); ib_field_list_add(geoip_lst, tmp_field); } tmp_str = GeoIP_continent_by_id(geoip_id); if (tmp_str) { ib_field_create(&tmp_field, tx->mp, IB_FIELD_NAME("continent_code"), IB_FTYPE_NULSTR, ib_ftype_nulstr_in(tmp_str)); ib_field_list_add(geoip_lst, tmp_field); } } else { ib_log_debug_tx(tx, "No GeoIP record found."); ib_field_create(&tmp_field, tx->mp, IB_FIELD_NAME("country_code"), IB_FTYPE_NULSTR, ib_ftype_nulstr_in("O1")); ib_field_list_add(geoip_lst, tmp_field); ib_field_create(&tmp_field, tx->mp, IB_FIELD_NAME("country_code3"), IB_FTYPE_NULSTR, ib_ftype_nulstr_in("O01")); ib_field_list_add(geoip_lst, tmp_field); ib_field_create(&tmp_field, tx->mp, IB_FIELD_NAME("country_name"), IB_FTYPE_NULSTR, ib_ftype_nulstr_in("Other Country")); ib_field_list_add(geoip_lst, tmp_field); ib_field_create(&tmp_field, tx->mp, IB_FIELD_NAME("continent_code"), IB_FTYPE_NULSTR, ib_ftype_nulstr_in("O1")); ib_field_list_add(geoip_lst, tmp_field); } return IB_OK; }
static GeoIPRecord * _extract_record(GeoIP * gi, unsigned int seek_record, int *next_record_ptr) { int record_pointer; unsigned char *record_buf = NULL; unsigned char *begin_record_buf = NULL; GeoIPRecord *record; int str_length = 0; int j; double latitude = 0, longitude = 0; int metroarea_combo = 0; int bytes_read = 0; int t; if (seek_record == gi->databaseSegments[0]) return NULL; record = malloc(sizeof(GeoIPRecord)); memset(record, 0, sizeof(GeoIPRecord)); record->charset = gi->charset; if (gi->databaseType == GEOIP_CITYCONFIDENCE_EDITION || gi->databaseType == GEOIP_CITYCONFIDENCEDIST_EDITION) { int fixed_rec_size = gi->record_length + ((gi->databaseType == GEOIP_CITYCONFIDENCE_EDITION) ? CITYCONFIDENCE_FIXED_RECORD : CITYCONFIDENCEDIST_FIXED_RECORD); //allocate max rec size, even for CITYCONFIDENCE_FIXED_RECORD //+4 is the max_record_length unsigned char tmp_fixed_record[CITYCONFIDENCEDIST_FIXED_RECORD + 4]; int dseg = gi->databaseSegments[0] * gi->record_length * 2 + gi->record_length; // int aligned_dseg = dseg ; int offset = seek_record - gi->databaseSegments[0] - 1; /* -1 b/c zero is not * found. but the array * start with 0 */ record_pointer = offset * fixed_rec_size + dseg + gi->dyn_seg_size; if (gi->cache == NULL) { /* read from disk */ bytes_read = pread(fileno(gi->GeoIPDatabase), tmp_fixed_record, fixed_rec_size, record_pointer); if (bytes_read != fixed_rec_size) return NULL; record->country_conf = tmp_fixed_record[0]; record->region_conf = tmp_fixed_record[1]; record->city_conf = tmp_fixed_record[2]; record->postal_conf = tmp_fixed_record[3]; record->accuracy_radius = gi->databaseType == GEOIP_CITYCONFIDENCEDIST_EDITION ? ((tmp_fixed_record[4] + (tmp_fixed_record[5] << 8)) & 0x3ff) : 0x3ff; t = fixed_rec_size - gi->record_length; record_pointer = dseg + tmp_fixed_record[t] + (tmp_fixed_record[t + 1] << 8) + (tmp_fixed_record[t + 2] << 16) ; if (gi->record_length == 4) record_pointer += (tmp_fixed_record[t + 3] << 24); begin_record_buf = record_buf = malloc(sizeof(char) * FULL_RECORD_LENGTH); bytes_read = pread(fileno(gi->GeoIPDatabase), record_buf, FULL_RECORD_LENGTH, record_pointer); if (bytes_read == 0) { /* eof or other error */ free(begin_record_buf); free(record); return NULL; } } else { record_buf = gi->cache + (long) record_pointer; record->country_conf = record_buf[0]; record->region_conf = record_buf[1]; record->city_conf = record_buf[2]; record->postal_conf = record_buf[3]; record->accuracy_radius = gi->databaseType == GEOIP_CITYCONFIDENCEDIST_EDITION ? ((record_buf[4] + (record_buf[5] << 8)) & 0x3ff) : 0x3ff; t = fixed_rec_size - gi->record_length; record_pointer = dseg + record_buf[t] + (record_buf[t + 1] << 8) + (record_buf[t + 2] << 16) ; if (gi->record_length == 4) record_pointer += (record_buf[t + 3] << 24); record_buf = gi->cache + (long) record_pointer; } } /* other city records */ else { record->country_conf = GEOIP_UNKNOWN_CONF; record->region_conf = GEOIP_UNKNOWN_CONF; record->city_conf = GEOIP_UNKNOWN_CONF; record->postal_conf = GEOIP_UNKNOWN_CONF; record->accuracy_radius = GEOIP_UNKNOWN_ACCURACY_RADIUS; record_pointer = seek_record + (2 * gi->record_length - 1) * gi->databaseSegments[0]; if (gi->cache == NULL) { begin_record_buf = record_buf = malloc(sizeof(char) * FULL_RECORD_LENGTH); bytes_read = pread(fileno(gi->GeoIPDatabase), record_buf, FULL_RECORD_LENGTH, record_pointer); if (bytes_read == 0) { /* eof or other error */ free(begin_record_buf); free(record); return NULL; } } else { record_buf = gi->cache + (long) record_pointer; } } /* get country */ record->continent_code = (char *) GeoIP_country_continent[record_buf[0]]; record->country_code = (char *) GeoIP_country_code[record_buf[0]]; record->country_code3 = (char *) GeoIP_country_code3[record_buf[0]]; record->country_name = (char *) GeoIP_country_name_by_id(gi, record_buf[0]); record_buf++; /* get region */ while (record_buf[str_length] != '\0') str_length++; if (str_length > 0) { record->region = malloc(str_length + 1); strncpy(record->region, (char *) record_buf, str_length + 1); } record_buf += str_length + 1; str_length = 0; /* get city */ while (record_buf[str_length] != '\0') str_length++; if (str_length > 0) { if (gi->charset == GEOIP_CHARSET_UTF8) { record->city = _GeoIP_iso_8859_1__utf8((const char *) record_buf); } else { record->city = malloc(str_length + 1); strncpy(record->city, (const char *) record_buf, str_length + 1); } } record_buf += (str_length + 1); str_length = 0; /* get postal code */ while (record_buf[str_length] != '\0') str_length++; if (str_length > 0) { record->postal_code = malloc(str_length + 1); strncpy(record->postal_code, (char *) record_buf, str_length + 1); } record_buf += (str_length + 1); /* get latitude */ for (j = 0; j < 3; ++j) latitude += (record_buf[j] << (j * 8)); record->latitude = latitude / 10000 - 180; record_buf += 3; /* get longitude */ for (j = 0; j < 3; ++j) longitude += (record_buf[j] << (j * 8)); record->longitude = longitude / 10000 - 180; /* * get area code and metro code for post April 2002 databases and for US * locations */ if (GEOIP_CITY_EDITION_REV1 == gi->databaseType || GEOIP_CITYCONFIDENCE_EDITION == gi->databaseType) { if (!strcmp(record->country_code, "US")) { record_buf += 3; for (j = 0; j < 3; ++j) metroarea_combo += (record_buf[j] << (j * 8)); record->metro_code = metroarea_combo / 1000; record->area_code = metroarea_combo % 1000; } } if (gi->cache == NULL) free(begin_record_buf); /* Used for GeoIP_next_record */ if (next_record_ptr != NULL) *next_record_ptr = seek_record + record_buf - begin_record_buf + 3; return record; }