3 * - parsing assistance functions (mainly for domains inside datagrams)
6 * This file is part of adns, which is
7 * Copyright (C) 1997-2000,2003,2006 Ian Jackson
8 * Copyright (C) 1999-2000,2003,2006 Tony Finch
9 * Copyright (C) 1991 Massachusetts Institute of Technology
10 * (See the file INSTALL for full details.)
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 3, or (at your option)
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software Foundation.
28 int vbuf__append_quoted1035(vbuf
*vb
, const byte
*buf
, int len
) {
34 for (i
=0; i
<len
; i
++) {
36 if (ch
<= ' ' || ch
>= 127) {
37 sprintf(qbuf
,"\\%03o",ch
);
39 } else if (!ctype_domainunquoted(ch
)) {
40 sprintf(qbuf
,"\\%c",ch
);
44 if (!adns__vbuf_append(vb
,buf
,i
) ||
45 !adns__vbuf_append(vb
,qbuf
,strlen(qbuf
)))
54 void adns__findlabel_start(findlabel_state
*fls
, adns_state ads
,
55 int serv
, adns_query qu
,
56 const byte
*dgram
, int dglen
, int max
,
57 int dmbegin
, int *dmend_rlater
) {
66 fls
->dmend_r
= dmend_rlater
;
69 adns_status
adns__findlabel_next(findlabel_state
*fls
,
70 int *lablen_r
, int *labstart_r
) {
76 if (fls
->cbyte
>= fls
->dglen
) goto x_truncated
;
77 if (fls
->cbyte
>= fls
->max
) goto x_badresponse
;
78 GET_B(fls
->cbyte
,lablen
);
79 if (!(lablen
& 0x0c0)) break;
80 if ((lablen
& 0x0c0) != 0x0c0) return adns_s_unknownformat
;
81 if (fls
->cbyte
>= fls
->dglen
) goto x_truncated
;
82 if (fls
->cbyte
>= fls
->max
) goto x_badresponse
;
83 GET_B(fls
->cbyte
,jumpto
);
84 jumpto
|= (lablen
&0x3f)<<8;
85 if (fls
->dmend_r
) *(fls
->dmend_r
)= fls
->cbyte
;
87 fls
->dmend_r
= 0; fls
->max
= fls
->dglen
+1;
89 if (labstart_r
) *labstart_r
= fls
->cbyte
;
91 if (fls
->namelen
) fls
->namelen
++;
92 fls
->namelen
+= lablen
;
93 if (fls
->namelen
> DNS_MAXDOMAIN
) return adns_s_answerdomaintoolong
;
95 if (fls
->cbyte
> fls
->dglen
) goto x_truncated
;
96 if (fls
->cbyte
> fls
->max
) goto x_badresponse
;
98 if (fls
->dmend_r
) *(fls
->dmend_r
)= fls
->cbyte
;
108 adns__diag(fls
->ads
,fls
->serv
,fls
->qu
,
109 "label in domain runs beyond end of domain");
110 return adns_s_invalidresponse
;
113 adns_status
adns__parse_domain(adns_state ads
, int serv
, adns_query qu
,
114 vbuf
*vb
, parsedomain_flags flags
,
115 const byte
*dgram
, int dglen
, int *cbyte_io
,
119 adns__findlabel_start(&fls
,ads
, serv
,qu
, dgram
,dglen
,max
,
122 return adns__parse_domain_more(&fls
,ads
,qu
, vb
,flags
,dgram
);
125 adns_status
adns__parse_domain_more(findlabel_state
*fls
, adns_state ads
,
126 adns_query qu
, vbuf
*vb
,
127 parsedomain_flags flags
,
129 int lablen
, labstart
, i
, ch
, first
;
134 st
= adns__findlabel_next(fls
,&lablen
,&labstart
);
136 if (lablen
<0) { vb
->used
=0; return adns_s_ok
; }
141 if (!adns__vbuf_append(vb
,".",1)) return adns_s_nomemory
;
143 if (flags
& pdf_quoteok
) {
144 if (!vbuf__append_quoted1035(vb
,dgram
+labstart
,lablen
))
145 return adns_s_nomemory
;
148 if (!ctype_alpha(ch
) && !ctype_digit(ch
))
149 return adns_s_answerdomaininvalid
;
150 for (i
= labstart
+1; i
<labstart
+lablen
; i
++) {
152 if (ch
!= '-' && !ctype_alpha(ch
) && !ctype_digit(ch
))
153 return adns_s_answerdomaininvalid
;
155 if (!adns__vbuf_append(vb
,dgram
+labstart
,lablen
))
156 return adns_s_nomemory
;
159 if (!adns__vbuf_append(vb
,"",1)) return adns_s_nomemory
;
163 bool adns__labels_equal(const byte
*a
, int al
, const byte
*b
, int bl
) {
164 if (al
!= bl
) return 0;
166 int ac
= ctype_toupper(*a
++);
167 int bc
= ctype_toupper(*b
++);
168 if (ac
!= bc
) return 0;
173 adns_status
adns__findrr_anychk(adns_query qu
, int serv
,
174 const byte
*dgram
, int dglen
, int *cbyte_io
,
175 int *type_r
, int *class_r
,
176 unsigned long *ttl_r
,
177 int *rdlen_r
, int *rdstart_r
,
178 const byte
*eo_dgram
, int eo_dglen
,
179 int eo_cbyte
, int *eo_matched_r
) {
180 findlabel_state fls
, eo_fls_buf
;
181 findlabel_state
*eo_fls
; /* 0 iff we know it's not matching eo_... */
186 int lablen
, labstart
;
187 int eo_lablen
, eo_labstart
;
192 adns__findlabel_start(&fls
,qu
->ads
, serv
,qu
, dgram
,dglen
,dglen
,cbyte
,&cbyte
);
195 adns__findlabel_start(eo_fls
,qu
->ads
, -1,0,
196 eo_dgram
,eo_dglen
,eo_dglen
,eo_cbyte
,0);
202 st
= adns__findlabel_next(&fls
,&lablen
,&labstart
);
204 if (lablen
<0) goto x_truncated
;
207 st
= adns__findlabel_next(eo_fls
,&eo_lablen
,&eo_labstart
);
208 assert(!st
); assert(eo_lablen
>=0);
209 if (!adns__labels_equal(dgram
+labstart
, lablen
,
210 eo_dgram
+eo_labstart
, eo_lablen
))
215 if (eo_matched_r
) *eo_matched_r
= !!eo_fls
;
217 if (cbyte
+10>dglen
) goto x_truncated
;
218 GET_W(cbyte
,tmp
); *type_r
= tmp
;
219 GET_W(cbyte
,tmp
); *class_r
= tmp
;
222 if (ttl
> MAXTTLBELIEVE
) ttl
= MAXTTLBELIEVE
;
225 GET_W(cbyte
,rdlen
); if (rdlen_r
) *rdlen_r
= rdlen
;
226 if (rdstart_r
) *rdstart_r
= cbyte
;
228 if (cbyte
>dglen
) goto x_truncated
;
237 adns_status
adns__findrr(adns_query qu
, int serv
,
238 const byte
*dgram
, int dglen
, int *cbyte_io
,
239 int *type_r
, int *class_r
, unsigned long *ttl_r
,
240 int *rdlen_r
, int *rdstart_r
,
241 int *ownermatchedquery_r
) {
242 if (!ownermatchedquery_r
) {
243 return adns__findrr_anychk(qu
,serv
,
244 dgram
,dglen
,cbyte_io
,
245 type_r
,class_r
,ttl_r
,rdlen_r
,rdstart_r
,
247 } else if (!qu
->cname_dgram
) {
248 return adns__findrr_anychk(qu
,serv
,
249 dgram
,dglen
,cbyte_io
,
250 type_r
,class_r
,ttl_r
,rdlen_r
,rdstart_r
,
251 qu
->query_dgram
,qu
->query_dglen
,DNS_HDRSIZE
,
252 ownermatchedquery_r
);
254 return adns__findrr_anychk(qu
,serv
,
255 dgram
,dglen
,cbyte_io
,
256 type_r
,class_r
,ttl_r
,rdlen_r
,rdstart_r
,
257 qu
->cname_dgram
,qu
->cname_dglen
,qu
->cname_begin
,
258 ownermatchedquery_r
);