]>
git.ipfire.org Git - thirdparty/squid.git/blob - lib/rfc1035.c
5 * Low level DNS protocol routines
6 * AUTHOR: Duane Wessels
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
39 * UDP replies with TC set should be retried via TCP
58 #include <sys/types.h>
64 #include <netinet/in.h>
67 #include <arpa/inet.h>
75 #define RFC1035_MAXLABELSZ 63
76 #define rfc1035_unpack_error 15
79 #define RFC1035_UNPACK_DEBUG fprintf(stderr, "unpack error at %s:%d\n", __FILE__,__LINE__)
81 #define RFC1035_UNPACK_DEBUG (void)0
87 const char *rfc1035_error_message
;
92 * Packs a rfc1035_header structure into a buffer.
93 * Returns number of octets packed (should always be 12)
96 rfc1035HeaderPack(char *buf
, size_t sz
, rfc1035_message
* hdr
)
103 memcpy(buf
+ off
, &s
, sizeof(s
));
107 t
|= (hdr
->opcode
<< 11);
108 t
|= (hdr
->aa
<< 10);
114 memcpy(buf
+ off
, &s
, sizeof(s
));
116 s
= htons(hdr
->qdcount
);
117 memcpy(buf
+ off
, &s
, sizeof(s
));
119 s
= htons(hdr
->ancount
);
120 memcpy(buf
+ off
, &s
, sizeof(s
));
122 s
= htons(hdr
->nscount
);
123 memcpy(buf
+ off
, &s
, sizeof(s
));
125 s
= htons(hdr
->arcount
);
126 memcpy(buf
+ off
, &s
, sizeof(s
));
135 * Packs a label into a buffer. The format of
136 * a label is one octet specifying the number of character
137 * bytes to follow. Labels must be smaller than 64 octets.
138 * Returns number of octets packed.
141 rfc1035LabelPack(char *buf
, size_t sz
, const char *label
)
144 size_t len
= label
? strlen(label
) : 0;
146 assert(!strchr(label
, '.'));
147 if (len
> RFC1035_MAXLABELSZ
)
148 len
= RFC1035_MAXLABELSZ
;
149 assert(sz
>= len
+ 1);
150 *(buf
+ off
) = (char) len
;
152 memcpy(buf
+ off
, label
, len
);
160 * Packs a name into a buffer. Names are packed as a
161 * sequence of labels, terminated with NULL label.
162 * Note message compression is not supported here.
163 * Returns number of octets packed.
166 rfc1035NamePack(char *buf
, size_t sz
, const char *name
)
168 unsigned int off
= 0;
169 char *copy
= xstrdup(name
);
172 * NOTE: use of strtok here makes names like foo....com valid.
174 for (t
= strtok(copy
, "."); t
; t
= strtok(NULL
, "."))
175 off
+= rfc1035LabelPack(buf
+ off
, sz
- off
, t
);
177 off
+= rfc1035LabelPack(buf
+ off
, sz
- off
, NULL
);
183 * rfc1035QuestionPack()
185 * Packs a QUESTION section of a message.
186 * Returns number of octets packed.
189 rfc1035QuestionPack(char *buf
,
192 const unsigned short type
,
193 const unsigned short _class
)
195 unsigned int off
= 0;
197 off
+= rfc1035NamePack(buf
+ off
, sz
- off
, name
);
199 memcpy(buf
+ off
, &s
, sizeof(s
));
202 memcpy(buf
+ off
, &s
, sizeof(s
));
209 * rfc1035HeaderUnpack()
211 * Unpacks a RFC1035 message header buffer into the header fields
212 * of the rfc1035_message structure.
214 * Updates the buffer offset, which is the same as number of
215 * octects unpacked since the header starts at offset 0.
217 * Returns 0 (success) or 1 (error)
220 rfc1035HeaderUnpack(const char *buf
, size_t sz
, unsigned int *off
, rfc1035_message
* h
)
226 * The header is 12 octets. This is a bogus message if the size
231 memcpy(&s
, buf
+ (*off
), sizeof(s
));
234 memcpy(&s
, buf
+ (*off
), sizeof(s
));
237 h
->qr
= (t
>> 15) & 0x01;
238 h
->opcode
= (t
>> 11) & 0x0F;
239 h
->aa
= (t
>> 10) & 0x01;
240 h
->tc
= (t
>> 9) & 0x01;
241 h
->rd
= (t
>> 8) & 0x01;
242 h
->ra
= (t
>> 7) & 0x01;
244 * We might want to check that the reserved 'Z' bits (6-4) are
245 * all zero as per RFC 1035. If not the message should be
247 * NO! RFCs say ignore inbound reserved, they may be used in future.
248 * NEW messages need to be set 0, thats all.
251 memcpy(&s
, buf
+ (*off
), sizeof(s
));
253 h
->qdcount
= ntohs(s
);
254 memcpy(&s
, buf
+ (*off
), sizeof(s
));
256 h
->ancount
= ntohs(s
);
257 memcpy(&s
, buf
+ (*off
), sizeof(s
));
259 h
->nscount
= ntohs(s
);
260 memcpy(&s
, buf
+ (*off
), sizeof(s
));
262 h
->arcount
= ntohs(s
);
263 assert((*off
) == 12);
268 * rfc1035NameUnpack()
270 * Unpacks a Name in a message buffer into a char*.
271 * Note 'buf' points to the beginning of the whole message,
272 * 'off' points to the spot where the Name begins, and 'sz'
273 * is the size of the whole message. 'name' must be allocated
276 * Supports the RFC1035 message compression through recursion.
278 * Updates the new buffer offset.
280 * Returns 0 (success) or 1 (error)
283 rfc1035NameUnpack(const char *buf
, size_t sz
, unsigned int *off
, unsigned short *rdlength
, char *name
, size_t ns
, int rdepth
)
293 /* blasted compression */
296 if (rdepth
> 64) { /* infinite pointer loop */
297 RFC1035_UNPACK_DEBUG
;
300 memcpy(&s
, buf
+ (*off
), sizeof(s
));
305 RFC1035_UNPACK_DEBUG
;
309 /* Make sure the pointer is inside this message */
311 RFC1035_UNPACK_DEBUG
;
314 return rfc1035NameUnpack(buf
, sz
, &ptr
, rdlength
, name
+ no
, ns
- no
, rdepth
+ 1);
315 } else if (c
> RFC1035_MAXLABELSZ
) {
317 * "(The 10 and 01 combinations are reserved for future use.)"
319 RFC1035_UNPACK_DEBUG
;
326 if (len
> (ns
- no
- 1)) { /* label won't fit */
327 RFC1035_UNPACK_DEBUG
;
330 if ((*off
) + len
>= sz
) { /* message is too short */
331 RFC1035_UNPACK_DEBUG
;
334 memcpy(name
+ no
, buf
+ (*off
), len
);
337 *(name
+ (no
++)) = '.';
339 *rdlength
+= len
+ 1;
341 } while (c
> 0 && no
< ns
);
343 *(name
+ no
- 1) = '\0';
346 /* make sure we didn't allow someone to overflow the name buffer */
354 * Unpacks a RFC1035 Resource Record into 'RR' from a message buffer.
355 * The caller must free RR->rdata!
357 * Updates the new message buffer offset.
359 * Returns 0 (success) or 1 (error)
362 rfc1035RRUnpack(const char *buf
, size_t sz
, unsigned int *off
, rfc1035_rr
* RR
)
366 unsigned short rdlength
;
367 unsigned int rdata_off
;
368 if (rfc1035NameUnpack(buf
, sz
, off
, NULL
, RR
->name
, RFC1035_MAXHOSTNAMESZ
, 0)) {
369 RFC1035_UNPACK_DEBUG
;
370 memset(RR
, '\0', sizeof(*RR
));
374 * Make sure the remaining message has enough octets for the
375 * rest of the RR fields.
377 if ((*off
) + 10 > sz
) {
378 RFC1035_UNPACK_DEBUG
;
379 memset(RR
, '\0', sizeof(*RR
));
382 memcpy(&s
, buf
+ (*off
), sizeof(s
));
385 memcpy(&s
, buf
+ (*off
), sizeof(s
));
387 RR
->_class
= ntohs(s
);
388 memcpy(&i
, buf
+ (*off
), sizeof(i
));
391 memcpy(&s
, buf
+ (*off
), sizeof(s
));
394 if ((*off
) + rdlength
> sz
) {
396 * We got a truncated packet. 'dnscache' truncates UDP
397 * replies at 512 octets, as per RFC 1035.
399 RFC1035_UNPACK_DEBUG
;
400 memset(RR
, '\0', sizeof(*RR
));
403 RR
->rdlength
= rdlength
;
406 case RFC1035_TYPE_CNAME
:
408 case RFC1035_TYPE_PTR
:
409 RR
->rdata
= (char*)xmalloc(RFC1035_MAXHOSTNAMESZ
);
411 RR
->rdlength
= 0; /* Filled in by rfc1035NameUnpack */
412 if (rfc1035NameUnpack(buf
, sz
, &rdata_off
, &RR
->rdlength
, RR
->rdata
, RFC1035_MAXHOSTNAMESZ
, 0)) {
413 RFC1035_UNPACK_DEBUG
;
416 if (rdata_off
> ((*off
) + rdlength
)) {
418 * This probably doesn't happen for valid packets, but
419 * I want to make sure that NameUnpack doesn't go beyond
422 RFC1035_UNPACK_DEBUG
;
424 memset(RR
, '\0', sizeof(*RR
));
430 RR
->rdata
= (char*)xmalloc(rdlength
);
431 memcpy(RR
->rdata
, buf
+ (*off
), rdlength
);
435 assert((*off
) <= sz
);
440 rfc1035SetErrno(int n
)
442 switch (rfc1035_errno
= n
) {
444 rfc1035_error_message
= "No error condition";
447 rfc1035_error_message
= "Format Error: The name server was "
448 "unable to interpret the query.";
451 rfc1035_error_message
= "Server Failure: The name server was "
452 "unable to process this query.";
455 rfc1035_error_message
= "Name Error: The domain name does "
459 rfc1035_error_message
= "Not Implemented: The name server does "
460 "not support the requested kind of query.";
463 rfc1035_error_message
= "Refused: The name server refuses to "
464 "perform the specified operation.";
466 case rfc1035_unpack_error
:
467 rfc1035_error_message
= "The DNS reply message is corrupt or could "
468 "not be safely parsed.";
471 rfc1035_error_message
= "Unknown Error";
477 rfc1035RRDestroy(rfc1035_rr
** rr
, int n
)
479 if (*rr
== NULL
|| n
< 1) {
485 xfree((*rr
)[n
].rdata
);
492 * rfc1035QueryUnpack()
494 * Unpacks a RFC1035 Query Record into 'query' from a message buffer.
496 * Updates the new message buffer offset.
498 * Returns 0 (success) or 1 (error)
501 rfc1035QueryUnpack(const char *buf
, size_t sz
, unsigned int *off
, rfc1035_query
* query
)
504 if (rfc1035NameUnpack(buf
, sz
, off
, NULL
, query
->name
, RFC1035_MAXHOSTNAMESZ
, 0)) {
505 RFC1035_UNPACK_DEBUG
;
506 memset(query
, '\0', sizeof(*query
));
510 RFC1035_UNPACK_DEBUG
;
511 memset(query
, '\0', sizeof(*query
));
514 memcpy(&s
, buf
+ *off
, 2);
516 query
->qtype
= ntohs(s
);
517 memcpy(&s
, buf
+ *off
, 2);
519 query
->qclass
= ntohs(s
);
524 rfc1035MessageDestroy(rfc1035_message
** msg
)
529 xfree((*msg
)->query
);
531 rfc1035RRDestroy(&(*msg
)->answer
, (*msg
)->ancount
);
537 * rfc1035QueryCompare()
539 * Compares two rfc1035_query entries
541 * Returns 0 (equal) or !=0 (different)
544 rfc1035QueryCompare(const rfc1035_query
* a
, const rfc1035_query
* b
)
547 if (a
->qtype
!= b
->qtype
)
549 if (a
->qclass
!= b
->qclass
)
551 la
= strlen(a
->name
);
552 lb
= strlen(b
->name
);
554 /* Trim root label(s) */
555 while (la
> 0 && a
->name
[la
- 1] == '.')
557 while (lb
> 0 && b
->name
[lb
- 1] == '.')
563 return strncasecmp(a
->name
, b
->name
, la
);
567 * rfc1035MessageUnpack()
569 * Takes the contents of a DNS reply and fills in an array
570 * of resource record structures. The records array is allocated
571 * here, and should be freed by calling rfc1035RRDestroy().
573 * Returns number of records unpacked, zero if DNS reply indicates
574 * zero answers, or an error number < 0.
578 rfc1035MessageUnpack(const char *buf
,
580 rfc1035_message
** answer
)
582 unsigned int off
= 0;
585 rfc1035_message
*msg
= NULL
;
586 rfc1035_rr
*recs
= NULL
;
587 rfc1035_query
*querys
= NULL
;
588 msg
= (rfc1035_message
*)xcalloc(1, sizeof(*msg
));
589 if (rfc1035HeaderUnpack(buf
+ off
, sz
- off
, &off
, msg
)) {
590 RFC1035_UNPACK_DEBUG
;
591 rfc1035SetErrno(rfc1035_unpack_error
);
593 return -rfc1035_unpack_error
;
596 rfc1035_error_message
= NULL
;
597 i
= (unsigned int) msg
->qdcount
;
599 /* This can not be an answer to our queries.. */
600 RFC1035_UNPACK_DEBUG
;
601 rfc1035SetErrno(rfc1035_unpack_error
);
603 return -rfc1035_unpack_error
;
605 querys
= msg
->query
= (rfc1035_query
*)xcalloc(i
, sizeof(*querys
));
606 for (j
= 0; j
< i
; j
++) {
607 if (rfc1035QueryUnpack(buf
, sz
, &off
, &querys
[j
])) {
608 RFC1035_UNPACK_DEBUG
;
609 rfc1035SetErrno(rfc1035_unpack_error
);
610 rfc1035MessageDestroy(&msg
);
611 return -rfc1035_unpack_error
;
616 RFC1035_UNPACK_DEBUG
;
617 rfc1035SetErrno((int) msg
->rcode
);
618 return -rfc1035_errno
;
620 if (msg
->ancount
== 0)
622 i
= (unsigned int) msg
->ancount
;
623 recs
= msg
->answer
= (rfc1035_rr
*)xcalloc(i
, sizeof(*recs
));
624 for (j
= 0; j
< i
; j
++) {
625 if (off
>= sz
) { /* corrupt packet */
626 RFC1035_UNPACK_DEBUG
;
629 if (rfc1035RRUnpack(buf
, sz
, &off
, &recs
[j
])) { /* corrupt RR */
630 RFC1035_UNPACK_DEBUG
;
637 * we expected to unpack some answers (ancount != 0), but
638 * didn't actually get any.
640 rfc1035MessageDestroy(&msg
);
642 rfc1035SetErrno(rfc1035_unpack_error
);
643 return -rfc1035_unpack_error
;
649 * rfc1035BuildAQuery()
651 * Builds a message buffer with a QUESTION to lookup A records
652 * for a hostname. Caller must allocate 'buf' which should
653 * probably be at least 512 octets. The 'szp' initially
654 * specifies the size of the buffer, on return it contains
655 * the size of the message (i.e. how much to write).
656 * Returns the size of the query
659 rfc1035BuildAQuery(const char *hostname
, char *buf
, size_t sz
, unsigned short qid
, rfc1035_query
* query
)
661 static rfc1035_message h
;
663 memset(&h
, '\0', sizeof(h
));
667 h
.opcode
= 0; /* QUERY */
668 h
.qdcount
= (unsigned int) 1;
669 offset
+= rfc1035HeaderPack(buf
+ offset
, sz
- offset
, &h
);
670 offset
+= rfc1035QuestionPack(buf
+ offset
,
676 query
->qtype
= RFC1035_TYPE_A
;
677 query
->qclass
= RFC1035_CLASS_IN
;
678 xstrncpy(query
->name
, hostname
, sizeof(query
->name
));
680 assert(offset
<= sz
);
685 * rfc1035BuildPTRQuery()
687 * Builds a message buffer with a QUESTION to lookup PTR records
688 * for an address. Caller must allocate 'buf' which should
689 * probably be at least 512 octets. The 'szp' initially
690 * specifies the size of the buffer, on return it contains
691 * the size of the message (i.e. how much to write).
692 * Returns the size of the query
695 rfc1035BuildPTRQuery(const struct in_addr addr
, char *buf
, size_t sz
, unsigned short qid
, rfc1035_query
* query
)
697 static rfc1035_message h
;
701 memset(&h
, '\0', sizeof(h
));
702 i
= (unsigned int) ntohl(addr
.s_addr
);
703 snprintf(rev
, 32, "%u.%u.%u.%u.in-addr.arpa.",
711 h
.opcode
= 0; /* QUERY */
712 h
.qdcount
= (unsigned int) 1;
713 offset
+= rfc1035HeaderPack(buf
+ offset
, sz
- offset
, &h
);
714 offset
+= rfc1035QuestionPack(buf
+ offset
,
720 query
->qtype
= RFC1035_TYPE_PTR
;
721 query
->qclass
= RFC1035_CLASS_IN
;
722 xstrncpy(query
->name
, rev
, sizeof(query
->name
));
724 assert(offset
<= sz
);
729 * We're going to retry a former query, but we
730 * just need a new ID for it. Lucky for us ID
731 * is the first field in the message buffer.
734 rfc1035SetQueryID(char *buf
, unsigned short qid
)
736 unsigned short s
= htons(qid
);
737 memcpy(buf
, &s
, sizeof(s
));
741 #include <sys/socket.h>
742 #include <sys/time.h>
744 main(int argc
, char *argv
[])
753 struct sockaddr_in S
;
755 fprintf(stderr
, "usage: %s ip port\n", argv
[0]);
758 setbuf(stdout
, NULL
);
759 setbuf(stderr
, NULL
);
760 s
= socket(PF_INET
, SOCK_DGRAM
, 0);
765 memset(&S
, '\0', sizeof(S
));
766 S
.sin_family
= AF_INET
;
767 S
.sin_port
= htons(atoi(argv
[2]));
768 S
.sin_addr
.s_addr
= inet_addr(argv
[1]);
769 while (fgets(input
, 512, stdin
)) {
771 strtok(input
, "\r\n");
772 memset(buf
, '\0', 512);
774 if (inet_pton(AF_INET
, input
, &junk
)) {
775 sid
= rfc1035BuildPTRQuery(junk
, buf
, &sz
);
777 sid
= rfc1035BuildAQuery(input
, buf
, &sz
);
779 sendto(s
, buf
, sz
, 0, (struct sockaddr
*) &S
, sizeof(S
));
787 rl
= select(s
+ 1, &R
, NULL
, NULL
, &to
);
793 memset(rbuf
, '\0', 512);
794 rl
= recv(s
, rbuf
, 512, 0);
796 unsigned short rid
= 0;
799 rfc1035_rr
*answers
= NULL
;
800 n
= rfc1035AnswersUnpack(rbuf
,
805 printf("ERROR %d\n", rfc1035_errno
);
806 } else if (rid
!= sid
) {
807 printf("ERROR, ID mismatch (%#hx, %#hx)\n", sid
, rid
);
809 printf("%d answers\n", n
);
810 for (i
= 0; i
< n
; i
++) {
811 if (answers
[i
].type
== RFC1035_TYPE_A
) {
813 memcpy(&a
, answers
[i
].rdata
, 4);
814 printf("A\t%d\t%s\n", answers
[i
].ttl
, inet_ntoa(a
));
815 } else if (answers
[i
].type
== RFC1035_TYPE_PTR
) {
817 strncpy(ptr
, answers
[i
].rdata
, answers
[i
].rdlength
);
818 printf("PTR\t%d\t%s\n", answers
[i
].ttl
, ptr
);
820 fprintf(stderr
, "can't print answer type %d\n",
821 (int) answers
[i
].type
);