示例#1
0
文件: geoip.c 项目: poona/ironbee
/**
 * 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;
}
示例#2
0
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;
}