source: mainline/uspace/srv/net/dnsrsrv/query.c@ e8d6ce2

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since e8d6ce2 was 0aa70f4, checked in by Martin Decky <martin@…>, 12 years ago

support for IPv6 DNS name resolution (AAAA)
if the desired address family of the DNS query is not explicitly specified, then IPv6 addresses take precendece over IPv4 addresses

  • Property mode set to 100644
File size: 5.5 KB
Line 
1/*
2 * Copyright (c) 2013 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup dnsres
30 * @{
31 */
32/**
33 * @file
34 */
35
36#include <errno.h>
37#include <io/log.h>
38#include <mem.h>
39#include <stdlib.h>
40#include <str.h>
41#include <net/socket_codes.h>
42#include "dns_msg.h"
43#include "dns_std.h"
44#include "dns_type.h"
45#include "query.h"
46#include "transport.h"
47
48static uint16_t msg_id;
49
50static int dns_name_query(const char *name, dns_qtype_t qtype,
51 dns_host_info_t *info)
52{
53 /* Start with the caller-provided name */
54 char *sname = str_dup(name);
55 if (sname == NULL)
56 return ENOMEM;
57
58 char *qname = str_dup(name);
59 if (qname == NULL) {
60 free(sname);
61 return ENOMEM;
62 }
63
64 dns_question_t *question = calloc(1, sizeof(dns_question_t));
65 if (question == NULL) {
66 free(qname);
67 free(sname);
68 return ENOMEM;
69 }
70
71 question->qname = qname;
72 question->qtype = qtype;
73 question->qclass = DC_IN;
74
75 dns_message_t *msg = dns_message_new();
76 if (msg == NULL) {
77 free(question);
78 free(qname);
79 free(sname);
80 return ENOMEM;
81 }
82
83 msg->id = msg_id++;
84 msg->qr = QR_QUERY;
85 msg->opcode = OPC_QUERY;
86 msg->aa = false;
87 msg->tc = false;
88 msg->rd = true;
89 msg->ra = false;
90
91 list_append(&question->msg, &msg->question);
92
93 dns_message_t *amsg;
94 int rc = dns_request(msg, &amsg);
95 if (rc != EOK) {
96 dns_message_destroy(msg);
97 free(sname);
98 return rc;
99 }
100
101 list_foreach(amsg->answer, link) {
102 dns_rr_t *rr = list_get_instance(link, dns_rr_t, msg);
103
104 log_msg(LOG_DEFAULT, LVL_DEBUG, " - '%s' %u/%u, dsize %zu",
105 rr->name, rr->rtype, rr->rclass, rr->rdata_size);
106
107 if ((rr->rtype == DTYPE_CNAME) && (rr->rclass == DC_IN) &&
108 (str_cmp(rr->name, sname) == 0)) {
109
110 log_msg(LOG_DEFAULT, LVL_DEBUG, "decode cname (%p, %zu, %zu)",
111 amsg->pdu.data, amsg->pdu.size, rr->roff);
112
113 char *cname;
114 size_t eoff;
115 rc = dns_name_decode(&amsg->pdu, rr->roff, &cname, &eoff);
116 if (rc != EOK) {
117 assert((rc == EINVAL) || (rc == ENOMEM));
118
119 log_msg(LOG_DEFAULT, LVL_DEBUG, "error decoding cname");
120
121 dns_message_destroy(msg);
122 dns_message_destroy(amsg);
123 free(sname);
124
125 return rc;
126 }
127
128 log_msg(LOG_DEFAULT, LVL_DEBUG, "name = '%s' "
129 "cname = '%s'", sname, cname);
130
131 /* Continue looking for the more canonical name */
132 free(sname);
133 sname = cname;
134 }
135
136 if ((qtype == DTYPE_A) && (rr->rtype == DTYPE_A) &&
137 (rr->rclass == DC_IN) && (rr->rdata_size == sizeof(addr32_t)) &&
138 (str_cmp(rr->name, sname) == 0)) {
139
140 info->cname = str_dup(rr->name);
141 if (info->cname == NULL) {
142 dns_message_destroy(msg);
143 dns_message_destroy(amsg);
144 free(sname);
145
146 return ENOMEM;
147 }
148
149 inet_addr_set(dns_uint32_t_decode(rr->rdata, rr->rdata_size),
150 &info->addr);
151
152 dns_message_destroy(msg);
153 dns_message_destroy(amsg);
154 free(sname);
155
156 return EOK;
157 }
158
159 if ((qtype == DTYPE_AAAA) && (rr->rtype == DTYPE_AAAA) &&
160 (rr->rclass == DC_IN) && (rr->rdata_size == sizeof(addr128_t)) &&
161 (str_cmp(rr->name, sname) == 0)) {
162
163 info->cname = str_dup(rr->name);
164 if (info->cname == NULL) {
165 dns_message_destroy(msg);
166 dns_message_destroy(amsg);
167 free(sname);
168
169 return ENOMEM;
170 }
171
172 addr128_t addr;
173 dns_addr128_t_decode(rr->rdata, rr->rdata_size, addr);
174
175 inet_addr_set6(addr, &info->addr);
176
177 dns_message_destroy(msg);
178 dns_message_destroy(amsg);
179 free(sname);
180
181 return EOK;
182 }
183 }
184
185 log_msg(LOG_DEFAULT, LVL_DEBUG, "'%s' not resolved, fail", sname);
186
187 dns_message_destroy(msg);
188 dns_message_destroy(amsg);
189 free(sname);
190
191 return EIO;
192}
193
194int dns_name2host(const char *name, dns_host_info_t **rinfo, uint16_t af)
195{
196 dns_host_info_t *info = calloc(1, sizeof(dns_host_info_t));
197 if (info == NULL)
198 return ENOMEM;
199
200 int rc;
201
202 switch (af) {
203 case AF_NONE:
204 rc = dns_name_query(name, DTYPE_AAAA, info);
205
206 if (rc != EOK)
207 rc = dns_name_query(name, DTYPE_A, info);
208
209 break;
210 case AF_INET:
211 rc = dns_name_query(name, DTYPE_A, info);
212 break;
213 case AF_INET6:
214 rc = dns_name_query(name, DTYPE_AAAA, info);
215 break;
216 default:
217 rc = EINVAL;
218 }
219
220 if (rc == EOK)
221 *rinfo = info;
222 else
223 free(info);
224
225 return rc;
226}
227
228void dns_hostinfo_destroy(dns_host_info_t *info)
229{
230 free(info->cname);
231 free(info);
232}
233
234/** @}
235 */
Note: See TracBrowser for help on using the repository browser.