/** * 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; }
/** * Parse the user agent header, splitting into component fields. * * Attempt to tokenize the user agent string passed in, storing the * result in the DPI associated with the transaction. * * @param[in] ib IronBee object * @param[in,out] tx Transaction object * @param[in] bs Byte string containing the agent string * * @returns Status code */ static ib_status_t modua_agent_fields(ib_engine_t *ib, ib_tx_t *tx, const ib_bytestr_t *bs) { const modua_match_rule_t *rule = NULL; ib_field_t *agent_list = NULL; char *product = NULL; char *platform = NULL; char *extra = NULL; char *agent; char *buf; size_t len; ib_status_t rc; /* Get the length of the byte string */ len = ib_bytestr_length(bs); /* Allocate memory for a copy of the string to split up below. */ buf = (char *)ib_mpool_calloc(tx->mp, 1, len+1); if (buf == NULL) { ib_log_error_tx(tx, "Failed to allocate %zd bytes for agent string", len+1); return IB_EALLOC; } /* Copy the string out */ memcpy(buf, ib_bytestr_const_ptr(bs), len); buf[len] = '\0'; ib_log_debug_tx(tx, "Found user agent: '%s'", buf); /* Copy the agent string */ agent = (char *)ib_mpool_strdup(tx->mp, buf); if (agent == NULL) { ib_log_error_tx(tx, "Failed to allocate copy of agent string"); return IB_EALLOC; } /* Parse the user agent string */ rc = modua_parse_uastring(buf, &product, &platform, &extra); if (rc != IB_OK) { ib_log_debug_tx(tx, "Failed to parse User Agent string '%s'", agent); return IB_OK; } /* Categorize the parsed string */ rule = modua_match_cat_rules(product, platform, extra); if (rule == NULL) { ib_log_debug_tx(tx, "No rule matched" ); } else { ib_log_debug_tx(tx, "Matched to rule #%d / category '%s'", rule->rule_num, rule->category ); } /* Build a new list. */ rc = ib_data_add_list(tx->data, "UA", &agent_list); if (rc != IB_OK) { ib_log_alert_tx(tx, "Unable to add UserAgent list to DPI."); return rc; } /* Store Agent */ rc = modua_store_field(ib, tx->mp, agent_list, "agent", agent); if (rc != IB_OK) { return rc; } /* Store product */ rc = modua_store_field(ib, tx->mp, agent_list, "PRODUCT", product); if (rc != IB_OK) { return rc; } /* Store Platform */ rc = modua_store_field(ib, tx->mp, agent_list, "OS", platform); if (rc != IB_OK) { return rc; } /* Store Extra */ rc = modua_store_field(ib, tx->mp, agent_list, "extra", extra); if (rc != IB_OK) { return rc; } /* Store Extra */ if (rule != NULL) { rc = modua_store_field(ib, tx->mp, agent_list, "category", rule->category); } else { rc = modua_store_field(ib, tx->mp, agent_list, "category", NULL ); } if (rc != IB_OK) { return rc; } /* Done */ return IB_OK; }
/** * Set the matches into the given field name as .0, .1, .2 ... .9. * * @param[in] ib The IronBee engine to log to. * @param[in] tx The transaction to store the values into (tx->dpi). * @param[in] field_name The field to populate with Regex matches. * @param[in] ovector The vector of integer pairs of matches from PCRE. * @param[in] matches The number of matches. * @param[in] subject The matched-against string data. * * @returns IB_OK or IB_EALLOC. */ static ib_status_t pcre_set_matches(ib_engine_t *ib, ib_tx_t *tx, const char* field_name, int *ovector, int matches, const char *subject) { IB_FTRACE_INIT(); /* IronBee status. */ ib_status_t rc; /* Iterator. */ int i; /* Length of field_name. */ const int field_name_sz = strlen(field_name); /* The length of the match. */ size_t match_len; /* The first character in the match. */ const char* match_start; /* +3 = '.', [digit], and \0. */ char *full_field_name = malloc(field_name_sz+3); /* Holder to build an optional debug message in. */ char *debug_msg; /* Holder for a copy of the field value when creating a new field. */ ib_bytestr_t *field_value; /* Field holder. */ ib_field_t *ib_field; /* Ensure the above allocations happened. */ if (full_field_name==NULL) { IB_FTRACE_RET_STATUS(IB_EALLOC); } rc = ensure_field_exists(ib, tx, field_name); if (rc != IB_OK) { ib_log_alert_tx(tx, "Could not ensure that field %s was a list.", field_name); free(full_field_name); IB_FTRACE_RET_STATUS(IB_EINVAL); } /* We have a match! Now populate TX.0-9 in tx->dpi. */ for (i=0; i<matches; i++) { /* Build the field name. Typically TX.0, TX.1 ... TX.9 */ sprintf(full_field_name, "%s.%d", field_name, i); /* Readability. Mark the start and length of the string. */ match_start = subject+ovector[i*2]; match_len = ovector[i*2+1] - ovector[i*2]; /* If debugging this, copy the string value out and print it to the * log. This could be dangerous as there could be non-character * values in the match. */ if (ib_log_get_level(ib) >= 7) { debug_msg = malloc(match_len+1); /* Notice: Don't provoke a crash if malloc fails. */ if (debug_msg != NULL) { memcpy(debug_msg, match_start, match_len); debug_msg[match_len] = '\0'; ib_log_debug2_tx(tx, "REGEX Setting %s=%s", full_field_name, debug_msg); free(debug_msg); } } ib_data_get(tx->dpi, full_field_name, &ib_field); if (ib_field == NULL) { ib_data_add_bytestr(tx->dpi, full_field_name, (uint8_t*)subject+ovector[i*2], match_len, NULL); } else { ib_bytestr_dup_mem(&field_value, tx->mp, (const uint8_t*)match_start, match_len); ib_field_setv_no_copy( ib_field, ib_ftype_bytestr_mutable_in(field_value) ); } } IB_FTRACE_RET_STATUS(IB_OK); }