2 * This file is part of secnet.
3 * See README for full list of copyright holders.
5 * secnet is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version d of the License, or
8 * (at your option) any later version.
10 * secnet is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * version 3 along with secnet; if not, see
17 * https://www.gnu.org/licenses/gpl.html.
19 /* Name resolution using adns */
25 #error secnet requires ADNS version 1.0 or above
28 #include <arpa/inet.h>
34 struct resolver_if ops
;
44 resolve_answer_fn
*answer
;
48 static resolve_request_fn resolve_request
;
49 static bool_t
resolve_request(void *sst
, cstring_t name
,
50 int port
, struct comm_if
*comm
,
51 resolve_answer_fn
*cb
, void *cst
)
58 ADNS_ADDR2TEXT_BUFLEN
*2
63 ssize_t l
=strlen(name
);
64 if (name
[0]=='[' && l
<maxlitlen
&& l
>2 && name
[l
-1]==']') {
65 char trimmed
[maxlitlen
+1];
66 memcpy(trimmed
,name
+1,l
-2);
72 socklen_t salen
=sizeof(ca
.ia
);
73 rv
=adns_text2addr(trimmed
, port
, adns_qf_addrlit_ipv4_quadonly
,
78 snprintf(msg
,sizeof(msg
),"invalid address literal: %s",
81 cb(cst
,0,0,0,name
,msg
);
83 cb(cst
,&ca
,1,1,name
,0);
86 ca
.ia
.sin
.sin_family
=AF_INET
;
87 ca
.ia
.sin
.sin_port
=htons(port
);
88 if (inet_aton(trimmed
,&ca
.ia
.sin
.sin_addr
))
89 cb(cst
,&ca
,1,1,name
,0);
91 cb(cst
,0,0,0,name
,"invalid IP address");
103 rv
=adns_submit(st
->ast
, name
, adns_r_addr
, 0, q
, &q
->query
);
106 "resolver: failed to submit lookup for %s: %s",name
,
115 static int resolver_beforepoll(void *sst
, struct pollfd
*fds
, int *nfds_io
,
119 return adns_beforepoll(st
->ast
, fds
, nfds_io
, timeout_io
, tv_now
);
122 static void resolver_afterpoll(void *sst
, struct pollfd
*fds
, int nfds
)
131 adns_afterpoll(st
->ast
, fds
, nfds
, tv_now
);
135 rv
=adns_check(st
->ast
, &aq
, &ans
, &qp
);
138 if (ans
->status
!=adns_s_ok
) {
139 q
->answer(q
->cst
,NULL
,0,0,q
->name
,adns_strerror(ans
->status
));
143 int rslot
, wslot
, total
;
144 int ca_len
=MIN(ans
->nrrs
,MAX_PEER_ADDRS
);
145 struct comm_addr ca_buf
[ca_len
];
146 for (rslot
=0, wslot
=0, total
=0;
150 if (!(wslot
<ca_len
)) continue;
151 adns_rr_addr
*ra
=&ans
->rrs
.addr
[rslot
];
152 struct comm_addr
*ca
=&ca_buf
[wslot
];
155 assert(ra
->len
<= (int)sizeof(ca
->ia
));
156 memcpy(&ca
->ia
,&ra
->addr
,ra
->len
);
157 switch (ra
->addr
.sa
.sa_family
) {
159 assert(ra
->len
== sizeof(ca
->ia
.sin
));
160 ca
->ia
.sin
.sin_port
=htons(q
->port
);
164 assert(ra
->len
== sizeof(ca
->ia
.sin6
));
165 ca
->ia
.sin6
.sin6_port
=htons(q
->port
);
167 #endif /*CONFIG_IPV6*/
169 /* silently skip unexpected AFs from adns */
174 q
->answer(q
->cst
,ca_buf
,wslot
,total
,q
->name
,0);
178 } else if (rv
==EAGAIN
|| rv
==ESRCH
) {
181 fatal("resolver_afterpoll: adns_check() returned %d",rv
);
188 /* Initialise adns, using parameters supplied */
189 static list_t
*adnsresolver_apply(closure_t
*self
, struct cloc loc
,
190 dict_t
*context
, list_t
*args
)
198 st
->cl
.description
="adns";
199 st
->cl
.type
=CL_RESOLVER
;
201 st
->cl
.interface
=&st
->ops
;
204 st
->ops
.request
=resolve_request
;
207 if (!i
|| i
->type
!=t_dict
) {
208 cfgfatal(st
->loc
,"adns","first argument must be a dictionary\n");
211 conf
=dict_read_string(d
,"config",False
,"adns",loc
);
214 if (adns_init_strcfg(&st
->ast
, 0, 0, conf
)) {
215 fatal_perror("Failed to initialise ADNS");
218 if (adns_init(&st
->ast
, 0, 0)) {
219 fatal_perror("Failed to initialise ADNS");
223 register_for_poll(st
, resolver_beforepoll
, resolver_afterpoll
,
226 return new_closure(&st
->cl
);
229 void resolver_module(dict_t
*dict
)
231 add_closure(dict
,"adns",adnsresolver_apply
);