/* * Callback used to generate connection fields. */ static ib_status_t core_gen_connect_fields(ib_engine_t *ib, ib_state_event_type_t event, ib_conn_t *conn, void *cbdata) { ib_status_t rc; assert(ib != NULL); assert(conn != NULL); assert(event == handle_connect_event); rc = ib_data_add_bytestr(conn->data, "server_addr", (uint8_t *)conn->local_ipstr, strlen(conn->local_ipstr), NULL); if (rc != IB_OK) { return rc; } rc = ib_data_add_num(conn->data, "server_port", conn->local_port, NULL); if (rc != IB_OK) { return rc; } rc = ib_data_add_bytestr(conn->data, "remote_addr", (uint8_t *)conn->remote_ipstr, strlen(conn->remote_ipstr), NULL); if (rc != IB_OK) { return rc; } rc = ib_data_add_num(conn->data, "remote_port", conn->remote_port, NULL); if (rc != IB_OK) { return rc; } return IB_OK; }
/** * Handle request_header events for remote IP extraction. * * Extract the "request_headers" field (a list) from the transactions's * data provider instance, then loop through the list, looking for the * "X-Forwarded-For" field. If found, the first value in the (comma * separated) list replaces the local ip address string in the connection * object. * * @param[in] ib IronBee object * @param[in,out] tx Transaction object * @param[in] event Event type * @param[in] cbdata Callback data (not used) * * @returns Status code */ static ib_status_t modua_remoteip(ib_engine_t *ib, ib_tx_t *tx, ib_state_event_type_t event, void *cbdata) { assert(ib != NULL); assert(tx != NULL); assert(tx->data != NULL); assert(event == request_header_finished_event); ib_field_t *field = NULL; ib_status_t rc = IB_OK; const ib_bytestr_t *bs; const uint8_t *data; size_t len; char *buf; uint8_t *comma; const ib_list_t *list; const ib_list_node_t *node; const ib_field_t *forwarded; uint8_t *stripped; size_t num; ib_flags_t flags; ib_log_debug3_tx(tx, "Checking for alternate remote address"); /* Extract the X-Forwarded-For from the provider instance */ rc = ib_data_get(tx->data, "request_headers:X-Forwarded-For", &field); if ( (field == NULL) || (rc != IB_OK) ) { ib_log_debug_tx(tx, "No X-Forwarded-For field"); return IB_OK; } /* Because we asked for a filtered item, what we get back is a list */ rc = ib_field_value(field, ib_ftype_list_out(&list)); if (rc != IB_OK) { ib_log_debug_tx(tx, "No request header collection"); return rc; } num = ib_list_elements(list); if (num == 0) { ib_log_debug_tx(tx, "No X-Forwarded-For header found"); return rc; } else if (num != 1) { ib_log_debug_tx(tx, "%zd X-Forwarded-For headers found: ignoring", num); return rc; } node = ib_list_last_const(list); if ( (node == NULL) || (node->data == NULL) ) { ib_log_notice_tx(tx, "Invalid X-Forwarded-For header found"); return rc; } forwarded = (const ib_field_t *)node->data; /* Found it: copy the data into a newly allocated string buffer */ rc = ib_field_value_type(forwarded, ib_ftype_bytestr_out(&bs), IB_FTYPE_BYTESTR); if (rc != IB_OK) { ib_log_notice_tx(tx, "Invalid X-Forwarded-For header value"); return rc; } if (bs == NULL) { ib_log_notice_tx(tx, "X-Forwarded-For header not a bytestr"); return IB_EINVAL; } len = ib_bytestr_length(bs); data = ib_bytestr_const_ptr(bs); /* Search for a comma in the buffer */ comma = memchr(data, ',', len); if (comma != NULL) { len = comma - data; } /* Trim whitespace */ stripped = (uint8_t *)data; rc = ib_strtrim_lr_ex(IB_STROP_INPLACE, tx->mp, stripped, len, &stripped, &len, &flags); if (rc != IB_OK) { return rc; } /* Verify that it looks like a valid IP v4/6 address */ rc = ib_ip_validate_ex((const char *)stripped, len); if (rc != IB_OK) { ib_log_error_tx(tx, "X-Forwarded-For \"%.*s\" is not a valid IP address", (int)len, stripped ); return IB_OK; } /* Allocate memory for copy of stripped string */ buf = (char *)ib_mpool_alloc(tx->mp, len+1); if (buf == NULL) { ib_log_error_tx(tx, "Failed to allocate %zd bytes for remote address", len+1); return IB_EALLOC; } /* Copy the string out */ memcpy(buf, stripped, len); buf[len] = '\0'; ib_log_debug_tx(tx, "Remote address changed to \"%s\"", buf); /* This will lose the pointer to the original address * buffer, but it should be cleaned up with the rest * of the memory pool. */ tx->er_ipstr = buf; /* Update the remote address field in the tx collection */ rc = ib_data_add_bytestr(tx->data, "remote_addr", (uint8_t*)buf, len, NULL); if (rc != IB_OK) { ib_log_error_tx(tx, "Failed to create remote address TX field: %s", ib_status_to_string(rc)); return rc; } return IB_OK; }
/** * Called to initialize data in a new connection. */ static ib_status_t ironbee_conn_init(ib_engine_t *ib, ib_state_event_type_t event, ib_conn_t *iconn, void *cbdata) { assert(event == conn_opened_event); //server_rec *s = cbdata; conn_rec *c = (conn_rec *)iconn->server_ctx; ib_status_t rc; ib_log_debug3(ib, "Initializing connection remote=%s:%d local=%s:%d", c->remote_ip, c->remote_addr->port, c->local_ip, c->local_addr->port); /* * Create connection fields */ /* remote_ip */ iconn->remote_ipstr = c->remote_ip; rc = ib_data_add_bytestr(iconn->dpi, "remote_ip", (uint8_t *)c->remote_ip, strlen(c->remote_ip), NULL); if (rc != IB_OK) { return rc; } /* remote_port */ iconn->remote_port = c->remote_addr->port; rc = ib_data_add_num(iconn->dpi, "remote_port", c->remote_addr->port, NULL); if (rc != IB_OK) { return rc; } /* local_ip */ iconn->local_ipstr = c->local_ip; rc = ib_data_add_bytestr(iconn->dpi, "local_ip", (uint8_t *)c->remote_ip, strlen(c->remote_ip), NULL); if (rc != IB_OK) { return rc; } /* local_port */ iconn->local_port = c->local_addr->port; rc = ib_data_add_num(iconn->dpi, "local_port", c->local_addr->port, NULL); if (rc != IB_OK) { return rc; } 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); }