extcap: add masked to options.
[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) printf(__VA_ARGS__); }
158 #define errmsg_print(...) { fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\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         errmsg_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         printf("Help\n");
407         printf(" Usage:\n");
408         printf(" %s --extcap-interfaces\n", binname);
409         printf(" %s --extcap-interface=INTERFACE --extcap-dlts\n", binname);
410         printf(" %s --extcap-interface=INTERFACE --extcap-config\n", binname);
411         printf(" %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         printf("\n\n");
415         printf("  --help: print this help\n");
416         printf("  --version: print the version\n");
417         printf("  --verbose: print more messages\n");
418         printf("  --extcap-interfaces: list the interfaces\n");
419         printf("  --extcap-interface <iface>: specify the interface\n");
420         printf("  --extcap-dlts: list the DTLs for an interface\n");
421         printf("  --extcap-config: list the additional configuration for an interface\n");
422         printf("  --extcap-capture-filter <filter>: the capture filter\n");
423         printf("  --capture: run the capture\n");
424         printf("  --fifo <file>: dump data to file or fifo\n");
425         printf("  --remote-host <host>: the remote SSH host\n");
426         printf("  --remote-port <port>: the remote SSH port (default: 22)\n");
427         printf("  --remote-username <username>: the remote SSH username (default: the current user)\n");
428         printf("  --remote-password <password>: the remote SSH password. If not specified, ssh-agent and ssh-key are used\n");
429         printf("  --sshkey <public key path>: the path of the ssh key\n");
430         printf("  --sshkey-passphrase <public key passphrase>: the passphrase to unlock public ssh\n");
431         printf("  --remote-interface <iface>: the remote capture interface (default: eth0)\n");
432         printf("  --remote-capture-bin <capture bin>: the remote dumcap binary (default: %s)\n", DEFAULT_CAPTURE_BIN);
433         printf("  --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         printf("extcap {version=%u.%u.%u}\n", SSHDUMP_VERSION_MAJOR, SSHDUMP_VERSION_MINOR, SSHDUMP_VERSION_RELEASE);
439         printf("interface {value=%s}{display=SSH remote capture}\n", SSH_EXTCAP_INTERFACE);
440         return EXIT_SUCCESS;
441 }
442
443 static int list_dlts(const char *interface)
444 {
445         if (!interface) {
446                 printf("ERROR: No interface specified.\n");
447                 return EXIT_FAILURE;
448         }
449
450         if (g_strcmp0(interface, SSH_EXTCAP_INTERFACE)) {
451                 printf("ERROR: interface must be %s\n", SSH_EXTCAP_INTERFACE);
452                 return EXIT_FAILURE;
453         }
454
455         printf("dlt {number=147}{name=%s}{display=Remote capture dependant DLT}\n", SSH_EXTCAP_INTERFACE);
456         return EXIT_SUCCESS;
457 }
458
459
460 static char* local_interfaces_to_filter(unsigned int remote_port)
461 {
462         char* filter = NULL;
463 #ifdef USE_GETIFADDRS
464         struct ifaddrs* ifap;
465         struct ifaddrs* ifa;
466         GString* interfaces;
467         int family;
468         char ip[INET6_ADDRSTRLEN];
469
470         if (getifaddrs(&ifap)) {
471                 goto end;
472         }
473
474         interfaces = g_string_new(NULL);
475
476         for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
477                 if (ifa->ifa_addr == NULL)
478                         continue;
479
480                 family = ifa->ifa_addr->sa_family;
481
482                 memset(&ip, 0x0, INET6_ADDRSTRLEN);
483
484                 switch (family) {
485                         case AF_INET:
486                                 {
487                                         struct sockaddr_in *addr4 = (struct sockaddr_in *)ifa->ifa_addr;
488                                         inet_ntop(family, (char *)&addr4->sin_addr, ip, sizeof(ip));
489                                         break;
490                                 }
491
492                         case AF_INET6:
493                                 {
494                                         struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)ifa->ifa_addr;
495                                         inet_ntop(family, (char *)&addr6->sin6_addr, ip, sizeof(ip));
496                                         break;
497                                 }
498
499                         default:
500                                 break;
501                 }
502
503                 /* skip loopback addresses */
504                 if (!g_strcmp0(ip, "127.0.0.1") || !g_strcmp0(ip, "::1"))
505                         continue;
506
507                 if (*ip) {
508                         if (interfaces->len)
509                                 g_string_append(interfaces, " or ");
510                         g_string_append_printf(interfaces, "host %s", ip);
511                 }
512         }
513         freeifaddrs(ifap);
514
515         if (interfaces->len)
516                 filter = g_strdup_printf("not ((%s) and port %u)", interfaces->str, remote_port);
517
518         g_string_free(interfaces, TRUE);
519 end:
520 #endif
521         if (!filter)
522                 filter = g_strdup_printf("not port %u", remote_port);
523         return filter;
524 }
525
526 static int list_config(char *interface, unsigned int remote_port)
527 {
528         unsigned inc = 0;
529         char* ipfilter;
530
531         if (!interface) {
532                 g_fprintf(stderr, "ERROR: No interface specified.\n");
533                 return EXIT_FAILURE;
534         }
535
536         if (g_strcmp0(interface, SSH_EXTCAP_INTERFACE)) {
537                 errmsg_print("ERROR: interface must be %s\n", SSH_EXTCAP_INTERFACE);
538                 return EXIT_FAILURE;
539         }
540
541         ipfilter = local_interfaces_to_filter(remote_port);
542
543         printf("arg {number=%u}{call=--remote-host}{display=Remote SSH server address}"
544                 "{type=string}{tooltip=The remote SSH host. It can be both "
545                 "an IP address or a hostname}{required=true}\n", inc++);
546         printf("arg {number=%u}{call=--remote-port}{display=Remote SSH server port}"
547                 "{type=unsigned}{default=22}{tooltip=The remote SSH host port (1-65535)}"
548                 "{range=1,65535}\n", inc++);
549         printf("arg {number=%u}{call=--remote-username}{display=Remote SSH server username}"
550                 "{type=string}{default=%s}{tooltip=The remote SSH username. If not provided, "
551                 "the current user will be used}\n", inc++, g_get_user_name());
552         printf("arg {number=%u}{call=--remote-password}{display=Remote SSH server password}"
553                 "{type=password}{tooltip=The SSH password, used when other methods (SSH agent "
554                 "or key files) are unavailable.}\n", inc++);
555         printf("arg {number=%u}{call=--sshkey}{display=Path to SSH private key}"
556                 "{type=fileselect}{tooltip=The path on the local filesystem of the private ssh key}\n",
557                 inc++);
558         printf("arg {number=%u}{call--sshkey-passphrase}{display=SSH key passphrase}\n"
559                 "{type=string}{tooltip=Passphrase to unlock the SSH private key}\n",
560                 inc++);
561         printf("arg {number=%u}{call=--remote-interface}{display=Remote interface}"
562                 "{type=string}{default=eth0}{tooltip=The remote network interface used for capture"
563                 "}\n", inc++);
564         printf("arg {number=%u}{call=--remote-capture-bin}{display=Remote capture binary}"
565                 "{type=string}{default=%s}{tooltip=The remote dumpcap binary used "
566                 "for capture.}\n", inc++, DEFAULT_CAPTURE_BIN);
567         printf("arg {number=%u}{call=--remote-filter}{display=Remote capture filter}"
568                 "{type=string}{default=%s}{tooltip=The remote capture filter}\n", inc++, ipfilter);
569         printf("arg {number=%u}{call=--remote-count}{display=Packets to capture}"
570                 "{type=unsigned}{default=0}{tooltip=The number of remote packets to capture. (Default: inf)}\n",
571                 inc++);
572
573         g_free(ipfilter);
574
575         return EXIT_SUCCESS;
576 }
577
578 static char* concat_filters(const char* extcap_filter, const char* remote_filter)
579 {
580         if (!extcap_filter && remote_filter)
581                 return g_strdup(remote_filter);
582
583         if (!remote_filter && extcap_filter)
584                 return g_strdup(extcap_filter);
585
586         if (!remote_filter && !extcap_filter)
587                 return NULL;
588
589         return g_strdup_printf("(%s) and (%s)", extcap_filter, remote_filter);
590 }
591
592 #ifdef _WIN32
593 BOOLEAN IsHandleRedirected(DWORD handle)
594 {
595         HANDLE h = GetStdHandle(handle);
596         if (h) {
597                 BY_HANDLE_FILE_INFORMATION fi;
598                 if (GetFileInformationByHandle(h, &fi)) {
599                         return TRUE;
600                 }
601         }
602         return FALSE;
603 }
604
605 static void attach_parent_console()
606 {
607         BOOL outRedirected, errRedirected;
608
609         outRedirected = IsHandleRedirected(STD_OUTPUT_HANDLE);
610         errRedirected = IsHandleRedirected(STD_ERROR_HANDLE);
611
612         if (outRedirected && errRedirected) {
613                 /* Both standard output and error handles are redirected.
614                  * There is no point in attaching to parent process console.
615                  */
616                 return;
617         }
618
619         if (AttachConsole(ATTACH_PARENT_PROCESS) == 0) {
620                 /* Console attach failed. */
621                 return;
622         }
623
624         /* Console attach succeeded */
625         if (outRedirected == FALSE) {
626                 freopen("CONOUT$", "w", stdout);
627         }
628
629         if (errRedirected == FALSE) {
630                 freopen("CONOUT$", "w", stderr);
631         }
632 }
633 #endif
634
635 int main(int argc, char **argv)
636 {
637         int result;
638         int option_idx = 0;
639         int do_list_interfaces = 0;
640         int do_config = 0;
641         int do_capture = 0;
642         int i;
643         char* interface = NULL;
644         char* remote_host = NULL;
645         unsigned int remote_port = 22;
646         char* remote_username = NULL;
647         char* remote_password = NULL;
648         int do_dlts = 0;
649         char* fifo = NULL;
650         char* remote_interface = NULL;
651         char* remote_capture_bin = NULL;
652         char* extcap_filter = NULL;
653         char* sshkey = NULL;
654         char* sshkey_passphrase = NULL;
655         char* remote_filter = NULL;
656         unsigned long int count = 0;
657
658 #ifdef _WIN32
659         WSADATA wsaData;
660
661         attach_parent_console();
662 #endif  /* _WIN32 */
663
664         opterr = 0;
665         optind = 0;
666
667         if (argc == 1) {
668                 help(argv[0]);
669                 return EXIT_FAILURE;
670         }
671
672         for (i = 0; i < argc; i++) {
673                 verbose_print("%s ", argv[i]);
674         }
675         verbose_print("\n");
676
677         while ((result = getopt_long(argc, argv, ":", longopts, &option_idx)) != -1) {
678
679                 switch (result) {
680
681                 case OPT_HELP:
682                         help(argv[0]);
683                         return EXIT_SUCCESS;
684
685                 case OPT_VERBOSE:
686                         verbose = TRUE;
687                         break;
688
689                 case OPT_VERSION:
690                         printf("%u.%u.%u\n", SSHDUMP_VERSION_MAJOR, SSHDUMP_VERSION_MINOR, SSHDUMP_VERSION_RELEASE);
691                         return EXIT_SUCCESS;
692
693                 case OPT_LIST_INTERFACES:
694                         do_list_interfaces = 1;
695                         break;
696
697                 case OPT_LIST_DLTS:
698                         do_dlts = 1;
699                         break;
700
701                 case OPT_INTERFACE:
702                         if (interface)
703                                 g_free(interface);
704                         interface = g_strdup(optarg);
705                         break;
706
707                 case OPT_CONFIG:
708                         do_config = 1;
709                         break;
710
711                 case OPT_CAPTURE:
712                         do_capture = 1;
713                         break;
714
715                 case OPT_FIFO:
716                         if (fifo)
717                                 g_free(fifo);
718                         fifo = g_strdup(optarg);
719                         break;
720
721                 case OPT_REMOTE_HOST:
722                         if (remote_host)
723                                 g_free(remote_host);
724                         remote_host = g_strdup(optarg);
725                         break;
726
727                 case OPT_REMOTE_PORT:
728                         remote_port = (unsigned int)strtoul(optarg, NULL, 10);
729                         if (remote_port > 65535 || remote_port == 0) {
730                                 printf("Invalid port: %s\n", optarg);
731                                 return EXIT_FAILURE;
732                         }
733                         break;
734
735                 case OPT_REMOTE_USERNAME:
736                         if (remote_username)
737                                 g_free(remote_username);
738                         remote_username = g_strdup(optarg);
739                         break;
740
741                 case OPT_REMOTE_PASSWORD:
742                         if (remote_password)
743                                 g_free(remote_password);
744                         remote_password = g_strdup(optarg);
745                         memset(optarg, 'X', strlen(optarg));
746                         break;
747
748                 case OPT_SSHKEY:
749                         if (sshkey)
750                                 g_free(sshkey);
751                         sshkey = g_strdup(optarg);
752                         break;
753
754                 case OPT_SSHKEY_PASSPHRASE:
755                         if (sshkey_passphrase)
756                                 g_free(sshkey_passphrase);
757                         sshkey_passphrase = g_strdup(optarg);
758                         memset(optarg, 'X', strlen(optarg));
759                         break;
760
761                 case OPT_REMOTE_INTERFACE:
762                         if (remote_interface)
763                                 g_free(remote_interface);
764                         remote_interface = g_strdup(optarg);
765                         break;
766
767                 case OPT_REMOTE_CAPTURE_BIN:
768                         if (remote_capture_bin)
769                                 g_free(remote_capture_bin);
770                         remote_capture_bin = g_strdup(optarg);
771                         break;
772
773                 case OPT_EXTCAP_FILTER:
774                         if (extcap_filter)
775                                 g_free(extcap_filter);
776                         extcap_filter = g_strdup(optarg);
777                         break;
778
779                 case OPT_REMOTE_FILTER:
780                         if (remote_filter)
781                                 g_free(remote_filter);
782                         remote_filter = g_strdup(optarg);
783                         break;
784
785                 case OPT_REMOTE_COUNT:
786                         count = strtoul(optarg, NULL, 10);
787                         break;
788
789                 case ':':
790                         /* missing option argument */
791                         printf("Option '%s' requires an argument\n", argv[optind - 1]);
792                         break;
793
794                 default:
795                         printf("Invalid option: %s\n", argv[optind - 1]);
796                         return EXIT_FAILURE;
797                 }
798         }
799
800         if (optind != argc) {
801                 printf("Unexpected extra option: %s\n", argv[optind]);
802                 return EXIT_FAILURE;
803         }
804
805         if (do_list_interfaces)
806                 return list_interfaces();
807
808         if (do_config)
809                 return list_config(interface, remote_port);
810
811         if (do_dlts)
812                 return list_dlts(interface);
813
814 #ifdef _WIN32
815         result = WSAStartup(MAKEWORD(1,1), &wsaData);
816         if (result != 0) {
817                 if (verbose)
818                         errmsg_print("ERROR: WSAStartup failed with error: %d\n", result);
819                 return 1;
820         }
821 #endif  /* _WIN32 */
822
823         if (do_capture) {
824                 char* filter;
825                 int ret = 0;
826                 if (!fifo) {
827                         errmsg_print("ERROR: No FIFO or file specified\n");
828                         return 1;
829                 }
830                 if (g_strcmp0(interface, SSH_EXTCAP_INTERFACE)) {
831                         errmsg_print("ERROR: invalid interface\n");
832                         return 1;
833                 }
834                 if (!remote_host) {
835                         errmsg_print("Missing parameter: --remote-host");
836                         return 1;
837                 }
838                 filter = concat_filters(extcap_filter, remote_filter);
839                 ret = ssh_open_remote_connection(remote_host, remote_port, remote_username,
840                         remote_password, sshkey, sshkey_passphrase, remote_interface,
841                         filter, remote_capture_bin, count, fifo);
842                 g_free(filter);
843                 return ret;
844         }
845
846         verbose_print("You should not come here... maybe some parameter missing?\n");
847         return 1;
848 }
849
850
851 #ifdef _WIN32
852 int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
853                 LPSTR lpCmdLine, int nCmdShow) {
854         return main(__argc, __argv);
855 }
856 #endif
857
858 /*
859  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
860  *
861  * Local variables:
862  * c-basic-offset: 4
863  * tab-width: 4
864  * indent-tabs-mode: t
865  * End:
866  *
867  * vi: set shiftwidth=4 tabstop=4 noexpandtab:
868  * :indentSize=4:tabSize=4:noTabs=false:
869  */