]> jfr.im git - solanum.git/blob - authd/dns.c
authd: allow querying the list of DNS servers.
[solanum.git] / authd / dns.c
1 /* authd/dns.h - header for authd DNS functions
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"
23 #include "res.h"
24
25 static void
26 submit_dns_answer(void *userdata, struct DNSReply *reply)
27 {
28 struct dns_request *req = userdata;
29 char response[64] = "*";
30 char status = 'E';
31
32 if (reply == NULL)
33 {
34 rb_helper_write(authd_helper, "E %s E %c *", req->reqid, req->type);
35 goto cleanup;
36 }
37
38 switch (req->type)
39 {
40 case '4':
41 if (GET_SS_FAMILY(&reply->addr) == AF_INET)
42 {
43 status = 'O';
44 rb_inet_ntop_sock((struct sockaddr *) &reply->addr, response, sizeof(response));
45 }
46 break;
47 #ifdef RB_IPV6
48 case '6':
49 if (GET_SS_FAMILY(&reply->addr) == AF_INET6)
50 {
51 char tmpres[63];
52 rb_inet_ntop_sock((struct sockaddr *) &reply->addr, tmpres, sizeof(tmpres));
53
54 if (*tmpres == ':')
55 {
56 rb_strlcpy(response, "0", sizeof(response));
57 rb_strlcat(response, tmpres, sizeof(response));
58 }
59 else
60 rb_strlcpy(response, tmpres, sizeof(response));
61
62 status = 'O';
63 }
64 break;
65 #endif
66 case 'R':
67 {
68 struct sockaddr_in *ip, *ip_fwd;
69 ip = (struct sockaddr_in *) &req->addr;
70 ip_fwd = (struct sockaddr_in *) &reply->addr;
71
72 if(ip->sin_addr.s_addr == ip_fwd->sin_addr.s_addr && strlen(reply->h_name) < 63)
73 {
74 rb_strlcpy(response, reply->h_name, sizeof(response));
75 status = 'O';
76 }
77 }
78 break;
79 #ifdef RB_IPV6
80 case 'S':
81 {
82 struct sockaddr_in6 *ip, *ip_fwd;
83 ip = (struct sockaddr_in6 *) &req->addr;
84 ip_fwd = (struct sockaddr_in6 *) &reply->addr;
85
86 if(memcmp(&ip->sin6_addr, &ip_fwd->sin6_addr, sizeof(struct in6_addr)) == 0 && strlen(reply->h_name) < 63)
87 {
88 rb_strlcpy(response, reply->h_name, sizeof(response));
89 status = 'O';
90 }
91 }
92 break;
93 #endif
94 default:
95 exit(7);
96 }
97
98 rb_helper_write(authd_helper, "E %s %c %c %s", req->reqid, status, req->type, response);
99 cleanup:
100 rb_free(req);
101 }
102
103 void
104 resolve_dns(int parc, char *parv[])
105 {
106 struct dns_request *req;
107 char *requestid = parv[1];
108 char *qtype = parv[2];
109 char *rec = parv[3];
110 int type;
111
112 req = rb_malloc(sizeof(*req));
113 rb_strlcpy(req->reqid, requestid, sizeof(req->reqid));
114 req->type = *qtype;
115
116 switch (req->type)
117 {
118 case '4':
119 type = T_A;
120 break;
121 case '6':
122 type = T_AAAA;
123 break;
124 case 'R':
125 case 'S':
126 if(!rb_inet_pton_sock(rec, (struct sockaddr *) &req->addr))
127 exit(6);
128 type = T_PTR;
129 break;
130 }
131
132 req->query.ptr = req;
133 req->query.callback = submit_dns_answer;
134
135 if (type != T_PTR)
136 gethost_byname_type(rec, &req->query, type);
137 else
138 gethost_byaddr(&req->addr, &req->query);
139 }
140
141 void
142 enumerate_nameservers(const char *rid, const char letter)
143 {
144 char buf[40 * IRCD_MAXNS]; /* Plenty */
145 char *c = buf;
146 int i;
147
148 if (!irc_nscount)
149 {
150 /* Shouldn't happen */
151 rb_helper_write(authd_helper, "X %s %c NONAMESERVERS", rid, letter);
152 return;
153 }
154
155 for(i = 0; i < irc_nscount; i++)
156 {
157 char addr[40];
158 int ret;
159
160 rb_inet_ntop_sock((struct sockaddr *)&irc_nsaddr_list[i], addr, sizeof(addr));
161
162 if (!addr[0])
163 {
164 /* Shouldn't happen */
165 rb_helper_write(authd_helper, "X %s %c INVALIDNAMESERVER", rid, letter);
166 return;
167 }
168
169 ret = snprintf(c, 40, "%s ", addr);
170 c += (size_t)ret;
171 }
172
173 *(--c) = '\0';
174
175 rb_helper_write(authd_helper, "Y %s %c %s", rid, letter, buf);
176 }