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