1 /*
2  * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
3  *
4  * Squid software is distributed under GPLv2+ license and includes
5  * contributions from numerous individuals and organizations.
6  * Please see the COPYING and CONTRIBUTORS files for details.
7  */
8 
9 /*
10  * Low level DNS protocol routines
11  *
12  * KNOWN BUGS:
13  *
14  * UDP replies with TC set should be retried via TCP
15  */
16 
17 #include "squid.h"
18 #include "dns/rfc1035.h"
19 #include "dns/rfc2671.h"
20 #include "util.h"
21 
22 #if HAVE_STRING_H
23 #include <string.h>
24 #endif
25 #if HAVE_UNISTD_H
26 #include <unistd.h>
27 #endif
28 #if HAVE_MEMORY_H
29 #include <memory.h>
30 #endif
31 #if HAVE_ASSERT_H
32 #include <assert.h>
33 #endif
34 #if HAVE_NETINET_IN_H
35 #include <netinet/in.h>
36 #endif
37 #if HAVE_ARPA_INET_H
38 #include <arpa/inet.h>
39 #endif
40 #if HAVE_STRINGS_H
41 #include <strings.h>
42 #endif
43 
44 #define RFC1035_MAXLABELSZ 63
45 #define rfc1035_unpack_error 15
46 
47 #if 0
48 #define RFC1035_UNPACK_DEBUG  fprintf(stderr, "unpack error at %s:%d\n", __FILE__,__LINE__)
49 #else
50 #define RFC1035_UNPACK_DEBUG  (void)0
51 #endif
52 
53 /*
54  * rfc1035HeaderPack()
55  *
56  * Packs a rfc1035_header structure into a buffer.
57  * Returns number of octets packed (should always be 12)
58  */
59 int
rfc1035HeaderPack(char * buf,size_t sz,rfc1035_message * hdr)60 rfc1035HeaderPack(char *buf, size_t sz, rfc1035_message * hdr)
61 {
62     int off = 0;
63     unsigned short s;
64     unsigned short t;
65     assert(sz >= 12);
66     s = htons(hdr->id);
67     memcpy(buf + off, &s, sizeof(s));
68     off += sizeof(s);
69     t = 0;
70     t |= hdr->qr << 15;
71     t |= (hdr->opcode << 11);
72     t |= (hdr->aa << 10);
73     t |= (hdr->tc << 9);
74     t |= (hdr->rd << 8);
75     t |= (hdr->ra << 7);
76     t |= hdr->rcode;
77     s = htons(t);
78     memcpy(buf + off, &s, sizeof(s));
79     off += sizeof(s);
80     s = htons(hdr->qdcount);
81     memcpy(buf + off, &s, sizeof(s));
82     off += sizeof(s);
83     s = htons(hdr->ancount);
84     memcpy(buf + off, &s, sizeof(s));
85     off += sizeof(s);
86     s = htons(hdr->nscount);
87     memcpy(buf + off, &s, sizeof(s));
88     off += sizeof(s);
89     s = htons(hdr->arcount);
90     memcpy(buf + off, &s, sizeof(s));
91     off += sizeof(s);
92     assert(off == 12);
93     return off;
94 }
95 
96 /*
97  * rfc1035LabelPack()
98  *
99  * Packs a label into a buffer.  The format of
100  * a label is one octet specifying the number of character
101  * bytes to follow.  Labels must be smaller than 64 octets.
102  * Returns number of octets packed.
103  */
104 static int
rfc1035LabelPack(char * buf,size_t sz,const char * label)105 rfc1035LabelPack(char *buf, size_t sz, const char *label)
106 {
107     int off = 0;
108     size_t len = label ? strlen(label) : 0;
109     if (label)
110         assert(!strchr(label, '.'));
111     if (len > RFC1035_MAXLABELSZ)
112         len = RFC1035_MAXLABELSZ;
113     assert(sz >= len + 1);
114     *(buf + off) = (char) len;
115     off++;
116     memcpy(buf + off, label, len);
117     off += len;
118     return off;
119 }
120 
121 /*
122  * rfc1035NamePack()
123  *
124  * Packs a name into a buffer.  Names are packed as a
125  * sequence of labels, terminated with NULL label.
126  * Note message compression is not supported here.
127  * Returns number of octets packed.
128  */
129 static int
rfc1035NamePack(char * buf,size_t sz,const char * name)130 rfc1035NamePack(char *buf, size_t sz, const char *name)
131 {
132     unsigned int off = 0;
133     char *copy = xstrdup(name);
134     char *t;
135     /*
136      * NOTE: use of strtok here makes names like foo....com valid.
137      */
138     for (t = strtok(copy, "."); t; t = strtok(NULL, "."))
139         off += rfc1035LabelPack(buf + off, sz - off, t);
140     xfree(copy);
141     off += rfc1035LabelPack(buf + off, sz - off, NULL);
142     assert(off <= sz);
143     return off;
144 }
145 
146 /*
147  * rfc1035QuestionPack()
148  *
149  * Packs a QUESTION section of a message.
150  * Returns number of octets packed.
151  */
152 int
rfc1035QuestionPack(char * buf,const size_t sz,const char * name,const unsigned short type,const unsigned short _class)153 rfc1035QuestionPack(char *buf,
154                     const size_t sz,
155                     const char *name,
156                     const unsigned short type,
157                     const unsigned short _class)
158 {
159     unsigned int off = 0;
160     unsigned short s;
161     off += rfc1035NamePack(buf + off, sz - off, name);
162     s = htons(type);
163     memcpy(buf + off, &s, sizeof(s));
164     off += sizeof(s);
165     s = htons(_class);
166     memcpy(buf + off, &s, sizeof(s));
167     off += sizeof(s);
168     assert(off <= sz);
169     return off;
170 }
171 
172 /*
173  * rfc1035HeaderUnpack()
174  *
175  * Unpacks a RFC1035 message header buffer into the header fields
176  * of the rfc1035_message structure.
177  *
178  * Updates the buffer offset, which is the same as number of
179  * octects unpacked since the header starts at offset 0.
180  *
181  * Returns 0 (success) or 1 (error)
182  */
183 int
rfc1035HeaderUnpack(const char * buf,size_t sz,unsigned int * off,rfc1035_message * h)184 rfc1035HeaderUnpack(const char *buf, size_t sz, unsigned int *off, rfc1035_message * h)
185 {
186     unsigned short s;
187     unsigned short t;
188     assert(*off == 0);
189     /*
190      * The header is 12 octets.  This is a bogus message if the size
191      * is less than that.
192      */
193     if (sz < 12)
194         return 1;
195     memcpy(&s, buf + (*off), sizeof(s));
196     (*off) += sizeof(s);
197     h->id = ntohs(s);
198     memcpy(&s, buf + (*off), sizeof(s));
199     (*off) += sizeof(s);
200     t = ntohs(s);
201     h->qr = (t >> 15) & 0x01;
202     h->opcode = (t >> 11) & 0x0F;
203     h->aa = (t >> 10) & 0x01;
204     h->tc = (t >> 9) & 0x01;
205     h->rd = (t >> 8) & 0x01;
206     h->ra = (t >> 7) & 0x01;
207     /*
208      * We might want to check that the reserved 'Z' bits (6-4) are
209      * all zero as per RFC 1035.  If not the message should be
210      * rejected.
211      * NO! RFCs say ignore inbound reserved, they may be used in future.
212      *  NEW messages need to be set 0, thats all.
213      */
214     h->rcode = t & 0x0F;
215     memcpy(&s, buf + (*off), sizeof(s));
216     (*off) += sizeof(s);
217     h->qdcount = ntohs(s);
218     memcpy(&s, buf + (*off), sizeof(s));
219     (*off) += sizeof(s);
220     h->ancount = ntohs(s);
221     memcpy(&s, buf + (*off), sizeof(s));
222     (*off) += sizeof(s);
223     h->nscount = ntohs(s);
224     memcpy(&s, buf + (*off), sizeof(s));
225     (*off) += sizeof(s);
226     h->arcount = ntohs(s);
227     assert((*off) == 12);
228     return 0;
229 }
230 
231 /*
232  * rfc1035NameUnpack()
233  *
234  * Unpacks a Name in a message buffer into a char*.
235  * Note 'buf' points to the beginning of the whole message,
236  * 'off' points to the spot where the Name begins, and 'sz'
237  * is the size of the whole message.  'name' must be allocated
238  * by the caller.
239  *
240  * Supports the RFC1035 message compression through recursion.
241  *
242  * Updates the new buffer offset.
243  *
244  * Returns 0 (success) or 1 (error)
245  */
246 static int
rfc1035NameUnpack(const char * buf,size_t sz,unsigned int * off,unsigned short * rdlength,char * name,size_t ns,int rdepth)247 rfc1035NameUnpack(const char *buf, size_t sz, unsigned int *off, unsigned short *rdlength, char *name, size_t ns, int rdepth)
248 {
249     unsigned int no = 0;
250     unsigned char c;
251     size_t len;
252     assert(ns > 0);
253     do {
254         if ((*off) >= sz) {
255             RFC1035_UNPACK_DEBUG;
256             return 1;
257         }
258         c = *(buf + (*off));
259         if (c > 191) {
260             /* blasted compression */
261             unsigned short s;
262             unsigned int ptr;
263             if (rdepth > 64) {  /* infinite pointer loop */
264                 RFC1035_UNPACK_DEBUG;
265                 return 1;
266             }
267             memcpy(&s, buf + (*off), sizeof(s));
268             s = ntohs(s);
269             (*off) += sizeof(s);
270             /* Sanity check */
271             if ((*off) > sz) {
272                 RFC1035_UNPACK_DEBUG;
273                 return 1;
274             }
275             ptr = s & 0x3FFF;
276             /* Make sure the pointer is inside this message */
277             if (ptr >= sz) {
278                 RFC1035_UNPACK_DEBUG;
279                 return 1;
280             }
281             return rfc1035NameUnpack(buf, sz, &ptr, rdlength, name + no, ns - no, rdepth + 1);
282         } else if (c > RFC1035_MAXLABELSZ) {
283             /*
284              * "(The 10 and 01 combinations are reserved for future use.)"
285              */
286             RFC1035_UNPACK_DEBUG;
287             return 1;
288         } else {
289             (*off)++;
290             len = (size_t) c;
291             if (len == 0)
292                 break;
293             if (len > (ns - no - 1)) {  /* label won't fit */
294                 RFC1035_UNPACK_DEBUG;
295                 return 1;
296             }
297             if ((*off) + len >= sz) {   /* message is too short */
298                 RFC1035_UNPACK_DEBUG;
299                 return 1;
300             }
301             memcpy(name + no, buf + (*off), len);
302             (*off) += len;
303             no += len;
304             *(name + (no++)) = '.';
305             if (rdlength)
306                 *rdlength += len + 1;
307         }
308     } while (c > 0 && no < ns);
309     if (no)
310         *(name + no - 1) = '\0';
311     else
312         *name = '\0';
313     /* make sure we didn't allow someone to overflow the name buffer */
314     assert(no <= ns);
315     return 0;
316 }
317 
318 /*
319  * rfc1035RRPack()
320  *
321  * Packs a RFC1035 Resource Record into a message buffer from 'RR'.
322  * The caller must allocate and free RR->rdata and RR->name!
323  *
324  * Updates the new message buffer.
325  *
326  * Returns the number of bytes added to the buffer or 0 for error.
327  */
328 int
rfc1035RRPack(char * buf,const size_t sz,const rfc1035_rr * RR)329 rfc1035RRPack(char *buf, const size_t sz, const rfc1035_rr * RR)
330 {
331     unsigned int off;
332     uint16_t s;
333     uint32_t i;
334 
335     off = rfc1035NamePack(buf, sz, RR->name);
336 
337     /*
338      * Make sure the remaining message has enough octets for the
339      * rest of the RR fields.
340      */
341     if ((off + sizeof(s)*3 + sizeof(i) + RR->rdlength) > sz) {
342         return 0;
343     }
344     s = htons(RR->type);
345     memcpy(buf + off, &s, sizeof(s));
346     off += sizeof(s);
347     s = htons(RR->_class);
348     memcpy(buf + off, &s, sizeof(s));
349     off += sizeof(s);
350     i = htonl(RR->ttl);
351     memcpy(buf + off, &i, sizeof(i));
352     off += sizeof(i);
353     s = htons(RR->rdlength);
354     memcpy(buf + off, &s, sizeof(s));
355     off += sizeof(s);
356     memcpy(buf + off, &(RR->rdata), RR->rdlength);
357     off += RR->rdlength;
358     assert(off <= sz);
359     return off;
360 }
361 
362 /*
363  * rfc1035RRUnpack()
364  *
365  * Unpacks a RFC1035 Resource Record into 'RR' from a message buffer.
366  * The caller must free RR->rdata!
367  *
368  * Updates the new message buffer offset.
369  *
370  * Returns 0 (success) or 1 (error)
371  */
372 static int
rfc1035RRUnpack(const char * buf,size_t sz,unsigned int * off,rfc1035_rr * RR)373 rfc1035RRUnpack(const char *buf, size_t sz, unsigned int *off, rfc1035_rr * RR)
374 {
375     unsigned short s;
376     unsigned int i;
377     unsigned short rdlength;
378     unsigned int rdata_off;
379     if (rfc1035NameUnpack(buf, sz, off, NULL, RR->name, RFC1035_MAXHOSTNAMESZ, 0)) {
380         RFC1035_UNPACK_DEBUG;
381         memset(RR, '\0', sizeof(*RR));
382         return 1;
383     }
384     /*
385      * Make sure the remaining message has enough octets for the
386      * rest of the RR fields.
387      */
388     if ((*off) + 10 > sz) {
389         RFC1035_UNPACK_DEBUG;
390         memset(RR, '\0', sizeof(*RR));
391         return 1;
392     }
393     memcpy(&s, buf + (*off), sizeof(s));
394     (*off) += sizeof(s);
395     RR->type = ntohs(s);
396     memcpy(&s, buf + (*off), sizeof(s));
397     (*off) += sizeof(s);
398     RR->_class = ntohs(s);
399     memcpy(&i, buf + (*off), sizeof(i));
400     (*off) += sizeof(i);
401     RR->ttl = ntohl(i);
402     memcpy(&s, buf + (*off), sizeof(s));
403     (*off) += sizeof(s);
404     rdlength = ntohs(s);
405     if ((*off) + rdlength > sz) {
406         /*
407          * We got a truncated packet.  'dnscache' truncates UDP
408          * replies at 512 octets, as per RFC 1035.
409          */
410         RFC1035_UNPACK_DEBUG;
411         memset(RR, '\0', sizeof(*RR));
412         return 1;
413     }
414     RR->rdlength = rdlength;
415     switch (RR->type) {
416 #if DNS_CNAME
417     case RFC1035_TYPE_CNAME:
418 #endif
419     case RFC1035_TYPE_PTR:
420         RR->rdata = (char*)xmalloc(RFC1035_MAXHOSTNAMESZ);
421         rdata_off = *off;
422         RR->rdlength = 0;   /* Filled in by rfc1035NameUnpack */
423         if (rfc1035NameUnpack(buf, sz, &rdata_off, &RR->rdlength, RR->rdata, RFC1035_MAXHOSTNAMESZ, 0)) {
424             RFC1035_UNPACK_DEBUG;
425             return 1;
426         }
427         if (rdata_off > ((*off) + rdlength)) {
428             /*
429              * This probably doesn't happen for valid packets, but
430              * I want to make sure that NameUnpack doesn't go beyond
431              * the RDATA area.
432              */
433             RFC1035_UNPACK_DEBUG;
434             xfree(RR->rdata);
435             memset(RR, '\0', sizeof(*RR));
436             return 1;
437         }
438         break;
439     case RFC1035_TYPE_A:
440     default:
441         RR->rdata = (char*)xmalloc(rdlength);
442         memcpy(RR->rdata, buf + (*off), rdlength);
443         break;
444     }
445     (*off) += rdlength;
446     assert((*off) <= sz);
447     return 0;
448 }
449 
450 const char *
rfc1035ErrorMessage(int n)451 rfc1035ErrorMessage(int n)
452 {
453     if (n < 0)
454         n = -n;
455     switch (n) {
456     case 0:
457         return "No error condition";
458         break;
459     case 1:
460         return "Format Error: The name server was "
461                "unable to interpret the query.";
462         break;
463     case 2:
464         return "Server Failure: The name server was "
465                "unable to process this query.";
466         break;
467     case 3:
468         return "Name Error: The domain name does "
469                "not exist.";
470         break;
471     case 4:
472         return "Not Implemented: The name server does "
473                "not support the requested kind of query.";
474         break;
475     case 5:
476         return "Refused: The name server refuses to "
477                "perform the specified operation.";
478         break;
479     case rfc1035_unpack_error:
480         return "The DNS reply message is corrupt or could "
481                "not be safely parsed.";
482         break;
483     default:
484         return "Unknown Error";
485         break;
486     }
487 }
488 
489 void
rfc1035RRDestroy(rfc1035_rr ** rr,int n)490 rfc1035RRDestroy(rfc1035_rr ** rr, int n)
491 {
492     if (*rr == NULL) {
493         return;
494     }
495 
496     while (n-- > 0) {
497         if ((*rr)[n].rdata)
498             xfree((*rr)[n].rdata);
499     }
500     xfree(*rr);
501     *rr = NULL;
502 }
503 
504 /*
505  * rfc1035QueryUnpack()
506  *
507  * Unpacks a RFC1035 Query Record into 'query' from a message buffer.
508  *
509  * Updates the new message buffer offset.
510  *
511  * Returns 0 (success) or 1 (error)
512  */
513 static int
rfc1035QueryUnpack(const char * buf,size_t sz,unsigned int * off,rfc1035_query * query)514 rfc1035QueryUnpack(const char *buf, size_t sz, unsigned int *off, rfc1035_query * query)
515 {
516     unsigned short s;
517     if (rfc1035NameUnpack(buf, sz, off, NULL, query->name, RFC1035_MAXHOSTNAMESZ, 0)) {
518         RFC1035_UNPACK_DEBUG;
519         memset(query, '\0', sizeof(*query));
520         return 1;
521     }
522     if (*off + 4 > sz) {
523         RFC1035_UNPACK_DEBUG;
524         memset(query, '\0', sizeof(*query));
525         return 1;
526     }
527     memcpy(&s, buf + *off, 2);
528     *off += 2;
529     query->qtype = ntohs(s);
530     memcpy(&s, buf + *off, 2);
531     *off += 2;
532     query->qclass = ntohs(s);
533     return 0;
534 }
535 
536 void
rfc1035MessageDestroy(rfc1035_message ** msg)537 rfc1035MessageDestroy(rfc1035_message ** msg)
538 {
539     if (!*msg)
540         return;
541     if ((*msg)->query)
542         xfree((*msg)->query);
543     if ((*msg)->answer)
544         rfc1035RRDestroy(&(*msg)->answer, (*msg)->ancount);
545     xfree(*msg);
546     *msg = NULL;
547 }
548 
549 /*
550  * rfc1035QueryCompare()
551  *
552  * Compares two rfc1035_query entries
553  *
554  * Returns 0 (equal) or !=0 (different)
555  */
556 int
rfc1035QueryCompare(const rfc1035_query * a,const rfc1035_query * b)557 rfc1035QueryCompare(const rfc1035_query * a, const rfc1035_query * b)
558 {
559     size_t la, lb;
560     if (a->qtype != b->qtype)
561         return 1;
562     if (a->qclass != b->qclass)
563         return 1;
564     la = strlen(a->name);
565     lb = strlen(b->name);
566     if (la != lb) {
567         /* Trim root label(s) */
568         while (la > 0 && a->name[la - 1] == '.')
569             la--;
570         while (lb > 0 && b->name[lb - 1] == '.')
571             lb--;
572     }
573     if (la != lb)
574         return 1;
575 
576     return strncasecmp(a->name, b->name, la);
577 }
578 
579 /*
580  * rfc1035MessageUnpack()
581  *
582  * Takes the contents of a DNS reply and fills in an array
583  * of resource record structures.  The records array is allocated
584  * here, and should be freed by calling rfc1035RRDestroy().
585  *
586  * Returns number of records unpacked, zero if DNS reply indicates
587  * zero answers, or an error number < 0.
588  */
589 
590 int
rfc1035MessageUnpack(const char * buf,size_t sz,rfc1035_message ** answer)591 rfc1035MessageUnpack(const char *buf,
592                      size_t sz,
593                      rfc1035_message ** answer)
594 {
595     unsigned int off = 0;
596     unsigned int i, j;
597     unsigned int nr = 0;
598     rfc1035_message *msg = NULL;
599     rfc1035_rr *recs = NULL;
600     rfc1035_query *querys = NULL;
601     msg = (rfc1035_message*)xcalloc(1, sizeof(*msg));
602     if (rfc1035HeaderUnpack(buf + off, sz - off, &off, msg)) {
603         RFC1035_UNPACK_DEBUG;
604         xfree(msg);
605         return -rfc1035_unpack_error;
606     }
607     i = (unsigned int) msg->qdcount;
608     if (i != 1) {
609         /* This can not be an answer to our queries.. */
610         RFC1035_UNPACK_DEBUG;
611         xfree(msg);
612         return -rfc1035_unpack_error;
613     }
614     querys = msg->query = (rfc1035_query*)xcalloc(i, sizeof(*querys));
615     for (j = 0; j < i; j++) {
616         if (rfc1035QueryUnpack(buf, sz, &off, &querys[j])) {
617             RFC1035_UNPACK_DEBUG;
618             rfc1035MessageDestroy(&msg);
619             return -rfc1035_unpack_error;
620         }
621     }
622     *answer = msg;
623     if (msg->rcode) {
624         RFC1035_UNPACK_DEBUG;
625         return -msg->rcode;
626     }
627     if (msg->ancount == 0)
628         return 0;
629     i = (unsigned int) msg->ancount;
630     recs = msg->answer = (rfc1035_rr*)xcalloc(i, sizeof(*recs));
631     for (j = 0; j < i; j++) {
632         if (off >= sz) {    /* corrupt packet */
633             RFC1035_UNPACK_DEBUG;
634             break;
635         }
636         if (rfc1035RRUnpack(buf, sz, &off, &recs[j])) {     /* corrupt RR */
637             RFC1035_UNPACK_DEBUG;
638             break;
639         }
640         nr++;
641     }
642     if (nr == 0) {
643         /*
644          * we expected to unpack some answers (ancount != 0), but
645          * didn't actually get any.
646          */
647         rfc1035MessageDestroy(&msg);
648         *answer = NULL;
649         return -rfc1035_unpack_error;
650     }
651     return nr;
652 }
653 
654 /*
655  * rfc1035BuildAQuery()
656  *
657  * Builds a message buffer with a QUESTION to lookup A records
658  * for a hostname.  Caller must allocate 'buf' which should
659  * probably be at least 512 octets.  The 'szp' initially
660  * specifies the size of the buffer, on return it contains
661  * the size of the message (i.e. how much to write).
662  * Returns the size of the query
663  */
664 ssize_t
rfc1035BuildAQuery(const char * hostname,char * buf,size_t sz,unsigned short qid,rfc1035_query * query,ssize_t edns_sz)665 rfc1035BuildAQuery(const char *hostname, char *buf, size_t sz, unsigned short qid, rfc1035_query * query, ssize_t edns_sz)
666 {
667     static rfc1035_message h;
668     size_t offset = 0;
669     memset(&h, '\0', sizeof(h));
670     h.id = qid;
671     h.qr = 0;
672     h.rd = 1;
673     h.opcode = 0;       /* QUERY */
674     h.qdcount = (unsigned int) 1;
675     h.arcount = (edns_sz > 0 ? 1 : 0);
676     offset += rfc1035HeaderPack(buf + offset, sz - offset, &h);
677     offset += rfc1035QuestionPack(buf + offset,
678                                   sz - offset,
679                                   hostname,
680                                   RFC1035_TYPE_A,
681                                   RFC1035_CLASS_IN);
682     if (edns_sz > 0)
683         offset += rfc2671RROptPack(buf + offset, sz - offset, edns_sz);
684     if (query) {
685         query->qtype = RFC1035_TYPE_A;
686         query->qclass = RFC1035_CLASS_IN;
687         xstrncpy(query->name, hostname, sizeof(query->name));
688     }
689     assert(offset <= sz);
690     return offset;
691 }
692 
693 /*
694  * rfc1035BuildPTRQuery()
695  *
696  * Builds a message buffer with a QUESTION to lookup PTR records
697  * for an address.  Caller must allocate 'buf' which should
698  * probably be at least 512 octets.  The 'szp' initially
699  * specifies the size of the buffer, on return it contains
700  * the size of the message (i.e. how much to write).
701  * Returns the size of the query
702  */
703 ssize_t
rfc1035BuildPTRQuery(const struct in_addr addr,char * buf,size_t sz,unsigned short qid,rfc1035_query * query,ssize_t edns_sz)704 rfc1035BuildPTRQuery(const struct in_addr addr, char *buf, size_t sz, unsigned short qid, rfc1035_query * query, ssize_t edns_sz)
705 {
706     static rfc1035_message h;
707     size_t offset = 0;
708     static char rev[32];
709     unsigned int i;
710     memset(&h, '\0', sizeof(h));
711     i = (unsigned int) ntohl(addr.s_addr);
712     snprintf(rev, 32, "%u.%u.%u.%u.in-addr.arpa.",
713              i & 255,
714              (i >> 8) & 255,
715              (i >> 16) & 255,
716              (i >> 24) & 255);
717     h.id = qid;
718     h.qr = 0;
719     h.rd = 1;
720     h.opcode = 0;       /* QUERY */
721     h.qdcount = (unsigned int) 1;
722     h.arcount = (edns_sz > 0 ? 1 : 0);
723     offset += rfc1035HeaderPack(buf + offset, sz - offset, &h);
724     offset += rfc1035QuestionPack(buf + offset,
725                                   sz - offset,
726                                   rev,
727                                   RFC1035_TYPE_PTR,
728                                   RFC1035_CLASS_IN);
729     if (edns_sz > 0)
730         offset += rfc2671RROptPack(buf + offset, sz - offset, edns_sz);
731     if (query) {
732         query->qtype = RFC1035_TYPE_PTR;
733         query->qclass = RFC1035_CLASS_IN;
734         xstrncpy(query->name, rev, sizeof(query->name));
735     }
736     assert(offset <= sz);
737     return offset;
738 }
739 
740 /*
741  * We're going to retry a former query, but we
742  * just need a new ID for it.  Lucky for us ID
743  * is the first field in the message buffer.
744  */
745 void
rfc1035SetQueryID(char * buf,unsigned short qid)746 rfc1035SetQueryID(char *buf, unsigned short qid)
747 {
748     unsigned short s = htons(qid);
749     memcpy(buf, &s, sizeof(s));
750 }
751 
752 #if DRIVER
753 #include <sys/socket.h>
754 int
main(int argc,char * argv[])755 main(int argc, char *argv[])
756 {
757     char input[SQUID_DNS_BUFSZ];
758     char buf[SQUID_DNS_BUFSZ];
759     char rbuf[SQUID_DNS_BUFSZ];
760     size_t sz = SQUID_DNS_BUFSZ;
761     unsigned short sid;
762     int s;
763     int rl;
764     struct sockaddr_in S;
765     if (3 != argc) {
766         fprintf(stderr, "usage: %s ip port\n", argv[0]);
767         return 1;
768     }
769     setbuf(stdout, NULL);
770     setbuf(stderr, NULL);
771     s = socket(PF_INET, SOCK_DGRAM, 0);
772     if (s < 0) {
773         perror("socket");
774         return 1;
775     }
776     memset(&S, '\0', sizeof(S));
777     S.sin_family = AF_INET;
778     S.sin_port = htons(atoi(argv[2]));
779     S.sin_addr.s_addr = inet_addr(argv[1]);
780     while (fgets(input, RFC1035_DEFAULT_PACKET_SZ, stdin)) {
781         struct in_addr junk;
782         strtok(input, "\r\n");
783         memset(buf, '\0', RFC1035_DEFAULT_PACKET_SZ);
784         sz = RFC1035_DEFAULT_PACKET_SZ;
785         if (inet_pton(AF_INET, input, &junk)) {
786             sid = rfc1035BuildPTRQuery(junk, buf, &sz);
787         } else {
788             sid = rfc1035BuildAQuery(input, buf, &sz);
789         }
790         sendto(s, buf, sz, 0, (struct sockaddr *) &S, sizeof(S));
791         do {
792             fd_set R;
793             struct timeval to;
794             FD_ZERO(&R);
795             FD_SET(s, &R);
796             to.tv_sec = 10;
797             to.tv_usec = 0;
798             rl = select(s + 1, &R, NULL, NULL, &to);
799         } while (0);
800         if (rl < 1) {
801             printf("TIMEOUT\n");
802             continue;
803         }
804         memset(rbuf, '\0', RFC1035_DEFAULT_PACKET_SZ);
805         rl = recv(s, rbuf, RFC1035_DEFAULT_PACKET_SZ, 0);
806         {
807             unsigned short rid = 0;
808             int i;
809             int n;
810             rfc1035_rr *answers = NULL;
811             n = rfc1035AnswersUnpack(rbuf,
812                                      rl,
813                                      &answers,
814                                      &rid);
815             if (n < 0) {
816                 printf("ERROR %d\n", -n);
817             } else if (rid != sid) {
818                 printf("ERROR, ID mismatch (%#hx, %#hx)\n", sid, rid);
819             } else {
820                 printf("%d answers\n", n);
821                 for (i = 0; i < n; i++) {
822                     if (answers[i].type == RFC1035_TYPE_A) {
823                         struct in_addr a;
824                         char ipa_str[sizeof(a)];
825                         memcpy(&a, answers[i].rdata, 4);
826                         printf("A\t%d\t%s\n", answers[i].ttl, inet_ntop(AF_INET,&a,tmp,sizeof(a)));
827                     } else if (answers[i].type == RFC1035_TYPE_PTR) {
828                         char ptr[128];
829                         strncpy(ptr, answers[i].rdata, answers[i].rdlength);
830                         printf("PTR\t%d\t%s\n", answers[i].ttl, ptr);
831                     } else {
832                         fprintf(stderr, "can't print answer type %d\n",
833                                 (int) answers[i].type);
834                     }
835                 }
836             }
837         }
838     }
839     return 0;
840 }
841 #endif
842 
843