source: trunk/third/sendmail/sendmail/sm_resolve.c @ 19204

Revision 19204, 9.8 KB checked in by zacheiss, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r19203, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * Copyright (c) 2000-2003 Sendmail, Inc. and its suppliers.
3 *      All rights reserved.
4 *
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.
8 *
9 */
10
11/*
12 * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Högskolan
13 * (Royal Institute of Technology, Stockholm, Sweden).
14 * All rights reserved.
15 *
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
19 *
20 * 1. Redistributions of source code must retain the above copyright
21 *    notice, this list of conditions and the following disclaimer.
22 *
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.
26 *
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.
30 *
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
41 * SUCH DAMAGE.
42 */
43
44#include <sendmail.h>
45#if DNSMAP
46# if NAMED_BIND
47#  include "sm_resolve.h"
48
49SM_RCSID("$Id: sm_resolve.c,v 1.1.1.1 2003-04-08 15:09:17 zacheiss Exp $")
50
51static struct stot
52{
53        const char      *st_name;
54        int             st_type;
55} stot[] =
56{
57#  if NETINET
58        {       "A",            T_A             },
59#  endif /* NETINET */
60#  if NETINET6
61        {       "AAAA",         T_AAAA          },
62#  endif /* NETINET6 */
63        {       "NS",           T_NS            },
64        {       "CNAME",        T_CNAME         },
65        {       "PTR",          T_PTR           },
66        {       "MX",           T_MX            },
67        {       "TXT",          T_TXT           },
68        {       "AFSDB",        T_AFSDB         },
69        {       "SRV",          T_SRV           },
70        {       NULL,           0               }
71};
72
73/*
74**  DNS_STRING_TO_TYPE -- convert resource record name into type
75**
76**      Parameters:
77**              name -- name of resource record type
78**
79**      Returns:
80**              type if succeeded.
81**              -1 otherwise.
82*/
83
84int
85dns_string_to_type(name)
86        const char *name;
87{
88        struct stot *p = stot;
89
90        for (p = stot; p->st_name != NULL; p++)
91                if (sm_strcasecmp(name, p->st_name) == 0)
92                        return p->st_type;
93        return -1;
94}
95
96/*
97**  DNS_TYPE_TO_STRING -- convert resource record type into name
98**
99**      Parameters:
100**              type -- resource record type
101**
102**      Returns:
103**              name if succeeded.
104**              NULL otherwise.
105*/
106
107const char *
108dns_type_to_string(type)
109        int type;
110{
111        struct stot *p = stot;
112
113        for (p = stot; p->st_name != NULL; p++)
114                if (type == p->st_type)
115                        return p->st_name;
116        return NULL;
117}
118
119/*
120**  DNS_FREE_DATA -- free all components of a DNS_REPLY_T
121**
122**      Parameters:
123**              r -- pointer to DNS_REPLY_T
124**
125**      Returns:
126**              none.
127*/
128
129void
130dns_free_data(r)
131        DNS_REPLY_T *r;
132{
133        RESOURCE_RECORD_T *rr;
134
135        if (r->dns_r_q.dns_q_domain != NULL)
136                sm_free(r->dns_r_q.dns_q_domain);
137        for (rr = r->dns_r_head; rr != NULL; )
138        {
139                RESOURCE_RECORD_T *tmp = rr;
140
141                if (rr->rr_domain != NULL)
142                        sm_free(rr->rr_domain);
143                if (rr->rr_u.rr_data != NULL)
144                        sm_free(rr->rr_u.rr_data);
145                rr = rr->rr_next;
146                sm_free(tmp);
147        }
148        sm_free(r);
149}
150
151/*
152**  PARSE_DNS_REPLY -- parse DNS reply data.
153**
154**      Parameters:
155**              data -- pointer to dns data
156**              len -- len of data
157**
158**      Returns:
159**              pointer to DNS_REPLY_T if succeeded.
160**              NULL otherwise.
161*/
162
163static DNS_REPLY_T *
164parse_dns_reply(data, len)
165        unsigned char *data;
166        int len;
167{
168        unsigned char *p;
169        int status;
170        size_t l;
171        char host[MAXHOSTNAMELEN];
172        DNS_REPLY_T *r;
173        RESOURCE_RECORD_T **rr;
174
175        r = (DNS_REPLY_T *) sm_malloc(sizeof(*r));
176        if (r == NULL)
177                return NULL;
178        memset(r, 0, sizeof(*r));
179
180        p = data;
181
182        /* doesn't work on Crays? */
183        memcpy(&r->dns_r_h, p, sizeof(r->dns_r_h));
184        p += sizeof(r->dns_r_h);
185        status = dn_expand(data, data + len, p, host, sizeof host);
186        if (status < 0)
187        {
188                dns_free_data(r);
189                return NULL;
190        }
191        r->dns_r_q.dns_q_domain = sm_strdup(host);
192        if (r->dns_r_q.dns_q_domain == NULL)
193        {
194                dns_free_data(r);
195                return NULL;
196        }
197        p += status;
198        GETSHORT(r->dns_r_q.dns_q_type, p);
199        GETSHORT(r->dns_r_q.dns_q_class, p);
200        rr = &r->dns_r_head;
201        while (p < data + len)
202        {
203                int type, class, ttl, size, txtlen;
204
205                status = dn_expand(data, data + len, p, host, sizeof host);
206                if (status < 0)
207                {
208                        dns_free_data(r);
209                        return NULL;
210                }
211                p += status;
212                GETSHORT(type, p);
213                GETSHORT(class, p);
214                GETLONG(ttl, p);
215                GETSHORT(size, p);
216                if (p + size > data + len)
217                {
218                        /*
219                        **  announced size of data exceeds length of
220                        **  data paket: someone is cheating.
221                        */
222
223                        if (LogLevel > 5)
224                                sm_syslog(LOG_WARNING, NOQID,
225                                          "ERROR: DNS RDLENGTH=%d > data len=%d",
226                                          size, len - (p - data));
227                        dns_free_data(r);
228                        return NULL;
229                }
230                *rr = (RESOURCE_RECORD_T *) sm_malloc(sizeof(**rr));
231                if (*rr == NULL)
232                {
233                        dns_free_data(r);
234                        return NULL;
235                }
236                memset(*rr, 0, sizeof(**rr));
237                (*rr)->rr_domain = sm_strdup(host);
238                if ((*rr)->rr_domain == NULL)
239                {
240                        dns_free_data(r);
241                        return NULL;
242                }
243                (*rr)->rr_type = type;
244                (*rr)->rr_class = class;
245                (*rr)->rr_ttl = ttl;
246                (*rr)->rr_size = size;
247                switch (type)
248                {
249                  case T_NS:
250                  case T_CNAME:
251                  case T_PTR:
252                        status = dn_expand(data, data + len, p, host,
253                                           sizeof host);
254                        if (status < 0)
255                        {
256                                dns_free_data(r);
257                                return NULL;
258                        }
259                        (*rr)->rr_u.rr_txt = sm_strdup(host);
260                        if ((*rr)->rr_u.rr_txt == NULL)
261                        {
262                                dns_free_data(r);
263                                return NULL;
264                        }
265                        break;
266
267                  case T_MX:
268                  case T_AFSDB:
269                        status = dn_expand(data, data + len, p + 2, host,
270                                           sizeof host);
271                        if (status < 0)
272                        {
273                                dns_free_data(r);
274                                return NULL;
275                        }
276                        l = strlen(host) + 1;
277                        (*rr)->rr_u.rr_mx = (MX_RECORD_T *)
278                                sm_malloc(sizeof(*((*rr)->rr_u.rr_mx)) + l);
279                        if ((*rr)->rr_u.rr_mx == NULL)
280                        {
281                                dns_free_data(r);
282                                return NULL;
283                        }
284                        (*rr)->rr_u.rr_mx->mx_r_preference = (p[0] << 8) | p[1];
285                        (void) sm_strlcpy((*rr)->rr_u.rr_mx->mx_r_domain,
286                                          host, l);
287                        break;
288
289                  case T_SRV:
290                        status = dn_expand(data, data + len, p + 6, host,
291                                           sizeof host);
292                        if (status < 0)
293                        {
294                                dns_free_data(r);
295                                return NULL;
296                        }
297                        l = strlen(host) + 1;
298                        (*rr)->rr_u.rr_srv = (SRV_RECORDT_T*)
299                                sm_malloc(sizeof(*((*rr)->rr_u.rr_srv)) + l);
300                        if ((*rr)->rr_u.rr_srv == NULL)
301                        {
302                                dns_free_data(r);
303                                return NULL;
304                        }
305                        (*rr)->rr_u.rr_srv->srv_r_priority = (p[0] << 8) | p[1];
306                        (*rr)->rr_u.rr_srv->srv_r_weight = (p[2] << 8) | p[3];
307                        (*rr)->rr_u.rr_srv->srv_r_port = (p[4] << 8) | p[5];
308                        (void) sm_strlcpy((*rr)->rr_u.rr_srv->srv_r_target,
309                                          host, l);
310                        break;
311
312                  case T_TXT:
313
314                        /*
315                        **  The TXT record contains the length as
316                        **  leading byte, hence the value is restricted
317                        **  to 255, which is less than the maximum value
318                        **  of RDLENGTH (size). Nevertheless, txtlen
319                        **  must be less than size because the latter
320                        **  specifies the length of the entire TXT
321                        **  record.
322                        */
323
324                        txtlen = *p;
325                        if (txtlen >= size)
326                        {
327                                if (LogLevel > 5)
328                                        sm_syslog(LOG_WARNING, NOQID,
329                                                  "ERROR: DNS TXT record size=%d <= text len=%d",
330                                                  size, txtlen);
331                                dns_free_data(r);
332                                return NULL;
333                        }
334                        (*rr)->rr_u.rr_txt = (char *) sm_malloc(txtlen + 1);
335                        if ((*rr)->rr_u.rr_txt == NULL)
336                        {
337                                dns_free_data(r);
338                                return NULL;
339                        }
340                        (void) sm_strlcpy((*rr)->rr_u.rr_txt, (char*) p + 1,
341                                          txtlen + 1);
342                        break;
343
344                  default:
345                        (*rr)->rr_u.rr_data = (unsigned char*) sm_malloc(size);
346                        if ((*rr)->rr_u.rr_data == NULL)
347                        {
348                                dns_free_data(r);
349                                return NULL;
350                        }
351                        (void) memcpy((*rr)->rr_u.rr_data, p, size);
352                        break;
353                }
354                p += size;
355                rr = &(*rr)->rr_next;
356        }
357        *rr = NULL;
358        return r;
359}
360
361/*
362**  DNS_LOOKUP_INT -- perform dns map lookup (internal helper routine)
363**
364**      Parameters:
365**              domain -- name to lookup
366**              rr_class -- resource record class
367**              rr_type -- resource record type
368**              retrans -- retransmission timeout
369**              retry -- number of retries
370**
371**      Returns:
372**              result of lookup if succeeded.
373**              NULL otherwise.
374*/
375
376DNS_REPLY_T *
377dns_lookup_int(domain, rr_class, rr_type, retrans, retry)
378        const char *domain;
379        int rr_class;
380        int rr_type;
381        time_t retrans;
382        int retry;
383{
384        int len;
385        unsigned long old_options = 0;
386        time_t save_retrans = 0;
387        int save_retry = 0;
388        DNS_REPLY_T *r = NULL;
389        unsigned char reply[1024];
390
391        if (tTd(8, 16))
392        {
393                old_options = _res.options;
394                _res.options |= RES_DEBUG;
395                sm_dprintf("dns_lookup(%s, %d, %s)\n", domain,
396                           rr_class, dns_type_to_string(rr_type));
397        }
398        if (retrans > 0)
399        {
400                save_retrans = _res.retrans;
401                _res.retrans = retrans;
402        }
403        if (retry > 0)
404        {
405                save_retry = _res.retry;
406                _res.retry = retry;
407        }
408        errno = 0;
409        SM_SET_H_ERRNO(0);
410        len = res_search(domain, rr_class, rr_type, reply, sizeof reply);
411        if (tTd(8, 16))
412        {
413                _res.options = old_options;
414                sm_dprintf("dns_lookup(%s, %d, %s) --> %d\n",
415                           domain, rr_class, dns_type_to_string(rr_type), len);
416        }
417        if (len >= 0)
418                r = parse_dns_reply(reply, len);
419        if (retrans > 0)
420                _res.retrans = save_retrans;
421        if (retry > 0)
422                _res.retry = save_retry;
423        return r;
424}
425
426#  if 0
427DNS_REPLY_T *
428dns_lookup(domain, type_name, retrans, retry)
429        const char *domain;
430        const char *type_name;
431        time_t retrans;
432        int retry;
433{
434        int type;
435
436        type = dns_string_to_type(type_name);
437        if (type == -1)
438        {
439                if (tTd(8, 16))
440                        sm_dprintf("dns_lookup: unknown resource type: `%s'\n",
441                                type_name);
442                return NULL;
443        }
444        return dns_lookup_int(domain, C_IN, type, retrans, retry);
445}
446#  endif /* 0 */
447# endif /* NAMED_BIND */
448#endif /* DNSMAP */
Note: See TracBrowser for help on using the repository browser.