VALUE rbhtp_connp_req_data( VALUE self, VALUE timestamp, VALUE data ) { if ( strncmp( "Time", rb_class2name( CLASS_OF( timestamp ) ), 4 ) != 0 ) { rb_raise( rb_eTypeError, "First argument must be a Time." ); return Qnil; } StringValue( data ); // try to make data a string. Check_Type( data, T_STRING ); size_t len = RSTRING_LEN( data ); char* data_c = RSTRING_PTR( data ); htp_time_t timestamp_c; timestamp_c.tv_sec = FIX2INT( rb_funcall( timestamp, rb_intern( "tv_sec" ), 0 ) ); timestamp_c.tv_usec = FIX2INT( rb_funcall( timestamp, rb_intern( "tv_usec" ), 0 ) ); VALUE connp_r = rb_iv_get( self, "@connp" ); htp_connp_t* connp = NULL; Data_Get_Struct( connp_r, htp_connp_t, connp ); int result = htp_connp_req_data( connp, ×tamp_c, (unsigned char*)data_c, len ); return INT2FIX( result ); }
/** * Closes the connection associated with the supplied parser. * * @param connp * @param timestamp */ void htp_connp_close(htp_connp_t *connp, htp_time_t timestamp) { // Update internal information connp->conn->close_timestamp = timestamp; connp->in_status = STREAM_STATE_CLOSED; connp->out_status = STREAM_STATE_CLOSED; // Call the parsers one last time, which will allow them // to process the events that depend on stream closure htp_connp_req_data(connp, timestamp, NULL, 0); htp_connp_res_data(connp, timestamp, NULL, 0); }
void htp_connp_close(htp_connp_t *connp, const htp_time_t *timestamp) { // Close the underlying connection. htp_conn_close(connp->conn, timestamp); // Update internal flags connp->in_status = HTP_STREAM_CLOSED; connp->out_status = HTP_STREAM_CLOSED; // Call the parsers one last time, which will allow them // to process the events that depend on stream closure htp_connp_req_data(connp, timestamp, NULL, 0); htp_connp_res_data(connp, timestamp, NULL, 0); }
/** * Closes the connection associated with the supplied parser. * * @param connp * @param timestamp Optional. */ void htp_connp_close(htp_connp_t *connp, htp_time_t *timestamp) { // Update timestamp if (timestamp != NULL) { memcpy(&connp->conn->close_timestamp, timestamp, sizeof(*timestamp)); } // Update internal flags connp->in_status = STREAM_STATE_CLOSED; connp->out_status = STREAM_STATE_CLOSED; // Call the parsers one last time, which will allow them // to process the events that depend on stream closure htp_connp_req_data(connp, timestamp, NULL, 0); htp_connp_res_data(connp, timestamp, NULL, 0); }
/** * Process as much buffered inbound and outbound data as possible * (in that order) * * @param sd */ void process_stored_stream_data(stream_data *sd) { int loop = 0; do { // Reset loop loop = 0; // Send as much inbound data as possible while((sd->connp->in_status == STREAM_STATE_DATA)&&(list_size(sd->inbound_chunks) > 0)) { chunk_t *chunk = (chunk_t *)list_get(sd->inbound_chunks, 0); int rc = htp_connp_req_data(sd->connp, 0, chunk->data + chunk->consumed, chunk->len - chunk->consumed); if (rc == STREAM_STATE_DATA) { // The entire chunk was consumed list_shift(sd->inbound_chunks); free(chunk->data); free(chunk); } else { // Partial consumption chunk->consumed = htp_connp_req_data_consumed(sd->connp); } } // Send as much outbound data as possible while((sd->connp->out_status == STREAM_STATE_DATA)&&(list_size(sd->outbound_chunks) > 0)) { chunk_t *chunk = (chunk_t *)list_get(sd->outbound_chunks, 0); int rc = htp_connp_res_data(sd->connp, 0, chunk->data + chunk->consumed, chunk->len - chunk->consumed); if (rc == STREAM_STATE_DATA) { // The entire chunk was consumed list_shift(sd->outbound_chunks); free(chunk->data); free(chunk); } else { // Partial consumption chunk->consumed = htp_connp_res_data_consumed(sd->connp); } // Whenever we send some outbound data to the parser, // we need to go back and try to send inbound data // if we have it. loop = 1; } } while(loop); }
/** * Process a chunk of the connection stream. * * @param sd * @param direction * @param hlf */ void process_stream_data(stream_data *sd, int direction, struct half_stream *hlf) { chunk_t *chunk = NULL; int rc; //printf("#DATA direction %d bytes %d\n", sd->direction, hlf->count_new); if (sd->direction == direction) { // Inbound data switch(sd->connp->in_status) { case STREAM_STATE_NEW : case STREAM_STATE_DATA : // Send data to parser rc = htp_connp_req_data(sd->connp, 0, hlf->data, hlf->count_new); if (rc == STREAM_STATE_DATA_OTHER) { // Encountered inbound parsing block // Store partial chunk for later chunk = calloc(1, sizeof(chunk_t)); // TODO chunk->len = hlf->count_new - htp_connp_req_data_consumed(sd->connp); chunk->data = malloc(chunk->len); // TODO memcpy(chunk->data, hlf->data + htp_connp_req_data_consumed(sd->connp), chunk->len); list_add(sd->inbound_chunks, chunk); } else if (rc != STREAM_STATE_DATA) { // Inbound parsing error sd->log_level = 0; fprintf(stderr, "[#%d] Inbound parsing error: %d\n", sd->id, rc); // TODO Write connection to disk } break; case STREAM_STATE_ERROR : // Do nothing break; case STREAM_STATE_DATA_OTHER : // Store data for later chunk = calloc(1, sizeof(chunk_t)); // TODO chunk->len = hlf->count_new; chunk->data = malloc(chunk->len); // TODO memcpy(chunk->data, hlf->data, chunk->len); list_add(sd->inbound_chunks, chunk); break; } } else { // Outbound data switch(sd->connp->out_status) { case STREAM_STATE_NEW : case STREAM_STATE_DATA : // Send data to parser rc = htp_connp_res_data(sd->connp, 0, hlf->data, hlf->count_new); if (rc == STREAM_STATE_DATA_OTHER) { // Encountered outbound parsing block // Store partial chunk for later chunk = calloc(1, sizeof(chunk_t)); // TODO chunk->len = hlf->count_new - htp_connp_res_data_consumed(sd->connp); chunk->data = malloc(chunk->len); // TODO memcpy(chunk->data, hlf->data + htp_connp_res_data_consumed(sd->connp), chunk->len); list_add(sd->outbound_chunks, chunk); } else if (rc != STREAM_STATE_DATA) { // Outbound parsing error sd->log_level = 0; fprintf(stderr, "[#%d] Outbound parsing error: %d\n", sd->id, rc); } break; case STREAM_STATE_ERROR : // Do nothing break; case STREAM_STATE_DATA_OTHER : // Store data for later chunk = calloc(1, sizeof(chunk_t)); // TODO chunk->len = hlf->count_new; chunk->data = malloc(chunk->len); // TODO memcpy(chunk->data, hlf->data, chunk->len); list_add(sd->outbound_chunks, chunk); break; } } // Process as much stored data as possible process_stored_stream_data(sd); }
/** * Runs a single test. * * @param[in] filename * @param[in] cfg * @return A pointer to the instance of htp_connp_t created during * the test, or NULL if the test failed for some reason. */ int test_run_ex(const char *testsdir, const char *testname, htp_cfg_t *cfg, htp_connp_t **connp, int clone_count) { char filename[1025]; test_t test; struct timeval tv_start, tv_end; int rc; *connp = NULL; strncpy(filename, testsdir, 1024); strncat(filename, "/", 1024 - strlen(filename)); strncat(filename, testname, 1024 - strlen(filename)); // printf("Filename: %s\n", filename); // Initinialize test rc = test_init(&test, filename, clone_count); if (rc < 0) { return rc; } gettimeofday(&tv_start, NULL); test_start(&test); // Create parser *connp = htp_connp_create(cfg); if (*connp == NULL) { fprintf(stderr, "Failed to create connection parser\n"); exit(1); } htp_connp_set_user_data(*connp, (void *) 0x02); // Does the filename contain connection metdata? if (strncmp(testname, "stream", 6) == 0) { // It does; use it char *remote_addr = NULL, *local_addr = NULL; int remote_port = -1, local_port = -1; parse_filename(testname, &remote_addr, &remote_port, &local_addr, &local_port); htp_connp_open(*connp, (const char *) remote_addr, remote_port, (const char *) local_addr, local_port, &tv_start); free(remote_addr); free(local_addr); } else { // No connection metadata; provide some fake information instead htp_connp_open(*connp, (const char *) "127.0.0.1", 10000, (const char *) "127.0.0.1", 80, &tv_start); } // Find all chunks and feed them to the parser int in_data_other = 0; char *in_data = NULL; size_t in_data_len = 0; size_t in_data_offset = 0; int out_data_other = 0; char *out_data = NULL; size_t out_data_len = 0; size_t out_data_offset = 0; for (;;) { if (test_next_chunk(&test) <= 0) { break; } if (test.chunk_direction == CLIENT) { if (in_data_other) { test_destroy(&test); fprintf(stderr, "Unable to buffer more than one inbound chunk.\n"); return -1; } rc = htp_connp_req_data(*connp, &tv_start, test.chunk, test.chunk_len); if (rc == HTP_STREAM_ERROR) { test_destroy(&test); return -101; } if (rc == HTP_STREAM_DATA_OTHER) { // Parser needs to see the outbound stream in order to continue // parsing the inbound stream. in_data_other = 1; in_data = test.chunk; in_data_len = test.chunk_len; in_data_offset = htp_connp_req_data_consumed(*connp); } } else { if (out_data_other) { rc = htp_connp_res_data(*connp, &tv_start, out_data + out_data_offset, out_data_len - out_data_offset); if (rc == HTP_STREAM_ERROR) { test_destroy(&test); return -104; } out_data_other = 0; } rc = htp_connp_res_data(*connp, &tv_start, test.chunk, test.chunk_len); if (rc == HTP_STREAM_ERROR) { test_destroy(&test); return -102; } if (rc == HTP_STREAM_DATA_OTHER) { // Parser needs to see the outbound stream in order to continue // parsing the inbound stream. out_data_other = 1; out_data = test.chunk; out_data_len = test.chunk_len; out_data_offset = htp_connp_res_data_consumed(*connp); // printf("# YYY out offset is %d\n", out_data_offset); } if (in_data_other) { rc = htp_connp_req_data(*connp, &tv_start, in_data + in_data_offset, in_data_len - in_data_offset); if (rc == HTP_STREAM_ERROR) { test_destroy(&test); return -103; } in_data_other = 0; } } } if (out_data_other) { rc = htp_connp_res_data(*connp, &tv_start, out_data + out_data_offset, out_data_len - out_data_offset); if (rc == HTP_STREAM_ERROR) { test_destroy(&test); return -104; } out_data_other = 0; } gettimeofday(&tv_end, NULL); // Close the connection htp_connp_close(*connp, &tv_end); // Clean up test_destroy(&test); return 1; }