8686 */
8787
8888int ares_mkquery (const char * name , int dnsclass , int type , unsigned short id ,
89- int rd , unsigned char * * buf , int * buflen )
89+ int rd , unsigned char * * bufp , int * buflenp )
9090{
91- int len ;
91+ size_t len ;
9292 unsigned char * q ;
9393 const char * p ;
94+ size_t buflen ;
95+ unsigned char * buf ;
9496
9597 /* Set our results early, in case we bail out early with an error. */
96- * buflen = 0 ;
97- * buf = NULL ;
98+ * buflenp = 0 ;
99+ * bufp = NULL ;
98100
99- /* Compute the length of the encoded name so we can check buflen.
100- * Start counting at 1 for the zero-length label at the end. */
101- len = 1 ;
102- for (p = name ; * p ; p ++ )
103- {
104- if (* p == '\\' && * (p + 1 ) != 0 )
105- p ++ ;
106- len ++ ;
107- }
108- /* If there are n periods in the name, there are n + 1 labels, and
109- * thus n + 1 length fields, unless the name is empty or ends with a
110- * period. So add 1 unless name is empty or ends with a period.
111- */
112- if (* name && * (p - 1 ) != '.' )
113- len ++ ;
114-
115- /* Immediately reject names that are longer than the maximum of 255
116- * bytes that's specified in RFC 1035 ("To simplify implementations,
117- * the total length of a domain name (i.e., label octets and label
118- * length octets) is restricted to 255 octets or less."). We aren't
119- * doing this just to be a stickler about RFCs. For names that are
120- * too long, 'dnscache' closes its TCP connection to us immediately
121- * (when using TCP) and ignores the request when using UDP, and
122- * BIND's named returns ServFail (TCP or UDP). Sending a request
123- * that we know will cause 'dnscache' to close the TCP connection is
124- * painful, since that makes any other outstanding requests on that
125- * connection fail. And sending a UDP request that we know
126- * 'dnscache' will ignore is bad because resources will be tied up
127- * until we time-out the request.
101+ /* Allocate a memory area for the maximum size this packet might need. +2
102+ * is for the length byte and zero termination if no dots or ecscaping is
103+ * used.
128104 */
129- if (len > MAXCDNAME )
130- return ARES_EBADNAME ;
131-
132- * buflen = len + HFIXEDSZ + QFIXEDSZ ;
133- * buf = malloc (* buflen );
134- if (!* buf )
135- return ARES_ENOMEM ;
105+ len = strlen (name ) + 2 + HFIXEDSZ + QFIXEDSZ ;
106+ buf = malloc (len );
107+ if (!buf )
108+ return ARES_ENOMEM ;
136109
137110 /* Set up the header. */
138- q = * buf ;
111+ q = buf ;
139112 memset (q , 0 , HFIXEDSZ );
140113 DNS_HEADER_SET_QID (q , id );
141114 DNS_HEADER_SET_OPCODE (q , QUERY );
@@ -155,8 +128,10 @@ int ares_mkquery(const char *name, int dnsclass, int type, unsigned short id,
155128 q += HFIXEDSZ ;
156129 while (* name )
157130 {
158- if (* name == '.' )
131+ if (* name == '.' ) {
132+ free (buf );
159133 return ARES_EBADNAME ;
134+ }
160135
161136 /* Count the number of bytes in this label. */
162137 len = 0 ;
@@ -166,8 +141,10 @@ int ares_mkquery(const char *name, int dnsclass, int type, unsigned short id,
166141 p ++ ;
167142 len ++ ;
168143 }
169- if (len > MAXLABEL )
144+ if (len > MAXLABEL ) {
145+ free (buf );
170146 return ARES_EBADNAME ;
147+ }
171148
172149 /* Encode the length and copy the data. */
173150 * q ++ = (unsigned char )len ;
@@ -191,5 +168,22 @@ int ares_mkquery(const char *name, int dnsclass, int type, unsigned short id,
191168 DNS_QUESTION_SET_TYPE (q , type );
192169 DNS_QUESTION_SET_CLASS (q , dnsclass );
193170
171+ q += QFIXEDSZ ;
172+
173+ buflen = (q - buf );
174+
175+ /* Reject names that are longer than the maximum of 255 bytes that's
176+ * specified in RFC 1035 ("To simplify implementations, the total length of
177+ * a domain name (i.e., label octets and label length octets) is restricted
178+ * to 255 octets or less."). */
179+ if (buflen > (MAXCDNAME + HFIXEDSZ + QFIXEDSZ )) {
180+ free (buf );
181+ return ARES_EBADNAME ;
182+ }
183+
184+ /* we know this fits in an int at this point */
185+ * buflenp = (int ) buflen ;
186+ * bufp = buf ;
187+
194188 return ARES_SUCCESS ;
195189}
0 commit comments