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 #include <sys/cdefs.h>
23 #ifndef lint
24 __RCSID("$NetBSD: util.c,v 1.5 2015/03/31 21:59:35 christos Exp $");
25 #endif
26
27 /*
28 * txtproto_print() derived from original code by Hannes Gredler
29 * (hannes@juniper.net):
30 *
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that: (1) source code
33 * distributions retain the above copyright notice and this paragraph
34 * in its entirety, and (2) distributions including binary code include
35 * the above copyright notice and this paragraph in its entirety in
36 * the documentation or other materials provided with the distribution.
37 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
38 * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
39 * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
40 * FOR A PARTICULAR PURPOSE.
41 */
42
43 #define NETDISSECT_REWORKED
44 #ifdef HAVE_CONFIG_H
45 #include "config.h"
46 #endif
47
48 #include <tcpdump-stdinc.h>
49
50 #include <sys/stat.h>
51
52 #ifdef HAVE_FCNTL_H
53 #include <fcntl.h>
54 #endif
55 #include <stdio.h>
56 #include <stdarg.h>
57 #include <stdlib.h>
58 #include <string.h>
59
60 #include "interface.h"
61
62 /*
63 * Print out a null-terminated filename (or other ascii string).
64 * If ep is NULL, assume no truncation check is needed.
65 * Return true if truncated.
66 */
67 int
fn_print(netdissect_options * ndo,register const u_char * s,register const u_char * ep)68 fn_print(netdissect_options *ndo,
69 register const u_char *s, register const u_char *ep)
70 {
71 register int ret;
72 register u_char c;
73
74 ret = 1; /* assume truncated */
75 while (ep == NULL || s < ep) {
76 c = *s++;
77 if (c == '\0') {
78 ret = 0;
79 break;
80 }
81 if (!ND_ISASCII(c)) {
82 c = ND_TOASCII(c);
83 ND_PRINT((ndo, "M-"));
84 }
85 if (!ND_ISPRINT(c)) {
86 c ^= 0x40; /* DEL to ?, others to alpha */
87 ND_PRINT((ndo, "^"));
88 }
89 ND_PRINT((ndo, "%c", c));
90 }
91 return(ret);
92 }
93
94 /*
95 * Print out a counted filename (or other ascii string).
96 * If ep is NULL, assume no truncation check is needed.
97 * Return true if truncated.
98 */
99 int
fn_printn(netdissect_options * ndo,register const u_char * s,register u_int n,register const u_char * ep)100 fn_printn(netdissect_options *ndo,
101 register const u_char *s, register u_int n, register const u_char *ep)
102 {
103 register u_char c;
104
105 while (n > 0 && (ep == NULL || s < ep)) {
106 n--;
107 c = *s++;
108 if (!ND_ISASCII(c)) {
109 c = ND_TOASCII(c);
110 ND_PRINT((ndo, "M-"));
111 }
112 if (!ND_ISPRINT(c)) {
113 c ^= 0x40; /* DEL to ?, others to alpha */
114 ND_PRINT((ndo, "^"));
115 }
116 ND_PRINT((ndo, "%c", c));
117 }
118 return (n == 0) ? 0 : 1;
119 }
120
121 /*
122 * Print out a null-padded filename (or other ascii string).
123 * If ep is NULL, assume no truncation check is needed.
124 * Return true if truncated.
125 */
126 int
fn_printzp(netdissect_options * ndo,register const u_char * s,register u_int n,register const u_char * ep)127 fn_printzp(netdissect_options *ndo,
128 register const u_char *s, register u_int n,
129 register const u_char *ep)
130 {
131 register int ret;
132 register u_char c;
133
134 ret = 1; /* assume truncated */
135 while (n > 0 && (ep == NULL || s < ep)) {
136 n--;
137 c = *s++;
138 if (c == '\0') {
139 ret = 0;
140 break;
141 }
142 if (!ND_ISASCII(c)) {
143 c = ND_TOASCII(c);
144 ND_PRINT((ndo, "M-"));
145 }
146 if (!ND_ISPRINT(c)) {
147 c ^= 0x40; /* DEL to ?, others to alpha */
148 ND_PRINT((ndo, "^"));
149 }
150 ND_PRINT((ndo, "%c", c));
151 }
152 return (n == 0) ? 0 : ret;
153 }
154
155 /*
156 * Format the timestamp
157 */
158 static char *
ts_format(netdissect_options * ndo _U_,int sec,int usec)159 ts_format(netdissect_options *ndo
160 #ifndef HAVE_PCAP_SET_TSTAMP_PRECISION
161 _U_
162 #endif
163 , int sec, int usec)
164 {
165 static char buf[sizeof("00:00:00.000000000")];
166 const char *format;
167
168 #ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
169 switch (ndo->ndo_tstamp_precision) {
170
171 case PCAP_TSTAMP_PRECISION_MICRO:
172 format = "%02d:%02d:%02d.%06u";
173 break;
174
175 case PCAP_TSTAMP_PRECISION_NANO:
176 format = "%02d:%02d:%02d.%09u";
177 break;
178
179 default:
180 format = "%02d:%02d:%02d.{unknown precision}";
181 break;
182 }
183 #else
184 format = "%02d:%02d:%02d.%06u";
185 #endif
186
187 snprintf(buf, sizeof(buf), format,
188 sec / 3600, (sec % 3600) / 60, sec % 60, usec);
189
190 return buf;
191 }
192
193 /*
194 * Print the timestamp
195 */
196 void
ts_print(netdissect_options * ndo,register const struct timeval * tvp)197 ts_print(netdissect_options *ndo,
198 register const struct timeval *tvp)
199 {
200 register int s;
201 struct tm *tm;
202 time_t Time;
203 static unsigned b_sec;
204 static unsigned b_usec;
205 int d_usec;
206 int d_sec;
207
208 switch (ndo->ndo_tflag) {
209
210 case 0: /* Default */
211 s = (tvp->tv_sec + thiszone) % 86400;
212 ND_PRINT((ndo, "%s ", ts_format(ndo, s, tvp->tv_usec)));
213 break;
214
215 case 1: /* No time stamp */
216 break;
217
218 case 2: /* Unix timeval style */
219 ND_PRINT((ndo, "%u.%06u ",
220 (unsigned)tvp->tv_sec,
221 (unsigned)tvp->tv_usec));
222 break;
223
224 case 3: /* Microseconds since previous packet */
225 case 5: /* Microseconds since first packet */
226 if (b_sec == 0) {
227 /* init timestamp for first packet */
228 b_usec = tvp->tv_usec;
229 b_sec = tvp->tv_sec;
230 }
231
232 d_usec = tvp->tv_usec - b_usec;
233 d_sec = tvp->tv_sec - b_sec;
234
235 while (d_usec < 0) {
236 d_usec += 1000000;
237 d_sec--;
238 }
239
240 ND_PRINT((ndo, "%s ", ts_format(ndo, d_sec, d_usec)));
241
242 if (ndo->ndo_tflag == 3) { /* set timestamp for last packet */
243 b_sec = tvp->tv_sec;
244 b_usec = tvp->tv_usec;
245 }
246 break;
247
248 case 4: /* Default + Date*/
249 s = (tvp->tv_sec + thiszone) % 86400;
250 Time = (tvp->tv_sec + thiszone) - s;
251 tm = gmtime (&Time);
252 if (!tm)
253 ND_PRINT((ndo, "Date fail "));
254 else
255 ND_PRINT((ndo, "%04d-%02d-%02d %s ",
256 tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
257 ts_format(ndo, s, tvp->tv_usec)));
258 break;
259 }
260 }
261
262 /*
263 * Print a relative number of seconds (e.g. hold time, prune timer)
264 * in the form 5m1s. This does no truncation, so 32230861 seconds
265 * is represented as 1y1w1d1h1m1s.
266 */
267 void
relts_print(netdissect_options * ndo,int secs)268 relts_print(netdissect_options *ndo,
269 int secs)
270 {
271 static const char *lengths[] = {"y", "w", "d", "h", "m", "s"};
272 static const int seconds[] = {31536000, 604800, 86400, 3600, 60, 1};
273 const char **l = lengths;
274 const int *s = seconds;
275
276 if (secs == 0) {
277 ND_PRINT((ndo, "0s"));
278 return;
279 }
280 if (secs < 0) {
281 ND_PRINT((ndo, "-"));
282 secs = -secs;
283 }
284 while (secs > 0) {
285 if (secs >= *s) {
286 ND_PRINT((ndo, "%d%s", secs / *s, *l));
287 secs -= (secs / *s) * *s;
288 }
289 s++;
290 l++;
291 }
292 }
293
294 /*
295 * this is a generic routine for printing unknown data;
296 * we pass on the linefeed plus indentation string to
297 * get a proper output - returns 0 on error
298 */
299
300 int
print_unknown_data(netdissect_options * ndo,const u_char * cp,const char * ident,int len)301 print_unknown_data(netdissect_options *ndo, const u_char *cp,const char *ident,int len)
302 {
303 if (len < 0) {
304 ND_PRINT((ndo,"%sDissector error: print_unknown_data called with negative length",
305 ident));
306 return(0);
307 }
308 if (ndo->ndo_snapend - cp < len)
309 len = ndo->ndo_snapend - cp;
310 if (len < 0) {
311 ND_PRINT((ndo,"%sDissector error: print_unknown_data called with pointer past end of packet",
312 ident));
313 return(0);
314 }
315 hex_print(ndo, ident,cp,len);
316 return(1); /* everything is ok */
317 }
318
319 /*
320 * Convert a token value to a string; use "fmt" if not found.
321 */
322 const char *
tok2strbuf(register const struct tok * lp,register const char * fmt,register u_int v,char * buf,size_t bufsize)323 tok2strbuf(register const struct tok *lp, register const char *fmt,
324 register u_int v, char *buf, size_t bufsize)
325 {
326 if (lp != NULL) {
327 while (lp->s != NULL) {
328 if (lp->v == v)
329 return (lp->s);
330 ++lp;
331 }
332 }
333 if (fmt == NULL)
334 fmt = "#%d";
335
336 (void)snprintf(buf, bufsize, fmt, v);
337 return (const char *)buf;
338 }
339
340 /*
341 * Convert a token value to a string; use "fmt" if not found.
342 */
343 const char *
tok2str(register const struct tok * lp,register const char * fmt,register int v)344 tok2str(register const struct tok *lp, register const char *fmt,
345 register int v)
346 {
347 static char buf[4][128];
348 static int idx = 0;
349 char *ret;
350
351 ret = buf[idx];
352 idx = (idx+1) & 3;
353 return tok2strbuf(lp, fmt, v, ret, sizeof(buf[0]));
354 }
355
356 /*
357 * Convert a bit token value to a string; use "fmt" if not found.
358 * this is useful for parsing bitfields, the output strings are seperated
359 * if the s field is positive.
360 */
361 static char *
bittok2str_internal(register const struct tok * lp,register const char * fmt,register int v,register int sep)362 bittok2str_internal(register const struct tok *lp, register const char *fmt,
363 register int v, register int sep)
364 {
365 static char buf[256]; /* our stringbuffer */
366 int buflen=0;
367 register int rotbit; /* this is the bit we rotate through all bitpositions */
368 register int tokval;
369 const char * sepstr = "";
370
371 while (lp != NULL && lp->s != NULL) {
372 tokval=lp->v; /* load our first value */
373 rotbit=1;
374 while (rotbit != 0) {
375 /*
376 * lets AND the rotating bit with our token value
377 * and see if we have got a match
378 */
379 if (tokval == (v&rotbit)) {
380 /* ok we have found something */
381 buflen+=snprintf(buf+buflen, sizeof(buf)-buflen, "%s%s",
382 sepstr, lp->s);
383 sepstr = sep ? ", " : "";
384 break;
385 }
386 rotbit=rotbit<<1; /* no match - lets shift and try again */
387 }
388 lp++;
389 }
390
391 if (buflen == 0)
392 /* bummer - lets print the "unknown" message as advised in the fmt string if we got one */
393 (void)snprintf(buf, sizeof(buf), fmt == NULL ? "#%d" : fmt, v);
394 return (buf);
395 }
396
397 /*
398 * Convert a bit token value to a string; use "fmt" if not found.
399 * this is useful for parsing bitfields, the output strings are not seperated.
400 */
401 char *
bittok2str_nosep(register const struct tok * lp,register const char * fmt,register int v)402 bittok2str_nosep(register const struct tok *lp, register const char *fmt,
403 register int v)
404 {
405 return (bittok2str_internal(lp, fmt, v, 0));
406 }
407
408 /*
409 * Convert a bit token value to a string; use "fmt" if not found.
410 * this is useful for parsing bitfields, the output strings are comma seperated.
411 */
412 char *
bittok2str(register const struct tok * lp,register const char * fmt,register int v)413 bittok2str(register const struct tok *lp, register const char *fmt,
414 register int v)
415 {
416 return (bittok2str_internal(lp, fmt, v, 1));
417 }
418
419 /*
420 * Convert a value to a string using an array; the macro
421 * tok2strary() in <interface.h> is the public interface to
422 * this function and ensures that the second argument is
423 * correct for bounds-checking.
424 */
425 const char *
tok2strary_internal(register const char ** lp,int n,register const char * fmt,register int v)426 tok2strary_internal(register const char **lp, int n, register const char *fmt,
427 register int v)
428 {
429 static char buf[128];
430
431 if (v >= 0 && v < n && lp[v] != NULL)
432 return lp[v];
433 if (fmt == NULL)
434 fmt = "#%d";
435 (void)snprintf(buf, sizeof(buf), fmt, v);
436 return (buf);
437 }
438
439 /*
440 * Convert a 32-bit netmask to prefixlen if possible
441 * the function returns the prefix-len; if plen == -1
442 * then conversion was not possible;
443 */
444
445 int
mask2plen(uint32_t mask)446 mask2plen(uint32_t mask)
447 {
448 uint32_t bitmasks[33] = {
449 0x00000000,
450 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000,
451 0xf8000000, 0xfc000000, 0xfe000000, 0xff000000,
452 0xff800000, 0xffc00000, 0xffe00000, 0xfff00000,
453 0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000,
454 0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000,
455 0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00,
456 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0,
457 0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff
458 };
459 int prefix_len = 32;
460
461 /* let's see if we can transform the mask into a prefixlen */
462 while (prefix_len >= 0) {
463 if (bitmasks[prefix_len] == mask)
464 break;
465 prefix_len--;
466 }
467 return (prefix_len);
468 }
469
470 #ifdef INET6
471 int
mask62plen(const u_char * mask)472 mask62plen(const u_char *mask)
473 {
474 u_char bitmasks[9] = {
475 0x00,
476 0x80, 0xc0, 0xe0, 0xf0,
477 0xf8, 0xfc, 0xfe, 0xff
478 };
479 int byte;
480 int cidr_len = 0;
481
482 for (byte = 0; byte < 16; byte++) {
483 u_int bits;
484
485 for (bits = 0; bits < (sizeof (bitmasks) / sizeof (bitmasks[0])); bits++) {
486 if (mask[byte] == bitmasks[bits]) {
487 cidr_len += bits;
488 break;
489 }
490 }
491
492 if (mask[byte] != 0xff)
493 break;
494 }
495 return (cidr_len);
496 }
497 #endif /* INET6 */
498
499 /*
500 * Routine to print out information for text-based protocols such as FTP,
501 * HTTP, SMTP, RTSP, SIP, ....
502 */
503 #define MAX_TOKEN 128
504
505 /*
506 * Fetch a token from a packet, starting at the specified index,
507 * and return the length of the token.
508 *
509 * Returns 0 on error; yes, this is indistinguishable from an empty
510 * token, but an "empty token" isn't a valid token - it just means
511 * either a space character at the beginning of the line (this
512 * includes a blank line) or no more tokens remaining on the line.
513 */
514 static int
fetch_token(netdissect_options * ndo,const u_char * pptr,u_int idx,u_int len,u_char * tbuf,size_t tbuflen)515 fetch_token(netdissect_options *ndo, const u_char *pptr, u_int idx, u_int len,
516 u_char *tbuf, size_t tbuflen)
517 {
518 size_t toklen = 0;
519
520 for (; idx < len; idx++) {
521 if (!ND_TTEST(*(pptr + idx))) {
522 /* ran past end of captured data */
523 return (0);
524 }
525 if (!isascii(*(pptr + idx))) {
526 /* not an ASCII character */
527 return (0);
528 }
529 if (isspace(*(pptr + idx))) {
530 /* end of token */
531 break;
532 }
533 if (!isprint(*(pptr + idx))) {
534 /* not part of a command token or response code */
535 return (0);
536 }
537 if (toklen + 2 > tbuflen) {
538 /* no room for this character and terminating '\0' */
539 return (0);
540 }
541 tbuf[toklen] = *(pptr + idx);
542 toklen++;
543 }
544 if (toklen == 0) {
545 /* no token */
546 return (0);
547 }
548 tbuf[toklen] = '\0';
549
550 /*
551 * Skip past any white space after the token, until we see
552 * an end-of-line (CR or LF).
553 */
554 for (; idx < len; idx++) {
555 if (!ND_TTEST(*(pptr + idx))) {
556 /* ran past end of captured data */
557 break;
558 }
559 if (*(pptr + idx) == '\r' || *(pptr + idx) == '\n') {
560 /* end of line */
561 break;
562 }
563 if (!isascii(*(pptr + idx)) || !isprint(*(pptr + idx))) {
564 /* not a printable ASCII character */
565 break;
566 }
567 if (!isspace(*(pptr + idx))) {
568 /* beginning of next token */
569 break;
570 }
571 }
572 return (idx);
573 }
574
575 /*
576 * Scan a buffer looking for a line ending - LF or CR-LF.
577 * Return the index of the character after the line ending or 0 if
578 * we encounter a non-ASCII or non-printable character or don't find
579 * the line ending.
580 */
581 static u_int
print_txt_line(netdissect_options * ndo,const char * protoname,const char * prefix,const u_char * pptr,u_int idx,u_int len)582 print_txt_line(netdissect_options *ndo, const char *protoname,
583 const char *prefix, const u_char *pptr, u_int idx, u_int len)
584 {
585 u_int startidx;
586 u_int linelen;
587
588 startidx = idx;
589 while (idx < len) {
590 ND_TCHECK(*(pptr+idx));
591 if (*(pptr+idx) == '\n') {
592 /*
593 * LF without CR; end of line.
594 * Skip the LF and print the line, with the
595 * exception of the LF.
596 */
597 linelen = idx - startidx;
598 idx++;
599 goto print;
600 } else if (*(pptr+idx) == '\r') {
601 /* CR - any LF? */
602 if ((idx+1) >= len) {
603 /* not in this packet */
604 return (0);
605 }
606 ND_TCHECK(*(pptr+idx+1));
607 if (*(pptr+idx+1) == '\n') {
608 /*
609 * CR-LF; end of line.
610 * Skip the CR-LF and print the line, with
611 * the exception of the CR-LF.
612 */
613 linelen = idx - startidx;
614 idx += 2;
615 goto print;
616 }
617
618 /*
619 * CR followed by something else; treat this
620 * as if it were binary data, and don't print
621 * it.
622 */
623 return (0);
624 } else if (!isascii(*(pptr+idx)) ||
625 (!isprint(*(pptr+idx)) && *(pptr+idx) != '\t')) {
626 /*
627 * Not a printable ASCII character and not a tab;
628 * treat this as if it were binary data, and
629 * don't print it.
630 */
631 return (0);
632 }
633 idx++;
634 }
635
636 /*
637 * All printable ASCII, but no line ending after that point
638 * in the buffer; treat this as if it were truncated.
639 */
640 trunc:
641 linelen = idx - startidx;
642 ND_PRINT((ndo, "%s%.*s[!%s]", prefix, (int)linelen, pptr + startidx,
643 protoname));
644 return (0);
645
646 print:
647 ND_PRINT((ndo, "%s%.*s", prefix, (int)linelen, pptr + startidx));
648 return (idx);
649 }
650
651 void
txtproto_print(netdissect_options * ndo,const u_char * pptr,u_int len,const char * protoname,const char ** cmds,u_int flags)652 txtproto_print(netdissect_options *ndo, const u_char *pptr, u_int len,
653 const char *protoname, const char **cmds, u_int flags)
654 {
655 u_int idx, eol;
656 u_char token[MAX_TOKEN+1];
657 const char *cmd;
658 int is_reqresp = 0;
659 const char *pnp;
660
661 if (cmds != NULL) {
662 /*
663 * This protocol has more than just request and
664 * response lines; see whether this looks like a
665 * request or response.
666 */
667 idx = fetch_token(ndo, pptr, 0, len, token, sizeof(token));
668 if (idx != 0) {
669 /* Is this a valid request name? */
670 while ((cmd = *cmds++) != NULL) {
671 if (strcasecmp((const char *)token, cmd) == 0) {
672 /* Yes. */
673 is_reqresp = 1;
674 break;
675 }
676 }
677
678 /*
679 * No - is this a valid response code (3 digits)?
680 *
681 * Is this token the response code, or is the next
682 * token the response code?
683 */
684 if (flags & RESP_CODE_SECOND_TOKEN) {
685 /*
686 * Next token - get it.
687 */
688 idx = fetch_token(ndo, pptr, idx, len, token,
689 sizeof(token));
690 }
691 if (idx != 0) {
692 if (isdigit(token[0]) && isdigit(token[1]) &&
693 isdigit(token[2]) && token[3] == '\0') {
694 /* Yes. */
695 is_reqresp = 1;
696 }
697 }
698 }
699 } else {
700 /*
701 * This protocol has only request and response lines
702 * (e.g., FTP, where all the data goes over a
703 * different connection); assume the payload is
704 * a request or response.
705 */
706 is_reqresp = 1;
707 }
708
709 /* Capitalize the protocol name */
710 for (pnp = protoname; *pnp != '\0'; pnp++)
711 ND_PRINT((ndo, "%c", toupper((unsigned char)*pnp)));
712
713 if (is_reqresp) {
714 /*
715 * In non-verbose mode, just print the protocol, followed
716 * by the first line as the request or response info.
717 *
718 * In verbose mode, print lines as text until we run out
719 * of characters or see something that's not a
720 * printable-ASCII line.
721 */
722 if (ndo->ndo_vflag) {
723 /*
724 * We're going to print all the text lines in the
725 * request or response; just print the length
726 * on the first line of the output.
727 */
728 ND_PRINT((ndo, ", length: %u", len));
729 for (idx = 0;
730 idx < len && (eol = print_txt_line(ndo, protoname, "\n\t", pptr, idx, len)) != 0;
731 idx = eol)
732 ;
733 } else {
734 /*
735 * Just print the first text line.
736 */
737 print_txt_line(ndo, protoname, ": ", pptr, 0, len);
738 }
739 }
740 }
741
742 /* VARARGS */
743 void
error(const char * fmt,...)744 error(const char *fmt, ...)
745 {
746 va_list ap;
747
748 (void)fprintf(stderr, "%s: ", program_name);
749 va_start(ap, fmt);
750 (void)vfprintf(stderr, fmt, ap);
751 va_end(ap);
752 if (*fmt) {
753 fmt += strlen(fmt);
754 if (fmt[-1] != '\n')
755 (void)fputc('\n', stderr);
756 }
757 exit(1);
758 /* NOTREACHED */
759 }
760
761 /* VARARGS */
762 void
warning(const char * fmt,...)763 warning(const char *fmt, ...)
764 {
765 va_list ap;
766
767 (void)fprintf(stderr, "%s: WARNING: ", program_name);
768 va_start(ap, fmt);
769 (void)vfprintf(stderr, fmt, ap);
770 va_end(ap);
771 if (*fmt) {
772 fmt += strlen(fmt);
773 if (fmt[-1] != '\n')
774 (void)fputc('\n', stderr);
775 }
776 }
777
778 /*
779 * Copy arg vector into a new buffer, concatenating arguments with spaces.
780 */
781 char *
copy_argv(register char ** argv)782 copy_argv(register char **argv)
783 {
784 register char **p;
785 register u_int len = 0;
786 char *buf;
787 char *src, *dst;
788
789 p = argv;
790 if (*p == 0)
791 return 0;
792
793 while (*p)
794 len += strlen(*p++) + 1;
795
796 buf = (char *)malloc(len);
797 if (buf == NULL)
798 error("copy_argv: malloc");
799
800 p = argv;
801 dst = buf;
802 while ((src = *p++) != NULL) {
803 while ((*dst++ = *src++) != '\0')
804 ;
805 dst[-1] = ' ';
806 }
807 dst[-1] = '\0';
808
809 return buf;
810 }
811
812 /*
813 * On Windows, we need to open the file in binary mode, so that
814 * we get all the bytes specified by the size we get from "fstat()".
815 * On UNIX, that's not necessary. O_BINARY is defined on Windows;
816 * we define it as 0 if it's not defined, so it does nothing.
817 */
818 #ifndef O_BINARY
819 #define O_BINARY 0
820 #endif
821
822 char *
read_infile(char * fname)823 read_infile(char *fname)
824 {
825 register int i, fd, cc;
826 register char *cp;
827 struct stat buf;
828
829 fd = open(fname, O_RDONLY|O_BINARY);
830 if (fd < 0)
831 error("can't open %s: %s", fname, pcap_strerror(errno));
832
833 if (fstat(fd, &buf) < 0)
834 error("can't stat %s: %s", fname, pcap_strerror(errno));
835
836 cp = malloc((u_int)buf.st_size + 1);
837 if (cp == NULL)
838 error("malloc(%d) for %s: %s", (u_int)buf.st_size + 1,
839 fname, pcap_strerror(errno));
840 cc = read(fd, cp, (u_int)buf.st_size);
841 if (cc < 0)
842 error("read %s: %s", fname, pcap_strerror(errno));
843 if (cc != buf.st_size)
844 error("short read %s (%d != %d)", fname, cc, (int)buf.st_size);
845
846 close(fd);
847 /* replace "# comment" with spaces */
848 for (i = 0; i < cc; i++) {
849 if (cp[i] == '#')
850 while (i < cc && cp[i] != '\n')
851 cp[i++] = ' ';
852 }
853 cp[cc] = '\0';
854 return (cp);
855 }
856
857 void
safeputs(netdissect_options * ndo,const u_char * s,const u_int maxlen)858 safeputs(netdissect_options *ndo,
859 const u_char *s, const u_int maxlen)
860 {
861 u_int idx = 0;
862
863 while (*s && idx < maxlen) {
864 safeputchar(ndo, *s);
865 idx++;
866 s++;
867 }
868 }
869
870 void
safeputchar(netdissect_options * ndo,const u_char c)871 safeputchar(netdissect_options *ndo,
872 const u_char c)
873 {
874 ND_PRINT((ndo, (c < 0x80 && ND_ISPRINT(c)) ? "%c" : "\\0x%02x", c));
875 }
876
877 #ifdef LBL_ALIGN
878 /*
879 * Some compilers try to optimize memcpy(), using the alignment constraint
880 * on the argument pointer type. by using this function, we try to avoid the
881 * optimization.
882 */
883 void
unaligned_memcpy(void * p,const void * q,size_t l)884 unaligned_memcpy(void *p, const void *q, size_t l)
885 {
886 memcpy(p, q, l);
887 }
888
889 /* As with memcpy(), so with memcmp(). */
890 int
unaligned_memcmp(const void * p,const void * q,size_t l)891 unaligned_memcmp(const void *p, const void *q, size_t l)
892 {
893 return (memcmp(p, q, l));
894 }
895 #endif
896