1 /* authd/dns.c - authd DNS functions
2 * Copyright (c) 2016 William Pitcock <nenolod@dereferenced.org>
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.
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.
26 static void handle_lookup_ip_reply(void *data
, struct DNSReply
*reply
);
27 static void handle_lookup_hostname_reply(void *data
, struct DNSReply
*reply
);
29 uint64_t query_count
= 0;
31 /* A bit different from ircd... you just get a dns_query object.
33 * It gets freed whenever the res code gets back to us.
36 lookup_ip(const char *host
, int aftype
, DNSCB callback
, void *data
)
38 struct dns_query
*query
= rb_malloc(sizeof(struct dns_query
));
43 query
->type
= QUERY_A
;
47 else if(aftype
== AF_INET6
)
49 query
->type
= QUERY_AAAA
;
59 query
->id
= query_count
++;
60 query
->callback
= callback
;
63 query
->query
.ptr
= query
;
64 query
->query
.callback
= handle_lookup_ip_reply
;
66 gethost_byname_type(host
, &query
->query
, g_type
);
71 /* See lookup_ip's comment */
73 lookup_hostname(const char *ip
, DNSCB callback
, void *data
)
75 struct dns_query
*query
= rb_malloc(sizeof(struct dns_query
));
78 if(!rb_inet_pton_sock(ip
, (struct sockaddr
*)&query
->addr
))
84 aftype
= GET_SS_FAMILY(&query
->addr
);
87 query
->type
= QUERY_PTR_A
;
89 else if(aftype
== AF_INET6
)
90 query
->type
= QUERY_PTR_AAAA
;
98 query
->id
= query_count
++;
99 query
->callback
= callback
;
102 query
->query
.ptr
= query
;
103 query
->query
.callback
= handle_lookup_hostname_reply
;
105 gethost_byaddr(&query
->addr
, &query
->query
);
110 /* Cancel a pending query */
112 cancel_query(struct dns_query
*query
)
114 query
->callback
= query
->data
= NULL
;
117 /* Callback from gethost_byname_type */
119 handle_lookup_ip_reply(void *data
, struct DNSReply
*reply
)
121 struct dns_query
*query
= data
;
122 char ip
[HOSTIPLEN
] = "*";
126 /* Shouldn't happen */
127 warn_opers(L_CRIT
, "DNS: handle_lookup_ip_reply: query == NULL!");
137 if(GET_SS_FAMILY(&reply
->addr
) == AF_INET
)
138 rb_inet_ntop_sock((struct sockaddr
*)&reply
->addr
, ip
, sizeof(ip
));
142 if(GET_SS_FAMILY(&reply
->addr
) == AF_INET6
)
144 rb_inet_ntop_sock((struct sockaddr
*)&reply
->addr
, ip
, sizeof(ip
));
147 memmove(&ip
[1], ip
, strlen(ip
));
154 warn_opers(L_CRIT
, "DNS: handle_lookup_ip_reply: unknown query type %d",
161 query
->callback(ip
, ip
[0] != '*', query
->type
, query
->data
);
166 /* Callback from gethost_byaddr */
168 handle_lookup_hostname_reply(void *data
, struct DNSReply
*reply
)
170 struct dns_query
*query
= data
;
171 char *hostname
= NULL
;
175 /* Shouldn't happen */
176 warn_opers(L_CRIT
, "DNS: handle_lookup_hostname_reply: query == NULL!");
183 if(query
->type
== QUERY_PTR_A
)
185 struct sockaddr_in
*ip
, *ip_fwd
;
186 ip
= (struct sockaddr_in
*) &query
->addr
;
187 ip_fwd
= (struct sockaddr_in
*) &reply
->addr
;
189 if(ip
->sin_addr
.s_addr
== ip_fwd
->sin_addr
.s_addr
)
190 hostname
= reply
->h_name
;
193 else if(query
->type
== QUERY_PTR_AAAA
)
195 struct sockaddr_in6
*ip
, *ip_fwd
;
196 ip
= (struct sockaddr_in6
*) &query
->addr
;
197 ip_fwd
= (struct sockaddr_in6
*) &reply
->addr
;
199 if(memcmp(&ip
->sin6_addr
, &ip_fwd
->sin6_addr
, sizeof(struct in6_addr
)) == 0)
200 hostname
= reply
->h_name
;
205 /* Shouldn't happen */
206 warn_opers(L_CRIT
, "DNS: handle_lookup_hostname_reply: unknown query type %d",
212 query
->callback(hostname
, hostname
!= NULL
, query
->type
, query
->data
);
218 submit_dns_answer(const char *reply
, bool status
, query_type type
, void *data
)
222 if(!id
|| type
== QUERY_INVALID
)
224 warn_opers(L_CRIT
, "DNS: submit_dns_answer gave us a bad query");
228 if(reply
== NULL
|| status
== false)
230 rb_helper_write(authd_helper
, "E %s E %c *", id
, type
);
235 rb_helper_write(authd_helper
, "E %s O %c %s", id
, type
, reply
);
240 handle_resolve_dns(int parc
, char *parv
[])
242 char *id
= rb_strdup(parv
[1]);
243 char qtype
= *parv
[2];
244 char *record
= parv
[3];
245 int aftype
= AF_INET
;
254 if(!lookup_ip(record
, aftype
, submit_dns_answer
, id
))
255 submit_dns_answer(NULL
, false, qtype
, NULL
);
261 if(!lookup_hostname(record
, submit_dns_answer
, id
))
262 submit_dns_answer(NULL
, false, qtype
, NULL
);
265 warn_opers(L_CRIT
, "DNS: handle_resolve_dns got an unknown query: %c", qtype
);
271 enumerate_nameservers(uint32_t rid
, const char letter
)
273 char buf
[(HOSTIPLEN
+ 1) * IRCD_MAXNS
];
278 /* Shouldn't happen */
279 warn_opers(L_CRIT
, "DNS: no name servers!");
280 stats_error(rid
, letter
, "NONAMESERVERS");
284 for(int i
= 0; i
< irc_nscount
; i
++)
286 char addr
[HOSTIPLEN
];
289 rb_inet_ntop_sock((struct sockaddr
*)&irc_nsaddr_list
[i
], addr
, sizeof(addr
));
293 /* Shouldn't happen */
294 warn_opers(L_CRIT
, "DNS: bad nameserver!");
295 stats_error(rid
, letter
, "INVALIDNAMESERVER");
299 addrlen
= strlen(addr
) + 1;
300 (void)snprintf(&buf
[s
], sizeof(buf
) - s
, "%s ", addr
);
307 stats_result(rid
, letter
, "%s", buf
);
311 reload_nameservers(const char letter
)
313 /* Not a whole lot to it */