]>
git.ipfire.org Git - people/ms/dma.git/blob - dns.c
2 * Copyright (c) 2008 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Simon 'corecode' Schubert <corecode@fs.ei.tum.de>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 #include <sys/types.h>
36 #include <netinet/in.h>
37 #include <arpa/inet.h>
38 #include <arpa/nameser.h>
48 sort_pref(const void *a
, const void *b
)
50 const struct mx_hostentry
*ha
= a
, *hb
= b
;
53 /* sort increasing by preference primarily */
54 v
= ha
->pref
- hb
->pref
;
58 /* sort PF_INET6 before PF_INET */
59 v
= - (ha
->ai
.ai_family
- hb
->ai
.ai_family
);
64 add_host(int pref
, const char *host
, int port
, struct mx_hostentry
**he
, size_t *ps
)
66 struct addrinfo hints
, *res
, *res0
= NULL
;
68 struct mx_hostentry
*p
;
69 const int count_inc
= 10;
72 memset(&hints
, 0, sizeof(hints
));
73 hints
.ai_family
= PF_UNSPEC
;
74 hints
.ai_socktype
= SOCK_STREAM
;
75 hints
.ai_protocol
= IPPROTO_TCP
;
77 snprintf(servname
, sizeof(servname
), "%d", port
);
78 err
= getaddrinfo(host
, servname
, &hints
, &res0
);
80 return (err
== EAI_AGAIN
? 1 : -1);
82 for (res
= res0
; res
!= NULL
; res
= res
->ai_next
) {
83 if (*ps
+ 1 >= roundup(*ps
, count_inc
)) {
84 size_t newsz
= roundup(*ps
+ 2, count_inc
);
85 *he
= reallocf(*he
, newsz
* sizeof(**he
));
91 strlcpy(p
->host
, host
, sizeof(p
->host
));
95 bcopy(res
->ai_addr
, &p
->sa
, p
->ai
.ai_addrlen
);
97 getnameinfo((struct sockaddr
*)&p
->sa
, p
->ai
.ai_addrlen
,
98 p
->addr
, sizeof(p
->addr
),
99 NULL
, 0, NI_NUMERICHOST
);
114 dns_get_mx_list(const char *host
, int port
, struct mx_hostentry
**he
, int no_mx
)
116 char outname
[MAXDNAME
];
119 const char *searchhost
;
120 const unsigned char *cp
;
122 struct mx_hostentry
*hosts
= NULL
;
144 err
= res_search(searchhost
, ns_c_in
, ns_t_mx
, ans
, anssz
);
149 * Host exists, but no MX (or CNAME) entry.
150 * Not an error, use host name instead.
154 /* transient error */
164 if (!ns_initparse(ans
, anssz
, &msg
))
167 switch (ns_msg_getflag(msg
, ns_f_rcode
)) {
176 for (i
= 0; i
< ns_msg_count(msg
, ns_s_an
); i
++) {
177 if (ns_parserr(&msg
, ns_s_an
, i
, &rr
))
180 cp
= ns_rr_rdata(rr
);
182 switch (ns_rr_type(rr
)) {
187 err
= ns_name_uncompress(ns_msg_base(msg
), ns_msg_end(msg
),
188 cp
, outname
, sizeof(outname
));
192 err
= add_host(pref
, outname
, port
, &hosts
, &nhosts
);
198 err
= ns_name_uncompress(ns_msg_base(msg
), ns_msg_end(msg
),
199 cp
, outname
, sizeof(outname
));
203 /* Prevent a CNAME loop */
204 if (cname_recurse
++ > 10)
207 searchhost
= outname
;
232 * If we didn't find any MX, use the hostname instead.
234 err
= add_host(0, host
, port
, &hosts
, &nhosts
);
235 } else if (nhosts
== 0) {
237 * We did get MX, but couldn't resolve any of them
238 * due to transient errors.
245 qsort(hosts
, nhosts
, sizeof(*hosts
), sort_pref
);
247 *hosts
[nhosts
].host
= 0;
265 main(int argc
, char **argv
)
267 struct mx_hostentry
*he
, *p
;
270 err
= dns_get_mx_list(argv
[1], 53, &he
, 0);
274 for (p
= he
; *p
->host
!= 0; p
++) {
275 printf("%d\t%s\t%s\n", p
->pref
, p
->host
, p
->addr
);