]>
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" | |
394b8dde | 23 | #include "res.h" |
8cf45447 | 24 | |
399c6333 EM |
25 | static void handle_lookup_ip_reply(void *data, struct DNSReply *reply); |
26 | static void handle_lookup_hostname_reply(void *data, struct DNSReply *reply); | |
27 | ||
28 | uint64_t query_count = 0; | |
29 | ||
30 | /* A bit different from ircd... you just get a dns_query object. | |
31 | * | |
32 | * It gets freed whenever the res code gets back to us. | |
33 | */ | |
34 | struct dns_query * | |
35 | lookup_ip(const char *host, int aftype, DNSCB callback, void *data) | |
8cf45447 | 36 | { |
399c6333 EM |
37 | struct dns_query *query = rb_malloc(sizeof(struct dns_query)); |
38 | int g_type; | |
8cf45447 | 39 | |
399c6333 | 40 | if(aftype == AF_INET) |
8cf45447 | 41 | { |
399c6333 EM |
42 | query->type = QUERY_A; |
43 | g_type = T_A; | |
8cf45447 | 44 | } |
399c6333 EM |
45 | #ifdef RB_IPV6 |
46 | else if(aftype == AF_INET6) | |
47 | { | |
48 | query->type = QUERY_AAAA; | |
49 | g_type = T_AAAA; | |
50 | } | |
51 | #endif | |
52 | else | |
53 | { | |
54 | rb_free(query); | |
55 | return NULL; | |
56 | } | |
57 | ||
58 | query->id = query_count++; | |
59 | query->callback = callback; | |
60 | query->data = data; | |
8cf45447 | 61 | |
399c6333 EM |
62 | query->query.ptr = query; |
63 | query->query.callback = handle_lookup_ip_reply; | |
64 | ||
65 | gethost_byname_type(host, &query->query, g_type); | |
66 | ||
67 | return query; | |
68 | } | |
69 | ||
70 | /* See lookup_ip's comment */ | |
71 | struct dns_query * | |
2b0cc3d3 | 72 | lookup_hostname(const char *ip, DNSCB callback, void *data) |
399c6333 EM |
73 | { |
74 | struct dns_query *query = rb_malloc(sizeof(struct dns_query)); | |
2b0cc3d3 | 75 | int aftype; |
399c6333 EM |
76 | |
77 | if(!rb_inet_pton_sock(ip, (struct sockaddr *)&query->addr)) | |
8cf45447 | 78 | { |
399c6333 EM |
79 | rb_free(query); |
80 | return NULL; | |
81 | } | |
82 | ||
2b0cc3d3 EM |
83 | aftype = GET_SS_FAMILY(&query->addr); |
84 | ||
399c6333 EM |
85 | if(aftype == AF_INET) |
86 | query->type = QUERY_PTR_A; | |
8cf45447 | 87 | #ifdef RB_IPV6 |
399c6333 EM |
88 | else if(aftype == AF_INET6) |
89 | query->type = QUERY_PTR_AAAA; | |
90 | #endif | |
91 | else | |
92 | { | |
93 | rb_free(query); | |
94 | return NULL; | |
95 | } | |
8cf45447 | 96 | |
399c6333 EM |
97 | query->id = query_count++; |
98 | query->callback = callback; | |
99 | query->data = data; | |
8cf45447 | 100 | |
399c6333 EM |
101 | query->query.ptr = query; |
102 | query->query.callback = handle_lookup_hostname_reply; | |
8cf45447 | 103 | |
399c6333 EM |
104 | gethost_byaddr(&query->addr, &query->query); |
105 | ||
106 | return query; | |
107 | } | |
108 | ||
45ac1e3c | 109 | /* Cancel a pending query */ |
540676fc | 110 | void |
45ac1e3c EM |
111 | cancel_query(struct dns_query *query) |
112 | { | |
113 | query->callback = query->data = NULL; | |
114 | } | |
115 | ||
399c6333 EM |
116 | /* Callback from gethost_byname_type */ |
117 | static void | |
118 | handle_lookup_ip_reply(void *data, struct DNSReply *reply) | |
119 | { | |
120 | struct dns_query *query = data; | |
121 | char ip[64] = "*"; | |
122 | query_type type = QUERY_INVALID; | |
123 | ||
124 | if(!query) | |
125 | /* Shouldn't happen */ | |
126 | exit(2); | |
2b0cc3d3 | 127 | |
399c6333 EM |
128 | type = query->type; |
129 | ||
2b0cc3d3 | 130 | if(reply == NULL) |
399c6333 EM |
131 | goto end; |
132 | ||
133 | switch(query->type) | |
134 | { | |
135 | case QUERY_A: | |
136 | if(GET_SS_FAMILY(&reply->addr) == AF_INET) | |
137 | rb_inet_ntop_sock((struct sockaddr *)&reply->addr, ip, sizeof(ip)); | |
8cf45447 AC |
138 | break; |
139 | #ifdef RB_IPV6 | |
399c6333 EM |
140 | case QUERY_AAAA: |
141 | if(GET_SS_FAMILY(&reply->addr) == AF_INET6) | |
8cf45447 | 142 | { |
399c6333 EM |
143 | rb_inet_ntop_sock((struct sockaddr *)&reply->addr, ip, sizeof(ip)); |
144 | if(ip[0] == ':') | |
8cf45447 | 145 | { |
399c6333 EM |
146 | memmove(&ip[1], ip, strlen(ip)); |
147 | ip[0] = '0'; | |
8cf45447 AC |
148 | } |
149 | } | |
150 | break; | |
151 | #endif | |
152 | default: | |
399c6333 | 153 | exit(3); |
8cf45447 AC |
154 | } |
155 | ||
399c6333 EM |
156 | end: |
157 | if(query->callback) | |
158 | query->callback(ip, ip[0] != '*', type, query->data); | |
159 | ||
160 | rb_free(query); | |
161 | } | |
162 | ||
163 | /* Callback from gethost_byaddr */ | |
164 | static void | |
165 | handle_lookup_hostname_reply(void *data, struct DNSReply *reply) | |
166 | { | |
167 | struct dns_query *query = data; | |
168 | char *hostname = NULL; | |
169 | query_type type = QUERY_INVALID; | |
170 | ||
2b0cc3d3 | 171 | if(query == NULL) |
399c6333 EM |
172 | /* Shouldn't happen */ |
173 | exit(4); | |
174 | ||
175 | type = query->type; | |
176 | ||
2b0cc3d3 | 177 | if(reply == NULL) |
399c6333 EM |
178 | goto end; |
179 | ||
180 | if(query->type == QUERY_PTR_A) | |
181 | { | |
182 | struct sockaddr_in *ip, *ip_fwd; | |
183 | ip = (struct sockaddr_in *) &query->addr; | |
184 | ip_fwd = (struct sockaddr_in *) &reply->addr; | |
185 | ||
2b0cc3d3 | 186 | if(ip->sin_addr.s_addr == ip_fwd->sin_addr.s_addr) |
399c6333 EM |
187 | hostname = reply->h_name; |
188 | } | |
189 | #ifdef RB_IPV6 | |
190 | else if(query->type == QUERY_PTR_AAAA) | |
191 | { | |
192 | struct sockaddr_in6 *ip, *ip_fwd; | |
193 | ip = (struct sockaddr_in6 *) &query->addr; | |
194 | ip_fwd = (struct sockaddr_in6 *) &reply->addr; | |
195 | ||
2b0cc3d3 | 196 | if(memcmp(&ip->sin6_addr, &ip_fwd->sin6_addr, sizeof(struct in6_addr)) == 0) |
399c6333 EM |
197 | hostname = reply->h_name; |
198 | } | |
199 | #endif | |
200 | else | |
201 | /* Shouldn't happen */ | |
202 | exit(5); | |
203 | end: | |
204 | if(query->callback) | |
205 | query->callback(hostname, hostname != NULL, query->type, query->data); | |
206 | ||
207 | rb_free(query); | |
208 | } | |
209 | ||
210 | static void | |
211 | submit_dns_answer(const char *reply, bool status, query_type type, void *data) | |
212 | { | |
213 | char *id = data; | |
214 | ||
215 | if(!id || type == QUERY_INVALID) | |
216 | exit(6); | |
217 | ||
2b0cc3d3 | 218 | if(reply == NULL || status == false) |
399c6333 EM |
219 | { |
220 | rb_helper_write(authd_helper, "E %s E %c *", id, type); | |
221 | rb_free(id); | |
1d9925cf | 222 | return; |
399c6333 EM |
223 | } |
224 | ||
225 | rb_helper_write(authd_helper, "E %s O %c %s", id, type, reply); | |
226 | rb_free(id); | |
8cf45447 AC |
227 | } |
228 | ||
229 | void | |
230 | resolve_dns(int parc, char *parv[]) | |
231 | { | |
399c6333 EM |
232 | char *id = rb_strdup(parv[1]); |
233 | char qtype = *parv[2]; | |
234 | char *record = parv[3]; | |
235 | int aftype = AF_INET; | |
8cf45447 | 236 | |
399c6333 | 237 | switch(qtype) |
8cf45447 | 238 | { |
399c6333 | 239 | #ifdef RB_IPV6 |
8cf45447 | 240 | case '6': |
399c6333 EM |
241 | aftype = AF_INET6; |
242 | #endif | |
243 | case '4': | |
244 | if(!lookup_ip(record, aftype, submit_dns_answer, id)) | |
245 | submit_dns_answer(NULL, false, qtype, NULL); | |
8cf45447 | 246 | break; |
399c6333 | 247 | #ifdef RB_IPV6 |
8cf45447 | 248 | case 'S': |
399c6333 EM |
249 | #endif |
250 | case 'R': | |
2b0cc3d3 | 251 | if(!lookup_hostname(record, submit_dns_answer, id)) |
399c6333 | 252 | submit_dns_answer(NULL, false, qtype, NULL); |
8cf45447 | 253 | break; |
399c6333 EM |
254 | default: |
255 | exit(7); | |
8cf45447 | 256 | } |
8cf45447 | 257 | } |
394b8dde EM |
258 | |
259 | void | |
260 | enumerate_nameservers(const char *rid, const char letter) | |
261 | { | |
2b0cc3d3 | 262 | char buf[(HOSTIPLEN + 1) * IRCD_MAXNS]; |
394b8dde EM |
263 | char *c = buf; |
264 | int i; | |
265 | ||
266 | if (!irc_nscount) | |
267 | { | |
268 | /* Shouldn't happen */ | |
269 | rb_helper_write(authd_helper, "X %s %c NONAMESERVERS", rid, letter); | |
270 | return; | |
271 | } | |
272 | ||
273 | for(i = 0; i < irc_nscount; i++) | |
274 | { | |
2b0cc3d3 | 275 | char addr[HOSTIPLEN]; |
394b8dde EM |
276 | |
277 | rb_inet_ntop_sock((struct sockaddr *)&irc_nsaddr_list[i], addr, sizeof(addr)); | |
278 | ||
279 | if (!addr[0]) | |
280 | { | |
281 | /* Shouldn't happen */ | |
282 | rb_helper_write(authd_helper, "X %s %c INVALIDNAMESERVER", rid, letter); | |
283 | return; | |
284 | } | |
285 | ||
2b0cc3d3 EM |
286 | (void)snprintf(c, HOSTIPLEN + 1, "%s ", addr); |
287 | c += strlen(addr) + 1; | |
394b8dde EM |
288 | } |
289 | ||
290 | *(--c) = '\0'; | |
291 | ||
292 | rb_helper_write(authd_helper, "Y %s %c %s", rid, letter, buf); | |
293 | } | |
6445c1cf EM |
294 | |
295 | void | |
296 | reload_nameservers(const char letter) | |
297 | { | |
298 | /* Not a whole lot to it */ | |
299 | restart_resolver(); | |
300 | } |