1 /*
2  * Copyright (c) 1988, 1989, 1990, 1991, 1992, 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 <unistd.h>
23 #include <stdlib.h>
24 
25 #include <argus_compat.h>
26 
27 #include <rabins.h>
28 #include <argus_util.h>
29 #include <argus_client.h>
30 #include <argus_main.h>
31 #include <argus_filter.h>
32 
33 #include <signal.h>
34 #include <ctype.h>
35 #include <argus/extract.h>
36 
37 extern u_char *snapend;
38 
39 #include "interface.h"
40 #include "nameser.h"
41 
42 extern char ArgusBuf[];
43 
44 static const char *ns_ops[] = {
45    "", " inv_q", " stat", " op3", " notify", " update", " op6", " op7",
46    " op8", " updataA", " updateD", " updateDA",
47    " updateM", " updateMA", " zoneInit", " zoneRef",
48 };
49 
50 static const char *ns_resp[] = {
51    "", " FormErr", " ServFail", " NXDomain",
52    " NotImp", " Refused", " YXDomain", " YXRRSet",
53    " NXRRSet", " NotAuth", " NotZone", " Resp11",
54    " Resp12", " Resp13", " Resp14", " NoChange",
55 };
56 
57 /* skip over a domain name */
58 static const u_char *
ns_nskip(register const u_char * cp)59 ns_nskip(register const u_char *cp)
60 {
61    register u_char i;
62 
63    if (!TTEST2(*cp, 1))
64       return (NULL);
65    i = *cp++;
66    while (i) {
67       if ((i & INDIR_MASK) == INDIR_MASK)
68          return (cp + 1);
69       if ((i & INDIR_MASK) == EDNS0_MASK) {
70          int bitlen, bytelen;
71 
72          if ((i & ~INDIR_MASK) != EDNS0_ELT_BITLABEL)
73             return(NULL); /* unknown ELT */
74          if (!TTEST2(*cp, 1))
75             return (NULL);
76          if ((bitlen = *cp++) == 0)
77             bitlen = 256;
78          bytelen = (bitlen + 7) / 8;
79          cp += bytelen;
80       } else
81          cp += i;
82       if (!TTEST2(*cp, 1))
83          return (NULL);
84       i = *cp++;
85    }
86    return (cp);
87 }
88 
89 /* print a <domain-name> */
90 static const u_char *
blabel_print(const u_char * cp)91 blabel_print(const u_char *cp)
92 {
93    int bitlen, slen, b;
94    const u_char *bitp, *lim;
95    char tc;
96 
97    if (!TTEST2(*cp, 1))
98       return(NULL);
99    if ((bitlen = *cp) == 0)
100       bitlen = 256;
101    slen = (bitlen + 3) / 4;
102    lim = cp + 1 + slen;
103 
104    /* print the bit string as a hex string */
105    sprintf(&ArgusBuf[strlen(ArgusBuf)],"\\[x");
106    for (bitp = cp + 1, b = bitlen; bitp < lim && b > 7; b -= 8, bitp++) {
107       TCHECK(*bitp);
108       sprintf(&ArgusBuf[strlen(ArgusBuf)],"%02x", *bitp);
109    }
110    if (b > 4) {
111       TCHECK(*bitp);
112       tc = *bitp++;
113       sprintf(&ArgusBuf[strlen(ArgusBuf)],"%02x", tc & (0xff << (8 - b)));
114    } else if (b > 0) {
115       TCHECK(*bitp);
116       tc = *bitp++;
117       sprintf(&ArgusBuf[strlen(ArgusBuf)],"%1x", ((tc >> 4) & 0x0f) & (0x0f << (4 - b)));
118    }
119    sprintf(&ArgusBuf[strlen(ArgusBuf)],"/%d]", bitlen);
120    return lim;
121 trunc:
122    sprintf(&ArgusBuf[strlen(ArgusBuf)],".../%d]", bitlen);
123    return NULL;
124 }
125 
126 static int
labellen(const u_char * cp)127 labellen(const u_char *cp)
128 {
129    register u_int i;
130 
131    if (!TTEST2(*cp, 1))
132       return(-1);
133    i = *cp;
134    if ((i & INDIR_MASK) == EDNS0_MASK) {
135       int bitlen, elt;
136       if ((elt = (i & ~INDIR_MASK)) != EDNS0_ELT_BITLABEL) {
137          sprintf(&ArgusBuf[strlen(ArgusBuf)],"<ELT %d>", elt);
138          return(-1);
139       }
140       if (!TTEST2(*(cp + 1), 1))
141          return(-1);
142       if ((bitlen = *(cp + 1)) == 0)
143          bitlen = 256;
144       return(((bitlen + 7) / 8) + 1);
145    } else
146       return(i);
147 }
148 
149 static const u_char *
ns_nprint(register const u_char * cp,register const u_char * bp)150 ns_nprint(register const u_char *cp, register const u_char *bp)
151 {
152    register u_int i, l;
153    register const u_char *rp = NULL;
154    register int compress = 0;
155    int chars_processed;
156    int elt;
157    int data_size = snapend - bp;
158 
159    if ((l = labellen(cp)) == (u_int)-1)
160       return(NULL);
161    if (!TTEST2(*cp, 1))
162       return(NULL);
163    chars_processed = 1;
164    if (((i = *cp++) & INDIR_MASK) != INDIR_MASK) {
165       compress = 0;
166       rp = cp + l;
167    }
168 
169    if (i != 0)
170       while (i && cp < snapend) {
171          if ((i & INDIR_MASK) == INDIR_MASK) {
172             if (!compress) {
173                rp = cp + 1;
174                compress = 1;
175             }
176             if (!TTEST2(*cp, 1))
177                return(NULL);
178             cp = bp + (((i << 8) | *cp) & 0x3fff);
179             if ((l = labellen(cp)) == (u_int)-1)
180                return(NULL);
181             if (!TTEST2(*cp, 1))
182                return(NULL);
183             i = *cp++;
184             chars_processed++;
185 
186             /*
187              * If we've looked at every character in
188              * the message, this pointer will make
189              * us look at some character again,
190              * which means we're looping.
191              */
192             if (chars_processed >= data_size) {
193                sprintf(&ArgusBuf[strlen(ArgusBuf)],"<LOOP>");
194                return (NULL);
195             }
196             continue;
197          }
198          if ((i & INDIR_MASK) == EDNS0_MASK) {
199             elt = (i & ~INDIR_MASK);
200             switch(elt) {
201             case EDNS0_ELT_BITLABEL:
202                if (blabel_print(cp) == NULL)
203                   return (NULL);
204                break;
205             default:
206                /* unknown ELT */
207                sprintf(&ArgusBuf[strlen(ArgusBuf)],"<ELT %d>", elt);
208                return(NULL);
209             }
210          } else {
211             if (fn_printn(cp, l, snapend, ArgusBuf))
212                return(NULL);
213          }
214 
215          cp += l;
216          chars_processed += l;
217          sprintf(&ArgusBuf[strlen(ArgusBuf)], "%c", '.');
218          if ((l = labellen(cp)) == (u_int)-1)
219             return(NULL);
220          if (!TTEST2(*cp, 1))
221             return(NULL);
222          i = *cp++;
223          chars_processed++;
224          if (!compress)
225             rp += l + 1;
226       }
227    else
228       sprintf(&ArgusBuf[strlen(ArgusBuf)], "%c", '.');
229    return (rp);
230 }
231 
232 /* print a <character-string> */
233 static const u_char *
ns_cprint(register const u_char * cp)234 ns_cprint(register const u_char *cp)
235 {
236    register u_int i;
237 
238    if (!TTEST2(*cp, 1))
239       return (NULL);
240    i = *cp++;
241    if (fn_printn(cp, i, snapend, ArgusBuf))
242       return (NULL);
243    return (cp + i);
244 }
245 
246 /* http://www.iana.org/assignments/dns-parameters */
247 struct tok ns_type2str[] = {
248    { T_A,      "A" },         /* RFC 1035 */
249    { T_NS,      "NS" },         /* RFC 1035 */
250    { T_MD,      "MD" },         /* RFC 1035 */
251    { T_MF,      "MF" },         /* RFC 1035 */
252    { T_CNAME,   "CNAME" },      /* RFC 1035 */
253    { T_SOA,   "SOA" },      /* RFC 1035 */
254    { T_MB,      "MB" },         /* RFC 1035 */
255    { T_MG,      "MG" },         /* RFC 1035 */
256    { T_MR,      "MR" },         /* RFC 1035 */
257    { T_NULL,   "NULL" },      /* RFC 1035 */
258    { T_WKS,   "WKS" },      /* RFC 1035 */
259    { T_PTR,   "PTR" },      /* RFC 1035 */
260    { T_HINFO,   "HINFO" },      /* RFC 1035 */
261    { T_MINFO,   "MINFO" },      /* RFC 1035 */
262    { T_MX,      "MX" },         /* RFC 1035 */
263    { T_TXT,   "TXT" },      /* RFC 1035 */
264    { T_RP,      "RP" },         /* RFC 1183 */
265    { T_AFSDB,   "AFSDB" },      /* RFC 1183 */
266    { T_X25,   "X25" },      /* RFC 1183 */
267    { T_ISDN,   "ISDN" },      /* RFC 1183 */
268    { T_RT,      "RT" },         /* RFC 1183 */
269    { T_NSAP,   "NSAP" },      /* RFC 1706 */
270    { T_NSAP_PTR,   "NSAP_PTR" },
271    { T_SIG,   "SIG" },      /* RFC 2535 */
272    { T_KEY,   "KEY" },      /* RFC 2535 */
273    { T_PX,      "PX" },         /* RFC 2163 */
274    { T_GPOS,   "GPOS" },      /* RFC 1712 */
275    { T_AAAA,   "AAAA" },      /* RFC 1886 */
276    { T_LOC,   "LOC" },      /* RFC 1876 */
277    { T_NXT,   "NXT" },      /* RFC 2535 */
278    { T_EID,   "EID" },      /* Nimrod */
279    { T_NIMLOC,   "NIMLOC" },      /* Nimrod */
280    { T_SRV,   "SRV" },      /* RFC 2782 */
281    { T_ATMA,   "ATMA" },      /* ATM Forum */
282    { T_NAPTR,   "NAPTR" },      /* RFC 2168, RFC 2915 */
283    { T_A6,      "A6" },         /* RFC 2874 */
284    { T_DNAME,   "DNAME" },      /* RFC 2672 */
285    { T_OPT,   "OPT" },      /* RFC 2671 */
286    { T_UINFO,   "UINFO" },
287    { T_UID,   "UID" },
288    { T_GID,   "GID" },
289    { T_UNSPEC,   "UNSPEC" },
290    { T_UNSPECA,   "UNSPECA" },
291    { T_TKEY,   "TKEY" },      /* RFC 2930 */
292    { T_TSIG,   "TSIG" },      /* RFC 2845 */
293    { T_IXFR,   "IXFR" },      /* RFC 1995 */
294    { T_AXFR,   "AXFR" },      /* RFC 1035 */
295    { T_MAILB,   "MAILB" },      /* RFC 1035 */
296    { T_MAILA,   "MAILA" },      /* RFC 1035 */
297    { T_ANY,   "ANY" },
298    { 0,      NULL }
299 };
300 
301 struct tok ns_class2str[] = {
302    { C_IN,      "IN" },      /* Not used */
303    { C_CHAOS,   "CHAOS" },
304    { C_HS,      "HS" },
305    { C_ANY,   "ANY" },
306    { 0,      NULL }
307 };
308 
309 /* print a query */
310 static const u_char *
ns_qprint(register const u_char * cp,register const u_char * bp,int is_mdns)311 ns_qprint(register const u_char *cp, register const u_char *bp, int is_mdns)
312 {
313    register const u_char *np = cp;
314    register u_int i;
315 
316    cp = ns_nskip(cp);
317 
318    if (cp == NULL || !TTEST2(*cp, 4))
319       return(NULL);
320 
321    /* print the qtype and qclass (if it's not IN) */
322    i = EXTRACT_16BITS(cp);
323    cp += 2;
324    sprintf(&ArgusBuf[strlen(ArgusBuf)]," %s", tok2str(ns_type2str, "Type%d", i));
325    i = EXTRACT_16BITS(cp);
326    cp += 2;
327    if (is_mdns && i == (C_IN|C_CACHE_FLUSH))
328       sprintf(&ArgusBuf[strlen(ArgusBuf)]," (Cache flush)");
329    else if (i != C_IN)
330       sprintf(&ArgusBuf[strlen(ArgusBuf)]," %s", tok2str(ns_class2str, "(Class %d)", i));
331 
332    sprintf(&ArgusBuf[strlen(ArgusBuf)],"? ");
333    cp = ns_nprint(np, bp);
334    return(cp ? cp + 4 : NULL);
335 }
336 
337 /* print a reply */
338 static const u_char *
ns_rprint(register const u_char * cp,register const u_char * bp,int is_mdns)339 ns_rprint(register const u_char *cp, register const u_char *bp, int is_mdns)
340 {
341    register u_int class;
342    register u_short typ, len;
343    register const u_char *rp;
344 
345    if (ArgusParser->vflag) {
346       sprintf(&ArgusBuf[strlen(ArgusBuf)], "%c", ' ');
347       if ((cp = ns_nprint(cp, bp)) == NULL)
348          return NULL;
349    } else
350       cp = ns_nskip(cp);
351 
352    if (cp == NULL || !TTEST2(*cp, 10))
353       return (snapend);
354 
355    /* print the type/qtype and class (if it's not IN) */
356    typ = EXTRACT_16BITS(cp);
357    cp += 2;
358    class = EXTRACT_16BITS(cp);
359    cp += 2;
360    if (is_mdns && class == (C_IN|C_CACHE_FLUSH))
361       sprintf(&ArgusBuf[strlen(ArgusBuf)]," (Cache flush)");
362    else if (class != C_IN && typ != T_OPT)
363       sprintf(&ArgusBuf[strlen(ArgusBuf)]," %s", tok2str(ns_class2str, "(Class %d)", class));
364 
365    /* ignore ttl */
366    cp += 4;
367 
368    len = EXTRACT_16BITS(cp);
369    cp += 2;
370 
371    rp = cp + len;
372 
373    sprintf(&ArgusBuf[strlen(ArgusBuf)]," %s", tok2str(ns_type2str, "Type%d", typ));
374    if (rp > snapend)
375       return(NULL);
376 
377    switch (typ) {
378    case T_A: {
379       unsigned int addr = htonl(*(unsigned int *)cp);
380       if (!TTEST2(*cp, sizeof(struct in_addr)))
381          return(NULL);
382       sprintf(&ArgusBuf[strlen(ArgusBuf)]," %s", ipaddr_string(&addr));
383       break;
384    }
385 
386    case T_NS:
387    case T_CNAME:
388    case T_PTR:
389 #ifdef T_DNAME
390    case T_DNAME:
391 #endif
392       sprintf(&ArgusBuf[strlen(ArgusBuf)], "%c", ' ');
393       if (ns_nprint(cp, bp) == NULL)
394          return(NULL);
395       break;
396 
397    case T_SOA:
398       if (!ArgusParser->vflag)
399          break;
400       sprintf(&ArgusBuf[strlen(ArgusBuf)], "%c", ' ');
401       if ((cp = ns_nprint(cp, bp)) == NULL)
402          return(NULL);
403       sprintf(&ArgusBuf[strlen(ArgusBuf)], "%c", ' ');
404       if ((cp = ns_nprint(cp, bp)) == NULL)
405          return(NULL);
406       if (!TTEST2(*cp, 5 * 4))
407          return(NULL);
408       sprintf(&ArgusBuf[strlen(ArgusBuf)]," %u", EXTRACT_32BITS(cp));
409       cp += 4;
410       sprintf(&ArgusBuf[strlen(ArgusBuf)]," %u", EXTRACT_32BITS(cp));
411       cp += 4;
412       sprintf(&ArgusBuf[strlen(ArgusBuf)]," %u", EXTRACT_32BITS(cp));
413       cp += 4;
414       sprintf(&ArgusBuf[strlen(ArgusBuf)]," %u", EXTRACT_32BITS(cp));
415       cp += 4;
416       sprintf(&ArgusBuf[strlen(ArgusBuf)]," %u", EXTRACT_32BITS(cp));
417       cp += 4;
418       break;
419    case T_MX:
420       sprintf(&ArgusBuf[strlen(ArgusBuf)], "%c", ' ');
421       if (!TTEST2(*cp, 2))
422          return(NULL);
423       if (ns_nprint(cp + 2, bp) == NULL)
424          return(NULL);
425       sprintf(&ArgusBuf[strlen(ArgusBuf)]," %d", EXTRACT_16BITS(cp));
426       break;
427 
428    case T_TXT:
429       while (cp < rp) {
430          sprintf(&ArgusBuf[strlen(ArgusBuf)]," \"");
431          cp = ns_cprint(cp);
432          if (cp == NULL)
433             return(NULL);
434          sprintf(&ArgusBuf[strlen(ArgusBuf)], "%c", '"');
435       }
436       break;
437 
438    case T_SRV:
439       sprintf(&ArgusBuf[strlen(ArgusBuf)], "%c", ' ');
440       if (!TTEST2(*cp, 6))
441          return(NULL);
442       if (ns_nprint(cp + 6, bp) == NULL)
443          return(NULL);
444       sprintf(&ArgusBuf[strlen(ArgusBuf)],":%d %d %d", EXTRACT_16BITS(cp + 4),
445          EXTRACT_16BITS(cp), EXTRACT_16BITS(cp + 2));
446       break;
447 
448 #ifdef INET6
449    case T_AAAA:
450       if (!TTEST2(*cp, sizeof(struct in6_addr)))
451          return(NULL);
452       sprintf(&ArgusBuf[strlen(ArgusBuf)]," %s", ip6addr_string(cp));
453       break;
454 
455    case T_A6:
456        {
457       struct in6_addr a;
458       int pbit, pbyte;
459 
460       if (!TTEST2(*cp, 1))
461          return(NULL);
462       pbit = *cp;
463       pbyte = (pbit & ~7) / 8;
464       if (pbit > 128) {
465          sprintf(&ArgusBuf[strlen(ArgusBuf)]," %u(bad plen)", pbit);
466          break;
467       } else if (pbit < 128) {
468          if (!TTEST2(*(cp + 1), sizeof(a) - pbyte))
469             return(NULL);
470          memset(&a, 0, sizeof(a));
471          memcpy(&a.s6_addr[pbyte], cp + 1, sizeof(a) - pbyte);
472          sprintf(&ArgusBuf[strlen(ArgusBuf)]," %u %s", pbit, ip6addr_string(&a));
473       }
474       if (pbit > 0) {
475          sprintf(&ArgusBuf[strlen(ArgusBuf)], "%c", ' ');
476          if (ns_nprint(cp + 1 + sizeof(a) - pbyte, bp) == NULL)
477             return(NULL);
478       }
479       break;
480        }
481 #endif /*INET6*/
482 
483    case T_OPT:
484       sprintf(&ArgusBuf[strlen(ArgusBuf)]," UDPsize=%u", class);
485       break;
486 
487    case T_UNSPECA:      /* One long string */
488       if (!TTEST2(*cp, len))
489          return(NULL);
490       if (fn_printn(cp, len, snapend, ArgusBuf))
491          return(NULL);
492       break;
493 
494    case T_TSIG:
495        {
496       if (cp + len > snapend)
497          return(NULL);
498       if (!ArgusParser->vflag)
499          break;
500       sprintf(&ArgusBuf[strlen(ArgusBuf)], "%c", ' ');
501       if ((cp = ns_nprint(cp, bp)) == NULL)
502          return(NULL);
503       cp += 6;
504       if (!TTEST2(*cp, 2))
505          return(NULL);
506       sprintf(&ArgusBuf[strlen(ArgusBuf)]," fudge=%u", EXTRACT_16BITS(cp));
507       cp += 2;
508       if (!TTEST2(*cp, 2))
509          return(NULL);
510       sprintf(&ArgusBuf[strlen(ArgusBuf)]," maclen=%u", EXTRACT_16BITS(cp));
511       cp += 2 + EXTRACT_16BITS(cp);
512       if (!TTEST2(*cp, 2))
513          return(NULL);
514       sprintf(&ArgusBuf[strlen(ArgusBuf)]," origid=%u", EXTRACT_16BITS(cp));
515       cp += 2;
516       if (!TTEST2(*cp, 2))
517          return(NULL);
518       sprintf(&ArgusBuf[strlen(ArgusBuf)]," error=%u", EXTRACT_16BITS(cp));
519       cp += 2;
520       if (!TTEST2(*cp, 2))
521          return(NULL);
522       sprintf(&ArgusBuf[strlen(ArgusBuf)]," otherlen=%u", EXTRACT_16BITS(cp));
523       cp += 2;
524        }
525    }
526    return (rp);      /* XXX This isn't always right */
527 }
528 
529 char *
ns_print(register const u_char * bp,u_int length,int is_mdns)530 ns_print(register const u_char *bp, u_int length, int is_mdns)
531 {
532    register const HEADER *np;
533    register int qdcount, ancount, nscount, arcount;
534    register const u_char *cp;
535    u_int16_t b2;
536 
537    np = (const HEADER *)bp;
538    TCHECK(*np);
539    /* get the byte-order right */
540    qdcount = EXTRACT_16BITS(&np->qdcount);
541    ancount = EXTRACT_16BITS(&np->ancount);
542    nscount = EXTRACT_16BITS(&np->nscount);
543    arcount = EXTRACT_16BITS(&np->arcount);
544 
545    if (DNS_QR(np)) {
546       /* this is a response */
547       sprintf(&ArgusBuf[strlen(ArgusBuf)],"%d%s%s%s%s%s%s",
548          EXTRACT_16BITS(&np->id),
549          ns_ops[DNS_OPCODE(np)],
550          ns_resp[DNS_RCODE(np)],
551          DNS_AA(np)? "*" : "",
552          DNS_RA(np)? "" : "-",
553          DNS_TC(np)? "|" : "",
554          DNS_AD(np)? "$" : "");
555 
556       if (qdcount != 1)
557          sprintf(&ArgusBuf[strlen(ArgusBuf)]," [%dq]", qdcount);
558 
559       /* Print QUESTION section on -vv */
560       cp = (const u_char *)(np + 1);
561       while (qdcount--) {
562          if (qdcount < EXTRACT_16BITS(&np->qdcount) - 1)
563             sprintf(&ArgusBuf[strlen(ArgusBuf)], "%c", ',');
564          if (ArgusParser->vflag > 1) {
565             sprintf(&ArgusBuf[strlen(ArgusBuf)]," q:");
566             if ((cp = ns_qprint(cp, bp, is_mdns)) == NULL)
567                goto trunc;
568          } else {
569             if ((cp = ns_nskip(cp)) == NULL)
570                goto trunc;
571             cp += 4;   /* skip QTYPE and QCLASS */
572          }
573       }
574       sprintf(&ArgusBuf[strlen(ArgusBuf)]," %d/%d/%d", ancount, nscount, arcount);
575       if (ancount--) {
576          if ((cp = ns_rprint(cp, bp, is_mdns)) == NULL)
577             goto trunc;
578          while (cp < snapend && ancount--) {
579             sprintf(&ArgusBuf[strlen(ArgusBuf)], "%c", ',');
580             if ((cp = ns_rprint(cp, bp, is_mdns)) == NULL)
581                goto trunc;
582          }
583       }
584       if (ancount > 0)
585          goto trunc;
586       /* Print NS and AR sections on -vv */
587       if (ArgusParser->vflag > 1) {
588          if (cp < snapend && nscount--) {
589             sprintf(&ArgusBuf[strlen(ArgusBuf)]," ns:");
590             if ((cp = ns_rprint(cp, bp, is_mdns)) == NULL)
591                goto trunc;
592             while (cp < snapend && nscount--) {
593                sprintf(&ArgusBuf[strlen(ArgusBuf)], "%c", ',');
594                if ((cp = ns_rprint(cp, bp, is_mdns)) == NULL)
595                   goto trunc;
596             }
597          }
598          if (nscount > 0)
599             goto trunc;
600          if (cp < snapend && arcount--) {
601             sprintf(&ArgusBuf[strlen(ArgusBuf)]," ar:");
602             if ((cp = ns_rprint(cp, bp, is_mdns)) == NULL)
603                goto trunc;
604             while (cp < snapend && arcount--) {
605                sprintf(&ArgusBuf[strlen(ArgusBuf)], "%c", ',');
606                if ((cp = ns_rprint(cp, bp, is_mdns)) == NULL)
607                   goto trunc;
608             }
609          }
610          if (arcount > 0)
611             goto trunc;
612       }
613    }
614    else {
615       char tbuf[128];
616       bzero(tbuf, sizeof(tbuf));
617 
618       /* this is a request */
619       sprintf(&ArgusBuf[strlen(ArgusBuf)],"%d%s%s%s", EXTRACT_16BITS(&np->id), ns_ops[DNS_OPCODE(np)],
620           DNS_RD(np) ? "+" : "",
621           DNS_CD(np) ? "%" : "");
622 
623       /* any weirdness? */
624       b2 = EXTRACT_16BITS(((u_short *)np)+1);
625       if (b2 & 0x6cf)
626          sprintf(&tbuf[strlen(tbuf)]," [b2&3=0x%x]", b2);
627 
628       if (DNS_OPCODE(np) == IQUERY) {
629          if (qdcount)
630             sprintf(&tbuf[strlen(tbuf)]," [%dq]", qdcount);
631          if (ancount != 1)
632             sprintf(&tbuf[strlen(tbuf)]," [%da]", ancount);
633       }
634       else {
635          if (ancount)
636             sprintf(&tbuf[strlen(tbuf)]," [%da]", ancount);
637          if (qdcount != 1)
638             sprintf(&tbuf[strlen(tbuf)]," [%dq]", qdcount);
639       }
640       if (nscount)
641          sprintf(&tbuf[strlen(tbuf)]," [%dn]", nscount);
642       if (arcount)
643          sprintf(&tbuf[strlen(tbuf)]," [%dau]", arcount);
644 
645       if (strlen(tbuf) > 0) {
646          sprintf(&ArgusBuf[strlen(ArgusBuf)]," %s", tbuf);
647       } else {
648          sprintf(&ArgusBuf[strlen(ArgusBuf)]," [_]");
649       }
650 
651       cp = (const u_char *)(np + 1);
652       if (qdcount--) {
653          cp = ns_qprint(cp, (const u_char *)np, is_mdns);
654          if (!cp)
655             goto trunc;
656          while (cp < snapend && qdcount--) {
657             cp = ns_qprint((const u_char *)cp,
658                       (const u_char *)np,
659                       is_mdns);
660             if (!cp)
661                goto trunc;
662          }
663       }
664       if (qdcount > 0)
665          goto trunc;
666 
667       /* Print remaining sections on -vv */
668       if (ArgusParser->vflag > 1) {
669          if (ancount--) {
670             if ((cp = ns_rprint(cp, bp, is_mdns)) == NULL)
671                goto trunc;
672             while (cp < snapend && ancount--) {
673                sprintf(&ArgusBuf[strlen(ArgusBuf)], "%c", ',');
674                if ((cp = ns_rprint(cp, bp, is_mdns)) == NULL)
675                   goto trunc;
676             }
677          }
678          if (ancount > 0)
679             goto trunc;
680          if (cp < snapend && nscount--) {
681             sprintf(&ArgusBuf[strlen(ArgusBuf)]," ns:");
682             if ((cp = ns_rprint(cp, bp, is_mdns)) == NULL)
683                goto trunc;
684             while (nscount-- && cp < snapend) {
685                sprintf(&ArgusBuf[strlen(ArgusBuf)], "%c", ',');
686                if ((cp = ns_rprint(cp, bp, is_mdns)) == NULL)
687                   goto trunc;
688             }
689          }
690          if (nscount > 0)
691             goto trunc;
692          if (cp < snapend && arcount--) {
693             sprintf(&ArgusBuf[strlen(ArgusBuf)]," ar:");
694             if ((cp = ns_rprint(cp, bp, is_mdns)) == NULL)
695                goto trunc;
696             while (cp < snapend && arcount--) {
697                sprintf(&ArgusBuf[strlen(ArgusBuf)], "%c", ',');
698                if ((cp = ns_rprint(cp, bp, is_mdns)) == NULL)
699                   goto trunc;
700             }
701          }
702          if (arcount > 0)
703             goto trunc;
704       }
705    }
706    sprintf(&ArgusBuf[strlen(ArgusBuf)]," (%d)", length);
707    return ArgusBuf;
708 
709   trunc:
710    sprintf(&ArgusBuf[strlen(ArgusBuf)],"[|domain]");
711    return ArgusBuf;
712 }
713