2 * Copyright (c) 2000-2004, 2010, 2015, 2020 Proofpoint, 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
48 # include <netinet/in_systm.h>
49 # include <netinet/ip.h>
51 # define _DEFINE_SMR_GLOBALS 1
52 # include "sm_resolve.h"
54 #include <arpa/inet.h>
56 SM_RCSID("$Id: sm_resolve.c,v 8.40 2013-11-22 20:51:56 ca Exp $")
85 { "DNSKEY", T_DNSKEY },
91 static DNS_REPLY_T *parse_dns_reply __P((unsigned char *, int, unsigned int));
92 # if DNSSEC_TEST && defined(T_TLSA)
93 static char *hex2bin __P((const char *, int));
97 ** DNS_STRING_TO_TYPE -- convert resource record name into type
100 ** name -- name of resource record type
103 ** type if succeeded.
108 dns_string_to_type(name)
111 struct stot *p = stot;
113 for (p = stot; p->st_name != NULL; p++)
114 if (sm_strcasecmp(name, p->st_name) == 0)
120 ** DNS_TYPE_TO_STRING -- convert resource record type into name
123 ** type -- resource record type
126 ** name if succeeded.
131 dns_type_to_string(type)
134 struct stot *p = stot;
136 for (p = stot; p->st_name != NULL; p++)
137 if (type == p->st_type)
143 ** DNS_FREE_DATA -- free all components of a DNS_REPLY_T
146 ** dr -- pointer to DNS_REPLY_T
156 RESOURCE_RECORD_T *rr;
160 if (dr->dns_r_q.dns_q_domain != NULL)
161 sm_free(dr->dns_r_q.dns_q_domain);
162 for (rr = dr->dns_r_head; rr != NULL; )
164 RESOURCE_RECORD_T *tmp = rr;
166 if (rr->rr_domain != NULL)
167 sm_free(rr->rr_domain);
168 if (rr->rr_u.rr_data != NULL)
169 sm_free(rr->rr_u.rr_data);
177 ** BIN2HEX -- convert binary TLSA RR to hex string
180 ** tlsa -- pointer to result (allocated here)
181 ** p -- binary data (TLSA RR)
182 ** size -- length of p
183 ** min_size -- minimum expected size
186 ** >0: length of string (*tlsa)
190 static int bin2hex __P((char **, unsigned char *, int, int));
193 bin2hex(tlsa, p, size, min_size)
202 if (txtlen <= size || size < min_size)
205 sm_syslog(LOG_WARNING, NOQID,
206 "ERROR: bin2hex: size %d wrong", size);
209 *tlsa = (char *) sm_malloc(txtlen);
213 sm_dprintf("len=%d, rr_data=NULL\n", txtlen);
216 snprintf(*tlsa, txtlen,
217 "%02X %02X %02X", p[0], p[1], p[2]);
220 /* why isn't there a print function like strlcat? */
221 for (i = 3; i < size && pos < txtlen; i++, pos += 3)
222 snprintf(*tlsa + pos, txtlen - pos, "%c%02X",
223 (i == 3) ? ' ' : ':', p[i]);
229 ** PARSE_DNS_REPLY -- parse DNS reply data.
232 ** data -- pointer to dns data
233 ** len -- len of data
234 ** flags -- flags (RR_*)
237 ** pointer to DNS_REPLY_T if succeeded.
241 ** use dns_free_data() to free() the result when no longer needed.
245 parse_dns_reply(data, len, flags)
251 unsigned short ans_cnt, ui;
254 char host[MAXHOSTNAMELEN];
256 RESOURCE_RECORD_T **rr;
262 fp = fopen("dns.buffer", "w");
265 fwrite(data, 1, len, fp);
270 sm_dprintf("parse_dns_reply: fp=%p, e=%d\n",
274 dr = (DNS_REPLY_T *) sm_malloc(sizeof(*dr));
277 memset(dr, 0, sizeof(*dr));
281 /* doesn't work on Crays? */
282 memcpy(&dr->dns_r_h, p, sizeof(dr->dns_r_h));
283 p += sizeof(dr->dns_r_h);
284 status = dn_expand(data, data + len, p, host, sizeof(host));
287 dr->dns_r_q.dns_q_domain = sm_strdup(host);
288 if (dr->dns_r_q.dns_q_domain == NULL)
291 ans_cnt = ntohs((unsigned short) dr->dns_r_h.ancount);
293 sm_dprintf("parse_dns_reply: ac=%d, ad=%d\n", ans_cnt,
297 GETSHORT(dr->dns_r_q.dns_q_type, p);
298 GETSHORT(dr->dns_r_q.dns_q_class, p);
299 rr = &dr->dns_r_head;
301 while (p < data + len && ui < ans_cnt)
303 int type, class, ttl, size, txtlen;
305 status = dn_expand(data, data + len, p, host, sizeof(host));
314 if (p + size > data + len)
317 ** announced size of data exceeds length of
318 ** data paket: someone is cheating.
322 sm_syslog(LOG_WARNING, NOQID,
323 "ERROR: DNS RDLENGTH=%d > data len=%d",
324 size, len - (int)(p - data));
327 *rr = (RESOURCE_RECORD_T *) sm_malloc(sizeof(**rr));
330 memset(*rr, 0, sizeof(**rr));
331 (*rr)->rr_domain = sm_strdup(host);
332 if ((*rr)->rr_domain == NULL)
334 (*rr)->rr_type = type;
335 (*rr)->rr_class = class;
337 (*rr)->rr_size = size;
343 status = dn_expand(data, data + len, p, host,
348 sm_dprintf("parse_dns_reply: type=%s, host=%s\n",
349 dns_type_to_string(type), host);
350 (*rr)->rr_u.rr_txt = sm_strdup(host);
351 if ((*rr)->rr_u.rr_txt == NULL)
357 status = dn_expand(data, data + len, p + 2, host,
361 l = strlen(host) + 1;
362 (*rr)->rr_u.rr_mx = (MX_RECORD_T *)
363 sm_malloc(sizeof(*((*rr)->rr_u.rr_mx)) + l);
364 if ((*rr)->rr_u.rr_mx == NULL)
366 (*rr)->rr_u.rr_mx->mx_r_preference = (p[0] << 8) | p[1];
367 (void) sm_strlcpy((*rr)->rr_u.rr_mx->mx_r_domain,
370 sm_dprintf("mx=%s, pref=%d\n", host,
371 (*rr)->rr_u.rr_mx->mx_r_preference);
375 status = dn_expand(data, data + len, p + 6, host,
379 l = strlen(host) + 1;
380 (*rr)->rr_u.rr_srv = (SRV_RECORDT_T*)
381 sm_malloc(sizeof(*((*rr)->rr_u.rr_srv)) + l);
382 if ((*rr)->rr_u.rr_srv == NULL)
384 (*rr)->rr_u.rr_srv->srv_r_priority = (p[0] << 8) | p[1];
385 (*rr)->rr_u.rr_srv->srv_r_weight = (p[2] << 8) | p[3];
386 (*rr)->rr_u.rr_srv->srv_r_port = (p[4] << 8) | p[5];
387 (void) sm_strlcpy((*rr)->rr_u.rr_srv->srv_r_target,
394 ** The TXT record contains the length as
395 ** leading byte, hence the value is restricted
396 ** to 255, which is less than the maximum value
397 ** of RDLENGTH (size). Nevertheless, txtlen
398 ** must be less than size because the latter
399 ** specifies the length of the entire TXT
407 sm_syslog(LOG_WARNING, NOQID,
408 "ERROR: DNS TXT record size=%d <= text len=%d",
412 (*rr)->rr_u.rr_txt = (char *) sm_malloc(txtlen + 1);
413 if ((*rr)->rr_u.rr_txt == NULL)
415 (void) sm_strlcpy((*rr)->rr_u.rr_txt, (char*) p + 1,
422 sm_dprintf("parse_dns_reply: TLSA, size=%d, flags=%X\n",
424 if ((flags & RR_AS_TEXT) != 0)
426 txtlen = bin2hex((char **)&((*rr)->rr_u.rr_data),
433 /* return "raw" data for caller to use as it pleases */
437 (*rr)->rr_u.rr_data = (unsigned char*) sm_malloc(size);
438 if ((*rr)->rr_u.rr_data == NULL)
440 (void) memcpy((*rr)->rr_u.rr_data, p, size);
441 if (tTd(8, 61) && type == T_A)
445 (void) memcpy((void *)&addr.sin.sin_addr.s_addr, p, size);
446 sm_dprintf("parse_dns_reply: IPv4=%s\n",
447 inet_ntoa(addr.sin.sin_addr));
452 rr = &(*rr)->rr_next;
464 #include <arpa/nameser.h>
466 static int gen_dns_reply __P((unsigned char *, int, unsigned char *,
467 const char *, int, const char *, int, int, int, int,
468 const char *, int, int, int));
469 static int dnscrtrr __P((const char *, const char *, int, char *, int,
470 unsigned int, int *, int *, unsigned char *, int, unsigned char *));
473 ** HERRNO2TXT -- return error text for h_errno
479 ** DNS error text if available
493 return "HOST_NOT_FOUND";
497 return "NO_RECOVERY";
501 return "bogus h_errno";
505 ** GEN_DNS_REPLY -- generate DNS reply data.
508 ** buf -- buffer to which DNS data is written
509 ** buflen -- length of buffer
510 ** bufpos -- position in buffer where DNS RRs are appended
511 ** query -- name of query
512 ** qtype -- resource record type of query
513 ** domain -- name of domain which has been "found"
514 ** class -- resource record class
515 ** type -- resource record type
517 ** size -- size of data
519 ** txtlen -- length of text
520 ** pref -- MX preference
524 ** >0 length of buffer that has been used.
529 gen_dns_reply(buf, buflen, bufpos, query, qtype, domain, class, type, ttl, size, data, txtlen, pref, ad)
532 unsigned char *bufpos;
545 unsigned short ans_cnt;
547 unsigned char *cp, *ep;
549 static unsigned char *dnptrs[20], **dpp, **lastdnptr;
551 SM_REQUIRE(NULL != buf);
552 SM_REQUIRE(buflen >= HFIXEDSZ);
553 SM_REQUIRE(query != NULL);
562 sm_dprintf("gen_dns_reply: query=%s, domain=%s, type=%s, size=%d, ad=%d\n",
563 query, domain, dns_type_to_string(type), size, ad);
567 lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0];
569 memset(buf, 0, HFIXEDSZ);
570 hp->id = 0xdead; /* HACK */
573 hp->rd = 0; /* recursion desired? */
574 hp->rcode = 0; /* !!! */
575 /* hp->aa = ?; * !!! */
576 /* hp->tc = ?; * !!! */
577 /* hp->ra = ?; * !!! */
578 hp->qdcount = htons(1);
581 n = dn_comp(query, cp, ep - cp - QFIXEDSZ, dnptrs, lastdnptr);
590 if (ep - cp < QFIXEDSZ)
592 n = dn_comp(domain, cp, ep - cp - QFIXEDSZ, dnptrs, lastdnptr);
600 ans_cnt = ntohs((unsigned short) hp->ancount);
602 hp->ancount = htons((unsigned short) ans_cnt);
607 n = dn_comp(data, cp + 4, ep - cp - QFIXEDSZ, dnptrs, lastdnptr);
618 PUTSHORT(txtlen, cp);
619 (void) sm_strlcpy((char *)cp, data, txtlen + 1);
624 n = dn_comp(data, cp + 2, ep - cp - QFIXEDSZ, dnptrs, lastdnptr);
636 tlsa = hex2bin(data, size);
641 (void) memcpy(cp, tlsa, n);
649 (void) memcpy(cp, data, size);
658 ** SETHERRNOFROMSTRING -- set h_errno based on text
661 ** str -- string which might contain h_errno text
662 ** prc -- pointer to rcode (EX_*)
670 setherrnofromstring(str, prc)
675 if (str == NULL || *str == '\0')
677 if (strstr(str, "herrno:") == NULL)
681 if (strstr(str, "host_not_found"))
682 SM_SET_H_ERRNO(HOST_NOT_FOUND);
683 else if (strstr(str, "try_again"))
685 SM_SET_H_ERRNO(TRY_AGAIN);
689 else if (strstr(str, "no_recovery"))
690 SM_SET_H_ERRNO(NO_RECOVERY);
691 else if (strstr(str, "no_data"))
692 SM_SET_H_ERRNO(NO_DATA);
694 SM_SET_H_ERRNO(NETDB_INTERNAL);
699 ** GETTTLFROMSTRING -- extract ttl from a string
702 ** str -- string which might contain ttl
710 getttlfromstring(str)
713 if (str == NULL || *str == '\0')
715 #define TTL_PRE "ttl="
716 if (strstr(str, TTL_PRE) == NULL)
718 return strtoul(str + strlen(TTL_PRE), NULL, 10);
722 ** NSPORTIP -- parse port@IPv4 and set NS accordingly
732 ** sets NS for DNS lookups
736 ** There should be a generic function for this...
737 ** milter_open(), socket_map_open(), others?
749 if (p == NULL || *p == '\0')
753 while (SM_ISSPACE(*p))
761 if (isascii(*p) && isdigit(*p))
769 r = inet_pton(AF_INET, p, &nsip);
772 if ((_res.options & RES_INIT) == 0)
774 dns_setns(&nsip, port);
778 return r > 0 ? 0 : -1;
782 ** DNS_SETNS -- set one NS in resolver context
785 ** ns -- (IPv4 address of) nameserver
786 ** port -- nameserver port
797 _res.nsaddr_list[0].sin_family = AF_INET;
798 _res.nsaddr_list[0].sin_addr = *ns;
800 _res.nsaddr_list[0].sin_port = htons(port);
803 sm_dprintf("dns_setns(%s,%u)\n", inet_ntoa(*ns), port);
808 ** HEX2BIN -- convert hex string to binary TLSA RR
811 ** p -- hex representation of TLSA RR
812 ** size -- length of p
815 ** pointer to binary TLSA RR
828 if (txtlen * 2 == size)
831 sm_syslog(LOG_WARNING, NOQID,
832 "ERROR: hex2bin: size %d wrong", size);
835 tlsa = sm_malloc(txtlen + 1);
839 sm_dprintf("len=%d, tlsa=NULL\n", txtlen);
843 #define CHAR2INT(c) (((c) <= '9') ? ((c) - '0') : (toupper(c) - 'A' + 10))
844 for (i = 0, pos = 0; i + 1 < size && pos < txtlen; i += 2, pos++)
845 tlsa[pos] = CHAR2INT(p[i]) * 16 + CHAR2INT(p[i+1]);
876 ** DNSCRTRR -- create DNS RR
879 ** domain -- original query domain
880 ** query -- name of query
881 ** qtype -- resource record type of query
882 ** value -- (list of) data to set
883 ** rr_type -- resource record type
884 ** flags -- flags how to handle various lookups
885 ** herr -- (pointer to) h_errno (output if non-NULL)
886 ** adp -- (pointer to) ad flag
887 ** answer -- buffer for RRs
888 ** anslen -- size of answer
889 ** anspos -- current position in answer
892 ** >0: length of data in answer
893 ** <0: error, check *herr
897 dnscrtrr(domain, query, qtype, value, rr_type, flags, herr, adp, answer, anslen, anspos)
906 unsigned char *answer;
908 unsigned char *anspos;
913 char data[IN6ADDRSZ];
917 if (NULL == value || '\0' == *value)
919 SM_REQUIRE(adp != NULL);
920 (void) sm_strlcpy(rhs, value, sizeof(rhs));
922 if (setherrnofromstring(p, NULL) != 0)
927 sm_dprintf("dnscrtrr rhs=%s h_errno=%d (%s)\n",
928 p, h_errno, herrno2txt(h_errno));
934 for (token = p; token != NULL && *token != '\0'; token = p)
937 while (p != NULL && *p != '\0' && !SM_ISSPACE(*p))
941 sm_dprintf("dnscrtrr: token=%s\n", token);
942 if (strcmp(token, "ad") == 0)
946 adflag = (_res.options & RES_USE_DNSSEC) != 0;
948 /* maybe print this only for the final RR? */
950 sm_dprintf("dnscrtrr: ad=1, adp=%d, adflag=%d\n",
952 if (*adp != 0 && adflag)
959 if (ttl == 0 && (ttl = getttlfromstring(token)) > 0)
962 sm_dprintf("dnscrtrr: ttl=%d\n", ttl);
968 addr.sin.sin_addr.s_addr = inet_addr(token);
969 (void) memmove(data, (void *)&addr.sin.sin_addr.s_addr,
971 rlen = gen_dns_reply(answer, anslen, anspos,
972 query, qtype, domain, C_IN, rr_type, ttl,
973 INADDRSZ, data, 0, 0, ad);
977 if (rr_type == T_AAAA)
979 anynet_pton(AF_INET6, token, &addr.sin6.sin6_addr);
980 memmove(data, (void *)&addr.sin6.sin6_addr, IN6ADDRSZ);
981 rlen = gen_dns_reply(answer, anslen, anspos,
982 query, qtype, domain, C_IN, rr_type, ttl,
983 IN6ADDRSZ, data, 0, 0, ad);
985 # endif /* NETINET6 */
992 pref = (int) strtoul(token, &endptr, 10);
993 if (endptr == NULL || *endptr != ':')
996 rlen = gen_dns_reply(answer, anslen, anspos,
997 query, qtype, domain, C_IN, rr_type, ttl,
998 strlen(token) + 1, token, 0, pref, ad);
1000 sm_dprintf("dnscrtrr: mx=%s, pref=%d\n",
1005 if (rr_type == T_TLSA)
1006 rlen = gen_dns_reply(answer, anslen, anspos,
1007 query, qtype, domain, C_IN, rr_type, ttl,
1008 strlen(token) + 1, token, 0, 0, ad);
1011 if (rr_type == T_CNAME)
1012 rlen = gen_dns_reply(answer, anslen, anspos,
1013 query, qtype, domain, C_IN, rr_type, ttl,
1014 strlen(token), token, 0, 0, ad);
1018 anspos = answer + rlen;
1027 if (herr != NULL && 0 == *herr)
1028 *herr = NO_RECOVERY;
1033 ** TSTDNS_SEARCH -- replacement for res_search() for testing
1036 ** domain -- query domain
1038 ** type -- resource record type
1039 ** answer -- buffer for RRs
1040 ** anslen -- size of answer
1043 ** >0: length of data in answer
1044 ** <0: error, check h_errno
1048 tstdns_search(domain, class, type, answer, anslen)
1052 unsigned char *answer;
1055 int rlen, ad, maprcode, cnt, flags, herr;
1062 char key[MAXNAME + 16];
1064 unsigned char *anspos;
1070 if (NULL == domain || '\0' == *domain)
1072 tag = rr_type2tag(type);
1081 map = stab("access", ST_MAP, ST_FIND);
1084 sm_dprintf("access map not found\n");
1087 if (!bitset(MF_OPEN, map->s_map.map_mflags) &&
1088 !openmap(&(map->s_map)))
1090 sm_dprintf("access map open failed\n");
1095 ** Look up tag:domain, if not found and domain does not end with a dot
1096 ** (and the proper debug level is selected), also try with trailing dot.
1099 #define SM_LOOKUP2(tag) \
1103 len = strlen(domain); \
1106 snprintf(key, sizeof(key), "%s:%s", tag, domain); \
1107 p = (*map->s_map.map_class->map_lookup)(&map->s_map, key, av, \
1111 if (!tTd(8, 112) || (len > 0 && '.' == domain[len - 1])) \
1113 snprintf(key, sizeof(key), "%s:%s.", tag, domain); \
1114 p = (*map->s_map.map_class->map_lookup)(&map->s_map, key, av, \
1119 found_cname = false;
1124 /* Should this try with/without trailing dot? */
1128 sm_dprintf("access map lookup key=%s, value=%s\n", key,
1132 if (NULL == p && (flags & RR_NO_CNAME) == 0)
1134 sm_dprintf("access map lookup failed key=%s, try cname\n",
1136 SM_LOOKUP2("cname");
1139 sm_dprintf("cname lookup key=%s, value=%s, ad=%d\n",
1141 rlen = dnscrtrr(domain, query, type, p, T_CNAME,
1142 flags, &herr, &ad, answer,
1147 anspos = answer + rlen;
1154 (void) sm_strlcpy(rhs, p, sizeof(rhs));
1157 /* skip (leading) ad/ttl: look for last ' ' */
1158 if ((last = strrchr(p, ' ')) != NULL && last[1] != '\0')
1167 char *tags[] = { "ipv4", "mx", "tlsa",
1174 for (t = 0; tags[t] != NULL; t++)
1176 if (strcmp(tag, tags[t]) == 0)
1178 SM_LOOKUP2(tags[t]);
1181 sm_dprintf("access map lookup failed key=%s:%s, but found key=%s\n",
1187 sm_dprintf("access map lookup failed key=%s\n", key);
1188 herr = HOST_NOT_FOUND;
1191 if (found_cname && (flags & RR_ONLY_CNAME) != 0)
1193 rlen = dnscrtrr(domain, query, type, p, type, flags, &herr, &ad,
1194 answer, anslen, anspos);
1202 SM_SET_H_ERRNO(herr);
1203 sm_dprintf("rlen=%d, herr=%d\n", rlen, herr);
1208 ** TSTDNS_QUERYDOMAIN -- replacement for res_querydomain() for testing
1211 ** name -- query name
1212 ** domain -- query domain
1214 ** type -- resource record type
1215 ** answer -- buffer for RRs
1216 ** anslen -- size of answer
1219 ** >0: length of data in answer
1220 ** <0: error, check h_errno
1224 tstdns_querydomain(name, domain, class, type, answer, anslen)
1229 unsigned char *answer;
1232 char query[MAXNAME];
1237 if (NULL == domain || '\0' == *domain)
1238 return tstdns_search(name, class, type, answer, anslen);
1240 len = snprintf(query, sizeof(query), "%s.%s", name, domain);
1241 if (len >= (int)sizeof(query))
1243 return tstdns_search(query, class, type, answer, anslen);
1246 SM_SET_H_ERRNO(NO_RECOVERY);
1250 # endif /* DNSSEC_TEST */
1253 ** DNS_LOOKUP_INT -- perform DNS lookup
1256 ** domain -- name to lookup
1257 ** rr_class -- resource record class
1258 ** rr_type -- resource record type
1259 ** retrans -- retransmission timeout
1260 ** retry -- number of retries
1261 ** options -- DNS resolver options
1262 ** flags -- currently only passed to parse_dns_reply()
1263 ** err -- (pointer to) errno (output if non-NULL)
1264 ** herr -- (pointer to) h_errno (output if non-NULL)
1267 ** result of lookup if succeeded.
1272 dns_lookup_int(domain, rr_class, rr_type, retrans, retry, options, flags, err, herr)
1278 unsigned int options;
1284 unsigned long old_options = 0;
1285 time_t save_retrans = 0;
1287 DNS_REPLY_T *dr = NULL;
1289 unsigned char *reply;
1290 int (*resfunc) __P((const char *, int, int, u_char *, int));
1292 # define SMRBSIZE ((int) sizeof(reply_buf))
1293 # ifndef IP_MAXPACKET
1294 # define IP_MAXPACKET 65535
1297 resfunc = res_search;
1300 resfunc = tstdns_search;
1303 old_options = _res.options;
1304 _res.options |= options;
1311 _res.options |= RES_DEBUG;
1312 sm_dprintf("dns_lookup_int(%s, %d, %s, %x)\n", domain,
1313 rr_class, dns_type_to_string(rr_type), options);
1317 sm_dprintf("NS=%s, port=%d\n",
1318 inet_ntoa(_res.nsaddr_list[0].sin_addr),
1319 ntohs(_res.nsaddr_list[0].sin_port));
1323 save_retrans = _res.retrans;
1324 _res.retrans = retrans;
1328 save_retry = _res.retry;
1333 reply = (unsigned char *)&reply_buf;
1334 len = (*resfunc)(domain, rr_class, rr_type, reply, SMRBSIZE);
1335 if (len >= SMRBSIZE)
1337 if (len >= IP_MAXPACKET)
1340 sm_dprintf("dns_lookup: domain=%s, length=%d, default_size=%d, max=%d, status=response too long\n",
1341 domain, len, SMRBSIZE, IP_MAXPACKET);
1346 sm_dprintf("dns_lookup: domain=%s, length=%d, default_size=%d, max=%d, status=response longer than default size, resizing\n",
1347 domain, len, SMRBSIZE, IP_MAXPACKET);
1348 reply = (unsigned char *)sm_malloc(IP_MAXPACKET);
1350 SM_SET_H_ERRNO(TRY_AGAIN);
1354 len = (*resfunc)(domain, rr_class, rr_type,
1355 reply, IP_MAXPACKET);
1359 _res.options = old_options;
1368 sm_dprintf("dns_lookup_int(%s, %d, %s, %x)=%d, errno=%d, h_errno=%d"
1373 domain, rr_class, dns_type_to_string(rr_type),
1374 options, len, errno, h_errno
1376 , herrno2txt(h_errno)
1381 else if (tTd(8, 16))
1383 sm_dprintf("dns_lookup_int(%s, %d, %s, %x)=%d\n",
1384 domain, rr_class, dns_type_to_string(rr_type),
1387 if (len >= 0 && len < IP_MAXPACKET && reply != NULL)
1388 dr = parse_dns_reply(reply, len, flags);
1389 if (reply != (unsigned char *)&reply_buf && reply != NULL)
1395 _res.retrans = save_retrans;
1397 _res.retry = save_retry;
1402 ** DNS_LOOKUP_MAP -- perform DNS map lookup
1405 ** domain -- name to lookup
1406 ** rr_class -- resource record class
1407 ** rr_type -- resource record type
1408 ** retrans -- retransmission timeout
1409 ** retry -- number of retries
1410 ** options -- DNS resolver options
1413 ** result of lookup if succeeded.
1418 dns_lookup_map(domain, rr_class, rr_type, retrans, retry, options)
1424 unsigned int options;
1426 return dns_lookup_int(domain, rr_class, rr_type, retrans, retry,
1427 options, RR_AS_TEXT, NULL, NULL);
1432 ** DNS2HE -- convert DNS_REPLY_T list to hostent struct
1435 ** dr -- DNS lookup result
1436 ** family -- address family
1439 ** hostent struct if succeeded.
1443 ** this returns a pointer to a static struct!
1451 # define SM_MAX_ADDRS 256
1452 static struct hostent he;
1453 static char *he_aliases[1];
1454 static char *he_addr_list[SM_MAX_ADDRS];
1456 # define IN_ADDRSZ IN6ADDRSZ
1458 # define IN_ADDRSZ INADDRSZ
1460 static char he_addrs[SM_MAX_ADDRS * IN_ADDRSZ];
1461 static char he_name[MAXNAME];
1462 static bool he_init = false;
1467 # if NETINET6 && DNSSEC_TEST
1468 struct in6_addr ia6;
1469 char buf6[INET6_ADDRSTRLEN];
1471 RESOURCE_RECORD_T *rr;
1479 he_aliases[0] = NULL;
1480 he.h_aliases = he_aliases;
1481 he.h_addr_list = he_addr_list;
1482 he.h_name = he_name;
1485 h->h_addrtype = family;
1488 sm_dprintf("dns2he: ad=%d\n", dr->dns_r_h.ad);
1490 /* do we want/need to copy the name? */
1491 rr = dr->dns_r_head;
1492 if (rr != NULL && rr->rr_domain != NULL)
1493 sm_strlcpy(h->h_name, rr->rr_domain, sizeof(he_name));
1495 h->h_name[0] = '\0';
1499 if (family == AF_INET)
1503 if (family == AF_INET6)
1510 for (rr = dr->dns_r_head, i = 0; rr != NULL && i < SM_MAX_ADDRS - 1;
1513 h->h_addr_list[i] = he_addrs + i * h->h_length;
1514 switch (rr->rr_type)
1518 if (family != AF_INET)
1520 memmove(h->h_addr_list[i], rr->rr_u.rr_a, INADDRSZ);
1523 # endif /* NETINET */
1526 if (family != AF_INET6)
1528 memmove(h->h_addr_list[i], rr->rr_u.rr_aaaa, IN6ADDRSZ);
1531 # endif /* NETINET6 */
1535 sm_dprintf("dns2he: cname: %s ttl=%d\n",
1536 rr->rr_u.rr_txt, rr->rr_ttl);
1542 sm_dprintf("dns2he: mx: %d %s ttl=%d\n",
1543 rr->rr_u.rr_mx->mx_r_preference,
1544 rr->rr_u.rr_mx->mx_r_domain,
1549 # if defined(T_TLSA)
1557 len = bin2hex(&tlsa, rr->rr_u.rr_data,
1560 sm_dprintf("dns2he: tlsa: %s ttl=%d\n",
1565 # endif /* T_TLSA */
1569 /* complain if list is too long! */
1570 SM_ASSERT(i < SM_MAX_ADDRS);
1571 h->h_addr_list[i] = NULL;
1576 for (i = 0; h->h_addr_list[i] != NULL && i < SM_MAX_ADDRS; i++)
1582 if (h->h_addrtype == AF_INET6)
1584 memmove(&ia6, h->h_addr_list[i], IN6ADDRSZ);
1585 addr = anynet_ntop(&ia6, buf6, sizeof(buf6));
1588 # endif /* NETINET6 */
1589 /* "else" in #if code above */
1591 memmove(&ia, h->h_addr_list[i], INADDRSZ);
1592 addr = (char *) inet_ntoa(ia);
1595 sm_dprintf("dns2he: addr[%d]: %s\n", i, addr);
1598 # endif /* DNSSEC_TEST */
1602 # endif /* NAMED_BIND */
1603 #endif /* DNSMAP || DANE */