main.cpp 37.6 KB
Newer Older
1
/* main.cpp
2 3 4 5 6
 *
 * Wireshark - Network traffic analyzer
 * By Gerald Combs <gerald@wireshark.org>
 * Copyright 1998 Gerald Combs
 *
7
 * SPDX-License-Identifier: GPL-2.0-or-later
8 9
 */

10
#include <config.h>
11

12 13
#include <glib.h>

Gerald Combs's avatar
Gerald Combs committed
14 15
#include <locale.h>

16 17 18 19 20
#ifdef _WIN32
#include <windows.h>
#include <tchar.h>
#include <wchar.h>
#include <shellapi.h>
21
#include "ui/win32/console_win32.h"
22 23
#endif

Guy Harris's avatar
Guy Harris committed
24 25 26 27 28 29 30 31
/*
 * If we have getopt_long() in the system library, include <getopt.h>.
 * Otherwise, we're using our own getopt_long() (either because the
 * system has getopt() but not getopt_long(), as with some UN*Xes,
 * or because it doesn't even have getopt(), as with Windows), so
 * include our getopt_long()'s header.
 */
#ifdef HAVE_GETOPT_LONG
32
#include <getopt.h>
Guy Harris's avatar
Guy Harris committed
33 34
#else
#include <wsutil/wsgetopt.h>
35 36
#endif

37 38
#include <ui/clopts_common.h>
#include <ui/cmdarg_err.h>
39
#include <ui/exit_codes.h>
Guy Harris's avatar
Guy Harris committed
40
#include <ui/urls.h>
41 42
#include <wsutil/filesystem.h>
#include <wsutil/privileges.h>
43
#include <wsutil/socket.h>
44 45 46
#ifdef HAVE_PLUGINS
#include <wsutil/plugins.h>
#endif
47
#include <wsutil/report_message.h>
48
#include <wsutil/please_report_bug.h>
49
#include <wsutil/unicode-utils.h>
50
#include <version_info.h>
51

52 53 54
#include <epan/addr_resolv.h>
#include <epan/ex-opt.h>
#include <epan/tap.h>
55
#include <epan/stat_tap_ui.h>
56
#include <epan/column.h>
57
#include <epan/disabled_protos.h>
58
#include <epan/prefs.h>
59

60
#ifdef HAVE_KERBEROS
61 62 63 64 65
#include <epan/packet.h>
#include <epan/asn1.h>
#include <epan/dissectors/packet-kerberos.h>
#endif

66
#include <wsutil/codecs.h>
67

68 69
#include <extcap.h>

70
/* general (not Qt specific) */
71
#include "file.h"
72
#include "epan/color_filters.h"
73 74
#include "log.h"

Gerald Combs's avatar
Gerald Combs committed
75 76 77
#include "epan/rtd_table.h"
#include "epan/srt_table.h"

78
#include "ui/alert_box.h"
79
#include "ui/console.h"
80
#include "ui/iface_lists.h"
Michal Labedzki's avatar
Michal Labedzki committed
81
#include "ui/language.h"
82
#include "ui/persfilepath_opt.h"
83
#include "ui/recent.h"
84
#include "ui/simple_dialog.h"
Gerald Combs's avatar
Gerald Combs committed
85
#include "ui/util.h"
86
#include "ui/dissect_opts.h"
87
#include "ui/commandline.h"
88
#include "ui/capture_ui_utils.h"
89
#include "ui/preference_utils.h"
90
#include "ui/software_update.h"
João Valverde's avatar
João Valverde committed
91
#include "ui/taps.h"
92

Gerald Combs's avatar
Gerald Combs committed
93
#include "ui/qt/conversation_dialog.h"
94
#include "ui/qt/utils/color_utils.h"
95
#include "ui/qt/coloring_rules_dialog.h"
Gerald Combs's avatar
Gerald Combs committed
96
#include "ui/qt/endpoint_dialog.h"
97
#include "ui/qt/main_window.h"
Gerald Combs's avatar
Gerald Combs committed
98 99 100
#include "ui/qt/response_time_delay_dialog.h"
#include "ui/qt/service_response_time_dialog.h"
#include "ui/qt/simple_dialog.h"
Gerald Combs's avatar
Gerald Combs committed
101
#include "ui/qt/simple_statistics_dialog.h"
102
#include <ui/qt/widgets/splash_overlay.h>
103 104
#include "ui/qt/wireshark_application.h"

105
#include "capture/capture-pcap-util.h"
106

107
#include <QMessageBox>
108
#include <QScreen>
109

110
#ifdef _WIN32
111
#  include "capture/capture-wpcap.h"
112
#  include <wsutil/file_util.h>
113 114 115
#endif /* _WIN32 */

#ifdef HAVE_AIRPCAP
116 117
#  include <capture/airpcap.h>
#  include <capture/airpcap_loader.h>
118 119
//#  include "airpcap_dlg.h"
//#  include "airpcap_gui_utils.h"
120 121
#endif

122
#include "epan/crypt/dot11decrypt_ws.h"
123

Roland Knall's avatar
Roland Knall committed
124 125 126 127 128
/* Handle the addition of View menu items without request */
#if defined(Q_OS_MAC)
#include <ui/macosx/cocoa_bridge.h>
#endif

Uli Heilmeier's avatar
Uli Heilmeier committed
129 130
#include <ui/qt/utils/qt_ui_utils.h>

131 132 133 134 135 136 137 138 139 140 141 142 143
//#define DEBUG_STARTUP_TIME 1
/*
# Log level
# Console log level (for debugging)
# A bitmask of log levels:
# ERROR    = 4
# CRITICAL = 8
# WARNING  = 16
# MESSAGE  = 32
# INFO     = 64
# DEBUG    = 128

#define DEBUG_STARTUP_TIME_LOGLEVEL 252
144
*/
145

146 147 148 149 150 151 152 153 154 155 156
/* update the main window */
void main_window_update(void)
{
    WiresharkApplication::processEvents();
}

#ifdef HAVE_LIBPCAP

/* quit the main window */
void main_window_quit(void)
{
157
    wsApp->quit();
158 159
}

Dario Lombardo's avatar
Dario Lombardo committed
160 161
#endif /* HAVE_LIBPCAP */

162 163 164 165 166 167 168
void exit_application(int status) {
    if (wsApp) {
        wsApp->quit();
    }
    exit(status);
}

169 170
/*
 * Report an error in command-line arguments.
Guy Harris's avatar
Guy Harris committed
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
 *
 * On Windows, Wireshark is built for the Windows subsystem, and runs
 * without a console, so we create a console on Windows to receive the
 * output.
 *
 * See create_console(), in ui/win32/console_win32.c, for an example
 * of code to check whether we need to create a console.
 *
 * On UN*Xes:
 *
 *  If Wireshark is run from the command line, its output either goes
 *  to the terminal or to wherever the standard error was redirected.
 *
 *  If Wireshark is run by executing it as a remote command, e.g. with
 *  ssh, its output either goes to whatever socket was set up for the
 *  remote command's standard error or to wherever the standard error
 *  was redirected.
 *
 *  If Wireshark was run from the GUI, e.g. by double-clicking on its
 *  icon or on a file that it opens, there are no guarantees as to
 *  where the standard error went.  It could be going to /dev/null
 *  (current macOS), or to a socket to systemd for the journal, or
 *  to a log file in the user's home directory, or to the "console
 *  device" ("workstation console"), or....
 *
 *  Part of determining that, at least for locally-run Wireshark,
 *  is to try to open /dev/tty to determine whether the process
 *  has a controlling terminal.  (It fails, at a minimum, for
 *  Wireshark launched from the GUI under macOS, Ubuntu with GNOME,
 *  and Ubuntu with KDE; in all cases, an attempt to open /dev/tty
 *  fails with ENXIO.)  If it does have a controlling terminal,
 *  write to the standard error, otherwise assume that the standard
 *  error might not go anywhere that the user will be able to see.
 *  That doesn't handle the "run by ssh" case, however; that will
 *  not have a controlling terminal.  (This means running it by
 *  remote execution, not by remote login.)  Perhaps there's an
 *  environment variable to check there.
208 209
 */
// xxx copied from ../gtk/main.c
Guy Harris's avatar
Guy Harris committed
210 211
static void
wireshark_cmdarg_err(const char *fmt, va_list ap)
212
{
213 214 215 216 217 218
#ifdef _WIN32
    create_console();
#endif
    fprintf(stderr, "wireshark: ");
    vfprintf(stderr, fmt, ap);
    fprintf(stderr, "\n");
219 220 221 222 223 224 225
}

/*
 * Report additional information for an error in command-line arguments.
 * Creates a console on Windows.
 */
// xxx copied from ../gtk/main.c
Guy Harris's avatar
Guy Harris committed
226 227
static void
wireshark_cmdarg_err_cont(const char *fmt, va_list ap)
228
{
229 230 231 232 233
#ifdef _WIN32
    create_console();
#endif
    vfprintf(stderr, fmt, ap);
    fprintf(stderr, "\n");
234 235
}

Alexis La Goutte's avatar
Alexis La Goutte committed
236
// xxx based from ../gtk/main.c:get_gtk_compiled_info
237
void
238
get_wireshark_qt_compiled_info(GString *str)
Alexis La Goutte's avatar
Alexis La Goutte committed
239
{
Alexis La Goutte's avatar
Alexis La Goutte committed
240 241
    g_string_append(str, "with ");
    g_string_append_printf(str,
Alexis La Goutte's avatar
Alexis La Goutte committed
242
#ifdef QT_VERSION
243
                    "Qt %s", QT_VERSION_STR);
Alexis La Goutte's avatar
Alexis La Goutte committed
244
#else
245
                    "Qt (version unknown)");
Alexis La Goutte's avatar
Alexis La Goutte committed
246
#endif
247

248
    /* Capture libraries */
249
    g_string_append(str, ", ");
250
    get_compiled_caplibs_version(str);
Alexis La Goutte's avatar
Alexis La Goutte committed
251 252 253
}

// xxx copied from ../gtk/main.c
254
void
Alexis La Goutte's avatar
Alexis La Goutte committed
255 256
get_gui_compiled_info(GString *str)
{
Alexis La Goutte's avatar
Alexis La Goutte committed
257
    epan_get_compiled_version_info(str);
Alexis La Goutte's avatar
Alexis La Goutte committed
258

Alexis La Goutte's avatar
Alexis La Goutte committed
259
    g_string_append(str, ", ");
260 261 262 263 264
#ifdef QT_MULTIMEDIA_LIB
    g_string_append(str, "with QtMultimedia");
#else
    g_string_append(str, "without QtMultimedia");
#endif
Alexis La Goutte's avatar
Alexis La Goutte committed
265

266 267 268 269 270 271 272 273
    g_string_append(str, ", ");
    const char *update_info = software_update_info();
    if (update_info) {
        g_string_append_printf(str, "with automatic updates using %s", update_info);
    } else {
        g_string_append_printf(str, "without automatic updates");
    }

274
#ifdef _WIN32
275
    g_string_append(str, ", ");
Alexis La Goutte's avatar
Alexis La Goutte committed
276
#ifdef HAVE_AIRPCAP
Alexis La Goutte's avatar
Alexis La Goutte committed
277
    get_compiled_airpcap_version(str);
Alexis La Goutte's avatar
Alexis La Goutte committed
278
#else
Alexis La Goutte's avatar
Alexis La Goutte committed
279
    g_string_append(str, "without AirPcap");
Alexis La Goutte's avatar
Alexis La Goutte committed
280
#endif
281
#endif /* _WIN32 */
282

283 284 285 286 287
#ifdef HAVE_SPEEXDSP
    g_string_append(str, ", with SpeexDSP (using system library)");
#else
    g_string_append(str, ", with SpeexDSP (using bundled resampler)");
#endif
288 289 290 291 292 293

#ifdef HAVE_MINIZIP
    g_string_append(str, ", with Minizip");
#else
    g_string_append(str, ", without Minizip");
#endif
Alexis La Goutte's avatar
Alexis La Goutte committed
294 295 296
}

// xxx copied from ../gtk/main.c
297
void
298
get_wireshark_runtime_info(GString *str)
Alexis La Goutte's avatar
Alexis La Goutte committed
299
{
300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319
    if (wsApp) {
        // Display information
        const char *display_mode = ColorUtils::themeIsDark() ? "dark" : "light";
        g_string_append_printf(str, ", with %s display mode", display_mode);

        int hidpi_count = 0;
        foreach (QScreen *screen, wsApp->screens()) {
            if (screen->devicePixelRatio() > 1.0) {
                hidpi_count++;
            }
        }
        if (hidpi_count == wsApp->screens().count()) {
            g_string_append(str, ", with HiDPI");
        } else if (hidpi_count) {
            g_string_append(str, ", with mixed DPI");
        } else {
            g_string_append(str, ", without HiDPI");
        }
    }

320
#ifdef HAVE_LIBPCAP
321
    /* Capture libraries */
322
    g_string_append(str, ", ");
323
    get_runtime_caplibs_version(str);
324
#endif
325 326

    /* stuff used by libwireshark */
Alexis La Goutte's avatar
Alexis La Goutte committed
327
    epan_get_runtime_version_info(str);
Alexis La Goutte's avatar
Alexis La Goutte committed
328 329

#ifdef HAVE_AIRPCAP
Alexis La Goutte's avatar
Alexis La Goutte committed
330 331
    g_string_append(str, ", ");
    get_runtime_airpcap_version(str);
Alexis La Goutte's avatar
Alexis La Goutte committed
332 333
#endif
}
334

335
static void
Gerald Combs's avatar
Gerald Combs committed
336 337 338 339 340 341 342 343
g_log_message_handler(QtMsgType type, const QMessageLogContext &, const QString &msg)
{
    GLogLevelFlags log_level = G_LOG_LEVEL_DEBUG;

    switch (type) {
    case QtInfoMsg:
        log_level = G_LOG_LEVEL_INFO;
        break;
344 345
    // We want qDebug() messages to show up at our default log level.
    case QtDebugMsg:
Gerald Combs's avatar
Gerald Combs committed
346 347 348 349 350 351 352 353 354
    case QtWarningMsg:
        log_level = G_LOG_LEVEL_WARNING;
        break;
    case QtCriticalMsg:
        log_level = G_LOG_LEVEL_CRITICAL;
        break;
    case QtFatalMsg:
        log_level = G_LOG_FLAG_FATAL;
        break;
355 356
    default:
        break;
Gerald Combs's avatar
Gerald Combs committed
357 358 359 360
    }
    g_log(LOG_DOMAIN_MAIN, log_level, "%s", qUtf8Printable(msg));
}

361
#ifdef HAVE_LIBPCAP
362 363 364 365 366
/*  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
367
check_and_warn_user_startup()
368 369 370 371 372 373 374 375
{
    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,
376 377 378 379 380
        "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"
        WS_WIKI_URL("CaptureSetup/CapturePrivileges"), cur_user, cur_group);
381 382 383 384
        g_free(cur_user);
        g_free(cur_group);
    }
}
385
#endif
386

Gerald Combs's avatar
Gerald Combs committed
387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406
#ifdef _WIN32
// Try to avoid library search path collisions. QCoreApplication will
// search QT_INSTALL_PREFIX/plugins for platform DLLs before searching
// the application directory. If
//
// - You have Qt version 5.x.y installed in the default location
//   (C:\Qt\5.x) on your machine.
//
// and
//
// - You install Wireshark that was built on a machine with Qt version
//   5.x.z installed in the default location.
//
// Qt5Core.dll will load qwindows.dll from your local C:\Qt\5.x\...\plugins
// directory. This may not be compatible with qwindows.dll from that
// same path on the build machine. At any rate, loading DLLs from paths
// you don't control is ill-advised. We work around this by removing every
// path except our application directory.

static inline void
407
win32_reset_library_path(void)
Gerald Combs's avatar
Gerald Combs committed
408 409 410 411 412 413 414 415 416
{
    QString app_path = QDir(get_progfile_dir()).path();
    foreach (QString path, QCoreApplication::libraryPaths()) {
        QCoreApplication::removeLibraryPath(path);
    }
    QCoreApplication::addLibraryPath(app_path);
}
#endif

417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466
#ifdef Q_OS_MAC
// Try to work around
//
//     https://gitlab.com/wireshark/wireshark/-/issues/17075
//
// aka
//
//     https://bugreports.qt.io/browse/QTBUG-87014
//
// The fix at
//
//     https://codereview.qt-project.org/c/qt/qtbase/+/322228/3/src/plugins/platforms/cocoa/qnsview_drawing.mm
//
// enables layer backing if we're running on Big Sur OR we're running on
// Catalina AND we were built with the Catalina SDK. Enable layer backing
// here by setting QT_MAC_WANTS_LAYER=1, but only if we're running on Big
// Sur and our version of Qt doesn't have a fix for QTBUG-87014.
#include <QOperatingSystemVersion>
static inline void
macos_enable_layer_backing(void)
{
    // At the time of this writing, the QTBUG-87014 for layerEnabledByMacOS is...
    //
    // ...in https://github.com/qt/qtbase/blob/5.12/src/plugins/platforms/cocoa/qnsview_drawing.mm
    // ...not in https://github.com/qt/qtbase/blob/5.12.10/src/plugins/platforms/cocoa/qnsview_drawing.mm
    // ...in https://github.com/qt/qtbase/blob/5.15/src/plugins/platforms/cocoa/qnsview_drawing.mm
    // ...not in https://github.com/qt/qtbase/blob/5.15.2/src/plugins/platforms/cocoa/qnsview_drawing.mm
    // ...not in https://github.com/qt/qtbase/blob/6.0/src/plugins/platforms/cocoa/qnsview_drawing.mm
    // ...not in https://github.com/qt/qtbase/blob/6.0.0/src/plugins/platforms/cocoa/qnsview_drawing.mm
    //
    // We'll assume that it will be fixed in 5.12.11, 5.15.3, and 6.0.1.
    // Note that we only ship LTS versions of Qt with our macOS packages.
    // Feel free to add other versions if needed.
#if  \
        (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) && QT_VERSION < QT_VERSION_CHECK(5, 12, 11) \
        || (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) &&  QT_VERSION < QT_VERSION_CHECK(5, 15, 3)) \
        || (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) &&  QT_VERSION < QT_VERSION_CHECK(6, 0, 1)) \
    )
    QOperatingSystemVersion os_ver = QOperatingSystemVersion::current();
    int major_ver = os_ver.majorVersion();
    int minor_ver = os_ver.minorVersion();
    if ( (major_ver == 10 && minor_ver >= 16) || major_ver >= 11 ) {
        if (qgetenv("QT_MAC_WANTS_LAYER").isEmpty()) {
            qputenv("QT_MAC_WANTS_LAYER", "1");
        }
    }
#endif
}
#endif

467
/* And now our feature presentation... [ fade to music ] */
Gerald Combs's avatar
Gerald Combs committed
468
int main(int argc, char *qt_argv[])
469
{
470
    MainWindow *main_w;
471

472
#ifdef _WIN32
473 474
    LPWSTR              *wc_argv;
    int                  wc_argc;
475
#endif
476
    int                  ret_val = EXIT_SUCCESS;
Gerald Combs's avatar
Gerald Combs committed
477
    char               **argv = qt_argv;
478 479 480 481

    char                *rf_path;
    int                  rf_open_errno;
#ifdef HAVE_LIBPCAP
482
    gchar               *err_str, *err_str_secondary;;
483 484 485 486 487 488 489
#else
#ifdef _WIN32
#ifdef HAVE_AIRPCAP
    gchar               *err_str;
#endif
#endif
#endif
490
    gchar               *err_msg = NULL;
491

492
    QString              dfilter, read_filter;
493
#ifdef HAVE_LIBPCAP
494
    int                  caps_queries = 0;
495
#endif
496 497
    /* Start time in microseconds */
    guint64 start_time = g_get_monotonic_time();
498 499 500 501 502 503 504 505 506 507 508 509
    static const struct report_message_routines wireshark_report_routines = {
        vfailure_alert_box,
        vwarning_alert_box,
        open_failure_alert_box,
        read_failure_alert_box,
        write_failure_alert_box,
        cfile_open_failure_alert_box,
        cfile_dump_open_failure_alert_box,
        cfile_read_failure_alert_box,
        cfile_write_failure_alert_box,
        cfile_close_failure_alert_box
    };
510

511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
    /*
     * See:
     *
     *    issue #16908;
     *
     *    https://doc.qt.io/qt-5/qvector.html#maximum-size-and-out-of-memory-conditions
     *
     *    https://forum.qt.io/topic/114950/qvector-realloc-throwing-sigsegv-when-very-large-surface3d-is-rendered
     *
     * for why we're doing this; the widget we use for the packet list
     * uses QVector, so those limitations apply to it.
     *
     * Apparently, this will be fixed in Qt 6:
     *
     *    https://github.com/qt/qtbase/commit/215ca735341b9487826023a7983382851ce8bf26
     *
     *    https://github.com/qt/qtbase/commit/2a6cdec718934ca2cc7f6f9c616ebe62f6912123#diff-724f419b0bb0487c2629bb16cf534c4b268ddcee89b5177189b607f940cfd83dR192
     *
     * Hopefully QList won't cause any performance hits relative to
     * QVector.
     *
     * We pick 53 million records as a value that should avoid the problem;
     * see the Wireshark issue for why that value was chosen.
     */
    cf_set_max_records(53000000);
#endif

539 540 541 542
#ifdef Q_OS_MAC
    macos_enable_layer_backing();
#endif

543 544 545 546 547 548 549
    /* Enable destinations for logging earlier in startup */
    set_console_log_handler();
    qInstallMessageHandler(g_log_message_handler);
#ifdef _WIN32
    restore_pipes();
#endif

550
#ifdef DEBUG_STARTUP_TIME
551
    /* At least on Windows there is a problem with the logging as the preferences is taken
552 553 554 555 556
     * into account and the preferences are loaded pretty late in the startup process.
     */
    prefs.console_log_level = DEBUG_STARTUP_TIME_LOGLEVEL;
    prefs.gui_console_open = console_open_always;
#endif /* DEBUG_STARTUP_TIME */
Guy Harris's avatar
Guy Harris committed
557 558
    cmdarg_err_init(wireshark_cmdarg_err, wireshark_cmdarg_err_cont);

Roland Knall's avatar
Roland Knall committed
559 560 561 562 563
#if defined(Q_OS_MAC)
    /* Disable automatic addition of tab menu entries in view menu */
    CocoaBridge::cleanOSGeneratedMenuItems();
#endif

564 565 566 567 568 569 570
    /*
     * Set the C-language locale to the native environment and set the
     * code page to UTF-8 on Windows.
     */
#ifdef _WIN32
    setlocale(LC_ALL, ".UTF-8");
#else
Gerald Combs's avatar
Gerald Combs committed
571
    setlocale(LC_ALL, "");
572
#endif
Gerald Combs's avatar
Gerald Combs committed
573

574
#ifdef _WIN32
575 576 577 578 579 580 581 582 583 584 585 586
    //
    // On Windows, QCoreApplication has its own WinMain(), which gets the
    // command line using GetCommandLineW(), breaks it into individual
    // arguments using CommandLineToArgvW(), and then "helpfully"
    // converts those UTF-16LE arguments into strings in the local code
    // page.
    //
    // We don't want that, because not all file names can be represented
    // in the local code page, so we do the same, but we convert the
    // strings into UTF-8.
    //
    wc_argv = CommandLineToArgvW(GetCommandLineW(), &wc_argc);
587 588 589 590
    if (wc_argv) {
        argc = wc_argc;
        argv = arg_list_utf_16to8(wc_argc, wc_argv);
        LocalFree(wc_argv);
591 592
    } /* XXX else bail because something is horribly, horribly wrong? */

593
    create_app_running_mutex();
594
#endif /* _WIN32 */
595

596 597 598 599 600 601 602 603
    /*
     * Get credential information for later use, and drop privileges
     * before doing anything else.
     * Let the user know if anything happened.
     */
    init_process_policies();
    relinquish_special_privs_perm();

604
    /*
605 606
     * Attempt to get the pathname of the directory containing the
     * executable file.
607
     */
608
    /* init_progfile_dir_error = */ init_progfile_dir(argv[0]);
609
    /* g_log(NULL, G_LOG_LEVEL_DEBUG, "progfile_dir: %s", get_progfile_dir()); */
610

611
#ifdef _WIN32
612
    ws_init_dll_search_path();
613 614 615 616 617 618 619 620 621 622 623 624 625 626 627
    /* Load wpcap if possible. Do this before collecting the run-time version information */
    load_wpcap();

#ifdef HAVE_AIRPCAP
    /* Load the airpcap.dll.  This must also be done before collecting
     * run-time version information. */
    load_airpcap();
#if 0
    airpcap_dll_ret_val = load_airpcap();

    switch (airpcap_dll_ret_val) {
    case AIRPCAP_DLL_OK:
        /* load the airpcap interfaces */
        g_airpcap_if_list = get_airpcap_interface_list(&err, &err_str);

628
        if (g_airpcap_if_list == NULL || g_list_length(g_airpcap_if_list) == 0) {
629 630 631 632 633 634 635 636
            if (err == CANT_GET_AIRPCAP_INTERFACE_LIST && err_str != NULL) {
                simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", "Failed to open Airpcap Adapters.");
                g_free(err_str);
            }
            airpcap_if_active = NULL;

        } else {

637
            /* select the first as default (THIS SHOULD BE CHANGED) */
638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659
            airpcap_if_active = airpcap_get_default_if(airpcap_if_list);
        }
        break;
    /*
     * XXX - Maybe we need to warn the user if one of the following happens???
     */
    case AIRPCAP_DLL_OLD:
        simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s","AIRPCAP_DLL_OLD\n");
        break;

    case AIRPCAP_DLL_ERROR:
        simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s","AIRPCAP_DLL_ERROR\n");
        break;

    case AIRPCAP_DLL_NOT_FOUND:
        simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s","AIRPCAP_DDL_NOT_FOUND\n");
        break;
    }
#endif
#endif /* HAVE_AIRPCAP */
#endif /* _WIN32 */

660
    /* Get the compile-time version information string */
661 662
    ws_init_version_info("Wireshark", get_wireshark_qt_compiled_info,
                         get_gui_compiled_info, get_wireshark_runtime_info);
663

664 665 666
    /* Create the user profiles directory */
    if (create_profiles_dir(&rf_path) == -1) {
        simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
667
                      "Could not create profiles directory\n\"%s\": %s.",
668
                      rf_path, g_strerror(errno));
669 670 671
        g_free (rf_path);
    }

672
    profile_store_persconffiles(TRUE);
673
    recent_init();
674 675 676 677 678 679

    /* Read the profile independent recent file.  We have to do this here so we can */
    /* set the profile before it can be set from the command line parameter */
    if (!recent_read_static(&rf_path, &rf_open_errno)) {
        simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
                      "Could not open common recent file\n\"%s\": %s.",
680
                      rf_path, g_strerror(rf_open_errno));
681 682 683
        g_free(rf_path);
    }

684
    commandline_early_options(argc, argv);
685

Gerald Combs's avatar
Gerald Combs committed
686
#ifdef _WIN32
687
    win32_reset_library_path();
Gerald Combs's avatar
Gerald Combs committed
688 689
#endif

690 691 692 693
    // Handle DPI scaling on Windows. This causes problems in at least
    // one case on X11 and we don't yet support Android.
    // We do the equivalent on macOS by setting NSHighResolutionCapable
    // in Info.plist.
694 695
    // Note that this enables Windows 8.1-style Per-monitor DPI
    // awareness but not Windows 10-style Per-monitor v2 awareness.
696 697
    // https://doc.qt.io/qt-5/scalability.html
    // https://doc.qt.io/qt-5/highdpi.html
698 699
    // https://bugreports.qt.io/browse/QTBUG-53022 - The device pixel ratio is pretty much bogus on Windows.
    // https://bugreports.qt.io/browse/QTBUG-55510 - Windows have wrong size
Gerald Combs's avatar
Gerald Combs committed
700
#if defined(Q_OS_WIN)
701
    QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
702 703
#endif

Gerald Combs's avatar
Gerald Combs committed
704
    /* Create The Wireshark app */
Gerald Combs's avatar
Gerald Combs committed
705
    WiresharkApplication ws_app(argc, qt_argv);
Gerald Combs's avatar
Gerald Combs committed
706

707 708 709 710
    /* initialize the funnel mini-api */
    // xxx qtshark
    //initialize_funnel_ops();

711
    Dot11DecryptInitContext(&dot11decrypt_ctx);
712

713
    QString cf_name;
714 715
    unsigned int in_file_type = WTAP_TYPE_AUTO;

716 717
    err_msg = ws_init_sockets();
    if (err_msg != NULL)
718
    {
719 720 721
        cmdarg_err("%s", err_msg);
        g_free(err_msg);
        cmdarg_err_cont("%s", please_report_bug());
722 723 724
        ret_val = INIT_FAILED;
        goto clean_exit;
    }
725

726 727 728 729
    /* Read the profile dependent (static part) of the recent file. */
    /* Only the static part of it will be read, as we don't have the gui now to fill the */
    /* recent lists which is done in the dynamic part. */
    /* We have to do this already here, so command line parameters can overwrite these values. */
Peter Wu's avatar
Peter Wu committed
730
    if (!recent_read_profile_static(&rf_path, &rf_open_errno)) {
731 732 733
        simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
                      "Could not open recent file\n\"%s\": %s.",
                      rf_path, g_strerror(rf_open_errno));
Peter Wu's avatar
Peter Wu committed
734
        g_free(rf_path);
735
    }
736
    wsApp->applyCustomColorsFromRecent();
737

Michal Labedzki's avatar
Michal Labedzki committed
738 739
    // Initialize our language
    read_language_prefs();
Gerald Combs's avatar
Gerald Combs committed
740
    wsApp->loadLanguage(language);
Michal Labedzki's avatar
Michal Labedzki committed
741

742
    /* g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Translator %s", language); */
Michal Labedzki's avatar
Michal Labedzki committed
743

744 745 746 747 748
    // Init the main window (and splash)
    main_w = new(MainWindow);
    main_w->show();
    // We may not need a queued connection here but it would seem to make sense
    // to force the issue.
749 750
    main_w->connect(&ws_app, SIGNAL(openCaptureFile(QString,QString,unsigned int)),
            main_w, SLOT(openCaptureFile(QString,QString,unsigned int)));
751 752
    main_w->connect(&ws_app, SIGNAL(openCaptureOptions()),
            main_w, SLOT(on_actionCaptureOptions_triggered()));
753

754 755 756 757 758 759 760 761 762
    /* Init the "Open file" dialog directory */
    /* (do this after the path settings are processed) */
    if (recent.gui_fileopen_remembered_dir &&
        test_for_directory(recent.gui_fileopen_remembered_dir) == EISDIR) {
      wsApp->setLastOpenDir(recent.gui_fileopen_remembered_dir);
    } else {
      wsApp->setLastOpenDir(get_persdatafile_dir());
    }

763 764 765
#ifdef DEBUG_STARTUP_TIME
    g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_INFO, "set_console_log_handler, elapsed time %" G_GUINT64_FORMAT " us \n", g_get_monotonic_time() - start_time);
#endif
766

767 768 769 770 771 772
#ifdef HAVE_LIBPCAP
    /* 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);
#endif

773
    init_report_message("Wireshark", &wireshark_report_routines);
774

775 776 777 778 779
    /*
     * Libwiretap must be initialized before libwireshark is, so that
     * dissection-time handlers for file-type-dependent blocks can
     * register using the file type/subtype value for the file type.
     */
780
    wtap_init(TRUE);
781

Guy Harris's avatar
Guy Harris committed
782
    splash_update(RA_DISSECTORS, NULL, NULL);
783 784 785
#ifdef DEBUG_STARTUP_TIME
    g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_INFO, "Calling epan init, elapsed time %" G_GUINT64_FORMAT " us \n", g_get_monotonic_time() - start_time);
#endif
786 787 788 789
    /* Register all dissectors; we must do this before checking for the
       "-G" flag, as the "-G" flag dumps information registered by the
       dissectors, and we must do it before we read the preferences, in
       case any dissectors register preferences. */
790
    if (!epan_init(splash_update, NULL, TRUE)) {
791
        SimpleDialog::displayQueuedMessages(main_w);
792 793
        ret_val = INIT_FAILED;
        goto clean_exit;
794
    }
795 796 797 798 799 800
#ifdef DEBUG_STARTUP_TIME
    /* epan_init resets the preferences */
    prefs.console_log_level = DEBUG_STARTUP_TIME_LOGLEVEL;
    prefs.gui_console_open = console_open_always;
    g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_INFO, "epan done, elapsed time %" G_GUINT64_FORMAT " us \n", g_get_monotonic_time() - start_time);
#endif
801

802 803 804
    /* Register all audio codecs. */
    codecs_init();

805 806 807 808 809 810 811 812 813
    // Read the dynamic part of the recent file. This determines whether or
    // not the recent list appears in the main window so the earlier we can
    // call this the better.
    if (!recent_read_dynamic(&rf_path, &rf_open_errno)) {
        simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
                      "Could not open recent file\n\"%s\": %s.",
                      rf_path, g_strerror(rf_open_errno));
        g_free(rf_path);
    }
814
    wsApp->refreshRecentCaptures();
815

816
    splash_update(RA_LISTENERS, NULL, NULL);
817 818 819
#ifdef DEBUG_STARTUP_TIME
    g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_INFO, "Register all tap listeners, elapsed time %" G_GUINT64_FORMAT " us \n", g_get_monotonic_time() - start_time);
#endif
820 821 822
    /* Register all tap listeners; we do this before we parse the arguments,
       as the "-z" argument can specify a registered tap. */

823
    register_all_tap_listeners(tap_reg_listener);
824

825
    conversation_table_set_gui_info(init_conversation_table);
826
    hostlist_table_set_gui_info(init_endpoint_table);
Gerald Combs's avatar
Gerald Combs committed
827
    srt_table_iterate_tables(register_service_response_tables, NULL);
Gerald Combs's avatar
Gerald Combs committed
828
    rtd_table_iterate_tables(register_response_time_delay_tables, NULL);
829
    stat_tap_iterate_tables(register_simple_stat_tables, NULL);
830

831 832 833 834
    if (ex_opt_count("read_format") > 0) {
        in_file_type = open_info_name_to_type(ex_opt_get_next("read_format"));
    }

835 836 837
#ifdef DEBUG_STARTUP_TIME
    g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_INFO, "Calling extcap_register_preferences, elapsed time %" G_GUINT64_FORMAT " us \n", g_get_monotonic_time() - start_time);
#endif
838 839
    splash_update(RA_EXTCAP, NULL, NULL);
    extcap_register_preferences();
840
    splash_update(RA_PREFERENCES, NULL, NULL);
841
#ifdef DEBUG_STARTUP_TIME
842
    g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_INFO, "Calling module preferences, elapsed time %" G_GUINT64_FORMAT " us \n", g_get_monotonic_time() - start_time);
843
#endif
844

845
    global_commandline_info.prefs_p = ws_app.readConfigurationFiles(false);
846

847
    /* Now get our args */
848
    commandline_other_options(argc, argv, TRUE);
849

850
    /* Convert some command-line parameters to QStrings */
851 852 853 854 855 856
    if (global_commandline_info.cf_name != NULL)
        cf_name = QString(global_commandline_info.cf_name);
    if (global_commandline_info.rfilter != NULL)
        read_filter = QString(global_commandline_info.rfilter);
    if (global_commandline_info.dfilter != NULL)
        dfilter = QString(global_commandline_info.dfilter);
857

858 859
    timestamp_set_type(recent.gui_time_format);
    timestamp_set_precision(recent.gui_time_precision);
860
    timestamp_set_seconds_type (recent.gui_seconds_format);
861

862
#ifdef HAVE_LIBPCAP
863 864 865
#ifdef DEBUG_STARTUP_TIME
    g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_INFO, "Calling fill_in_local_interfaces, elapsed time %" G_GUINT64_FORMAT " us \n", g_get_monotonic_time() - start_time);
#endif
866 867
    splash_update(RA_INTERFACES, NULL, NULL);

868
    if (!global_commandline_info.cf_name && !prefs.capture_no_interface_load)
869
        fill_in_local_interfaces(main_window_update);
870

871 872
    if  (global_commandline_info.list_link_layer_types)
        caps_queries |= CAPS_QUERY_LINK_TYPES;
873
     if (global_commandline_info.list_timestamp_types)
874 875 876 877
        caps_queries |= CAPS_QUERY_TIMESTAMP_TYPES;

    if (global_commandline_info.start_capture || caps_queries) {
        /* We're supposed to do a live capture or get a list of link-layer/timestamp
878 879
           types for a live capture device; if the user didn't specify an
           interface to use, pick a default. */
880
        ret_val = capture_opts_default_iface_if_necessary(&global_capture_opts,
881
        ((global_commandline_info.prefs_p->capture_device) && (*global_commandline_info.prefs_p->capture_device != '\0')) ? get_if_name(global_commandline_info.prefs_p->capture_device) : NULL);
882 883
        if (ret_val != 0) {
            goto clean_exit;
884 885 886
        }
    }

887 888 889 890
    /*
     * If requested, list the link layer types and/or time stamp types
     * and exit.
     */
891
    if (caps_queries) {
892
        guint i;
893

894 895 896
#ifdef _WIN32
        create_console();
#endif /* _WIN32 */
897
        /* Get the list of link-layer types for the capture devices. */
898
        ret_val = EXIT_SUCCESS;
899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917
        for (i = 0; i < global_capture_opts.ifaces->len; i++) {
            interface_options *interface_opts;
            if_capabilities_t *caps;
            char *auth_str = NULL;

            interface_opts = &g_array_index(global_capture_opts.ifaces, interface_options, i);
#ifdef HAVE_PCAP_REMOTE
            if (interface_opts->auth_type == CAPTURE_AUTH_PWD) {
                auth_str = g_strdup_printf("%s:%s", interface_opts->auth_username, interface_opts->auth_password);
            }
#endif
            caps = capture_get_if_capabilities(interface_opts->name, interface_opts->monitor_mode,
                                               auth_str, &err_str, &err_str_secondary, NULL);
            g_free(auth_str);
            if (caps == NULL) {
                cmdarg_err("%s%s%s", err_str, err_str_secondary ? "\n" : "", err_str_secondary ? err_str_secondary : "");
                g_free(err_str);
                g_free(err_str_secondary);
                ret_val = INVALID_CAPABILITY;
918
                break;
919
            }
920 921
            ret_val = capture_opts_print_if_capabilities(caps, interface_opts,
                                                         caps_queries);
922 923
            free_if_capabilities(caps);
            if (ret_val != EXIT_SUCCESS) {
924
                break;
925
            }
926
        }
927 928 929
#ifdef _WIN32
        destroy_console();
#endif /* _WIN32 */
930
        goto clean_exit;
931 932
    }

933 934 935 936
    capture_opts_trim_snaplen(&global_capture_opts, MIN_PACKET_SIZE);
    capture_opts_trim_ring_num_files(&global_capture_opts);
#endif /* HAVE_LIBPCAP */

937 938 939
    /* Notify all registered modules that have had any of their preferences
       changed either from one of the preferences file or from the command
       line that their preferences have changed. */
940 941 942
#ifdef DEBUG_STARTUP_TIME
    g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_INFO, "Calling prefs_apply_all, elapsed time %" G_GUINT64_FORMAT " us \n", g_get_monotonic_time() - start_time);
#endif
Gerald Combs's avatar