1 /* snifftest.c
2  *
3  * Copyright (C) 2006-2021 wolfSSL Inc.
4  *
5  * This file is part of wolfSSL.
6  *
7  * wolfSSL is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * wolfSSL is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
20  */
21 
22 
23 #ifdef HAVE_CONFIG_H
24     #include <config.h>
25 #endif
26 
27 #include <wolfssl/wolfcrypt/settings.h>
28 #include <wolfssl/wolfcrypt/types.h>
29 #include <wolfssl/wolfcrypt/logging.h>
30 
31 #ifdef WOLFSSL_SNIFFER_STORE_DATA_CB
32     #include <wolfssl/wolfcrypt/memory.h>
33 #endif
34 
35 #ifdef _WIN32
36     #define WOLFSSL_SNIFFER
37 #endif
38 
39 #ifndef WOLFSSL_SNIFFER
40 #ifndef NO_MAIN_DRIVER
41 /* blank build */
42 #include <stdio.h>
43 #include <stdlib.h>
main(void)44 int main(void)
45 {
46     printf("do ./configure --enable-sniffer to enable build support\n");
47     return EXIT_SUCCESS;
48 }
49 #endif /* !NO_MAIN_DRIVER */
50 #else
51 /* do a full build */
52 
53 #ifdef _MSC_VER
54     /* builds on *nix too, for scanf device and port */
55     #define _CRT_SECURE_NO_WARNINGS
56 #endif
57 
58 #include <pcap/pcap.h>     /* pcap stuff */
59 #include <stdio.h>         /* printf */
60 #include <stdlib.h>        /* EXIT_SUCCESS */
61 #include <string.h>        /* strcmp */
62 #include <signal.h>        /* signal */
63 #include <ctype.h>         /* isprint */
64 
65 #include <cyassl/sniffer.h>
66 
67 
68 #ifndef _WIN32
69     #include <sys/socket.h>    /* AF_INET */
70     #include <arpa/inet.h>
71     #include <netinet/in.h>
72 #endif
73 
74 typedef unsigned char byte;
75 
76 enum {
77     ETHER_IF_FRAME_LEN = 14,   /* ethernet interface frame length */
78     NULL_IF_FRAME_LEN =   4,   /* no link interface frame length  */
79 };
80 
81 
82 /* A TLS record can be 16k and change. The chain is broken up into 2K chunks.
83  * This covers the TLS record, plus a chunk for TCP/IP headers. */
84 #ifndef CHAIN_INPUT_CHUNK_SIZE
85     #define CHAIN_INPUT_CHUNK_SIZE 2048
86 #elif (CHAIN_INPUT_CHUNK_SIZE < 256)
87     #undef CHAIN_INPUT_CHUNK_SIZE
88     #define CHAIN_INPUT_CHUNK_SIZE 256
89 #elif (CHAIN_INPUT_CHUNK_SIZE > 16384)
90     #undef CHAIN_INPUT_CHUNK_SIZE
91     #define CHAIN_INPUT_CHUNK_SIZE 16384
92 #endif
93 #define CHAIN_INPUT_COUNT ((16384 / CHAIN_INPUT_CHUNK_SIZE) + 1)
94 
95 
96 #ifndef STORE_DATA_BLOCK_SZ
97     #define STORE_DATA_BLOCK_SZ 1024
98 #endif
99 
100 #if defined(HAVE_ECC) && !defined(NO_ECC_SECP) && (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES))
101     #define DEFAULT_SERVER_EPH_KEY_ECC "../../certs/statickeys/ecc-secp256r1.pem"
102 #else
103     #define DEFAULT_SERVER_EPH_KEY_ECC ""
104 #endif
105 #ifndef NO_DH
106     #define DEFAULT_SERVER_EPH_KEY_DH "../../certs/statickeys/dh-ffdhe2048.pem"
107 #else
108     #define DEFAULT_SERVER_EPH_KEY_DH ""
109 #endif
110 #ifdef HAVE_CURVE25519
111     #define DEFAULT_SERVER_EPH_KEY_X25519 "../../certs/statickeys/x25519.pem"
112 #else
113     #define DEFAULT_SERVER_EPH_KEY_X25519 ""
114 #endif
115 
116 #ifndef DEFAULT_SERVER_EPH_KEY
117     #define DEFAULT_SERVER_EPH_KEY \
118                 DEFAULT_SERVER_EPH_KEY_ECC "," \
119                 DEFAULT_SERVER_EPH_KEY_DH "," \
120                 DEFAULT_SERVER_EPH_KEY_X25519
121 #endif
122 
123 #define DEFAULT_SERVER_KEY_RSA "../../certs/server-key.pem"
124 #define DEFAULT_SERVER_KEY_ECC "../../certs/ecc-key.pem"
125 #ifndef DEFAULT_SERVER_KEY
126     #ifndef NO_RSA
127         #define DEFAULT_SERVER_KEY DEFAULT_SERVER_KEY_RSA
128     #elif defined(HAVE_ECC)
129         #define DEFAULT_SERVER_KEY DEFAULT_SERVER_KEY_ECC
130     #endif
131 #endif
132 
133 
134 #ifdef WOLFSSL_SNIFFER_WATCH
135 static const byte rsaHash[] = {
136     0x3d, 0x4a, 0x60, 0xfc, 0xbf, 0xe5, 0x4d, 0x3e,
137     0x85, 0x62, 0xf2, 0xfc, 0xdb, 0x0d, 0x51, 0xdd,
138     0xcd, 0xc2, 0x53, 0x81, 0x1a, 0x67, 0x31, 0xa0,
139     0x7f, 0xd2, 0x11, 0x74, 0xbf, 0xea, 0xc9, 0xc5
140 };
141 static const byte eccHash[] = {
142     0x9e, 0x45, 0xb6, 0xf8, 0xc6, 0x5d, 0x60, 0x90,
143     0x40, 0x8f, 0xd2, 0x0e, 0xb1, 0x59, 0xe7, 0xbd,
144     0xb0, 0x9b, 0x3c, 0x7a, 0x3a, 0xbe, 0x13, 0x52,
145     0x07, 0x4f, 0x1a, 0x64, 0x45, 0xe0, 0x13, 0x34
146 };
147 #endif
148 
149 
150 pcap_t* pcap = NULL;
151 pcap_if_t* alldevs = NULL;
152 
153 
FreeAll(void)154 static void FreeAll(void)
155 {
156     if (pcap)
157         pcap_close(pcap);
158     if (alldevs)
159         pcap_freealldevs(alldevs);
160 #ifndef _WIN32
161     ssl_FreeSniffer();
162 #endif
163 }
164 
165 
166 #ifdef WOLFSSL_SNIFFER_STATS
DumpStats(void)167 static void DumpStats(void)
168 {
169     SSLStats sslStats;
170     ssl_ReadStatistics(&sslStats);
171 
172     printf("SSL Stats (sslStandardConns):%lu\n",
173             sslStats.sslStandardConns);
174     printf("SSL Stats (sslClientAuthConns):%lu\n",
175             sslStats.sslClientAuthConns);
176     printf("SSL Stats (sslResumedConns):%lu\n",
177             sslStats.sslResumedConns);
178     printf("SSL Stats (sslEphemeralMisses):%lu\n",
179             sslStats.sslEphemeralMisses);
180     printf("SSL Stats (sslResumptionInserts):%lu\n",
181             sslStats.sslResumptionInserts);
182     printf("SSL Stats (sslResumeMisses):%lu\n",
183             sslStats.sslResumeMisses);
184     printf("SSL Stats (sslCiphersUnsupported):%lu\n",
185             sslStats.sslCiphersUnsupported);
186     printf("SSL Stats (sslKeysUnmatched):%lu\n",
187             sslStats.sslKeysUnmatched);
188     printf("SSL Stats (sslKeyFails):%lu\n",
189             sslStats.sslKeyFails);
190     printf("SSL Stats (sslDecodeFails):%lu\n",
191             sslStats.sslDecodeFails);
192     printf("SSL Stats (sslAlerts):%lu\n",
193             sslStats.sslAlerts);
194     printf("SSL Stats (sslDecryptedBytes):%lu\n",
195             sslStats.sslDecryptedBytes);
196     printf("SSL Stats (sslEncryptedBytes):%lu\n",
197             sslStats.sslEncryptedBytes);
198     printf("SSL Stats (sslEncryptedPackets):%lu\n",
199             sslStats.sslEncryptedPackets);
200     printf("SSL Stats (sslDecryptedPackets):%lu\n",
201             sslStats.sslDecryptedPackets);
202     printf("SSL Stats (sslKeyMatches):%lu\n",
203             sslStats.sslKeyMatches);
204     printf("SSL Stats (sslEncryptedConns):%lu\n",
205             sslStats.sslEncryptedConns);
206 }
207 #endif /* WOLFSSL_SNIFFER_STATS */
208 
209 
sig_handler(const int sig)210 static void sig_handler(const int sig)
211 {
212     printf("SIGINT handled = %d.\n", sig);
213     FreeAll();
214 #ifdef WOLFSSL_SNIFFER_STATS
215     DumpStats();
216 #endif
217     if (sig)
218         exit(EXIT_SUCCESS);
219 }
220 
221 
err_sys(const char * msg)222 static void err_sys(const char* msg)
223 {
224     fprintf(stderr, "%s\n", msg);
225     if (msg)
226         exit(EXIT_FAILURE);
227 }
228 
229 
230 #ifdef _WIN32
231     #define SNPRINTF _snprintf
232 #else
233     #define SNPRINTF snprintf
234 #endif
235 
236 
iptos(const struct in_addr * addr)237 static char* iptos(const struct in_addr* addr)
238 {
239     static char output[32];
240     byte *p = (byte*)&addr->s_addr;
241 
242     snprintf(output, sizeof(output), "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
243 
244     return output;
245 }
246 
ip6tos(const struct in6_addr * addr)247 static const char* ip6tos(const struct in6_addr* addr)
248 {
249     static char output[42];
250     return inet_ntop(AF_INET6, addr, output, 42);
251 }
252 
253 
254 #if defined(WOLFSSL_SNIFFER_STORE_DATA_CB) || defined(WOLFSSL_SNIFFER_CHAIN_INPUT)
min(unsigned int a,unsigned int b)255 static inline unsigned int min(unsigned int a, unsigned int b)
256 {
257     return a > b ? b : a;
258 }
259 #endif
260 
261 
262 #ifdef WOLFSSL_SNIFFER_WATCH
myWatchCb(void * vSniffer,const unsigned char * certHash,unsigned int certHashSz,const unsigned char * certChain,unsigned int certChainSz,void * ctx,char * error)263 static int myWatchCb(void* vSniffer,
264         const unsigned char* certHash, unsigned int certHashSz,
265         const unsigned char* certChain, unsigned int certChainSz,
266         void* ctx, char* error)
267 {
268     const char* certName = NULL;
269 
270     (void)certChain;
271     (void)certChainSz;
272     (void)ctx;
273 
274     if (certHashSz == sizeof(rsaHash) &&
275             XMEMCMP(certHash, rsaHash, certHashSz) == 0) {
276         certName = DEFAULT_SERVER_KEY_RSA;
277     }
278     if (certHashSz == sizeof(eccHash) &&
279             XMEMCMP(certHash, eccHash, certHashSz) == 0) {
280         certName = DEFAULT_SERVER_KEY_ECC;
281     }
282 
283     if (certName == NULL) {
284         /* don't return error if key is not loaded */
285         printf("Warning: No matching key found for cert hash\n");
286         return 0;
287     }
288 
289     return ssl_SetWatchKey_file(vSniffer, certName, FILETYPE_PEM, NULL, error);
290 }
291 #endif /* WOLFSSL_SNIFFER_WATCH */
292 
293 
294 #ifdef WOLFSSL_SNIFFER_STORE_DATA_CB
myStoreDataCb(const unsigned char * decryptBuf,unsigned int decryptBufSz,unsigned int decryptBufOffset,void * ctx)295 static int myStoreDataCb(const unsigned char* decryptBuf,
296         unsigned int decryptBufSz, unsigned int decryptBufOffset, void* ctx)
297 {
298     byte** data = (byte**)ctx;
299     unsigned int qty;
300 
301     if (data == NULL)
302         return -1;
303 
304     if (decryptBufSz < decryptBufOffset)
305         return -1;
306 
307     qty = min(decryptBufSz - decryptBufOffset, STORE_DATA_BLOCK_SZ);
308 
309     if (*data == NULL) {
310         byte* tmpData;
311         tmpData = (byte*)XREALLOC(*data, decryptBufSz + 1,
312                 NULL, DYNAMIC_TYPE_TMP_BUFFER);
313         if (tmpData == NULL) {
314             XFREE(*data, NULL, DYNAMIC_TYPE_TMP_BUFFER);
315             *data = NULL;
316             return -1;
317         }
318         *data = tmpData;
319     }
320 
321     XMEMCPY(*data + decryptBufOffset, decryptBuf + decryptBufOffset, qty);
322 
323     return qty;
324 }
325 #endif /* WOLFSSL_SNIFFER_STORE_DATA_CB */
326 
327 /* try and load as both static ephemeral and private key */
328 /* only fail if no key is loaded */
329 /* Allow comma seperated list of files */
load_key(const char * name,const char * server,int port,const char * keyFiles,const char * passwd,char * err)330 static int load_key(const char* name, const char* server, int port,
331     const char* keyFiles, const char* passwd, char* err)
332 {
333     int ret = -1;
334     int loadCount = 0;
335     char *keyFile, *ptr = NULL;
336 
337     keyFile = XSTRTOK((char*)keyFiles, ",", &ptr);
338     while (keyFile != NULL) {
339 #ifdef WOLFSSL_STATIC_EPHEMERAL
340     #ifdef HAVE_SNI
341         ret = ssl_SetNamedEphemeralKey(name, server, port, keyFile,
342                             FILETYPE_PEM, passwd, err);
343     #else
344         ret = ssl_SetEphemeralKey(server, port, keyFile,
345                             FILETYPE_PEM, passwd, err);
346     #endif
347         if (ret == 0)
348             loadCount++;
349 #endif
350     #ifdef HAVE_SNI
351         ret = ssl_SetNamedPrivateKey(name, server, port, keyFile,
352                             FILETYPE_PEM, passwd, err);
353     #else
354         ret = ssl_SetPrivateKey(server, port, keyFile,
355                             FILETYPE_PEM, passwd, err);
356     #endif
357         if (ret == 0)
358             loadCount++;
359 
360         if (loadCount == 0) {
361             printf("Failed loading private key %s: ret %d\n", keyFile, ret);
362             printf("Please run directly from sslSniffer/sslSnifferTest dir\n");
363             ret = -1;
364         }
365         else {
366             ret = 0;
367         }
368 
369         keyFile = XSTRTOK(NULL, ",", &ptr);
370     }
371 
372     (void)name;
373     return ret;
374 }
375 
TrimNewLine(char * str)376 static void TrimNewLine(char* str)
377 {
378     word32 strSz = 0;
379     if (str)
380         strSz = (word32)XSTRLEN(str);
381     if (strSz > 0 && (str[strSz-1] == '\n' || str[strSz-1] == '\r'))
382         str[strSz-1] = '\0';
383 }
384 
main(int argc,char ** argv)385 int main(int argc, char** argv)
386 {
387     int          ret = 0;
388     int          hadBadPacket = 0;
389     int          inum = 0;
390     int          port = 0;
391     int          saveFile = 0;
392     int          i = 0, defDev = 0;
393     int          frame = ETHER_IF_FRAME_LEN;
394     char         err[PCAP_ERRBUF_SIZE];
395     char         filter[32];
396     const char  *keyFilesSrc = NULL;
397     char         keyFilesBuf[MAX_FILENAME_SZ];
398     char         keyFilesUser[MAX_FILENAME_SZ];
399     const char  *server = NULL;
400     const char  *sniName = NULL;
401     struct       bpf_program fp;
402     pcap_if_t   *d;
403     pcap_addr_t *a;
404 #ifdef WOLFSSL_SNIFFER_CHAIN_INPUT
405     struct iovec chain[CHAIN_INPUT_COUNT];
406     int          chainSz;
407 #endif
408 
409     signal(SIGINT, sig_handler);
410 
411 #ifndef _WIN32
412     ssl_InitSniffer();   /* dll load on Windows */
413 #endif
414     ssl_Trace("./tracefile.txt", err);
415     ssl_EnableRecovery(1, -1, err);
416 #ifdef WOLFSSL_SNIFFER_WATCH
417     ssl_SetWatchKeyCallback(myWatchCb, err);
418 #endif
419 #ifdef WOLFSSL_SNIFFER_STORE_DATA_CB
420     ssl_SetStoreDataCallback(myStoreDataCb);
421 #endif
422 
423     if (argc == 1) {
424         char cmdLineArg[128];
425         /* normal case, user chooses device and port */
426 
427         if (pcap_findalldevs(&alldevs, err) == -1)
428             err_sys("Error in pcap_findalldevs");
429 
430         for (d = alldevs; d; d=d->next) {
431             printf("%d. %s", ++i, d->name);
432             if (strcmp(d->name, "lo0") == 0) {
433                 defDev = i;
434             }
435             if (d->description)
436                 printf(" (%s)\n", d->description);
437             else
438                 printf(" (No description available)\n");
439         }
440 
441         if (i == 0)
442             err_sys("No interfaces found! Make sure pcap or WinPcap is"
443                     " installed correctly and you have sufficient permissions");
444 
445         printf("Enter the interface number (1-%d) [default: %d]: ", i, defDev);
446         XMEMSET(cmdLineArg, 0, sizeof(cmdLineArg));
447         if (XFGETS(cmdLineArg, sizeof(cmdLineArg), stdin))
448             inum = XATOI(cmdLineArg);
449         if (inum == 0)
450             inum = defDev;
451         else if (inum < 1 || inum > i)
452             err_sys("Interface number out of range");
453 
454         /* Jump to the selected adapter */
455         for (d = alldevs, i = 0; i < inum - 1; d = d->next, i++);
456 
457         pcap = pcap_create(d->name, err);
458 
459         if (pcap == NULL) printf("pcap_create failed %s\n", err);
460 
461         /* print out addresses for selected interface */
462         for (a = d->addresses; a; a = a->next) {
463             if (a->addr->sa_family == AF_INET) {
464                 server =
465                     iptos(&((struct sockaddr_in *)a->addr)->sin_addr);
466                 printf("server = %s\n", server);
467             }
468             else if (a->addr->sa_family == AF_INET6) {
469                 server =
470                     ip6tos(&((struct sockaddr_in6 *)a->addr)->sin6_addr);
471                 printf("server = %s\n", server);
472             }
473         }
474         if (server == NULL)
475             err_sys("Unable to get device IPv4 or IPv6 address");
476 
477         ret = pcap_set_snaplen(pcap, 65536);
478         if (ret != 0) printf("pcap_set_snaplen failed %s\n", pcap_geterr(pcap));
479 
480         ret = pcap_set_timeout(pcap, 1000);
481         if (ret != 0) printf("pcap_set_timeout failed %s\n", pcap_geterr(pcap));
482 
483         ret = pcap_set_buffer_size(pcap, 1000000);
484         if (ret != 0)
485             printf("pcap_set_buffer_size failed %s\n", pcap_geterr(pcap));
486 
487         ret = pcap_set_promisc(pcap, 1);
488         if (ret != 0) printf("pcap_set_promisc failed %s\n", pcap_geterr(pcap));
489 
490 
491         ret = pcap_activate(pcap);
492         if (ret != 0) printf("pcap_activate failed %s\n", pcap_geterr(pcap));
493 
494         printf("Enter the port to scan [default: 11111]: ");
495         XMEMSET(cmdLineArg, 0, sizeof(cmdLineArg));
496         if (XFGETS(cmdLineArg, sizeof(cmdLineArg), stdin)) {
497             port = XATOI(cmdLineArg);
498         }
499         if (port <= 0)
500             port = 11111;
501 
502         SNPRINTF(filter, sizeof(filter), "tcp and port %d", port);
503 
504         ret = pcap_compile(pcap, &fp, filter, 0, 0);
505         if (ret != 0) printf("pcap_compile failed %s\n", pcap_geterr(pcap));
506 
507         ret = pcap_setfilter(pcap, &fp);
508         if (ret != 0) printf("pcap_setfilter failed %s\n", pcap_geterr(pcap));
509 
510         /* optionally enter the private key to use */
511     #if defined(WOLFSSL_STATIC_EPHEMERAL) && defined(DEFAULT_SERVER_EPH_KEY)
512         keyFilesSrc = DEFAULT_SERVER_EPH_KEY;
513     #else
514         keyFilesSrc = DEFAULT_SERVER_KEY;
515     #endif
516         printf("Enter the server key [default: %s]: ", keyFilesSrc);
517         XMEMSET(keyFilesBuf, 0, sizeof(keyFilesBuf));
518         XMEMSET(keyFilesUser, 0, sizeof(keyFilesUser));
519         if (XFGETS(keyFilesUser, sizeof(keyFilesUser), stdin)) {
520             TrimNewLine(keyFilesUser);
521             if (XSTRLEN(keyFilesUser) > 0) {
522                 keyFilesSrc = keyFilesUser;
523             }
524         }
525         XSTRNCPY(keyFilesBuf, keyFilesSrc, sizeof(keyFilesBuf));
526 
527         /* optionally enter a named key (SNI) */
528     #if !defined(WOLFSSL_SNIFFER_WATCH) && defined(HAVE_SNI)
529         printf("Enter alternate SNI [default: none]: ");
530         XMEMSET(cmdLineArg, 0, sizeof(cmdLineArg));
531         if (XFGETS(cmdLineArg, sizeof(cmdLineArg), stdin)) {
532             TrimNewLine(cmdLineArg);
533             if (XSTRLEN(cmdLineArg) > 0) {
534                 sniName = cmdLineArg;
535             }
536         }
537     #endif /* !WOLFSSL_SNIFFER_WATCH && HAVE_SNI */
538 
539         /* get IPv4 or IPv6 addresses for selected interface */
540         for (a = d->addresses; a; a = a->next) {
541             server = NULL;
542             if (a->addr->sa_family == AF_INET) {
543                 server =
544                     iptos(&((struct sockaddr_in *)a->addr)->sin_addr);
545             }
546             else if (a->addr->sa_family == AF_INET6) {
547                 server =
548                     ip6tos(&((struct sockaddr_in6 *)a->addr)->sin6_addr);
549             }
550 
551             if (server) {
552                 XSTRNCPY(keyFilesBuf, keyFilesSrc, sizeof(keyFilesBuf));
553                 ret = load_key(sniName, server, port, keyFilesBuf, NULL, err);
554                 if (ret != 0) {
555                     exit(EXIT_FAILURE);
556                 }
557             }
558         }
559     }
560     else if (argc >= 3) {
561         saveFile = 1;
562         pcap = pcap_open_offline(argv[1], err);
563         if (pcap == NULL) {
564             printf("pcap_open_offline failed %s\n", err);
565             ret = -1;
566         }
567         else {
568             const char* passwd = NULL;
569 
570             /* defaults for server and port */
571             port = 443;
572             server = "127.0.0.1";
573             keyFilesSrc = argv[2];
574 
575             if (argc >= 4)
576                 server = argv[3];
577 
578             if (argc >= 5)
579                 port = XATOI(argv[4]);
580 
581             if (argc >= 6)
582                 passwd = argv[5];
583 
584             ret = load_key(NULL, server, port, keyFilesSrc, passwd, err);
585             if (ret != 0) {
586                 exit(EXIT_FAILURE);
587             }
588 
589             /* Only let through TCP/IP packets */
590             ret = pcap_compile(pcap, &fp, "(ip6 or ip) and tcp", 0, 0);
591             if (ret != 0) {
592                 printf("pcap_compile failed %s\n", pcap_geterr(pcap));
593                 exit(EXIT_FAILURE);
594             }
595 
596             ret = pcap_setfilter(pcap, &fp);
597             if (ret != 0) {
598                 printf("pcap_setfilter failed %s\n", pcap_geterr(pcap));
599                 exit(EXIT_FAILURE);
600             }
601         }
602     }
603     else {
604         /* usage error */
605         printf( "usage: ./snifftest or ./snifftest dump pemKey"
606                 " [server] [port] [password]\n");
607         exit(EXIT_FAILURE);
608     }
609 
610     if (ret != 0)
611         err_sys(err);
612 
613     if (pcap_datalink(pcap) == DLT_NULL)
614         frame = NULL_IF_FRAME_LEN;
615 
616     while (1) {
617         static int packetNumber = 0;
618         struct pcap_pkthdr header;
619         const unsigned char* packet = pcap_next(pcap, &header);
620         SSLInfo sslInfo;
621         packetNumber++;
622         if (packet) {
623 
624             byte* data = NULL;
625 
626             if (header.caplen > 40)  { /* min ip(20) + min tcp(20) */
627                 packet        += frame;
628                 header.caplen -= frame;
629             }
630             else
631                 continue;
632 #ifdef WOLFSSL_SNIFFER_CHAIN_INPUT
633             {
634                 unsigned int j = 0;
635                 unsigned int remainder = header.caplen;
636 
637                 chainSz = 0;
638                 do {
639                     unsigned int chunkSz;
640 
641                     chunkSz = min(remainder, CHAIN_INPUT_CHUNK_SIZE);
642                     chain[chainSz].iov_base = (void*)(packet + j);
643                     chain[chainSz].iov_len = chunkSz;
644                     j += chunkSz;
645                     remainder -= chunkSz;
646                     chainSz++;
647                 } while (j < header.caplen);
648             }
649 #endif
650 
651 #if defined(WOLFSSL_SNIFFER_CHAIN_INPUT) && \
652     defined(WOLFSSL_SNIFFER_STORE_DATA_CB)
653             ret = ssl_DecodePacketWithChainSessionInfoStoreData(chain, chainSz,
654                     &data, &sslInfo, err);
655 #elif defined(WOLFSSL_SNIFFER_CHAIN_INPUT)
656             (void)sslInfo;
657             ret = ssl_DecodePacketWithChain(chain, chainSz, &data, err);
658 #elif defined(WOLFSSL_SNIFFER_STORE_DATA_CB)
659             ret = ssl_DecodePacketWithSessionInfoStoreData(packet,
660                     header.caplen, &data, &sslInfo, err);
661 #else
662             ret = ssl_DecodePacketWithSessionInfo(packet, header.caplen, &data,
663                                                   &sslInfo, err);
664 #endif
665             if (ret < 0) {
666                 printf("ssl_Decode ret = %d, %s\n", ret, err);
667                 hadBadPacket = 1;
668             }
669             if (ret > 0) {
670                 int j;
671                 /* Convert non-printable data to periods. */
672                 for (j = 0; j < ret; j++) {
673                     if (isprint(data[j]) || isspace(data[j])) continue;
674                     data[j] = '.';
675                 }
676                 data[ret] = 0;
677                 printf("SSL App Data(%d:%d):%s\n", packetNumber, ret, data);
678                 ssl_FreeZeroDecodeBuffer(&data, ret, err);
679             }
680         }
681         else if (saveFile)
682             break;      /* we're done reading file */
683     }
684     FreeAll();
685 
686     return hadBadPacket ? EXIT_FAILURE : EXIT_SUCCESS;
687 }
688 
689 #endif /* full build */
690