Qt: Start capture from the command line.

Fill in the capture-related mise en place so that -k and -i work. Get
rid of global_capture_session in ui/qt and make it a member of
MainWindow.

Copy over privilege checking from GTK+.

Move the global capture session struct to MainWindow.

Change-Id: Iab5ec683860a40255a7e1d82e3872ced24fd55cb
Reviewed-on: https://code.wireshark.org/review/4382
Reviewed-by: Gerald Combs <gerald@wireshark.org>
This commit is contained in:
Gerald Combs 2014-09-29 16:27:11 -07:00
parent 5330875336
commit ced39b6de8
5 changed files with 205 additions and 28 deletions

View File

@ -37,6 +37,7 @@ if (WERROR)
)
endif()
file(GLOB CAPCHILD_HEADERS capture_session.h)
add_library(capchild STATIC
${CAPCHILD_SRC}

View File

@ -113,13 +113,14 @@
#ifdef HAVE_LIBPCAP
# include "caputils/capture_ifinfo.h"
# include "ui/capture.h"
# include <capchild/capture_sync.h>
# include "capchild/capture_sync.h"
#endif
#ifdef _WIN32
# include "caputils/capture-wpcap.h"
# include "caputils/capture_wpcap_packet.h"
# include <tchar.h> /* Needed for Unicode */
# include <wsutil/os_version_info.h>
# include <wsutil/unicode-utils.h>
# include <commctrl.h>
# include <shellapi.h>
@ -132,22 +133,22 @@
//# include "airpcap_gui_utils.h"
#endif
#include <epan/crypt/airpdcap_ws.h>
#include "epan/crypt/airpdcap_ws.h"
#include <QDebug>
#include <QDateTime>
#include <QLibraryInfo>
#include <QLocale>
#include <QMessageBox>
#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
#include <QTextCodec>
#endif
#include <qtranslator.h>
#include <qlocale.h>
#include <qlibraryinfo.h>
#include <QTranslator>
#include "conversation_dialog.h"
#include "endpoint_dialog.h"
#ifdef HAVE_LIBPCAP
capture_options global_capture_opts;
capture_session global_capture_session;
#endif
capture_file cfile;
@ -428,6 +429,44 @@ get_wireshark_runtime_info(GString *str)
}
}
/* Check if there's something important to tell the user during startup.
* We want to do this *after* showing the main window so that any windows
* we pop up will be above the main window.
*/
static void
check_and_warn_user_startup(const QString &cf_name)
{
#ifndef _WIN32
Q_UNUSED(cf_name)
#endif
gchar *cur_user, *cur_group;
/* Tell the user not to run as root. */
if (running_with_special_privs() && recent.privs_warn_if_elevated) {
cur_user = get_cur_username();
cur_group = get_cur_groupname();
simple_message_box(ESD_TYPE_WARN, &recent.privs_warn_if_elevated,
"Running as user \"%s\" and group \"%s\".\n"
"This could be dangerous.\n\n"
"If you're running Wireshark this way in order to perform live capture, "
"you may want to be aware that there is a better way documented at\n"
"http://wiki.wireshark.org/CaptureSetup/CapturePrivileges", cur_user, cur_group);
g_free(cur_user);
g_free(cur_group);
}
#ifdef _WIN32
/* Warn the user if npf.sys isn't loaded. */
if (!get_stdin_capture() && cf_name.isEmpty() && !npf_sys_is_running() && recent.privs_warn_if_no_npf && get_windows_major_version() >= 6) {
simple_message_box(ESD_TYPE_WARN, &recent.privs_warn_if_no_npf, "%s",
"The NPF driver isn't running. You may have trouble\n"
"capturing or listing interfaces.");
}
#endif
}
/* And now our feature presentation... [ fade to music ] */
int main(int argc, char *argv[])
{
@ -447,7 +486,7 @@ int main(int argc, char *argv[])
#ifdef HAVE_LIBPCAP
int err;
gboolean start_capture = FALSE;
// gboolean list_link_layer_types = FALSE;
gboolean list_link_layer_types = FALSE;
GList *if_list;
gchar *err_str;
int status;
@ -461,6 +500,7 @@ int main(int argc, char *argv[])
#endif
e_prefs *prefs_p;
char badopt;
guint go_to_packet = 0;
cmdarg_err_init(wireshark_cmdarg_err, wireshark_cmdarg_err_cont);
@ -540,8 +580,8 @@ int main(int argc, char *argv[])
#endif /* _WIN32 */
QString locale;
QString *cf_name = NULL;
QString *display_filter = NULL;
QString cf_name;
QString display_filter;
int optind_initial;
unsigned int in_file_type = WTAP_TYPE_AUTO;
@ -790,8 +830,6 @@ int main(int argc, char *argv[])
/* Set the initial values in the capture options. This might be overwritten
by preference settings and then again by the command line parameters. */
capture_opts_init(&global_capture_opts);
capture_session_init(&global_capture_session, (void *)&cfile);
#endif
init_report_err(failure_alert_box, open_failure_alert_box,
@ -931,7 +969,7 @@ int main(int argc, char *argv[])
/* Not supported yet */
break;
case 'g': /* Go to packet with the given packet number */
/* Not supported yet */
go_to_packet = get_positive_int(optarg, "go to packet");
break;
case 'J': /* Jump to the first packet which matches the filter criteria */
/* Not supported yet */
@ -940,7 +978,12 @@ int main(int argc, char *argv[])
/* Not supported yet */
break;
case 'L': /* Print list of link-layer types and exit */
/* Not supported yet */
#ifdef HAVE_LIBPCAP
list_link_layer_types = TRUE;
#else
capture_option_specified = TRUE;
arg_error = TRUE;
#endif
break;
case 'm': /* Fixed-width font for the display */
/* Not supported yet */
@ -1000,7 +1043,7 @@ int main(int argc, char *argv[])
/* Path settings were already processed just ignore them this time*/
break;
case 'r':
cf_name = new QString(optarg);
cf_name = optarg;
break;
case 'R': /* Read file filter */
/* Not supported yet */
@ -1084,7 +1127,7 @@ int main(int argc, char *argv[])
argc -= optind;
argv += optind;
if (argc >= 1) {
if (cf_name != NULL) {
if (!cf_name.isEmpty()) {
/*
* Input file name specified with "-r" *and* specified as a regular
* command-line argument.
@ -1102,7 +1145,7 @@ int main(int argc, char *argv[])
* file - yes, you could have "-r" as the last part of the command,
* but that's a bit ugly.
*/
cf_name = new QString(g_strdup(argv[0]));
cf_name = argv[0];
}
argc--;
@ -1139,6 +1182,105 @@ int main(int argc, char *argv[])
#ifdef HAVE_LIBPCAP
fill_in_local_interfaces(main_window_update);
if (start_capture && list_link_layer_types) {
/* Specifying *both* is bogus. */
cmdarg_err("You can't specify both -L and a live capture.");
exit(1);
}
if (list_link_layer_types) {
/* We're supposed to list the link-layer types for an interface;
did the user also specify a capture file to be read? */
if (!cf_name.isEmpty()) {
/* Yes - that's bogus. */
cmdarg_err("You can't specify -L and a capture file to be read.");
exit(1);
}
/* No - did they specify a ring buffer option? */
if (global_capture_opts.multi_files_on) {
cmdarg_err("Ring buffer requested, but a capture isn't being done.");
exit(1);
}
} else {
/* We're supposed to do a live capture; did the user also specify
a capture file to be read? */
if (start_capture && !cf_name.isEmpty()) {
/* Yes - that's bogus. */
cmdarg_err("You can't specify both a live capture and a capture file to be read.");
exit(1);
}
/* No - was the ring buffer option specified and, if so, does it make
sense? */
if (global_capture_opts.multi_files_on) {
/* Ring buffer works only under certain conditions:
a) ring buffer does not work with temporary files;
b) real_time_mode and multi_files_on are mutually exclusive -
real_time_mode takes precedence;
c) it makes no sense to enable the ring buffer if the maximum
file size is set to "infinite". */
if (global_capture_opts.save_file == NULL) {
cmdarg_err("Ring buffer requested, but capture isn't being saved to a permanent file.");
global_capture_opts.multi_files_on = FALSE;
}
if (!global_capture_opts.has_autostop_filesize && !global_capture_opts.has_file_duration) {
cmdarg_err("Ring buffer requested, but no maximum capture file size or duration were specified.");
/* XXX - this must be redesigned as the conditions changed */
}
}
}
if (start_capture || list_link_layer_types) {
/* We're supposed to do a live capture or get a list of link-layer
types for a live capture device; if the user didn't specify an
interface to use, pick a default. */
status = capture_opts_default_iface_if_necessary(&global_capture_opts,
((prefs_p->capture_device) && (*prefs_p->capture_device != '\0')) ? get_if_name(prefs_p->capture_device) : NULL);
if (status != 0) {
exit(status);
}
}
if (list_link_layer_types) {
/* Get the list of link-layer types for the capture devices. */
if_capabilities_t *caps;
guint i;
interface_t device;
for (i = 0; i < global_capture_opts.all_ifaces->len; i++) {
device = g_array_index(global_capture_opts.all_ifaces, interface_t, i);
if (device.selected) {
#if defined(HAVE_PCAP_CREATE)
caps = capture_get_if_capabilities(device.name, device.monitor_mode_supported, &err_str, main_window_update);
#else
caps = capture_get_if_capabilities(device.name, FALSE, &err_str,main_window_update);
#endif
if (caps == NULL) {
cmdarg_err("%s", err_str);
g_free(err_str);
exit(2);
}
if (caps->data_link_types == NULL) {
cmdarg_err("The capture device \"%s\" has no data link types.", device.name);
exit(2);
}
#ifdef _WIN32
create_console();
#endif /* _WIN32 */
#if defined(HAVE_PCAP_CREATE)
capture_opts_print_if_capabilities(caps, device.name, device.monitor_mode_supported);
#else
capture_opts_print_if_capabilities(caps, device.name, FALSE);
#endif
#ifdef _WIN32
destroy_console();
#endif /* _WIN32 */
free_if_capabilities(caps);
}
}
exit(0);
}
capture_opts_trim_snaplen(&global_capture_opts, MIN_PACKET_SIZE);
capture_opts_trim_ring_num_files(&global_capture_opts);
#endif /* HAVE_LIBPCAP */
@ -1214,15 +1356,11 @@ int main(int argc, char *argv[])
g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_INFO, "Wireshark is up and ready to go");
/* user could specify filename, or display filter, or both */
if (cf_name != NULL || display_filter != NULL) {
if (display_filter == NULL)
display_filter = new QString();
if (cf_name == NULL)
cf_name = new QString();
if (!cf_name.isEmpty()) {
// XXX We need to call cf_open + start_requested_stats + cf_read
// similar to gtk/main.c:3110.
main_w->openCaptureFile(*cf_name, *display_filter, in_file_type);
main_w->openCaptureFile(cf_name, display_filter, in_file_type);
/* Open stat windows; we do so after creating the main window,
to avoid Qt warnings, and after successfully opening the
@ -1233,6 +1371,42 @@ int main(int argc, char *argv[])
filter. */
start_requested_stats();
}
#ifdef HAVE_LIBPCAP
else {
if (start_capture) {
if (global_capture_opts.save_file != NULL) {
/* Save the directory name for future file dialogs. */
/* (get_dirname overwrites filename) */
gchar *s = get_dirname(g_strdup(global_capture_opts.save_file));
set_last_open_dir(s);
g_free(s);
}
/* "-k" was specified; start a capture. */
// show_main_window(FALSE);
check_and_warn_user_startup(cf_name);
/* If no user interfaces were specified on the command line,
copy the list of selected interfaces to the set of interfaces
to use for this capture. */
if (global_capture_opts.ifaces->len == 0)
collect_ifaces(&global_capture_opts);
cfile.window = main_w;
if (capture_start(&global_capture_opts, main_w->captureSession(), main_window_update)) {
/* The capture started. Open stat windows; we do so after creating
the main window, to avoid GTK warnings, and after successfully
opening the capture file, so we know we have something to compute
stats on, and after registering all dissectors, so that MATE will
have registered its field array and we can have a tap filter with
one of MATE's late-registered fields as part of the filter. */
start_requested_stats();
}
}
/* if the user didn't supply a capture filter, use the one to filter out remote connections like SSH */
if (!start_capture && !global_capture_opts.default_options.cfilter) {
global_capture_opts.default_options.cfilter = g_strdup(get_conn_cfilter());
}
}
#endif /* HAVE_LIBPCAP */
g_main_loop_new(NULL, FALSE);
return wsApp->exec();

View File

@ -162,6 +162,7 @@ MainWindow::MainWindow(QWidget *parent) :
this, SLOT(openStatCommandDialog(QString,const char*,void*)));
}
gbl_cur_main_window_ = this;
capture_session_init(&cap_session_, (void *)&cfile);
main_ui_->setupUi(this);
setTitlebarForCaptureFile();
setMenusForCaptureFile();

View File

@ -76,6 +76,7 @@ public:
void setPipeInputHandler(gint source, gpointer user_data, int *child_process, pipe_input_cb_t input_cb);
QString getFilter();
capture_session *captureSession() { return &cap_session_; }
protected:
bool eventFilter(QObject *obj, QEvent *event);
@ -106,6 +107,7 @@ private:
MainWelcome *main_welcome_;
DisplayFilterCombo *df_combo_box_;
capture_file *cap_file_;
capture_session cap_session_;
QFont mono_font_;
// XXX - packet_list_, proto_tree_, and byte_view_tab_ should
// probably be full-on values instead of pointers.

View File

@ -373,7 +373,6 @@ void MainWindow::filterAction(QString &action_filter, FilterAction::Action actio
void MainWindow::captureCapturePrepared(capture_session *cap_session) {
#ifdef HAVE_LIBPCAP
qDebug() << "FIX captureCapturePrepared";
setTitlebarForCaptureInProgress();
setWindowIcon(wsApp->captureIcon());
@ -625,18 +624,18 @@ void MainWindow::startCapture() {
// main_auto_scroll_live_changed(auto_scroll_live);
/* XXX - can this ever happen? */
if (global_capture_session.state != CAPTURE_STOPPED)
if (cap_session_.state != CAPTURE_STOPPED)
return;
/* close the currently loaded capture file */
cf_close((capture_file *) global_capture_session.cf);
cf_close((capture_file *) cap_session_.cf);
/* Copy the selected interfaces to the set of interfaces to use for
this capture. */
collect_ifaces(&global_capture_opts);
cfile.window = this;
if (capture_start(&global_capture_opts, &global_capture_session, main_window_update)) {
if (capture_start(&global_capture_opts, &cap_session_, main_window_update)) {
/* The capture succeeded, which means the capture filter syntax is
valid; add this capture filter to the recent capture filter list. */
for (i = 0; i < global_capture_opts.ifaces->len; i++) {
@ -730,7 +729,7 @@ void MainWindow::stopCapture() {
//#endif
#ifdef HAVE_LIBPCAP
capture_stop(&global_capture_session);
capture_stop(&cap_session_);
#endif // HAVE_LIBPCAP
}