2 * Copyright (c) 2000-2004 Sendmail, Inc. and its suppliers.
5 * By using this file, you agree to the terms and conditions set
6 * forth in the LICENSE file which can be found at the top level of
7 * the sendmail distribution.
12 * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Högskolan
13 * (Royal Institute of Technology, Stockholm, Sweden).
14 * All rights reserved.
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
20 * 1. Redistributions of source code must retain the above copyright
21 * notice, this list of conditions and the following disclaimer.
23 * 2. Redistributions in binary form must reproduce the above copyright
24 * notice, this list of conditions and the following disclaimer in the
25 * documentation and/or other materials provided with the distribution.
27 * 3. Neither the name of the Institute nor the names of its contributors
28 * may be used to endorse or promote products derived from this software
29 * without specific prior written permission.
31 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
32 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
33 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
34 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
35 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
39 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
40 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47 # include "sm_resolve.h"
49 SM_RCSID("$Id: sm_resolve.c,v 8.35 2007/06/25 16:20:14 ca Exp $")
62 # endif /* NETINET6 */
73 static DNS_REPLY_T
*parse_dns_reply
__P((unsigned char *, int));
76 ** DNS_STRING_TO_TYPE -- convert resource record name into type
79 ** name -- name of resource record type
87 dns_string_to_type(name
)
90 struct stot
*p
= stot
;
92 for (p
= stot
; p
->st_name
!= NULL
; p
++)
93 if (sm_strcasecmp(name
, p
->st_name
) == 0)
99 ** DNS_TYPE_TO_STRING -- convert resource record type into name
102 ** type -- resource record type
105 ** name if succeeded.
110 dns_type_to_string(type
)
113 struct stot
*p
= stot
;
115 for (p
= stot
; p
->st_name
!= NULL
; p
++)
116 if (type
== p
->st_type
)
122 ** DNS_FREE_DATA -- free all components of a DNS_REPLY_T
125 ** r -- pointer to DNS_REPLY_T
135 RESOURCE_RECORD_T
*rr
;
137 if (r
->dns_r_q
.dns_q_domain
!= NULL
)
138 sm_free(r
->dns_r_q
.dns_q_domain
);
139 for (rr
= r
->dns_r_head
; rr
!= NULL
; )
141 RESOURCE_RECORD_T
*tmp
= rr
;
143 if (rr
->rr_domain
!= NULL
)
144 sm_free(rr
->rr_domain
);
145 if (rr
->rr_u
.rr_data
!= NULL
)
146 sm_free(rr
->rr_u
.rr_data
);
154 ** PARSE_DNS_REPLY -- parse DNS reply data.
157 ** data -- pointer to dns data
158 ** len -- len of data
161 ** pointer to DNS_REPLY_T if succeeded.
166 parse_dns_reply(data
, len
)
174 char host
[MAXHOSTNAMELEN
];
176 RESOURCE_RECORD_T
**rr
;
178 r
= (DNS_REPLY_T
*) sm_malloc(sizeof(*r
));
181 memset(r
, 0, sizeof(*r
));
185 /* doesn't work on Crays? */
186 memcpy(&r
->dns_r_h
, p
, sizeof(r
->dns_r_h
));
187 p
+= sizeof(r
->dns_r_h
);
188 status
= dn_expand(data
, data
+ len
, p
, host
, sizeof(host
));
194 r
->dns_r_q
.dns_q_domain
= sm_strdup(host
);
195 if (r
->dns_r_q
.dns_q_domain
== NULL
)
201 ans_cnt
= ntohs((ushort
) r
->dns_r_h
.ancount
);
204 GETSHORT(r
->dns_r_q
.dns_q_type
, p
);
205 GETSHORT(r
->dns_r_q
.dns_q_class
, p
);
208 while (p
< data
+ len
&& ui
< ans_cnt
)
210 int type
, class, ttl
, size
, txtlen
;
212 status
= dn_expand(data
, data
+ len
, p
, host
, sizeof(host
));
224 if (p
+ size
> data
+ len
)
227 ** announced size of data exceeds length of
228 ** data paket: someone is cheating.
232 sm_syslog(LOG_WARNING
, NOQID
,
233 "ERROR: DNS RDLENGTH=%d > data len=%d",
234 size
, len
- (p
- data
));
238 *rr
= (RESOURCE_RECORD_T
*) sm_malloc(sizeof(**rr
));
244 memset(*rr
, 0, sizeof(**rr
));
245 (*rr
)->rr_domain
= sm_strdup(host
);
246 if ((*rr
)->rr_domain
== NULL
)
251 (*rr
)->rr_type
= type
;
252 (*rr
)->rr_class
= class;
254 (*rr
)->rr_size
= size
;
260 status
= dn_expand(data
, data
+ len
, p
, host
,
267 (*rr
)->rr_u
.rr_txt
= sm_strdup(host
);
268 if ((*rr
)->rr_u
.rr_txt
== NULL
)
277 status
= dn_expand(data
, data
+ len
, p
+ 2, host
,
284 l
= strlen(host
) + 1;
285 (*rr
)->rr_u
.rr_mx
= (MX_RECORD_T
*)
286 sm_malloc(sizeof(*((*rr
)->rr_u
.rr_mx
)) + l
);
287 if ((*rr
)->rr_u
.rr_mx
== NULL
)
292 (*rr
)->rr_u
.rr_mx
->mx_r_preference
= (p
[0] << 8) | p
[1];
293 (void) sm_strlcpy((*rr
)->rr_u
.rr_mx
->mx_r_domain
,
298 status
= dn_expand(data
, data
+ len
, p
+ 6, host
,
305 l
= strlen(host
) + 1;
306 (*rr
)->rr_u
.rr_srv
= (SRV_RECORDT_T
*)
307 sm_malloc(sizeof(*((*rr
)->rr_u
.rr_srv
)) + l
);
308 if ((*rr
)->rr_u
.rr_srv
== NULL
)
313 (*rr
)->rr_u
.rr_srv
->srv_r_priority
= (p
[0] << 8) | p
[1];
314 (*rr
)->rr_u
.rr_srv
->srv_r_weight
= (p
[2] << 8) | p
[3];
315 (*rr
)->rr_u
.rr_srv
->srv_r_port
= (p
[4] << 8) | p
[5];
316 (void) sm_strlcpy((*rr
)->rr_u
.rr_srv
->srv_r_target
,
323 ** The TXT record contains the length as
324 ** leading byte, hence the value is restricted
325 ** to 255, which is less than the maximum value
326 ** of RDLENGTH (size). Nevertheless, txtlen
327 ** must be less than size because the latter
328 ** specifies the length of the entire TXT
336 sm_syslog(LOG_WARNING
, NOQID
,
337 "ERROR: DNS TXT record size=%d <= text len=%d",
342 (*rr
)->rr_u
.rr_txt
= (char *) sm_malloc(txtlen
+ 1);
343 if ((*rr
)->rr_u
.rr_txt
== NULL
)
348 (void) sm_strlcpy((*rr
)->rr_u
.rr_txt
, (char*) p
+ 1,
353 (*rr
)->rr_u
.rr_data
= (unsigned char*) sm_malloc(size
);
354 if ((*rr
)->rr_u
.rr_data
== NULL
)
359 (void) memcpy((*rr
)->rr_u
.rr_data
, p
, size
);
363 rr
= &(*rr
)->rr_next
;
370 ** DNS_LOOKUP_INT -- perform dns map lookup (internal helper routine)
373 ** domain -- name to lookup
374 ** rr_class -- resource record class
375 ** rr_type -- resource record type
376 ** retrans -- retransmission timeout
377 ** retry -- number of retries
380 ** result of lookup if succeeded.
385 dns_lookup_int(domain
, rr_class
, rr_type
, retrans
, retry
)
393 unsigned long old_options
= 0;
394 time_t save_retrans
= 0;
396 DNS_REPLY_T
*r
= NULL
;
397 unsigned char reply
[1024];
401 old_options
= _res
.options
;
402 _res
.options
|= RES_DEBUG
;
403 sm_dprintf("dns_lookup(%s, %d, %s)\n", domain
,
404 rr_class
, dns_type_to_string(rr_type
));
408 save_retrans
= _res
.retrans
;
409 _res
.retrans
= retrans
;
413 save_retry
= _res
.retry
;
418 len
= res_search(domain
, rr_class
, rr_type
, reply
, sizeof(reply
));
421 _res
.options
= old_options
;
422 sm_dprintf("dns_lookup(%s, %d, %s) --> %d\n",
423 domain
, rr_class
, dns_type_to_string(rr_type
), len
);
426 r
= parse_dns_reply(reply
, len
);
428 _res
.retrans
= save_retrans
;
430 _res
.retry
= save_retry
;
436 dns_lookup(domain
, type_name
, retrans
, retry
)
438 const char *type_name
;
444 type
= dns_string_to_type(type_name
);
448 sm_dprintf("dns_lookup: unknown resource type: `%s'\n",
452 return dns_lookup_int(domain
, C_IN
, type
, retrans
, retry
);
455 # endif /* NAMED_BIND */