extcap: add sshdump.
[metze/wireshark/wip.git] / extcap / sshdump.c
1 /* sshdump.c
2  * sshdump is extcap tool used to capture data using a remote ssh host
3  *
4  * Copyright 2015, Dario Lombardo
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23  */
24
25 #include "config.h"
26
27 #include <glib.h>
28 #include <glib/gprintf.h>
29 #include <glib/gstdio.h>
30 #include <stdio.h>
31 #include <stdint.h>
32 #include <stdlib.h>
33 #include <stdarg.h>
34 #include <string.h>
35 #include <errno.h>
36 #include <time.h>
37 #include <string.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <fcntl.h>
41 #include <libssh/libssh.h>
42
43 #ifdef HAVE_ARPA_INET_H
44         #include <arpa/inet.h>
45 #endif
46
47 #include "log.h"
48
49 #ifdef _WIN32
50 #include <io.h>
51 #endif
52
53 #ifdef HAVE_GETOPT_H
54 #include <getopt.h>
55 #endif
56
57 #ifndef HAVE_GETOPT_LONG
58         #include "wsutil/wsgetopt.h"
59 #endif
60
61 #if defined(_WIN32) && !defined(__CYGWIN__)
62         #ifdef HAVE_WINDOWS_H
63                 #include <windows.h>
64         #endif
65
66         #include <ws2tcpip.h>
67
68         #ifdef HAVE_WINSOCK2_H
69                 #include <winsock2.h>
70         #endif
71
72         #include <process.h>
73
74         #define socket_handle_t SOCKET
75 #else
76 /*
77  * UN*X, or Windows pretending to be UN*X with the aid of Cygwin.
78  */
79 #define closesocket(socket)  close(socket)
80 #define socket_handle_t int
81 #define INVALID_SOCKET (-1)
82 #define SOCKET_ERROR (-1)
83 #endif
84
85 #if defined(__FreeBSD__) || defined(BSD) || defined(__APPLE__) || defined(__linux__)
86 #define USE_GETIFADDRS 1
87 #include <ifaddrs.h>
88 #endif
89
90 #ifndef STDERR_FILENO
91 #define STDERR_FILENO 2
92 #endif
93
94 #ifndef STDOUT_FILENO
95 #define STDOUT_FILENO 1
96 #endif
97
98 #define SSHDUMP_VERSION_MAJOR 1U
99 #define SSHDUMP_VERSION_MINOR 0U
100 #define SSHDUMP_VERSION_RELEASE 0U
101
102 #define SSH_EXTCAP_INTERFACE "ssh"
103 #define SSH_READ_BLOCK_SIZE 256
104
105 static gboolean verbose = FALSE;
106
107 enum {
108         OPT_HELP = 1,
109         OPT_VERSION,
110         OPT_VERBOSE,
111         OPT_LIST_INTERFACES,
112         OPT_LIST_DLTS,
113         OPT_INTERFACE,
114         OPT_CONFIG,
115         OPT_CAPTURE,
116         OPT_FIFO,
117         OPT_EXTCAP_FILTER,
118         OPT_REMOTE_HOST,
119         OPT_REMOTE_PORT,
120         OPT_REMOTE_USERNAME,
121         OPT_REMOTE_PASSWORD,
122         OPT_REMOTE_INTERFACE,
123         OPT_REMOTE_CAPTURE_BIN,
124         OPT_REMOTE_FILTER,
125         OPT_SSHKEY,
126         OPT_SSHKEY_PASSPHRASE
127 };
128
129 static struct option longopts[] = {
130 /* Generic application options */
131         { "help", no_argument, NULL, OPT_HELP},
132         { "version", no_argument, NULL, OPT_VERSION},
133         { "verbose", optional_argument, NULL, OPT_VERBOSE},
134         { "extcap-interfaces", no_argument, NULL, OPT_LIST_INTERFACES},
135         { "extcap-dlts", no_argument, NULL, OPT_LIST_DLTS},
136         { "extcap-interface", required_argument, NULL, OPT_INTERFACE},
137         { "extcap-config", no_argument, NULL, OPT_CONFIG},
138         { "extcap-capture-filter", required_argument, NULL, OPT_EXTCAP_FILTER},
139         { "capture", no_argument, NULL, OPT_CAPTURE},
140         { "fifo", required_argument, NULL, OPT_FIFO},
141         { "remote-host", required_argument, NULL, OPT_REMOTE_HOST},
142         { "remote-port", required_argument, NULL, OPT_REMOTE_PORT},
143         { "remote-username", required_argument, NULL, OPT_REMOTE_USERNAME},
144         { "remote-password", required_argument, NULL, OPT_REMOTE_PASSWORD},
145         { "remote-interface", required_argument, NULL, OPT_REMOTE_INTERFACE},
146         { "remote-capture-bin", required_argument, NULL, OPT_REMOTE_CAPTURE_BIN},
147         { "remote-filter", required_argument, NULL, OPT_REMOTE_FILTER},
148         { "sshkey", required_argument, NULL, OPT_SSHKEY},
149         { "sshkey-passphrase", required_argument, NULL, OPT_SSHKEY_PASSPHRASE},
150         { 0, 0, 0, 0}
151 };
152
153 #define verbose_print(...) { if (verbose) g_print(__VA_ARGS__); }
154 #define errmsg_print(...) { g_print(__VA_ARGS__); g_print("\n"); }
155
156 static char* local_interfaces_to_filter(unsigned int remote_port);
157
158 static void ssh_cleanup(ssh_session sshs, ssh_channel channel)
159 {
160         if (channel) {
161                 ssh_channel_send_eof(channel);
162                 ssh_channel_close(channel);
163                 ssh_channel_free(channel);
164         }
165
166         if (sshs) {
167                 ssh_disconnect(sshs);
168                 ssh_free(sshs);
169         }
170 }
171
172 static ssh_session create_ssh_connection(const char* hostname, const unsigned int port, const char* username,
173         const char* password, const char* sshkey_path, const char* sshkey_passphrase)
174 {
175         ssh_session sshs;
176
177         /* Open session and set options */
178         sshs = ssh_new();
179         if (sshs == NULL) {
180                 errmsg_print("Can't create ssh session");
181                 return NULL;
182         }
183
184         if (!hostname)
185                 return NULL;
186
187         if (ssh_options_set(sshs, SSH_OPTIONS_HOST, hostname)) {
188                 errmsg_print("Can't set the hostname: %s\n", hostname);
189                 goto failure;
190         }
191
192         if (port != 0) {
193                 if (ssh_options_set(sshs, SSH_OPTIONS_PORT, &port)) {
194                         errmsg_print("Can't set the port: %d\n", port);
195                         goto failure;
196                 }
197         }
198
199         if (!username)
200                 username = g_get_user_name();
201
202         if (ssh_options_set(sshs, SSH_OPTIONS_USER, username)) {
203                 errmsg_print("Can't set the username: %s\n", username);
204                 goto failure;
205         }
206
207         verbose_print("Opening ssh connection to %s@%s:%u\n", username, hostname, port);
208
209         /* Connect to server */
210         if (ssh_connect(sshs) != SSH_OK) {
211                 errmsg_print("Error connecting to %s@%s:%u (%s)\n", username, hostname, port,
212                         ssh_get_error(sshs));
213                 goto failure;
214         }
215
216 #ifdef HAVE_LIBSSH_USERAUTH_AGENT
217         verbose_print("Connecting using ssh-agent...");
218         /* Try to authenticate using ssh agent */
219         if (ssh_userauth_agent(sshs, NULL) == SSH_AUTH_SUCCESS) {
220                 verbose_print("done\n");
221                 return sshs;
222         }
223         verbose_print("failed\n");
224 #endif
225
226         /* If a public key path has been provided, try to authenticate using it */
227         if (sshkey_path) {
228                 ssh_key pkey = ssh_key_new();
229                 int ret;
230
231                 verbose_print("Connecting using public key in %s...", sshkey_path);
232                 ret = ssh_pki_import_privkey_file(sshkey_path, sshkey_passphrase, NULL, NULL, &pkey);
233
234                 if (ret == SSH_OK) {
235                         if (ssh_userauth_publickey(sshs, NULL, pkey) == SSH_AUTH_SUCCESS) {
236                                 verbose_print("done\n");
237                                 ssh_key_free(pkey);
238                                 return sshs;
239                         }
240                 }
241                 ssh_key_free(pkey);
242                 verbose_print("failed (%s)\n", ssh_get_error(sshs));
243         }
244
245         /* Try to authenticate using standard public key */
246         verbose_print("Connecting using standard public key...");
247         if (ssh_userauth_publickey_auto(sshs, NULL, NULL) == SSH_AUTH_SUCCESS) {
248                 verbose_print("done\n");
249                 return sshs;
250         }
251         verbose_print("failed\n");
252
253         /* If a password has been provided and all previous attempts failed, try to use it */
254         if (password) {
255                 verbose_print("Connecting using password...");
256                 if (ssh_userauth_password(sshs, username, password) == SSH_AUTH_SUCCESS) {
257                         verbose_print("done\n");
258                         return sshs;
259                 }
260                 verbose_print("failed\n");
261         }
262
263         verbose_print("Can't find a valid authentication. Disconnecting.\n");
264
265         /* All authentication failed. Disconnect and return */
266         ssh_disconnect(sshs);
267
268 failure:
269         ssh_free(sshs);
270         return NULL;
271 }
272
273 static void ssh_loop_read(ssh_channel channel, int fd)
274 {
275         int nbytes;
276         char buffer[SSH_READ_BLOCK_SIZE];
277
278         /* read from stdin until data are available */
279         do {
280                 nbytes = ssh_channel_read(channel, buffer, SSH_READ_BLOCK_SIZE, 0);
281                 if (write(fd, buffer, nbytes) != nbytes) {
282                         errmsg_print("ERROR reading: %s\n", g_strerror(errno));
283                         return;
284                 }
285         } while(nbytes > 0);
286
287         /* read loop finished... maybe something wrong happened. Read from stderr */
288         do {
289                 nbytes = ssh_channel_read(channel, buffer, SSH_READ_BLOCK_SIZE, 1);
290                 if (write(STDERR_FILENO, buffer, nbytes) != nbytes) {
291                         return;
292                 }
293         } while(nbytes > 0);
294
295         if (ssh_channel_send_eof(channel) != SSH_OK)
296                 return;
297 }
298
299 static ssh_channel run_ssh_command(ssh_session sshs, const char* capture_bin, const char* iface, const char* cfilter)
300 {
301         gchar* cmdline;
302         ssh_channel channel;
303         char* quoted_bin;
304         char* quoted_iface;
305         char* default_filter;
306         char* quoted_filter;
307         unsigned int remote_port = 22;
308
309         if (!capture_bin)
310                 capture_bin = "dumpcap";
311
312         if (!iface)
313                 iface = "eth0";
314
315         channel = ssh_channel_new(sshs);
316         if (!channel)
317                 return NULL;
318
319         if (ssh_channel_open_session(channel) != SSH_OK) {
320                 ssh_channel_free(channel);
321                 return NULL;
322         }
323
324         ssh_options_get_port(sshs, &remote_port);
325
326         /* escape parameters to go save with the shell */
327         quoted_bin = g_shell_quote(capture_bin);
328         quoted_iface = g_shell_quote(iface);
329         default_filter = local_interfaces_to_filter(remote_port);
330         if (!cfilter)
331                 cfilter = default_filter;
332         quoted_filter = g_shell_quote(cfilter);
333
334         cmdline = g_strdup_printf("%s -i %s -P -w - -f %s", quoted_bin, quoted_iface, quoted_filter);
335
336         verbose_print("Running: %s\n", cmdline);
337         if (ssh_channel_request_exec(channel, cmdline) != SSH_OK) {
338                 ssh_channel_close(channel);
339                 ssh_channel_free(channel);
340                 channel = NULL;
341         }
342
343         g_free(quoted_bin);
344         g_free(quoted_iface);
345         g_free(default_filter);
346         g_free(quoted_filter);
347         g_free(cmdline);
348
349         return channel;
350 }
351
352 static int ssh_open_remote_connection(const char* hostname, const unsigned int port, const char* username, const char* password,
353         const char* sshkey, const char* sshkey_passphrase, const char* iface, const char* cfilter, const char* capture_bin,
354         const char* fifo)
355 {
356         ssh_session sshs;
357         ssh_channel channel;
358         int fd;
359
360         if (!g_strcmp0(fifo, "-")) {
361                 /* use stdout */
362                 fd = STDOUT_FILENO;
363         } else {
364                 /* Open or create the output file */
365                 fd = open(fifo, O_WRONLY);
366                 if (fd == -1) {
367                         fd = open(fifo, O_WRONLY | O_CREAT, 0640);
368                         if (fd == -1) {
369                                 errmsg_print("Error creating output file: %s\n", g_strerror(errno));
370                                 return EXIT_FAILURE;
371                         }
372                 }
373         }
374
375         sshs = create_ssh_connection(hostname, port, username, password, sshkey, sshkey_passphrase);
376
377         if (!sshs)
378                 return EXIT_FAILURE;
379
380         channel = run_ssh_command(sshs, capture_bin, iface, cfilter);
381         if (!channel)
382                 return EXIT_FAILURE;
383
384         /* read from channel and write into fd */
385         ssh_loop_read(channel, fd);
386
387         /* clean up and exit */
388         ssh_cleanup(sshs, channel);
389
390         return EXIT_SUCCESS;
391 }
392
393 static void help(const char* binname)
394 {
395         g_print("Help\n");
396         g_print(" Usage:\n");
397         g_print(" %s --extcap-interfaces\n", binname);
398         g_print(" %s --extcap-interface=INTERFACE --extcap-dlts\n", binname);
399         g_print(" %s --extcap-interface=INTERFACE --extcap-config\n", binname);
400         g_print(" %s --extcap-interface=INTERFACE --remote-host myhost --remote-port 22222 "
401                 "--remote-username myuser --remote-interface eth2 --remote-capture-bin /bin/dumpcap "
402                 "--fifo=FILENAME --capture\n", binname);
403         g_print("\n\n");
404         g_print("  --help: print this help\n");
405         g_print("  --version: print the version\n");
406         g_print("  --verbose: print more messages\n");
407         g_print("  --extcap-interfaces: list the interfaces\n");
408         g_print("  --extcap-interface <iface>: specify the interface\n");
409         g_print("  --extcap-dlts: list the DTLs for an interface\n");
410         g_print("  --extcap-config: list the additional configuration for an interface\n");
411         g_print("  --extcap-capture-filter <filter>: the capture filter\n");
412         g_print("  --capture: run the capture\n");
413         g_print("  --fifo <file>: dump data to file or fifo\n");
414         g_print("  --remote-host <host>: the remote SSH host\n");
415         g_print("  --remote-port <port>: the remote SSH port (default: 22)\n");
416         g_print("  --remote-username <username>: the remote SSH username (default: the current user)\n");
417         g_print("  --remote-password <password>: the remote SSH password. If not specified, ssh-agent and ssh-key are used\n");
418         g_print("  --sshkey <public key path>: the path of the ssh key\n");
419         g_print("  --sshkey-passphrase <public key passphrase>: the passphrase to unlock public ssh\n");
420         g_print("  --remote-interface <iface>: the remote capture interface (default: eth0)\n");
421         g_print("  --remote-capture-bin <capture bin>: the remote dumcap binary (default: dumpcap\n");
422         g_print("  --remote-filter <filter>: a filter for remote capture (default: don't listen on local local interfaces IPs)\n");
423 }
424
425 static int list_interfaces(void)
426 {
427         g_print("interface {value=%s}{display=SSH remote capture}\n", SSH_EXTCAP_INTERFACE);
428         return EXIT_SUCCESS;
429 }
430
431 static int list_dlts(const char *interface)
432 {
433         if (!interface) {
434                 g_print("ERROR: No interface specified.\n");
435                 return EXIT_FAILURE;
436         }
437
438         if (g_strcmp0(interface, SSH_EXTCAP_INTERFACE)) {
439                 g_print("ERROR: interface must be %s\n", SSH_EXTCAP_INTERFACE);
440                 return EXIT_FAILURE;
441         }
442
443         g_print("dlt {number=147}{name=%s}{display=Remote capture dependant DLT}\n", SSH_EXTCAP_INTERFACE);
444         return EXIT_SUCCESS;
445 }
446
447
448 static char* local_interfaces_to_filter(unsigned int remote_port)
449 {
450 #ifdef USE_GETIFADDRS
451         struct ifaddrs* ifap;
452         struct ifaddrs* ifa;
453         GString* interfaces;
454         char* filter = NULL;
455         int family;
456         char ip[INET6_ADDRSTRLEN];
457
458         if (getifaddrs(&ifap)) {
459                 return NULL;
460         }
461
462         interfaces = g_string_new(NULL);
463
464         for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
465                 if (ifa->ifa_addr == NULL)
466                         continue;
467
468                 family = ifa->ifa_addr->sa_family;
469
470                 memset(&ip, 0x0, INET6_ADDRSTRLEN);
471
472                 switch (family) {
473                         case AF_INET:
474                                 {
475                                         struct sockaddr_in *addr4 = (struct sockaddr_in *)ifa->ifa_addr;
476                                         inet_ntop(family, (char *)&addr4->sin_addr, ip, sizeof(ip));
477                                         break;
478                                 }
479
480                         case AF_INET6:
481                                 {
482                                         struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)ifa->ifa_addr;
483                                         inet_ntop(family, (char *)&addr6->sin6_addr, ip, sizeof(ip));
484                                         break;
485                                 }
486
487                         default:
488                                 break;
489                 }
490
491                 /* skip loopback addresses */
492                 if (!g_strcmp0(ip, "127.0.0.1") || !g_strcmp0(ip, "::1"))
493                         continue;
494
495                 if (*ip) {
496                         if (interfaces->len)
497                                 g_string_append(interfaces, " or ");
498                         g_string_append_printf(interfaces, "host %s", ip);
499                 }
500         }
501         freeifaddrs(ifap);
502
503         if (interfaces->len)
504                 filter = g_strdup_printf("not ((%s) and port %u)", interfaces->str, remote_port);
505         g_string_free(interfaces, TRUE);
506
507         return filter;
508 #else
509         return NULL;
510 #endif
511 }
512
513 static int list_config(char *interface, unsigned int remote_port)
514 {
515         unsigned inc = 0;
516         char* ipfilter;
517
518         if (!interface) {
519                 g_fprintf(stderr, "ERROR: No interface specified.\n");
520                 return EXIT_FAILURE;
521         }
522
523         if (g_strcmp0(interface, SSH_EXTCAP_INTERFACE)) {
524                 errmsg_print("ERROR: interface must be %s\n", SSH_EXTCAP_INTERFACE);
525                 return EXIT_FAILURE;
526         }
527
528         ipfilter = local_interfaces_to_filter(remote_port);
529         if (!ipfilter)
530                 return EXIT_FAILURE;
531
532         g_print("arg {number=%u}{call=--remote-host}{display=Remote SSH server address}"
533                 "{type=string}{tooltip=The remote SSH host. It can be both "
534                 "an IP address or a hostname}\n", inc++);
535         g_print("arg {number=%u}{call=--remote-port}{display=Remote SSH server port}"
536                 "{type=unsigned}{default=22}{tooltip=The remote SSH host port (1-65535)}"
537                 "{range=1,65535}\n", inc++);
538         g_print("arg {number=%u}{call=--remote-username}{display=Remote SSH server username}"
539                 "{type=string}{default=%s}{tooltip=The remote SSH username. If not provided, "
540                 "the current user will be used}\n", inc++, g_get_user_name());
541         g_print("arg {number=%u}{call=--remote-password}{display=Remote SSH server password}"
542                 "{type=string}{tooltip=The SSH password, used when other methods (SSH agent "
543                 "or key files) are unavailable.}\n", inc++);
544         g_print("arg {number=%u}{call=--sshkey}{display=Path to SSH private key}"
545                 "{type=fileselect}{tooltip=The path on the local filesystem of the private ssh key}\n",
546                 inc++);
547         g_print("arg {number=%u}{call--sshkey-passphrase}{display=SSH key passphrase}\n"
548                 "{type=string}{tooltip=Passphrase to unlock the SSH private key}\n",
549                 inc++);
550         g_print("arg {number=%u}{call=--remote-interface}{display=Remote interface}"
551                 "{type=string}{default=eth0}{tooltip=The remote network interface used for capture"
552                 "}\n", inc++);
553         g_print("arg {number=%u}{call=--remote-capture-bin}{display=Remote capture binary}"
554                 "{type=string}{default=dumpcap}{tooltip=The remote dumpcap binary used "
555                 "for capture.}\n", inc++);
556         g_print("arg {number=%u}{call=--remote-filter}{display=Remote capture filter}"
557                 "{type=string}{default=%s}{tooltip=The remote capture filter}\n", inc++, ipfilter);
558
559         g_free(ipfilter);
560
561         return EXIT_SUCCESS;
562 }
563
564 static char* concat_filters(const char* extcap_filter, const char* remote_filter)
565 {
566         if (!extcap_filter && remote_filter)
567                 return g_strdup(remote_filter);
568
569         if (!remote_filter && extcap_filter)
570                 return g_strdup(extcap_filter);
571
572         if (!remote_filter && !extcap_filter)
573                 return NULL;
574
575         return g_strdup_printf("(%s) and (%s)", extcap_filter, remote_filter);
576 }
577
578 #ifdef _WIN32
579 BOOLEAN IsHandleRedirected(DWORD handle)
580 {
581         HANDLE h = GetStdHandle(handle);
582         if (h) {
583                 BY_HANDLE_FILE_INFORMATION fi;
584                 if (GetFileInformationByHandle(h, &fi)) {
585                         return TRUE;
586                 }
587         }
588         return FALSE;
589 }
590
591 static void attach_parent_console()
592 {
593         BOOL outRedirected, errRedirected;
594
595         outRedirected = IsHandleRedirected(STD_OUTPUT_HANDLE);
596         errRedirected = IsHandleRedirected(STD_ERROR_HANDLE);
597
598         if (outRedirected && errRedirected) {
599                 /* Both standard output and error handles are redirected.
600                  * There is no point in attaching to parent process console.
601                  */
602                 return;
603         }
604
605         if (AttachConsole(ATTACH_PARENT_PROCESS) == 0) {
606                 /* Console attach failed. */
607                 return;
608         }
609
610         /* Console attach succeeded */
611         if (outRedirected == FALSE) {
612                 freopen("CONOUT$", "w", stdout);
613         }
614
615         if (errRedirected == FALSE) {
616                 freopen("CONOUT$", "w", stderr);
617         }
618 }
619 #endif
620
621 int main(int argc, char **argv)
622 {
623         int result;
624         int option_idx = 0;
625         int do_list_interfaces = 0;
626         int do_config = 0;
627         int do_capture = 0;
628         int i;
629         char* interface = NULL;
630         char* remote_host = NULL;
631         unsigned int remote_port = 22;
632         char* remote_username = NULL;
633         char* remote_password = NULL;
634         int do_dlts = 0;
635         char* fifo = NULL;
636         char* remote_interface = NULL;
637         char* remote_capture_bin = NULL;
638         char* extcap_filter = NULL;
639         char* sshkey = NULL;
640         char* sshkey_passphrase = NULL;
641         char* remote_filter = NULL;
642
643 #ifdef _WIN32
644         WSADATA wsaData;
645
646         attach_parent_console();
647 #endif  /* _WIN32 */
648
649         opterr = 0;
650         optind = 0;
651
652         if (argc == 1) {
653                 help(argv[0]);
654                 return EXIT_FAILURE;
655         }
656
657         for (i = 0; i < argc; i++) {
658                 verbose_print("%s ", argv[i]);
659         }
660         verbose_print("\n");
661
662         while ((result = getopt_long(argc, argv, ":", longopts, &option_idx)) != -1) {
663
664                 switch (result) {
665
666                 case OPT_HELP:
667                         help(argv[0]);
668                         return EXIT_SUCCESS;
669
670                 case OPT_VERBOSE:
671                         verbose = TRUE;
672                         break;
673
674                 case OPT_VERSION:
675                         g_print("%u.%u.%u\n", SSHDUMP_VERSION_MAJOR, SSHDUMP_VERSION_MINOR, SSHDUMP_VERSION_RELEASE);
676                         return EXIT_SUCCESS;
677
678                 case OPT_LIST_INTERFACES:
679                         do_list_interfaces = 1;
680                         break;
681
682                 case OPT_LIST_DLTS:
683                         do_dlts = 1;
684                         break;
685
686                 case OPT_INTERFACE:
687                         if (interface)
688                                 g_free(interface);
689                         interface = g_strdup(optarg);
690                         break;
691
692                 case OPT_CONFIG:
693                         do_config = 1;
694                         break;
695
696                 case OPT_CAPTURE:
697                         do_capture = 1;
698                         break;
699
700                 case OPT_FIFO:
701                         if (fifo)
702                                 g_free(fifo);
703                         fifo = g_strdup(optarg);
704                         break;
705
706                 case OPT_REMOTE_HOST:
707                         if (remote_host)
708                                 g_free(remote_host);
709                         remote_host = g_strdup(optarg);
710                         break;
711
712                 case OPT_REMOTE_PORT:
713                         remote_port = (unsigned int)strtoul(optarg, NULL, 10);
714                         if (remote_port > 65535 || remote_port == 0) {
715                                 g_print("Invalid port: %s\n", optarg);
716                                 return EXIT_FAILURE;
717                         }
718                         break;
719
720                 case OPT_REMOTE_USERNAME:
721                         if (remote_username)
722                                 g_free(remote_username);
723                         remote_username = g_strdup(optarg);
724                         break;
725
726                 case OPT_REMOTE_PASSWORD:
727                         if (remote_password)
728                                 g_free(remote_password);
729                         remote_password = g_strdup(optarg);
730                         memset(optarg, 'X', strlen(optarg));
731                         break;
732
733                 case OPT_SSHKEY:
734                         if (sshkey)
735                                 g_free(sshkey);
736                         sshkey = g_strdup(optarg);
737                         break;
738
739                 case OPT_SSHKEY_PASSPHRASE:
740                         if (sshkey_passphrase)
741                                 g_free(sshkey_passphrase);
742                         sshkey_passphrase = g_strdup(optarg);
743                         memset(optarg, 'X', strlen(optarg));
744                         break;
745
746                 case OPT_REMOTE_INTERFACE:
747                         if (remote_interface)
748                                 g_free(remote_interface);
749                         remote_interface = g_strdup(optarg);
750                         break;
751
752                 case OPT_REMOTE_CAPTURE_BIN:
753                         if (remote_capture_bin)
754                                 g_free(remote_capture_bin);
755                         remote_capture_bin = g_strdup(optarg);
756                         break;
757
758                 case OPT_EXTCAP_FILTER:
759                         if (extcap_filter)
760                                 g_free(extcap_filter);
761                         extcap_filter = g_strdup(optarg);
762                         break;
763
764                 case OPT_REMOTE_FILTER:
765                         if (remote_filter)
766                                 g_free(remote_filter);
767                         remote_filter = g_strdup(optarg);
768                         break;
769
770                 case ':':
771                         /* missing option argument */
772                         g_print("Option '%s' requires an argument\n", argv[optind - 1]);
773                         break;
774
775                 default:
776                         g_print("Invalid option: %s\n", argv[optind - 1]);
777                         return EXIT_FAILURE;
778                 }
779         }
780
781         if (optind != argc) {
782                 g_print("Unexpected extra option: %s\n", argv[optind]);
783                 return EXIT_FAILURE;
784         }
785
786         if (do_list_interfaces)
787                 return list_interfaces();
788
789         if (do_config)
790                 return list_config(interface, remote_port);
791
792         if (do_dlts)
793                 return list_dlts(interface);
794
795 #ifdef _WIN32
796         result = WSAStartup(MAKEWORD(1,1), &wsaData);
797         if (result != 0) {
798                 if (verbose)
799                         errmsg_print("ERROR: WSAStartup failed with error: %d\n", result);
800                 return 1;
801         }
802 #endif  /* _WIN32 */
803
804         if (do_capture) {
805                 char* filter;
806                 int ret = 0;
807                 if (!fifo) {
808                         errmsg_print("ERROR: No FIFO or file specified\n");
809                         return 1;
810                 }
811                 if (g_strcmp0(interface, SSH_EXTCAP_INTERFACE)) {
812                         errmsg_print("ERROR: invalid interface\n");
813                         return 1;
814                 }
815                 if (!remote_host) {
816                         errmsg_print("Missing parameter: --remote-host");
817                         return 1;
818                 }
819                 filter = concat_filters(extcap_filter, remote_filter);
820                 ret = ssh_open_remote_connection(remote_host, remote_port, remote_username,
821                         remote_password, sshkey, sshkey_passphrase, remote_interface,
822                         filter, remote_capture_bin, fifo);
823                 g_free(filter);
824                 return ret;
825         }
826
827         verbose_print("You should not come here... maybe some parameter missing?\n");
828         return 1;
829 }
830
831
832 #ifdef _WIN32
833 int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
834                 LPSTR lpCmdLine, int nCmdShow) {
835         return main(__argc, __argv);
836 }
837 #endif
838
839 /*
840  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
841  *
842  * Local variables:
843  * c-basic-offset: 4
844  * tab-width: 4
845  * indent-tabs-mode: t
846  * End:
847  *
848  * vi: set shiftwidth=4 tabstop=4 noexpandtab:
849  * :indentSize=4:tabSize=4:noTabs=false:
850  */