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;
70
const int count_inc = 10;
75
memset(&hints, 0, sizeof(hints));
76
hints.ai_family = PF_UNSPEC;
77
hints.ai_socktype = SOCK_STREAM;
78
hints.ai_protocol = IPPROTO_TCP;
80
snprintf(servname, sizeof(servname), "%d", port);
81
err = getaddrinfo(host, servname, &hints, &res0);
85
for (res = res0; res != NULL; res = res->ai_next) {
86
if (*ps + 1 >= roundup(*ps, count_inc)) {
87
size_t newsz = roundup(*ps + 2, count_inc);
88
*he = reallocf(*he, newsz * sizeof(**he));
94
strlcpy(p->host, host, sizeof(p->host));
98
bcopy(res->ai_addr, &p->sa, p->ai.ai_addrlen);
100
getnameinfo((struct sockaddr *)&p->sa, p->ai.ai_addrlen,
101
p->addr, sizeof(p->addr),
102
NULL, 0, NI_NUMERICHOST);
108
return (*ps - onhosts);
117
dns_get_mx_list(const char *host, int port, struct mx_hostentry **he, int no_mx)
119
char outname[MAXDNAME];
122
const char *searchhost;
125
struct mx_hostentry *hosts = NULL;
146
err = res_search(searchhost, ns_c_in, ns_t_mx, ans, anssz);
151
* Host exists, but no MX (or CNAME) entry.
152
* Not an error, use host name instead.
156
/* transient error */
166
if (!ns_initparse(ans, anssz, &msg))
169
switch (ns_msg_getflag(msg, ns_f_rcode)) {
178
for (i = 0; i < ns_msg_count(msg, ns_s_an); i++) {
179
if (ns_parserr(&msg, ns_s_an, i, &rr))
182
cp = (const char *)ns_rr_rdata(rr);
184
switch (ns_rr_type(rr)) {
188
err = ns_name_uncompress(ns_msg_base(msg), ns_msg_end(msg),
189
cp, outname, sizeof(outname));
193
add_host(pref, outname, port, &hosts, &nhosts);
197
err = ns_name_uncompress(ns_msg_base(msg), ns_msg_end(msg),
198
cp, outname, sizeof(outname));
202
/* Prevent a CNAME loop */
203
if (cname_recurse++ > 10)
206
searchhost = outname;
230
* If we didn't find any MX, use the hostname instead.
233
add_host(0, searchhost, port, &hosts, &nhosts);
235
qsort(hosts, nhosts, sizeof(*hosts), sort_pref);
240
*hosts[nhosts].host = 0;
258
main(int argc, char **argv)
260
struct mx_hostentry *he, *p;
263
err = dns_get_mx_list(argv[1], 53, &he, 0);
267
for (p = he; *p->host != 0; p++) {
268
printf("%d\t%s\t%s\n", p->pref, p->host, p->addr);