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