]> The Tcpdump Group git mirrors - tcpdump/blob - util-print.c
Add a nd_printjnp() function
[tcpdump] / util-print.c
1 /*
2 * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that: (1) source code distributions
7 * retain the above copyright notice and this paragraph in its entirety, (2)
8 * distributions including binary code include the above copyright notice and
9 * this paragraph in its entirety in the documentation or other materials
10 * provided with the distribution, and (3) all advertising materials mentioning
11 * features or use of this software display the following acknowledgement:
12 * ``This product includes software developed by the University of California,
13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14 * the University nor the names of its contributors may be used to endorse
15 * or promote products derived from this software without specific prior
16 * written permission.
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 */
21
22 /*
23 * txtproto_print() derived from original code by Hannes Gredler
24 * (hannes@gredler.at):
25 *
26 * Redistribution and use in source and binary forms, with or without
27 * modification, are permitted provided that: (1) source code
28 * distributions retain the above copyright notice and this paragraph
29 * in its entirety, and (2) distributions including binary code include
30 * the above copyright notice and this paragraph in its entirety in
31 * the documentation or other materials provided with the distribution.
32 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
33 * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
34 * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
35 * FOR A PARTICULAR PURPOSE.
36 */
37
38 #ifdef HAVE_CONFIG_H
39 #include <config.h>
40 #endif
41
42 #include "netdissect-stdinc.h"
43
44 #include <sys/stat.h>
45
46 #ifdef HAVE_FCNTL_H
47 #include <fcntl.h>
48 #endif
49 #include <stdio.h>
50 #include <stdarg.h>
51 #include <stdlib.h>
52 #include <string.h>
53
54 #include "netdissect-ctype.h"
55
56 #include "netdissect.h"
57 #include "extract.h"
58 #include "ascii_strcasecmp.h"
59 #include "timeval-operations.h"
60
61 #define TOKBUFSIZE 128
62
63 enum date_flag { WITHOUT_DATE = 0, WITH_DATE = 1 };
64 enum time_flag { UTC_TIME = 0, LOCAL_TIME = 1 };
65
66 /*
67 * Print out a character, filtering out the non-printable ones
68 */
69 void
70 fn_print_char(netdissect_options *ndo, u_char c)
71 {
72 if (!ND_ISASCII(c)) {
73 c = ND_TOASCII(c);
74 ND_PRINT("M-");
75 }
76 if (!ND_ASCII_ISPRINT(c)) {
77 c ^= 0x40; /* DEL to ?, others to alpha */
78 ND_PRINT("^");
79 }
80 ND_PRINT("%c", c);
81 }
82
83 /*
84 * Print a null-terminated string, filtering out non-printable characters.
85 * DON'T USE IT with a pointer on the packet buffer because there is no
86 * truncation check. For this use, see the nd_printX() functions below.
87 */
88 void
89 fn_print_str(netdissect_options *ndo, const u_char *s)
90 {
91 while (*s != '\0') {
92 fn_print_char(ndo, *s);
93 s++;
94 }
95 }
96
97 /*
98 * Print out a null-terminated filename (or other ASCII string), part of
99 * the packet buffer.
100 * If ep is NULL, assume no truncation check is needed.
101 * Return true if truncated.
102 * Stop at ep (if given) or before the null char, whichever is first.
103 */
104 int
105 nd_print(netdissect_options *ndo,
106 const u_char *s, const u_char *ep)
107 {
108 int ret;
109 u_char c;
110
111 ret = 1; /* assume truncated */
112 while (ep == NULL || s < ep) {
113 c = GET_U_1(s);
114 s++;
115 if (c == '\0') {
116 ret = 0;
117 break;
118 }
119 fn_print_char(ndo, c);
120 }
121 return(ret);
122 }
123
124 /*
125 * Print out a null-terminated filename (or other ASCII string) from
126 * a fixed-length field in the packet buffer, or from what remains of
127 * the packet.
128 *
129 * n is the length of the fixed-length field, or the number of bytes
130 * remaining in the packet based on its on-the-network length.
131 *
132 * If ep is non-null, it should point just past the last captured byte
133 * of the packet, e.g. ndo->ndo_snapend. If ep is NULL, we assume no
134 * truncation check, other than the checks of the field length/remaining
135 * packet data length, is needed.
136 *
137 * Return the number of bytes of string processed, including the
138 * terminating null, if not truncated; as the terminating null is
139 * included in the count, and as there must be a terminating null,
140 * this will always be non-zero. Return 0 if truncated.
141 */
142 u_int
143 nd_printztn(netdissect_options *ndo,
144 const u_char *s, u_int n, const u_char *ep)
145 {
146 u_int bytes;
147 u_char c;
148
149 bytes = 0;
150 for (;;) {
151 if (n == 0 || (ep != NULL && s >= ep)) {
152 /*
153 * Truncated. This includes "no null before we
154 * got to the end of the fixed-length buffer or
155 * the end of the packet".
156 *
157 * XXX - BOOTP says "null-terminated", which
158 * means the maximum length of the string, in
159 * bytes, is 1 less than the size of the buffer,
160 * as there must always be a terminating null.
161 */
162 bytes = 0;
163 break;
164 }
165
166 c = GET_U_1(s);
167 s++;
168 bytes++;
169 n--;
170 if (c == '\0') {
171 /* End of string */
172 break;
173 }
174 fn_print_char(ndo, c);
175 }
176 return(bytes);
177 }
178
179 /*
180 * Print out a counted filename (or other ASCII string), part of
181 * the packet buffer.
182 * If ep is NULL, assume no truncation check is needed.
183 * Return true if truncated.
184 * Stop at ep (if given) or after n bytes, whichever is first.
185 */
186 int
187 nd_printn(netdissect_options *ndo,
188 const u_char *s, u_int n, const u_char *ep)
189 {
190 u_char c;
191
192 while (n > 0 && (ep == NULL || s < ep)) {
193 n--;
194 c = GET_U_1(s);
195 s++;
196 fn_print_char(ndo, c);
197 }
198 return (n == 0) ? 0 : 1;
199 }
200
201 /*
202 * Print out a null-padded filename (or other ASCII string), part of
203 * the packet buffer.
204 * If ep is NULL, assume no truncation check is needed.
205 * Return true if truncated.
206 * Stop at ep (if given) or after n bytes or before the null char,
207 * whichever is first.
208 */
209 int
210 nd_printzp(netdissect_options *ndo,
211 const u_char *s, u_int n,
212 const u_char *ep)
213 {
214 int ret;
215 u_char c;
216
217 ret = 1; /* assume truncated */
218 while (n > 0 && (ep == NULL || s < ep)) {
219 n--;
220 c = GET_U_1(s);
221 s++;
222 if (c == '\0') {
223 ret = 0;
224 break;
225 }
226 fn_print_char(ndo, c);
227 }
228 return (n == 0) ? 0 : ret;
229 }
230
231 /*
232 * Print a null-padded filename (or other ASCII string), part of
233 * the packet buffer, filtering out non-printable characters.
234 * Stop if truncated (via GET_U_1/longjmp) or after n bytes or before
235 * the null char, whichever occurs first.
236 * The suffix comes from: j:longJmp, n:after N bytes, p:null-Padded.
237 */
238 void
239 nd_printjnp(netdissect_options *ndo, const u_char *s, u_int n)
240 {
241 u_char c;
242
243 while (n > 0) {
244 c = GET_U_1(s);
245 if (c == '\0')
246 break;
247 fn_print_char(ndo, c);
248 n--;
249 s++;
250 }
251 }
252
253 /*
254 * Print the timestamp .FRAC part (Microseconds/nanoseconds)
255 */
256 static void
257 ts_frac_print(netdissect_options *ndo, long usec)
258 {
259 #ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
260 switch (ndo->ndo_tstamp_precision) {
261
262 case PCAP_TSTAMP_PRECISION_MICRO:
263 ND_PRINT(".%06u", (unsigned)usec);
264 break;
265
266 case PCAP_TSTAMP_PRECISION_NANO:
267 ND_PRINT(".%09u", (unsigned)usec);
268 break;
269
270 default:
271 ND_PRINT(".{unknown}");
272 break;
273 }
274 #else
275 ND_PRINT(".%06u", (unsigned)usec);
276 #endif
277 }
278
279 /*
280 * Print the timestamp as [YY:MM:DD] HH:MM:SS.FRAC.
281 * if time_flag == LOCAL_TIME print local time else UTC/GMT time
282 * if date_flag == WITH_DATE print YY:MM:DD before HH:MM:SS.FRAC
283 */
284 static void
285 ts_date_hmsfrac_print(netdissect_options *ndo, long sec, long usec,
286 enum date_flag date_flag, enum time_flag time_flag)
287 {
288 time_t Time = sec;
289 struct tm *tm;
290 char timestr[32];
291
292 if ((unsigned)sec & 0x80000000) {
293 ND_PRINT("[Error converting time]");
294 return;
295 }
296
297 if (time_flag == LOCAL_TIME)
298 tm = localtime(&Time);
299 else
300 tm = gmtime(&Time);
301
302 if (!tm) {
303 ND_PRINT("[Error converting time]");
304 return;
305 }
306 if (date_flag == WITH_DATE)
307 strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S", tm);
308 else
309 strftime(timestr, sizeof(timestr), "%H:%M:%S", tm);
310 ND_PRINT("%s", timestr);
311
312 ts_frac_print(ndo, usec);
313 }
314
315 /*
316 * Print the timestamp - Unix timeval style, as SECS.FRAC.
317 */
318 static void
319 ts_unix_print(netdissect_options *ndo, long sec, long usec)
320 {
321 if ((unsigned)sec & 0x80000000) {
322 ND_PRINT("[Error converting time]");
323 return;
324 }
325
326 ND_PRINT("%u", (unsigned)sec);
327 ts_frac_print(ndo, usec);
328 }
329
330 /*
331 * Print the timestamp
332 */
333 void
334 ts_print(netdissect_options *ndo,
335 const struct timeval *tvp)
336 {
337 static struct timeval tv_ref;
338 struct timeval tv_result;
339 int negative_offset;
340 int nano_prec;
341
342 switch (ndo->ndo_tflag) {
343
344 case 0: /* Default */
345 ts_date_hmsfrac_print(ndo, tvp->tv_sec, tvp->tv_usec,
346 WITHOUT_DATE, LOCAL_TIME);
347 ND_PRINT(" ");
348 break;
349
350 case 1: /* No time stamp */
351 break;
352
353 case 2: /* Unix timeval style */
354 ts_unix_print(ndo, tvp->tv_sec, tvp->tv_usec);
355 ND_PRINT(" ");
356 break;
357
358 case 3: /* Microseconds/nanoseconds since previous packet */
359 case 5: /* Microseconds/nanoseconds since first packet */
360 #ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
361 switch (ndo->ndo_tstamp_precision) {
362 case PCAP_TSTAMP_PRECISION_MICRO:
363 nano_prec = 0;
364 break;
365 case PCAP_TSTAMP_PRECISION_NANO:
366 nano_prec = 1;
367 break;
368 default:
369 nano_prec = 0;
370 break;
371 }
372 #else
373 nano_prec = 0;
374 #endif
375 if (!(netdissect_timevalisset(&tv_ref)))
376 tv_ref = *tvp; /* set timestamp for first packet */
377
378 negative_offset = netdissect_timevalcmp(tvp, &tv_ref, <);
379 if (negative_offset)
380 netdissect_timevalsub(&tv_ref, tvp, &tv_result, nano_prec);
381 else
382 netdissect_timevalsub(tvp, &tv_ref, &tv_result, nano_prec);
383
384 ND_PRINT((negative_offset ? "-" : " "));
385 ts_date_hmsfrac_print(ndo, tv_result.tv_sec, tv_result.tv_usec,
386 WITHOUT_DATE, UTC_TIME);
387 ND_PRINT(" ");
388
389 if (ndo->ndo_tflag == 3)
390 tv_ref = *tvp; /* set timestamp for previous packet */
391 break;
392
393 case 4: /* Date + Default */
394 ts_date_hmsfrac_print(ndo, tvp->tv_sec, tvp->tv_usec,
395 WITH_DATE, LOCAL_TIME);
396 ND_PRINT(" ");
397 break;
398 }
399 }
400
401 /*
402 * Print an unsigned relative number of seconds (e.g. hold time, prune timer)
403 * in the form 5m1s. This does no truncation, so 32230861 seconds
404 * is represented as 1y1w1d1h1m1s.
405 */
406 void
407 unsigned_relts_print(netdissect_options *ndo,
408 uint32_t secs)
409 {
410 static const char *lengths[] = {"y", "w", "d", "h", "m", "s"};
411 static const u_int seconds[] = {31536000, 604800, 86400, 3600, 60, 1};
412 const char **l = lengths;
413 const u_int *s = seconds;
414
415 if (secs == 0) {
416 ND_PRINT("0s");
417 return;
418 }
419 while (secs > 0) {
420 if (secs >= *s) {
421 ND_PRINT("%u%s", secs / *s, *l);
422 secs -= (secs / *s) * *s;
423 }
424 s++;
425 l++;
426 }
427 }
428
429 /*
430 * Print a signed relative number of seconds (e.g. hold time, prune timer)
431 * in the form 5m1s. This does no truncation, so 32230861 seconds
432 * is represented as 1y1w1d1h1m1s.
433 */
434 void
435 signed_relts_print(netdissect_options *ndo,
436 int32_t secs)
437 {
438 if (secs < 0) {
439 ND_PRINT("-");
440 if (secs == INT32_MIN) {
441 /*
442 * -2^31; you can't fit its absolute value into
443 * a 32-bit signed integer.
444 *
445 * Just directly pass said absolute value to
446 * unsigned_relts_print() directly.
447 *
448 * (XXX - does ISO C guarantee that -(-2^n),
449 * when calculated and cast to an n-bit unsigned
450 * integer type, will have the value 2^n?)
451 */
452 unsigned_relts_print(ndo, 2147483648U);
453 } else {
454 /*
455 * We now know -secs will fit into an int32_t;
456 * negate it and pass that to unsigned_relts_print().
457 */
458 unsigned_relts_print(ndo, -secs);
459 }
460 return;
461 }
462 unsigned_relts_print(ndo, secs);
463 }
464
465 /* Print the truncated string */
466 void nd_print_trunc(netdissect_options *ndo)
467 {
468 ND_PRINT(" [|%s]", ndo->ndo_protocol);
469 }
470
471 /* Print the protocol name */
472 void nd_print_protocol(netdissect_options *ndo)
473 {
474 ND_PRINT("%s", ndo->ndo_protocol);
475 }
476
477 /* Print the protocol name in caps (uppercases) */
478 void nd_print_protocol_caps(netdissect_options *ndo)
479 {
480 const char *p;
481 for (p = ndo->ndo_protocol; *p != '\0'; p++)
482 ND_PRINT("%c", ND_ASCII_TOUPPER(*p));
483 }
484
485 /* Print the invalid string */
486 void nd_print_invalid(netdissect_options *ndo)
487 {
488 ND_PRINT(" (invalid)");
489 }
490
491 /*
492 * this is a generic routine for printing unknown data;
493 * we pass on the linefeed plus indentation string to
494 * get a proper output - returns 0 on error
495 */
496
497 int
498 print_unknown_data(netdissect_options *ndo, const u_char *cp,
499 const char *ident, u_int len)
500 {
501 u_int len_to_print;
502
503 len_to_print = len;
504 if (!ND_TTEST_LEN(cp, 0)) {
505 ND_PRINT("%sDissector error: print_unknown_data called with pointer past end of packet",
506 ident);
507 return(0);
508 }
509 if (ND_BYTES_AVAILABLE_AFTER(cp) < len_to_print)
510 len_to_print = ND_BYTES_AVAILABLE_AFTER(cp);
511 hex_print(ndo, ident, cp, len_to_print);
512 return(1); /* everything is ok */
513 }
514
515 /*
516 * Convert a token value to a string; use "fmt" if not found.
517 */
518 const char *
519 tok2strbuf(const struct tok *lp, const char *fmt,
520 u_int v, char *buf, size_t bufsize)
521 {
522 if (lp != NULL) {
523 while (lp->s != NULL) {
524 if (lp->v == v)
525 return (lp->s);
526 ++lp;
527 }
528 }
529 if (fmt == NULL)
530 fmt = "#%d";
531
532 (void)snprintf(buf, bufsize, fmt, v);
533 return (const char *)buf;
534 }
535
536 /*
537 * Convert a token value to a string; use "fmt" if not found.
538 * Uses tok2strbuf() on one of four local static buffers of size TOKBUFSIZE
539 * in round-robin fashion.
540 */
541 const char *
542 tok2str(const struct tok *lp, const char *fmt,
543 u_int v)
544 {
545 static char buf[4][TOKBUFSIZE];
546 static int idx = 0;
547 char *ret;
548
549 ret = buf[idx];
550 idx = (idx+1) & 3;
551 return tok2strbuf(lp, fmt, v, ret, sizeof(buf[0]));
552 }
553
554 /*
555 * Convert a bit token value to a string; use "fmt" if not found.
556 * this is useful for parsing bitfields, the output strings are separated
557 * if the s field is positive.
558 *
559 * A token matches iff it has one or more bits set and every bit that is set
560 * in the token is set in v. Consequently, a 0 token never matches.
561 */
562 static char *
563 bittok2str_internal(const struct tok *lp, const char *fmt,
564 u_int v, const char *sep)
565 {
566 static char buf[1024+1]; /* our string buffer */
567 char *bufp = buf;
568 size_t space_left = sizeof(buf), string_size;
569 const char * sepstr = "";
570
571 while (lp != NULL && lp->s != NULL) {
572 if (lp->v && (v & lp->v) == lp->v) {
573 /* ok we have found something */
574 if (space_left <= 1)
575 return (buf); /* only enough room left for NUL, if that */
576 string_size = strlcpy(bufp, sepstr, space_left);
577 if (string_size >= space_left)
578 return (buf); /* we ran out of room */
579 bufp += string_size;
580 space_left -= string_size;
581 if (space_left <= 1)
582 return (buf); /* only enough room left for NUL, if that */
583 string_size = strlcpy(bufp, lp->s, space_left);
584 if (string_size >= space_left)
585 return (buf); /* we ran out of room */
586 bufp += string_size;
587 space_left -= string_size;
588 sepstr = sep;
589 }
590 lp++;
591 }
592
593 if (bufp == buf)
594 /* bummer - lets print the "unknown" message as advised in the fmt string if we got one */
595 (void)snprintf(buf, sizeof(buf), fmt == NULL ? "#%08x" : fmt, v);
596 return (buf);
597 }
598
599 /*
600 * Convert a bit token value to a string; use "fmt" if not found.
601 * this is useful for parsing bitfields, the output strings are not separated.
602 */
603 char *
604 bittok2str_nosep(const struct tok *lp, const char *fmt,
605 u_int v)
606 {
607 return (bittok2str_internal(lp, fmt, v, ""));
608 }
609
610 /*
611 * Convert a bit token value to a string; use "fmt" if not found.
612 * this is useful for parsing bitfields, the output strings are comma separated.
613 */
614 char *
615 bittok2str(const struct tok *lp, const char *fmt,
616 u_int v)
617 {
618 return (bittok2str_internal(lp, fmt, v, ", "));
619 }
620
621 /*
622 * Convert a value to a string using an array; the macro
623 * tok2strary() in <netdissect.h> is the public interface to
624 * this function and ensures that the second argument is
625 * correct for bounds-checking.
626 */
627 const char *
628 tok2strary_internal(const char **lp, int n, const char *fmt,
629 int v)
630 {
631 static char buf[TOKBUFSIZE];
632
633 if (v >= 0 && v < n && lp[v] != NULL)
634 return lp[v];
635 if (fmt == NULL)
636 fmt = "#%d";
637 (void)snprintf(buf, sizeof(buf), fmt, v);
638 return (buf);
639 }
640
641 const struct tok *
642 uint2tokary_internal(const struct uint_tokary dict[], const size_t size,
643 const u_int val)
644 {
645 size_t i;
646 /* Try a direct lookup before the full scan. */
647 if (val < size && dict[val].uintval == val)
648 return dict[val].tokary; /* OK if NULL */
649 for (i = 0; i < size; i++)
650 if (dict[i].uintval == val)
651 return dict[i].tokary; /* OK if NULL */
652 return NULL;
653 }
654
655 /*
656 * Convert a 32-bit netmask to prefixlen if possible
657 * the function returns the prefix-len; if plen == -1
658 * then conversion was not possible;
659 */
660
661 int
662 mask2plen(uint32_t mask)
663 {
664 uint32_t bitmasks[33] = {
665 0x00000000,
666 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000,
667 0xf8000000, 0xfc000000, 0xfe000000, 0xff000000,
668 0xff800000, 0xffc00000, 0xffe00000, 0xfff00000,
669 0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000,
670 0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000,
671 0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00,
672 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0,
673 0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff
674 };
675 int prefix_len = 32;
676
677 /* let's see if we can transform the mask into a prefixlen */
678 while (prefix_len >= 0) {
679 if (bitmasks[prefix_len] == mask)
680 break;
681 prefix_len--;
682 }
683 return (prefix_len);
684 }
685
686 int
687 mask62plen(const u_char *mask)
688 {
689 u_char bitmasks[9] = {
690 0x00,
691 0x80, 0xc0, 0xe0, 0xf0,
692 0xf8, 0xfc, 0xfe, 0xff
693 };
694 int byte;
695 int cidr_len = 0;
696
697 for (byte = 0; byte < 16; byte++) {
698 u_int bits;
699
700 for (bits = 0; bits < (sizeof (bitmasks) / sizeof (bitmasks[0])); bits++) {
701 if (mask[byte] == bitmasks[bits]) {
702 cidr_len += bits;
703 break;
704 }
705 }
706
707 if (mask[byte] != 0xff)
708 break;
709 }
710 return (cidr_len);
711 }
712
713 /*
714 * Routine to print out information for text-based protocols such as FTP,
715 * HTTP, SMTP, RTSP, SIP, ....
716 */
717 #define MAX_TOKEN 128
718
719 /*
720 * Fetch a token from a packet, starting at the specified index,
721 * and return the length of the token.
722 *
723 * Returns 0 on error; yes, this is indistinguishable from an empty
724 * token, but an "empty token" isn't a valid token - it just means
725 * either a space character at the beginning of the line (this
726 * includes a blank line) or no more tokens remaining on the line.
727 */
728 static int
729 fetch_token(netdissect_options *ndo, const u_char *pptr, u_int idx, u_int len,
730 u_char *tbuf, size_t tbuflen)
731 {
732 size_t toklen = 0;
733 u_char c;
734
735 for (; idx < len; idx++) {
736 if (!ND_TTEST_1(pptr + idx)) {
737 /* ran past end of captured data */
738 return (0);
739 }
740 c = GET_U_1(pptr + idx);
741 if (!ND_ISASCII(c)) {
742 /* not an ASCII character */
743 return (0);
744 }
745 if (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
746 /* end of token */
747 break;
748 }
749 if (!ND_ASCII_ISPRINT(c)) {
750 /* not part of a command token or response code */
751 return (0);
752 }
753 if (toklen + 2 > tbuflen) {
754 /* no room for this character and terminating '\0' */
755 return (0);
756 }
757 tbuf[toklen] = c;
758 toklen++;
759 }
760 if (toklen == 0) {
761 /* no token */
762 return (0);
763 }
764 tbuf[toklen] = '\0';
765
766 /*
767 * Skip past any white space after the token, until we see
768 * an end-of-line (CR or LF).
769 */
770 for (; idx < len; idx++) {
771 if (!ND_TTEST_1(pptr + idx)) {
772 /* ran past end of captured data */
773 break;
774 }
775 c = GET_U_1(pptr + idx);
776 if (c == '\r' || c == '\n') {
777 /* end of line */
778 break;
779 }
780 if (!ND_ASCII_ISPRINT(c)) {
781 /* not a printable ASCII character */
782 break;
783 }
784 if (c != ' ' && c != '\t' && c != '\r' && c != '\n') {
785 /* beginning of next token */
786 break;
787 }
788 }
789 return (idx);
790 }
791
792 /*
793 * Scan a buffer looking for a line ending - LF or CR-LF.
794 * Return the index of the character after the line ending or 0 if
795 * we encounter a non-ASCII or non-printable character or don't find
796 * the line ending.
797 */
798 static u_int
799 print_txt_line(netdissect_options *ndo, const char *prefix,
800 const u_char *pptr, u_int idx, u_int len)
801 {
802 u_int startidx;
803 u_int linelen;
804 u_char c;
805
806 startidx = idx;
807 while (idx < len) {
808 c = GET_U_1(pptr + idx);
809 if (c == '\n') {
810 /*
811 * LF without CR; end of line.
812 * Skip the LF and print the line, with the
813 * exception of the LF.
814 */
815 linelen = idx - startidx;
816 idx++;
817 goto print;
818 } else if (c == '\r') {
819 /* CR - any LF? */
820 if ((idx+1) >= len) {
821 /* not in this packet */
822 return (0);
823 }
824 if (GET_U_1(pptr + idx + 1) == '\n') {
825 /*
826 * CR-LF; end of line.
827 * Skip the CR-LF and print the line, with
828 * the exception of the CR-LF.
829 */
830 linelen = idx - startidx;
831 idx += 2;
832 goto print;
833 }
834
835 /*
836 * CR followed by something else; treat this
837 * as if it were binary data, and don't print
838 * it.
839 */
840 return (0);
841 } else if (!ND_ASCII_ISPRINT(c) && c != '\t') {
842 /*
843 * Not a printable ASCII character and not a tab;
844 * treat this as if it were binary data, and
845 * don't print it.
846 */
847 return (0);
848 }
849 idx++;
850 }
851
852 /*
853 * All printable ASCII, but no line ending after that point
854 * in the buffer; treat this as if it were truncated.
855 */
856 linelen = idx - startidx;
857 ND_PRINT("%s%.*s", prefix, (int)linelen, pptr + startidx);
858 nd_print_trunc(ndo);
859 return (0);
860
861 print:
862 ND_PRINT("%s%.*s", prefix, (int)linelen, pptr + startidx);
863 return (idx);
864 }
865
866 /* Assign needed before calling txtproto_print(): ndo->ndo_protocol = "proto" */
867 void
868 txtproto_print(netdissect_options *ndo, const u_char *pptr, u_int len,
869 const char **cmds, u_int flags)
870 {
871 u_int idx, eol;
872 u_char token[MAX_TOKEN+1];
873 const char *cmd;
874 int print_this = 0;
875
876 if (cmds != NULL) {
877 /*
878 * This protocol has more than just request and
879 * response lines; see whether this looks like a
880 * request or response and, if so, print it and,
881 * in verbose mode, print everything after it.
882 *
883 * This is for HTTP-like protocols, where we
884 * want to print requests and responses, but
885 * don't want to print continuations of request
886 * or response bodies in packets that don't
887 * contain the request or response line.
888 */
889 idx = fetch_token(ndo, pptr, 0, len, token, sizeof(token));
890 if (idx != 0) {
891 /* Is this a valid request name? */
892 while ((cmd = *cmds++) != NULL) {
893 if (ascii_strcasecmp((const char *)token, cmd) == 0) {
894 /* Yes. */
895 print_this = 1;
896 break;
897 }
898 }
899
900 /*
901 * No - is this a valid response code (3 digits)?
902 *
903 * Is this token the response code, or is the next
904 * token the response code?
905 */
906 if (flags & RESP_CODE_SECOND_TOKEN) {
907 /*
908 * Next token - get it.
909 */
910 idx = fetch_token(ndo, pptr, idx, len, token,
911 sizeof(token));
912 }
913 if (idx != 0) {
914 if (ND_ASCII_ISDIGIT(token[0]) && ND_ASCII_ISDIGIT(token[1]) &&
915 ND_ASCII_ISDIGIT(token[2]) && token[3] == '\0') {
916 /* Yes. */
917 print_this = 1;
918 }
919 }
920 }
921 } else {
922 /*
923 * Either:
924 *
925 * 1) This protocol has only request and response lines
926 * (e.g., FTP, where all the data goes over a different
927 * connection); assume the payload is a request or
928 * response.
929 *
930 * or
931 *
932 * 2) This protocol is just text, so that we should
933 * always, at minimum, print the first line and,
934 * in verbose mode, print all lines.
935 */
936 print_this = 1;
937 }
938
939 nd_print_protocol_caps(ndo);
940
941 if (print_this) {
942 /*
943 * In non-verbose mode, just print the protocol, followed
944 * by the first line.
945 *
946 * In verbose mode, print lines as text until we run out
947 * of characters or see something that's not a
948 * printable-ASCII line.
949 */
950 if (ndo->ndo_vflag) {
951 /*
952 * We're going to print all the text lines in the
953 * request or response; just print the length
954 * on the first line of the output.
955 */
956 ND_PRINT(", length: %u", len);
957 for (idx = 0;
958 idx < len && (eol = print_txt_line(ndo, "\n\t", pptr, idx, len)) != 0;
959 idx = eol)
960 ;
961 } else {
962 /*
963 * Just print the first text line.
964 */
965 print_txt_line(ndo, ": ", pptr, 0, len);
966 }
967 }
968 }
969
970 #if (defined(__i386__) || defined(_M_IX86) || defined(__X86__) || defined(__x86_64__) || defined(_M_X64)) || \
971 (defined(__arm__) || defined(_M_ARM) || defined(__aarch64__)) || \
972 (defined(__m68k__) && (!defined(__mc68000__) && !defined(__mc68010__))) || \
973 (defined(__ppc__) || defined(__ppc64__) || defined(_M_PPC) || defined(_ARCH_PPC) || defined(_ARCH_PPC64)) || \
974 (defined(__s390__) || defined(__s390x__) || defined(__zarch__)) || \
975 defined(__vax__)
976 /*
977 * The procesor natively handles unaligned loads, so just use memcpy()
978 * and memcmp(), to enable those optimizations.
979 *
980 * XXX - are those all the x86 tests we need?
981 * XXX - do we need to worry about ARMv1 through ARMv5, which didn't
982 * support unaligned loads, and, if so, do we need to worry about all
983 * of them, or just some of them, e.g. ARMv5?
984 * XXX - are those the only 68k tests we need not to generated
985 * unaligned accesses if the target is the 68000 or 68010?
986 * XXX - are there any tests we don't need, because some definitions are for
987 * compilers that also predefine the GCC symbols?
988 * XXX - do we need to test for both 32-bit and 64-bit versions of those
989 * architectures in all cases?
990 */
991 #else
992 /*
993 * The processor doesn't natively handle unaligned loads,
994 * and the compiler might "helpfully" optimize memcpy()
995 * and memcmp(), when handed pointers that would normally
996 * be properly aligned, into sequences that assume proper
997 * alignment.
998 *
999 * Do copies and compares of possibly-unaligned data by
1000 * calling routines that wrap memcpy() and memcmp(), to
1001 * prevent that optimization.
1002 */
1003 void
1004 unaligned_memcpy(void *p, const void *q, size_t l)
1005 {
1006 memcpy(p, q, l);
1007 }
1008
1009 /* As with memcpy(), so with memcmp(). */
1010 int
1011 unaligned_memcmp(const void *p, const void *q, size_t l)
1012 {
1013 return (memcmp(p, q, l));
1014 }
1015 #endif
1016