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