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() endif()
file(GLOB CAPCHILD_HEADERS capture_session.h)
add_library(capchild STATIC add_library(capchild STATIC
${CAPCHILD_SRC} ${CAPCHILD_SRC}

View File

@ -113,13 +113,14 @@
#ifdef HAVE_LIBPCAP #ifdef HAVE_LIBPCAP
# include "caputils/capture_ifinfo.h" # include "caputils/capture_ifinfo.h"
# include "ui/capture.h" # include "ui/capture.h"
# include <capchild/capture_sync.h> # include "capchild/capture_sync.h"
#endif #endif
#ifdef _WIN32 #ifdef _WIN32
# include "caputils/capture-wpcap.h" # include "caputils/capture-wpcap.h"
# include "caputils/capture_wpcap_packet.h" # include "caputils/capture_wpcap_packet.h"
# include <tchar.h> /* Needed for Unicode */ # include <tchar.h> /* Needed for Unicode */
# include <wsutil/os_version_info.h>
# include <wsutil/unicode-utils.h> # include <wsutil/unicode-utils.h>
# include <commctrl.h> # include <commctrl.h>
# include <shellapi.h> # include <shellapi.h>
@ -132,22 +133,22 @@
//# include "airpcap_gui_utils.h" //# include "airpcap_gui_utils.h"
#endif #endif
#include <epan/crypt/airpdcap_ws.h> #include "epan/crypt/airpdcap_ws.h"
#include <QDebug>
#include <QDateTime> #include <QDateTime>
#include <QLibraryInfo>
#include <QLocale>
#include <QMessageBox>
#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0)) #if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
#include <QTextCodec> #include <QTextCodec>
#endif #endif
#include <qtranslator.h> #include <QTranslator>
#include <qlocale.h>
#include <qlibraryinfo.h>
#include "conversation_dialog.h" #include "conversation_dialog.h"
#include "endpoint_dialog.h" #include "endpoint_dialog.h"
#ifdef HAVE_LIBPCAP #ifdef HAVE_LIBPCAP
capture_options global_capture_opts; capture_options global_capture_opts;
capture_session global_capture_session;
#endif #endif
capture_file cfile; 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 ] */ /* And now our feature presentation... [ fade to music ] */
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
@ -447,7 +486,7 @@ int main(int argc, char *argv[])
#ifdef HAVE_LIBPCAP #ifdef HAVE_LIBPCAP
int err; int err;
gboolean start_capture = FALSE; gboolean start_capture = FALSE;
// gboolean list_link_layer_types = FALSE; gboolean list_link_layer_types = FALSE;
GList *if_list; GList *if_list;
gchar *err_str; gchar *err_str;
int status; int status;
@ -461,6 +500,7 @@ int main(int argc, char *argv[])
#endif #endif
e_prefs *prefs_p; e_prefs *prefs_p;
char badopt; char badopt;
guint go_to_packet = 0;
cmdarg_err_init(wireshark_cmdarg_err, wireshark_cmdarg_err_cont); cmdarg_err_init(wireshark_cmdarg_err, wireshark_cmdarg_err_cont);
@ -540,8 +580,8 @@ int main(int argc, char *argv[])
#endif /* _WIN32 */ #endif /* _WIN32 */
QString locale; QString locale;
QString *cf_name = NULL; QString cf_name;
QString *display_filter = NULL; QString display_filter;
int optind_initial; int optind_initial;
unsigned int in_file_type = WTAP_TYPE_AUTO; 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 /* Set the initial values in the capture options. This might be overwritten
by preference settings and then again by the command line parameters. */ by preference settings and then again by the command line parameters. */
capture_opts_init(&global_capture_opts); capture_opts_init(&global_capture_opts);
capture_session_init(&global_capture_session, (void *)&cfile);
#endif #endif
init_report_err(failure_alert_box, open_failure_alert_box, init_report_err(failure_alert_box, open_failure_alert_box,
@ -931,7 +969,7 @@ int main(int argc, char *argv[])
/* Not supported yet */ /* Not supported yet */
break; break;
case 'g': /* Go to packet with the given packet number */ case 'g': /* Go to packet with the given packet number */
/* Not supported yet */ go_to_packet = get_positive_int(optarg, "go to packet");
break; break;
case 'J': /* Jump to the first packet which matches the filter criteria */ case 'J': /* Jump to the first packet which matches the filter criteria */
/* Not supported yet */ /* Not supported yet */
@ -940,7 +978,12 @@ int main(int argc, char *argv[])
/* Not supported yet */ /* Not supported yet */
break; break;
case 'L': /* Print list of link-layer types and exit */ 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; break;
case 'm': /* Fixed-width font for the display */ case 'm': /* Fixed-width font for the display */
/* Not supported yet */ /* Not supported yet */
@ -1000,7 +1043,7 @@ int main(int argc, char *argv[])
/* Path settings were already processed just ignore them this time*/ /* Path settings were already processed just ignore them this time*/
break; break;
case 'r': case 'r':
cf_name = new QString(optarg); cf_name = optarg;
break; break;
case 'R': /* Read file filter */ case 'R': /* Read file filter */
/* Not supported yet */ /* Not supported yet */
@ -1084,7 +1127,7 @@ int main(int argc, char *argv[])
argc -= optind; argc -= optind;
argv += optind; argv += optind;
if (argc >= 1) { if (argc >= 1) {
if (cf_name != NULL) { if (!cf_name.isEmpty()) {
/* /*
* Input file name specified with "-r" *and* specified as a regular * Input file name specified with "-r" *and* specified as a regular
* command-line argument. * 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, * file - yes, you could have "-r" as the last part of the command,
* but that's a bit ugly. * but that's a bit ugly.
*/ */
cf_name = new QString(g_strdup(argv[0])); cf_name = argv[0];
} }
argc--; argc--;
@ -1139,6 +1182,105 @@ int main(int argc, char *argv[])
#ifdef HAVE_LIBPCAP #ifdef HAVE_LIBPCAP
fill_in_local_interfaces(main_window_update); 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_snaplen(&global_capture_opts, MIN_PACKET_SIZE);
capture_opts_trim_ring_num_files(&global_capture_opts); capture_opts_trim_ring_num_files(&global_capture_opts);
#endif /* HAVE_LIBPCAP */ #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"); 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 */ /* user could specify filename, or display filter, or both */
if (cf_name != NULL || display_filter != NULL) { if (!cf_name.isEmpty()) {
if (display_filter == NULL)
display_filter = new QString();
if (cf_name == NULL)
cf_name = new QString();
// XXX We need to call cf_open + start_requested_stats + cf_read // XXX We need to call cf_open + start_requested_stats + cf_read
// similar to gtk/main.c:3110. // 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, /* Open stat windows; we do so after creating the main window,
to avoid Qt warnings, and after successfully opening the to avoid Qt warnings, and after successfully opening the
@ -1233,6 +1371,42 @@ int main(int argc, char *argv[])
filter. */ filter. */
start_requested_stats(); 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); g_main_loop_new(NULL, FALSE);
return wsApp->exec(); return wsApp->exec();

View File

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

View File

@ -76,6 +76,7 @@ public:
void setPipeInputHandler(gint source, gpointer user_data, int *child_process, pipe_input_cb_t input_cb); void setPipeInputHandler(gint source, gpointer user_data, int *child_process, pipe_input_cb_t input_cb);
QString getFilter(); QString getFilter();
capture_session *captureSession() { return &cap_session_; }
protected: protected:
bool eventFilter(QObject *obj, QEvent *event); bool eventFilter(QObject *obj, QEvent *event);
@ -106,6 +107,7 @@ private:
MainWelcome *main_welcome_; MainWelcome *main_welcome_;
DisplayFilterCombo *df_combo_box_; DisplayFilterCombo *df_combo_box_;
capture_file *cap_file_; capture_file *cap_file_;
capture_session cap_session_;
QFont mono_font_; QFont mono_font_;
// XXX - packet_list_, proto_tree_, and byte_view_tab_ should // XXX - packet_list_, proto_tree_, and byte_view_tab_ should
// probably be full-on values instead of pointers. // 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) { void MainWindow::captureCapturePrepared(capture_session *cap_session) {
#ifdef HAVE_LIBPCAP #ifdef HAVE_LIBPCAP
qDebug() << "FIX captureCapturePrepared";
setTitlebarForCaptureInProgress(); setTitlebarForCaptureInProgress();
setWindowIcon(wsApp->captureIcon()); setWindowIcon(wsApp->captureIcon());
@ -625,18 +624,18 @@ void MainWindow::startCapture() {
// main_auto_scroll_live_changed(auto_scroll_live); // main_auto_scroll_live_changed(auto_scroll_live);
/* XXX - can this ever happen? */ /* XXX - can this ever happen? */
if (global_capture_session.state != CAPTURE_STOPPED) if (cap_session_.state != CAPTURE_STOPPED)
return; return;
/* close the currently loaded capture file */ /* 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 /* Copy the selected interfaces to the set of interfaces to use for
this capture. */ this capture. */
collect_ifaces(&global_capture_opts); collect_ifaces(&global_capture_opts);
cfile.window = this; 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 /* The capture succeeded, which means the capture filter syntax is
valid; add this capture filter to the recent capture filter list. */ valid; add this capture filter to the recent capture filter list. */
for (i = 0; i < global_capture_opts.ifaces->len; i++) { for (i = 0; i < global_capture_opts.ifaces->len; i++) {
@ -730,7 +729,7 @@ void MainWindow::stopCapture() {
//#endif //#endif
#ifdef HAVE_LIBPCAP #ifdef HAVE_LIBPCAP
capture_stop(&global_capture_session); capture_stop(&cap_session_);
#endif // HAVE_LIBPCAP #endif // HAVE_LIBPCAP
} }