]>
Commit | Line | Data |
---|---|---|
399c6333 | 1 | /* authd/dns.c - authd DNS functions |
8cf45447 AC |
2 | * Copyright (c) 2016 William Pitcock <nenolod@dereferenced.org> |
3 | * | |
4 | * Permission to use, copy, modify, and/or distribute this software for any | |
5 | * purpose with or without fee is hereby granted, provided that the above | |
6 | * copyright notice and this permission notice is present in all copies. | |
7 | * | |
8 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |
9 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
10 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
11 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, | |
12 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
13 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
14 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
15 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
16 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | |
17 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
18 | * POSSIBILITY OF SUCH DAMAGE. | |
19 | */ | |
20 | ||
21 | #include "authd.h" | |
22 | #include "dns.h" | |
02e141f7 | 23 | #include "notice.h" |
394b8dde | 24 | #include "res.h" |
8cf45447 | 25 | |
399c6333 EM |
26 | static void handle_lookup_ip_reply(void *data, struct DNSReply *reply); |
27 | static void handle_lookup_hostname_reply(void *data, struct DNSReply *reply); | |
28 | ||
29 | uint64_t query_count = 0; | |
30 | ||
31 | /* A bit different from ircd... you just get a dns_query object. | |
32 | * | |
33 | * It gets freed whenever the res code gets back to us. | |
34 | */ | |
35 | struct dns_query * | |
36 | lookup_ip(const char *host, int aftype, DNSCB callback, void *data) | |
8cf45447 | 37 | { |
399c6333 EM |
38 | struct dns_query *query = rb_malloc(sizeof(struct dns_query)); |
39 | int g_type; | |
8cf45447 | 40 | |
399c6333 | 41 | if(aftype == AF_INET) |
8cf45447 | 42 | { |
399c6333 EM |
43 | query->type = QUERY_A; |
44 | g_type = T_A; | |
8cf45447 | 45 | } |
399c6333 EM |
46 | #ifdef RB_IPV6 |
47 | else if(aftype == AF_INET6) | |
48 | { | |
49 | query->type = QUERY_AAAA; | |
50 | g_type = T_AAAA; | |
51 | } | |
52 | #endif | |
53 | else | |
54 | { | |
55 | rb_free(query); | |
56 | return NULL; | |
57 | } | |
58 | ||
59 | query->id = query_count++; | |
60 | query->callback = callback; | |
61 | query->data = data; | |
8cf45447 | 62 | |
399c6333 EM |
63 | query->query.ptr = query; |
64 | query->query.callback = handle_lookup_ip_reply; | |
65 | ||
66 | gethost_byname_type(host, &query->query, g_type); | |
67 | ||
68 | return query; | |
69 | } | |
70 | ||
71 | /* See lookup_ip's comment */ | |
72 | struct dns_query * | |
2b0cc3d3 | 73 | lookup_hostname(const char *ip, DNSCB callback, void *data) |
399c6333 EM |
74 | { |
75 | struct dns_query *query = rb_malloc(sizeof(struct dns_query)); | |
2b0cc3d3 | 76 | int aftype; |
399c6333 EM |
77 | |
78 | if(!rb_inet_pton_sock(ip, (struct sockaddr *)&query->addr)) | |
8cf45447 | 79 | { |
399c6333 EM |
80 | rb_free(query); |
81 | return NULL; | |
82 | } | |
83 | ||
2b0cc3d3 EM |
84 | aftype = GET_SS_FAMILY(&query->addr); |
85 | ||
399c6333 EM |
86 | if(aftype == AF_INET) |
87 | query->type = QUERY_PTR_A; | |
8cf45447 | 88 | #ifdef RB_IPV6 |
399c6333 EM |
89 | else if(aftype == AF_INET6) |
90 | query->type = QUERY_PTR_AAAA; | |
91 | #endif | |
92 | else | |
93 | { | |
94 | rb_free(query); | |
95 | return NULL; | |
96 | } | |
8cf45447 | 97 | |
399c6333 EM |
98 | query->id = query_count++; |
99 | query->callback = callback; | |
100 | query->data = data; | |
8cf45447 | 101 | |
399c6333 EM |
102 | query->query.ptr = query; |
103 | query->query.callback = handle_lookup_hostname_reply; | |
8cf45447 | 104 | |
399c6333 EM |
105 | gethost_byaddr(&query->addr, &query->query); |
106 | ||
107 | return query; | |
108 | } | |
109 | ||
45ac1e3c | 110 | /* Cancel a pending query */ |
540676fc | 111 | void |
45ac1e3c EM |
112 | cancel_query(struct dns_query *query) |
113 | { | |
114 | query->callback = query->data = NULL; | |
115 | } | |
116 | ||
399c6333 EM |
117 | /* Callback from gethost_byname_type */ |
118 | static void | |
119 | handle_lookup_ip_reply(void *data, struct DNSReply *reply) | |
120 | { | |
121 | struct dns_query *query = data; | |
10960258 | 122 | char ip[HOSTIPLEN] = "*"; |
399c6333 | 123 | |
238a9ed5 | 124 | if(query == NULL) |
34b96d7f | 125 | { |
399c6333 | 126 | /* Shouldn't happen */ |
34b96d7f EM |
127 | warn_opers(L_CRIT, "DNS: handle_lookup_ip_reply: query == NULL!"); |
128 | exit(EX_DNS_ERROR); | |
129 | } | |
2b0cc3d3 | 130 | |
2b0cc3d3 | 131 | if(reply == NULL) |
399c6333 EM |
132 | goto end; |
133 | ||
134 | switch(query->type) | |
135 | { | |
136 | case QUERY_A: | |
137 | if(GET_SS_FAMILY(&reply->addr) == AF_INET) | |
138 | rb_inet_ntop_sock((struct sockaddr *)&reply->addr, ip, sizeof(ip)); | |
8cf45447 AC |
139 | break; |
140 | #ifdef RB_IPV6 | |
399c6333 EM |
141 | case QUERY_AAAA: |
142 | if(GET_SS_FAMILY(&reply->addr) == AF_INET6) | |
8cf45447 | 143 | { |
399c6333 EM |
144 | rb_inet_ntop_sock((struct sockaddr *)&reply->addr, ip, sizeof(ip)); |
145 | if(ip[0] == ':') | |
8cf45447 | 146 | { |
399c6333 EM |
147 | memmove(&ip[1], ip, strlen(ip)); |
148 | ip[0] = '0'; | |
8cf45447 AC |
149 | } |
150 | } | |
151 | break; | |
152 | #endif | |
153 | default: | |
34b96d7f EM |
154 | warn_opers(L_CRIT, "DNS: handle_lookup_ip_reply: unknown query type %d", |
155 | query->type); | |
156 | exit(EX_DNS_ERROR); | |
8cf45447 AC |
157 | } |
158 | ||
399c6333 EM |
159 | end: |
160 | if(query->callback) | |
238a9ed5 | 161 | query->callback(ip, ip[0] != '*', query->type, query->data); |
399c6333 EM |
162 | |
163 | rb_free(query); | |
164 | } | |
165 | ||
166 | /* Callback from gethost_byaddr */ | |
167 | static void | |
168 | handle_lookup_hostname_reply(void *data, struct DNSReply *reply) | |
169 | { | |
170 | struct dns_query *query = data; | |
171 | char *hostname = NULL; | |
399c6333 | 172 | |
2b0cc3d3 | 173 | if(query == NULL) |
34b96d7f | 174 | { |
399c6333 | 175 | /* Shouldn't happen */ |
34b96d7f EM |
176 | warn_opers(L_CRIT, "DNS: handle_lookup_hostname_reply: query == NULL!"); |
177 | exit(EX_DNS_ERROR); | |
178 | } | |
399c6333 | 179 | |
2b0cc3d3 | 180 | if(reply == NULL) |
399c6333 EM |
181 | goto end; |
182 | ||
183 | if(query->type == QUERY_PTR_A) | |
184 | { | |
185 | struct sockaddr_in *ip, *ip_fwd; | |
186 | ip = (struct sockaddr_in *) &query->addr; | |
187 | ip_fwd = (struct sockaddr_in *) &reply->addr; | |
188 | ||
2b0cc3d3 | 189 | if(ip->sin_addr.s_addr == ip_fwd->sin_addr.s_addr) |
399c6333 EM |
190 | hostname = reply->h_name; |
191 | } | |
192 | #ifdef RB_IPV6 | |
193 | else if(query->type == QUERY_PTR_AAAA) | |
194 | { | |
195 | struct sockaddr_in6 *ip, *ip_fwd; | |
196 | ip = (struct sockaddr_in6 *) &query->addr; | |
197 | ip_fwd = (struct sockaddr_in6 *) &reply->addr; | |
198 | ||
2b0cc3d3 | 199 | if(memcmp(&ip->sin6_addr, &ip_fwd->sin6_addr, sizeof(struct in6_addr)) == 0) |
399c6333 EM |
200 | hostname = reply->h_name; |
201 | } | |
202 | #endif | |
203 | else | |
34b96d7f | 204 | { |
399c6333 | 205 | /* Shouldn't happen */ |
34b96d7f EM |
206 | warn_opers(L_CRIT, "DNS: handle_lookup_hostname_reply: unknown query type %d", |
207 | query->type); | |
208 | exit(EX_DNS_ERROR); | |
209 | } | |
399c6333 EM |
210 | end: |
211 | if(query->callback) | |
212 | query->callback(hostname, hostname != NULL, query->type, query->data); | |
213 | ||
214 | rb_free(query); | |
215 | } | |
216 | ||
217 | static void | |
218 | submit_dns_answer(const char *reply, bool status, query_type type, void *data) | |
219 | { | |
220 | char *id = data; | |
221 | ||
222 | if(!id || type == QUERY_INVALID) | |
34b96d7f EM |
223 | { |
224 | warn_opers(L_CRIT, "DNS: submit_dns_answer gave us a bad query"); | |
225 | exit(EX_DNS_ERROR); | |
226 | } | |
399c6333 | 227 | |
2b0cc3d3 | 228 | if(reply == NULL || status == false) |
399c6333 EM |
229 | { |
230 | rb_helper_write(authd_helper, "E %s E %c *", id, type); | |
231 | rb_free(id); | |
1d9925cf | 232 | return; |
399c6333 EM |
233 | } |
234 | ||
235 | rb_helper_write(authd_helper, "E %s O %c %s", id, type, reply); | |
236 | rb_free(id); | |
8cf45447 AC |
237 | } |
238 | ||
239 | void | |
60374ac9 | 240 | handle_resolve_dns(int parc, char *parv[]) |
8cf45447 | 241 | { |
399c6333 EM |
242 | char *id = rb_strdup(parv[1]); |
243 | char qtype = *parv[2]; | |
244 | char *record = parv[3]; | |
245 | int aftype = AF_INET; | |
8cf45447 | 246 | |
399c6333 | 247 | switch(qtype) |
8cf45447 | 248 | { |
399c6333 | 249 | #ifdef RB_IPV6 |
8cf45447 | 250 | case '6': |
399c6333 EM |
251 | aftype = AF_INET6; |
252 | #endif | |
253 | case '4': | |
254 | if(!lookup_ip(record, aftype, submit_dns_answer, id)) | |
255 | submit_dns_answer(NULL, false, qtype, NULL); | |
8cf45447 | 256 | break; |
399c6333 | 257 | #ifdef RB_IPV6 |
8cf45447 | 258 | case 'S': |
399c6333 EM |
259 | #endif |
260 | case 'R': | |
2b0cc3d3 | 261 | if(!lookup_hostname(record, submit_dns_answer, id)) |
399c6333 | 262 | submit_dns_answer(NULL, false, qtype, NULL); |
8cf45447 | 263 | break; |
399c6333 | 264 | default: |
34b96d7f EM |
265 | warn_opers(L_CRIT, "DNS: handle_resolve_dns got an unknown query: %c", qtype); |
266 | exit(EX_DNS_ERROR); | |
8cf45447 | 267 | } |
8cf45447 | 268 | } |
394b8dde EM |
269 | |
270 | void | |
26d491b9 | 271 | enumerate_nameservers(uint32_t rid, const char letter) |
394b8dde | 272 | { |
2b0cc3d3 | 273 | char buf[(HOSTIPLEN + 1) * IRCD_MAXNS]; |
02e141f7 | 274 | size_t s = 0; |
394b8dde EM |
275 | |
276 | if (!irc_nscount) | |
277 | { | |
278 | /* Shouldn't happen */ | |
34b96d7f | 279 | warn_opers(L_CRIT, "DNS: no name servers!"); |
26d491b9 | 280 | stats_error(rid, letter, "NONAMESERVERS"); |
34b96d7f | 281 | exit(EX_DNS_ERROR); |
394b8dde EM |
282 | } |
283 | ||
02e141f7 | 284 | for(int i = 0; i < irc_nscount; i++) |
394b8dde | 285 | { |
2b0cc3d3 | 286 | char addr[HOSTIPLEN]; |
02e141f7 | 287 | size_t addrlen; |
394b8dde EM |
288 | |
289 | rb_inet_ntop_sock((struct sockaddr *)&irc_nsaddr_list[i], addr, sizeof(addr)); | |
290 | ||
291 | if (!addr[0]) | |
292 | { | |
293 | /* Shouldn't happen */ | |
34b96d7f | 294 | warn_opers(L_CRIT, "DNS: bad nameserver!"); |
26d491b9 | 295 | stats_error(rid, letter, "INVALIDNAMESERVER"); |
34b96d7f | 296 | exit(EX_DNS_ERROR); |
394b8dde EM |
297 | } |
298 | ||
02e141f7 | 299 | addrlen = strlen(addr) + 1; |
26d491b9 | 300 | (void)snprintf(&buf[s], sizeof(buf) - s, "%s ", addr); |
02e141f7 | 301 | s += addrlen; |
394b8dde EM |
302 | } |
303 | ||
26d491b9 EM |
304 | if(s > 0) |
305 | buf[--s] = '\0'; | |
394b8dde | 306 | |
26d491b9 | 307 | stats_result(rid, letter, "%s", buf); |
394b8dde | 308 | } |
6445c1cf EM |
309 | |
310 | void | |
311 | reload_nameservers(const char letter) | |
312 | { | |
313 | /* Not a whole lot to it */ | |
314 | restart_resolver(); | |
315 | } |