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