char *get_conversation_port(wmem_allocator_t *allocator, guint32 port, port_type ptype, gboolean resolve_names) { if(!resolve_names) ptype = PT_NONE; switch(ptype) { case(PT_TCP): return tcp_port_to_display(allocator, port); case(PT_UDP): return udp_port_to_display(allocator, port); case(PT_SCTP): return sctp_port_to_display(allocator, port); default: return wmem_strdup_printf(allocator, "%d", port); } }
bool FollowStreamDialog::follow(QString previous_filter, bool use_stream_index) { int tmp_fd; QString follow_filter; const char *hostname0 = NULL, *hostname1 = NULL; char *port0 = NULL, *port1 = NULL; QString server_to_client_string; QString client_to_server_string; QString both_directions_string; follow_stats_t stats; tcp_stream_chunk sc; size_t nchars; gboolean is_tcp = FALSE, is_udp = FALSE; beginRetapPackets(); resetStream(); if (file_closed_) { QMessageBox::warning(this, tr("No capture file."), tr("Please make sure you have a capture file opened.")); return false; } if (cap_file_.capFile()->edt == NULL) { QMessageBox::warning(this, tr("Error following stream."), tr("Capture file invalid.")); return false; } proto_get_frame_protocols(cap_file_.capFile()->edt->pi.layers, NULL, &is_tcp, &is_udp, NULL, NULL, NULL, NULL); switch (follow_type_) { case FOLLOW_TCP: if (!is_tcp) { QMessageBox::warning(this, tr("Error following stream."), tr("Please make sure you have a TCP packet selected.")); return false; } break; case FOLLOW_UDP: if (!is_udp) { QMessageBox::warning(this, tr("Error following stream."), tr("Please make sure you have a UDP packet selected.")); return false; } break; case FOLLOW_SSL: /* we got ssl so we can follow */ removeStreamControls(); if (!epan_dissect_packet_contains_field(cap_file_.capFile()->edt, "ssl")) { QMessageBox::critical(this, tr("Error following stream."), tr("Please make sure you have an SSL packet selected.")); return false; } break; } if (follow_type_ == FOLLOW_TCP || follow_type_ == FOLLOW_SSL) { /* Create a new filter that matches all packets in the TCP stream, and set the display filter entry accordingly */ reset_tcp_reassembly(); } else { reset_udp_follow(); } if (use_stream_index) { follow_filter = gchar_free_to_qstring( build_follow_index_filter((follow_type_ == FOLLOW_TCP) ? TCP_STREAM : UDP_STREAM)); } else { follow_filter = gchar_free_to_qstring(build_follow_conv_filter(&cap_file_.capFile()->edt->pi)); } if (follow_filter.isEmpty()) { QMessageBox::warning(this, tr("Error creating filter for this stream."), tr("A transport or network layer header is needed.")); return false; } if (follow_type_ == FOLLOW_TCP || follow_type_ == FOLLOW_SSL) { /* Create a temporary file into which to dump the reassembled data from the TCP stream, and set "data_out_file" to refer to it, so that the TCP code will write to it. XXX - it might be nicer to just have the TCP code directly append stuff to the text widget for the TCP stream window, if we can arrange that said window not pop up until we're done. */ gchar *data_out_filename; tmp_fd = create_tempfile(&data_out_filename, "follow"); data_out_filename_ = data_out_filename; if (tmp_fd == -1) { QMessageBox::warning(this, "Error", "Could not create temporary file %1: %2", data_out_filename_, g_strerror(errno)); data_out_filename_.clear(); return false; } data_out_file = fdopen(tmp_fd, "w+b"); if (data_out_file == NULL) { QMessageBox::warning(this, "Error", "Could not create temporary file %1: %2", data_out_filename_, g_strerror(errno)); //ws_close(tmp_fd); ws_unlink(data_out_filename_.toUtf8().constData()); data_out_filename_.clear(); return false; } } /* append the negation */ if(!previous_filter.isEmpty()) { filter_out_filter_ = QString("%1 and !(%2)") .arg(previous_filter).arg(follow_filter); } else { filter_out_filter_ = QString("!(%1)").arg(follow_filter); } switch (follow_type_) { case FOLLOW_TCP: { int stream_count = get_tcp_stream_count() - 1; ui->streamNumberSpinBox->blockSignals(true); ui->streamNumberSpinBox->setMaximum(stream_count); ui->streamNumberSpinBox->setValue(get_follow_index(TCP_STREAM)); ui->streamNumberSpinBox->blockSignals(false); ui->streamNumberSpinBox->setToolTip(tr("%Ln total stream(s).", "", stream_count)); ui->streamNumberLabel->setToolTip(ui->streamNumberSpinBox->toolTip()); break; } case FOLLOW_UDP: { /* data will be passed via tap callback*/ if (!registerTapListener("udp_follow", &follow_info_, follow_filter.toUtf8().constData(), 0, NULL, udp_queue_packet_data, NULL)) { return false; } int stream_count = get_udp_stream_count() - 1; ui->streamNumberSpinBox->blockSignals(true); ui->streamNumberSpinBox->setMaximum(stream_count); ui->streamNumberSpinBox->setValue(get_follow_index(UDP_STREAM)); ui->streamNumberSpinBox->blockSignals(false); ui->streamNumberSpinBox->setToolTip(tr("%Ln total stream(s).", "", stream_count)); ui->streamNumberLabel->setToolTip(ui->streamNumberSpinBox->toolTip()); break; } case FOLLOW_SSL: /* we got ssl so we can follow */ if (!registerTapListener("ssl", &follow_info_, follow_filter.toUtf8().constData(), 0, NULL, ssl_queue_packet_data, NULL)) { return false; } break; } /* Run the display filter so it goes in effect - even if it's the same as the previous display filter. */ emit updateFilter(follow_filter, TRUE); switch (follow_type_) { case FOLLOW_TCP: break; case FOLLOW_UDP: case FOLLOW_SSL: removeTapListeners(); break; } if (follow_type_ == FOLLOW_TCP) { /* Check whether we got any data written to the file. */ if (empty_tcp_stream) { QMessageBox::warning(this, "Error", "The packets in the capture file for that stream have no data."); //ws_close(tmp_fd); ws_unlink(data_out_filename_.toUtf8().constData()); data_out_filename_.clear(); return false; } /* Go back to the top of the file and read the first tcp_stream_chunk * to ensure that the IP addresses and port numbers in the drop-down * list are tied to the correct lines displayed by follow_read_stream() * later on (which also reads from this file). Close the file when * we're done. * * We read the data now, before we pop up a window, in case the * read fails. We use the data later. */ rewind(data_out_file); nchars=fread(&sc, 1, sizeof(sc), data_out_file); if (nchars != sizeof(sc)) { if (ferror(data_out_file)) { QMessageBox::warning(this, "Error", QString(tr("Could not read from temporary file %1: %2")) .arg(data_out_filename_) .arg(g_strerror(errno))); } else { QMessageBox::warning(this, "Error", QString(tr("Short read from temporary file %1: expected %2, got %3")) .arg(data_out_filename_) .arg((unsigned long)sizeof(sc)) .arg((unsigned long)nchars)); } //ws_close(tmp_fd); ws_unlink(data_out_filename_.toUtf8().constData()); data_out_filename_.clear(); return false; } fclose(data_out_file); data_out_file = NULL; } /* Stream to show */ follow_stats(&stats); if (stats.is_ipv6) { struct e_in6_addr ipaddr; memcpy(&ipaddr, stats.ip_address[0], 16); hostname0 = get_hostname6(&ipaddr); memcpy(&ipaddr, stats.ip_address[1], 16); hostname1 = get_hostname6(&ipaddr); } else { guint32 ipaddr; memcpy(&ipaddr, stats.ip_address[0], 4); hostname0 = get_hostname(ipaddr); memcpy(&ipaddr, stats.ip_address[1], 4); hostname1 = get_hostname(ipaddr); } switch (follow_type_) { case FOLLOW_TCP: port0 = tcp_port_to_display(NULL, stats.port[0]); port1 = tcp_port_to_display(NULL, stats.port[1]); break; case FOLLOW_UDP: port0 = udp_port_to_display(NULL, stats.port[0]); port1 = udp_port_to_display(NULL, stats.port[1]); break; case FOLLOW_SSL: port0 = tcp_port_to_display(NULL, stats.port[0]); port1 = tcp_port_to_display(NULL, stats.port[1]); break; } follow_info_.is_ipv6 = stats.is_ipv6; if (follow_type_ == FOLLOW_TCP) { /* Host 0 --> Host 1 */ if ((sc.src_port == stats.port[0]) && ((stats.is_ipv6 && (memcmp(sc.src_addr, stats.ip_address[0], 16) == 0)) || (!stats.is_ipv6 && (memcmp(sc.src_addr, stats.ip_address[0], 4) == 0)))) { server_to_client_string = QString("%1:%2 %3 %4:%5 (%6)") .arg(hostname0).arg(port0) .arg(UTF8_RIGHTWARDS_ARROW) .arg(hostname1).arg(port1) .arg(gchar_free_to_qstring(format_size( stats.bytes_written[0], format_size_unit_bytes|format_size_prefix_si))); } else { server_to_client_string = QString("%1:%2 %3 %4:%5 (%6)") .arg(hostname1).arg(port1) .arg(UTF8_RIGHTWARDS_ARROW) .arg(hostname0).arg(port0) .arg(gchar_free_to_qstring(format_size( stats.bytes_written[0], format_size_unit_bytes|format_size_prefix_si))); } /* Host 1 --> Host 0 */ if ((sc.src_port == stats.port[1]) && ((stats.is_ipv6 && (memcmp(sc.src_addr, stats.ip_address[1], 16) == 0)) || (!stats.is_ipv6 && (memcmp(sc.src_addr, stats.ip_address[1], 4) == 0)))) { client_to_server_string = QString("%1:%2 %3 %4:%5 (%6)") .arg(hostname0).arg(port0) .arg(UTF8_RIGHTWARDS_ARROW) .arg(hostname1).arg(port1) .arg(gchar_free_to_qstring(format_size( stats.bytes_written[1], format_size_unit_bytes|format_size_prefix_si))); } else { client_to_server_string = QString("%1:%2 %3 %4:%5 (%6)") .arg(hostname1).arg(port1) .arg(UTF8_RIGHTWARDS_ARROW) .arg(hostname0).arg(port0) .arg(gchar_free_to_qstring(format_size( stats.bytes_written[1], format_size_unit_bytes|format_size_prefix_si))); } } else { if ((follow_info_.client_port == stats.port[0]) && ((stats.is_ipv6 && (memcmp(follow_info_.client_ip.data, stats.ip_address[0], 16) == 0)) || (!stats.is_ipv6 && (memcmp(follow_info_.client_ip.data, stats.ip_address[0], 4) == 0)))) { server_to_client_string = QString("%1:%2 %3 %4:%5 (%6)") .arg(hostname0).arg(port0) .arg(UTF8_RIGHTWARDS_ARROW) .arg(hostname1).arg(port1) .arg(gchar_free_to_qstring(format_size( follow_info_.bytes_written[0], format_size_unit_bytes|format_size_prefix_si))); client_to_server_string = QString("%1:%2 %3 %4:%5 (%6)") .arg(hostname1).arg(port1) .arg(UTF8_RIGHTWARDS_ARROW) .arg(hostname0).arg(port0) .arg(gchar_free_to_qstring(format_size( follow_info_.bytes_written[1], format_size_unit_bytes|format_size_prefix_si))); } else { server_to_client_string = QString("%1:%2 %3 %4:%5 (%6)") .arg(hostname1).arg(port1) .arg(UTF8_RIGHTWARDS_ARROW) .arg(hostname0).arg(port0) .arg(gchar_free_to_qstring(format_size( follow_info_.bytes_written[0], format_size_unit_bytes|format_size_prefix_si))); client_to_server_string = QString("%1:%2 %3 %4:%5 (%6)") .arg(hostname0).arg(port0) .arg(UTF8_RIGHTWARDS_ARROW) .arg(hostname1).arg(port1) .arg(gchar_free_to_qstring(format_size( follow_info_.bytes_written[1], format_size_unit_bytes|format_size_prefix_si))); } } wmem_free(NULL, port0); wmem_free(NULL, port1); /* Both Stream Directions */ switch (follow_type_) { case FOLLOW_TCP: both_directions_string = QString("Entire conversation (%1)") .arg(gchar_free_to_qstring(format_size( stats.bytes_written[0] + stats.bytes_written[1], format_size_unit_bytes|format_size_prefix_si))); setWindowSubtitle(tr("Follow TCP Stream (%1)").arg(follow_filter)); break; case FOLLOW_UDP: both_directions_string = QString("Entire conversation (%1)") .arg(gchar_free_to_qstring(format_size( follow_info_.bytes_written[0] + follow_info_.bytes_written[1], format_size_unit_bytes|format_size_prefix_si))); setWindowSubtitle(tr("Follow UDP Stream (%1)").arg(follow_filter)); break; case FOLLOW_SSL: both_directions_string = QString("Entire conversation (%1)") .arg(gchar_free_to_qstring(format_size( follow_info_.bytes_written[0] + follow_info_.bytes_written[1], format_size_unit_bytes|format_size_prefix_si))); setWindowSubtitle(tr("Follow SSL Stream (%1)").arg(follow_filter)); break; } ui->cbDirections->clear(); ui->cbDirections->addItem(both_directions_string); ui->cbDirections->addItem(client_to_server_string); ui->cbDirections->addItem(server_to_client_string); followStream(); fillHintLabel(-1); if (data_out_file) { fclose(data_out_file); data_out_file = NULL; } endRetapPackets(); return true; }