summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarsten Haitzler (Rasterman) <raster@rasterman.com>2016-05-22 17:03:26 +0900
committerCarsten Haitzler (Rasterman) <raster@rasterman.com>2016-05-24 09:20:49 +0900
commit1eba9d9de026d9ec28aa5b42457b144e437dbfe3 (patch)
treea081fc4b41fc3c79258425953fa4a5792924bc61
parent6e23780bb13fdc16a2034d01bf3fc06a2355fbee (diff)
ecore-con - simplify down to a single libc resolver
Summary: this removes the cares/ares based resolver and the compiled-in dns.c resolver, modified the getaddrinfo based resolver to use threads not forking (almost halving its size) and now makes that the only resolver we have. getaddrinfo handles ipv6 and ipv4 (according to docs). this simplifies code paths, drops code size of the efl tree by about 11k lines of code, makes it easier to test and more robust to future changes with ip resolving as it now just relies on libc. we won't have coverity complaints on dns.c imported code anymore to fix and don't have tokeep up with bugfixes/security from the upstream imported code. this means we use a single resolver on all platforms (windows, mac, linux) as opposed to before where cares was used for windows, and dns.c on linux/mac. oh and the forking original was broken since our move to eo too. so it couldnt even compile if enabled, letalone work. so fix bug with missing /etc/resolv.conf that dns.c couldn't cope with, fix testability, fix maintainability and reduce efl codebase size. this fixes T3668 @fix @improve Subscribers: cedric, seoz, jpeg Maniphest Tasks: T3668 Differential Revision: https://phab.enlightenment.org/D3971
-rw-r--r--configure.ac20
-rw-r--r--src/Makefile_Ecore_Con.am20
-rw-r--r--src/lib/ecore_con/ecore_con_ares.c635
-rw-r--r--src/lib/ecore_con/ecore_con_dns.c351
-rw-r--r--src/lib/ecore_con/ecore_con_info.c407
-rw-r--r--src/static_libs/dns/dns.c8701
-rw-r--r--src/static_libs/dns/dns.h1177
7 files changed, 130 insertions, 11181 deletions
diff --git a/configure.ac b/configure.ac
index a3753201a7..cae4e39594 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1732,6 +1732,7 @@ AC_CHECK_HEADERS([sys/socket.h])
1732 1732
1733AC_CHECK_HEADERS([ \ 1733AC_CHECK_HEADERS([ \
1734arpa/inet.h \ 1734arpa/inet.h \
1735arpa/nameser.h \
1735langinfo.h \ 1736langinfo.h \
1736features.h \ 1737features.h \
1737netinet/in.h \ 1738netinet/in.h \
@@ -2878,17 +2879,12 @@ want_ecore_con_local_sockets="yes"
2878want_ecore_con_abstract_sockets="yes" 2879want_ecore_con_abstract_sockets="yes"
2879 2880
2880if test "${have_win32}" = "yes"; then 2881if test "${have_win32}" = "yes"; then
2881 want_cares="yes"
2882 want_ecore_con_abstract_sockets="no" 2882 want_ecore_con_abstract_sockets="no"
2883elif test "${have_darwin}" = "yes"; then 2883elif test "${have_darwin}" = "yes"; then
2884 want_cares="no"
2885 want_ecore_con_abstract_sockets="yes" 2884 want_ecore_con_abstract_sockets="yes"
2886elif test "${have_ps3}" = "yes"; then 2885elif test "${have_ps3}" = "yes"; then
2887 want_cares="no"
2888 want_ecore_con_local_sockets="no" 2886 want_ecore_con_local_sockets="no"
2889 want_ecore_con_abstract_sockets="no" 2887 want_ecore_con_abstract_sockets="no"
2890else
2891 want_cares="no"
2892fi 2888fi
2893 2889
2894AC_DEFINE_IF([HAVE_LOCAL_SOCKETS], 2890AC_DEFINE_IF([HAVE_LOCAL_SOCKETS],
@@ -2914,24 +2910,10 @@ EFL_INTERNAL_DEPEND_PKG([ECORE_CON], [emile])
2914 2910
2915EFL_ADD_LIBS([ECORE_CON], [-lm]) 2911EFL_ADD_LIBS([ECORE_CON], [-lm])
2916 2912
2917EFL_OPTIONAL_DEPEND_PKG([ECORE_CON], [${want_cares}],
2918 [CARES], [libcares >= 1.6.1])
2919AM_CONDITIONAL([HAVE_CARES], [test "x${have_cares}" = "xyes"])
2920
2921if test "x$have_cares" = "xyes" ; then
2922 ecore_con_resolver="cares"
2923elif test "x$ac_cv_prog_cc_c99" != "xno" ; then
2924 ecore_con_resolver="dns.c"
2925else
2926 ecore_con_resolver="fork"
2927fi
2928
2929EFL_OPTIONAL_DEPEND_PKG([ECORE_CON], [${want_systemd}], [SYSTEMD], [libsystemd]) 2913EFL_OPTIONAL_DEPEND_PKG([ECORE_CON], [${want_systemd}], [SYSTEMD], [libsystemd])
2930 2914
2931EFL_ADD_FEATURE([ECORE_CON], [cares])
2932EFL_ADD_FEATURE([ECORE_CON], [local-sockets], [${want_ecore_con_local_sockets}]) 2915EFL_ADD_FEATURE([ECORE_CON], [local-sockets], [${want_ecore_con_local_sockets}])
2933EFL_ADD_FEATURE([ECORE_CON], [abstract-sockets], [${want_ecore_con_abstract_sockets}]) 2916EFL_ADD_FEATURE([ECORE_CON], [abstract-sockets], [${want_ecore_con_abstract_sockets}])
2934EFL_ADD_FEATURE([ECORE_CON], [resolver], [${ecore_con_resolver}])
2935EFL_ADD_FEATURE([ECORE_CON], [systemd-daemon], [${want_systemd}]) 2917EFL_ADD_FEATURE([ECORE_CON], [systemd-daemon], [${want_systemd}])
2936 2918
2937EFL_EVAL_PKGS([ECORE_CON]) 2919EFL_EVAL_PKGS([ECORE_CON])
diff --git a/src/Makefile_Ecore_Con.am b/src/Makefile_Ecore_Con.am
index 266e7b4f74..d68a777951 100644
--- a/src/Makefile_Ecore_Con.am
+++ b/src/Makefile_Ecore_Con.am
@@ -51,7 +51,8 @@ lib/ecore_con/ecore_con_url_curl.c \
51lib/ecore_con/ecore_con_url_curl.h \ 51lib/ecore_con/ecore_con_url_curl.h \
52static_libs/http-parser/http_parser.c \ 52static_libs/http-parser/http_parser.c \
53static_libs/http-parser/http_parser.h \ 53static_libs/http-parser/http_parser.h \
54lib/ecore_con/ecore_con_private.h 54lib/ecore_con/ecore_con_private.h \
55lib/ecore_con/ecore_con_info.c
55 56
56EXTRA_DIST += lib/ecore_con/ecore_con_legacy.c 57EXTRA_DIST += lib/ecore_con/ecore_con_legacy.c
57 58
@@ -61,19 +62,6 @@ else
61lib_ecore_con_libecore_con_la_SOURCES += lib/ecore_con/ecore_con_local.c 62lib_ecore_con_libecore_con_la_SOURCES += lib/ecore_con/ecore_con_local.c
62endif 63endif
63 64
64if HAVE_CARES
65lib_ecore_con_libecore_con_la_SOURCES += lib/ecore_con/ecore_con_ares.c
66else
67if HAVE_IPV6
68lib_ecore_con_libecore_con_la_SOURCES += \
69lib/ecore_con/ecore_con_dns.c \
70static_libs/dns/dns.c \
71static_libs/dns/dns.h
72else
73lib_ecore_con_libecore_con_la_SOURCES += lib/ecore_con/ecore_con_info.c
74endif
75endif
76
77lib_ecore_con_libecore_con_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl @ECORE_CON_CFLAGS@ 65lib_ecore_con_libecore_con_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl @ECORE_CON_CFLAGS@
78lib_ecore_con_libecore_con_la_LIBADD = @ECORE_CON_LIBS@ @EVIL_LIBS@ 66lib_ecore_con_libecore_con_la_LIBADD = @ECORE_CON_LIBS@ @EVIL_LIBS@
79lib_ecore_con_libecore_con_la_DEPENDENCIES = @ECORE_CON_INTERNAL_LIBS@ 67lib_ecore_con_libecore_con_la_DEPENDENCIES = @ECORE_CON_INTERNAL_LIBS@
@@ -81,10 +69,6 @@ lib_ecore_con_libecore_con_la_LDFLAGS = @EFL_LTLIBRARY_FLAGS@
81 69
82lib_ecore_con_libecore_con_la_CPPFLAGS += -I$(top_srcdir)/src/static_libs/http-parser 70lib_ecore_con_libecore_con_la_CPPFLAGS += -I$(top_srcdir)/src/static_libs/http-parser
83 71
84if HAVE_IPV6
85lib_ecore_con_libecore_con_la_CPPFLAGS += -I$(top_srcdir)/src/static_libs/dns/
86endif
87
88EXTRA_DIST += \ 72EXTRA_DIST += \
89tests/ecore_con/server.key \ 73tests/ecore_con/server.key \
90tests/ecore_con/server.pem \ 74tests/ecore_con/server.pem \
diff --git a/src/lib/ecore_con/ecore_con_ares.c b/src/lib/ecore_con/ecore_con_ares.c
deleted file mode 100644
index e3d37798b1..0000000000
--- a/src/lib/ecore_con/ecore_con_ares.c
+++ /dev/null
@@ -1,635 +0,0 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5/*
6 * This version of ecore_con_info use c-ares to provide asynchronous dns lookup.
7 *
8 * Note: It doesn't fork nor does it use libc getaddrinfo.
9 * http://c-ares.haxx.se/docs.html
10 */
11
12#include <string.h>
13#include <sys/types.h>
14
15#ifdef HAVE_NETINET_IN_H
16# include <netinet/in.h>
17#endif
18
19#ifdef HAVE_ARPA_INET_H
20# include <arpa/inet.h>
21#endif
22
23#include <ares.h>
24
25#include "Ecore.h"
26#include "Ecore_Con.h"
27#include "ecore_con_private.h"
28
29typedef struct _Ecore_Con_FD Ecore_Con_FD;
30typedef struct _Ecore_Con_CAres Ecore_Con_CAres;
31
32struct _Ecore_Con_FD
33{
34 Ecore_Fd_Handler *handler;
35 Ecore_Timer *timer;
36 int fd;
37};
38
39struct _Ecore_Con_CAres
40{
41 Ecore_Con_Server *svr;
42 Ecore_Con_Info_Cb done_cb;
43 void *data;
44 struct addrinfo hints;
45 Ecore_Con_Info *result;
46
47 union
48 {
49 struct in_addr v4;
50#ifdef HAVE_IPV6
51 struct in6_addr v6;
52#endif
53 } addr;
54
55 Eina_Bool byaddr : 1;
56 Eina_Bool isv6 : 1;
57};
58
59static ares_channel info_channel;
60static int info_init = 0;
61static Eina_List *info_fds = NULL;
62
63static void _ecore_con_info_ares_nameinfo(Ecore_Con_CAres *arg,
64 int status,
65 int timeouts,
66 char *node,
67 char *service);
68static void _ecore_con_info_ares_host_cb(Ecore_Con_CAres *arg,
69 int status,
70 int timeouts,
71 struct hostent *hostent);
72static Eina_Bool _ecore_con_info_cares_fd_cb(Ecore_Con_FD *ecf,
73 Ecore_Fd_Handler *fd_handler);
74static Eina_Bool _ecore_con_info_cares_timeout_cb(void *data);
75
76static void
77 _ecore_con_info_cares_state_cb(void *data,
78 ares_socket_t fd,
79 int readable,
80 int writable);
81static int
82 _ecore_con_info_fds_search(const Ecore_Con_FD *fd1,
83 const Ecore_Con_FD *fd2);
84
85int
86ecore_con_info_init(void)
87{
88 struct ares_options opts;
89
90 if (!info_init)
91 {
92 if (ares_library_init(ARES_LIB_INIT_ALL))
93 return 0;
94
95 opts.lookups = "fb"; /* hosts file then dns */
96 opts.sock_state_cb = _ecore_con_info_cares_state_cb;
97
98 if (ares_init_options(&info_channel, &opts,
99 ARES_OPT_LOOKUPS | ARES_OPT_SOCK_STATE_CB) != ARES_SUCCESS)
100 {
101 ares_library_cleanup();
102 return 0;
103 }
104 }
105
106 info_init++;
107 return info_init;
108}
109
110int
111ecore_con_info_shutdown(void)
112{
113 info_init--;
114 if (info_init == 0)
115 {
116 /* Cancel all ongoing request */
117 ares_cancel(info_channel);
118 ares_destroy(info_channel);
119
120 /* Shutdown ares */
121 ares_library_cleanup();
122 }
123
124 return info_init;
125}
126
127int
128ecore_con_info_tcp_connect(Ecore_Con_Server *svr,
129 Ecore_Con_Info_Cb done_cb,
130 void *data)
131{
132 struct addrinfo hints;
133
134 memset(&hints, 0, sizeof(struct addrinfo));
135#ifdef HAVE_IPV6
136 hints.ai_family = AF_INET6;
137#else
138 hints.ai_family = AF_INET;
139#endif
140 hints.ai_socktype = SOCK_STREAM;
141 hints.ai_flags = AI_CANONNAME;
142 hints.ai_protocol = IPPROTO_TCP;
143 hints.ai_canonname = NULL;
144 hints.ai_next = NULL;
145 hints.ai_addr = NULL;
146
147 return ecore_con_info_get(svr, done_cb, data, &hints);
148}
149
150int
151ecore_con_info_tcp_listen(Ecore_Con_Server *svr,
152 Ecore_Con_Info_Cb done_cb,
153 void *data)
154{
155 struct addrinfo hints;
156
157 memset(&hints, 0, sizeof(struct addrinfo));
158#ifdef HAVE_IPV6
159 hints.ai_family = AF_INET6;
160#else
161 hints.ai_family = AF_INET;
162#endif
163 hints.ai_socktype = SOCK_STREAM;
164 hints.ai_flags = AI_PASSIVE;
165 hints.ai_protocol = IPPROTO_TCP;
166 hints.ai_canonname = NULL;
167 hints.ai_next = NULL;
168 hints.ai_addr = NULL;
169
170 return ecore_con_info_get(svr, done_cb, data, &hints);
171}
172
173int
174ecore_con_info_udp_connect(Ecore_Con_Server *svr,
175 Ecore_Con_Info_Cb done_cb,
176 void *data)
177{
178 struct addrinfo hints;
179
180 memset(&hints, 0, sizeof(struct addrinfo));
181#ifdef HAVE_IPV6
182 hints.ai_family = AF_INET6;
183#else
184 hints.ai_family = AF_INET;
185#endif
186 hints.ai_socktype = SOCK_DGRAM;
187 hints.ai_flags = AI_CANONNAME;
188 hints.ai_protocol = IPPROTO_UDP;
189 hints.ai_canonname = NULL;
190 hints.ai_next = NULL;
191 hints.ai_addr = NULL;
192
193 return ecore_con_info_get(svr, done_cb, data, &hints);
194}
195
196int
197ecore_con_info_udp_listen(Ecore_Con_Server *svr,
198 Ecore_Con_Info_Cb done_cb,
199 void *data)
200{
201 struct addrinfo hints;
202
203 memset(&hints, 0, sizeof(struct addrinfo));
204#ifdef HAVE_IPV6
205 hints.ai_family = AF_INET6;
206#else
207 hints.ai_family = AF_INET;
208#endif
209 hints.ai_socktype = SOCK_DGRAM;
210 hints.ai_flags = AI_PASSIVE;
211 hints.ai_protocol = IPPROTO_UDP;
212 hints.ai_canonname = NULL;
213 hints.ai_next = NULL;
214 hints.ai_addr = NULL;
215
216 return ecore_con_info_get(svr, done_cb, data, &hints);
217}
218
219int
220ecore_con_info_mcast_listen(Ecore_Con_Server *svr,
221 Ecore_Con_Info_Cb done_cb,
222 void *data)
223{
224 struct addrinfo hints;
225
226 memset(&hints, 0, sizeof(struct addrinfo));
227#ifdef HAVE_IPV6
228 hints.ai_family = AF_INET6;
229#else
230 hints.ai_family = AF_INET;
231#endif
232 hints.ai_socktype = SOCK_DGRAM;
233 hints.ai_flags = 0;
234 hints.ai_protocol = IPPROTO_UDP;
235 hints.ai_canonname = NULL;
236 hints.ai_next = NULL;
237 hints.ai_addr = NULL;
238
239 return ecore_con_info_get(svr, done_cb, data, &hints);
240}
241
242static Eina_Bool
243_ecore_con_info_ares_getnameinfo(Ecore_Con_CAres *arg,
244 int addrtype,
245 const char *name,
246 struct sockaddr *addr,
247 int addrlen)
248{
249 int length = 0;
250
251 if (name)
252 length = strlen(name) + 1;
253 else
254 length = 1;
255
256 arg->result = malloc(sizeof(Ecore_Con_Info) + length);
257 if (!arg->result)
258 return EINA_FALSE;
259
260 /* FIXME: What to do when hint is not set ? */
261 arg->result->info.ai_flags = arg->hints.ai_flags;
262 arg->result->info.ai_socktype = arg->hints.ai_socktype;
263 arg->result->info.ai_protocol = arg->hints.ai_protocol;
264
265 arg->result->info.ai_family = addrtype;
266 arg->result->info.ai_addrlen = addrlen;
267 arg->result->info.ai_addr = addr;
268 arg->result->info.ai_canonname = (char *)(arg->result + 1);
269
270 if (!name)
271 *arg->result->info.ai_canonname = '\0';
272 else
273 strcpy(arg->result->info.ai_canonname, name);
274
275 arg->result->info.ai_next = NULL;
276
277 ares_getnameinfo(
278 info_channel, addr, addrlen,
279 ARES_NI_NUMERICSERV | ARES_NI_NUMERICHOST |
280 ARES_NI_LOOKUPSERVICE | ARES_NI_LOOKUPHOST,
281 (ares_nameinfo_callback)_ecore_con_info_ares_nameinfo, arg);
282
283 return EINA_TRUE;
284}
285
286EAPI int
287ecore_con_info_get(Ecore_Con_Server *obj,
288 Ecore_Con_Info_Cb done_cb,
289 void *data,
290 struct addrinfo *hints)
291{
292 Efl_Network_Server_Data *svr = eo_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS);
293 Ecore_Con_CAres *cares;
294#ifdef HAVE_IPV6
295 int ai_family = AF_INET6;
296#else
297 int ai_family = AF_INET;
298#endif
299
300 cares = calloc(1, sizeof(Ecore_Con_CAres));
301 if (!cares)
302 return 0;
303
304 cares->svr = obj;
305 cares->done_cb = done_cb;
306 cares->data = data;
307
308 if (hints)
309 {
310 ai_family = hints->ai_family;
311 memcpy(&cares->hints, hints, sizeof(struct addrinfo));
312 }
313
314 if (inet_pton(AF_INET, svr->ecs ? svr->ecs->ip : svr->name, &cares->addr.v4) == 1)
315 {
316 cares->byaddr = EINA_TRUE;
317 cares->isv6 = EINA_FALSE;
318 ares_gethostbyaddr(info_channel, &cares->addr.v4,
319 sizeof(cares->addr.v4),
320 AF_INET,
321 (ares_host_callback)_ecore_con_info_ares_host_cb,
322 cares);
323 }
324#ifdef HAVE_IPV6
325 else if (inet_pton(AF_INET6, svr->ecs ? svr->ecs->ip : svr->name, &cares->addr.v6) == 1)
326 {
327 cares->byaddr = EINA_TRUE;
328 cares->isv6 = EINA_TRUE;
329 ares_gethostbyaddr(info_channel, &cares->addr.v6,
330 sizeof(cares->addr.v6),
331 AF_INET6,
332 (ares_host_callback)_ecore_con_info_ares_host_cb,
333 cares);
334 }
335#endif
336 else
337 {
338 cares->byaddr = EINA_FALSE;
339 ares_gethostbyname(info_channel, svr->ecs ? svr->ecs->ip : svr->name, ai_family,
340 (ares_host_callback)_ecore_con_info_ares_host_cb,
341 cares);
342 }
343
344 svr->infos = eina_list_append(svr->infos, cares);
345 return 1;
346}
347
348void
349ecore_con_info_data_clear(void *info)
350{
351 Ecore_Con_CAres *cares = info;
352 if (cares) cares->data = NULL;
353}
354
355static Eina_Bool
356_ecore_con_info_cares_timeout_cb(void *data EINA_UNUSED)
357{
358 ares_process_fd(info_channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
359 return ECORE_CALLBACK_RENEW;
360}
361
362static Eina_Bool
363_ecore_con_info_cares_fd_cb(Ecore_Con_FD *ecf,
364 Ecore_Fd_Handler *fd_handler)
365{
366 ares_socket_t read_fd, write_fd;
367
368 read_fd = write_fd = ARES_SOCKET_BAD;
369
370 if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ))
371 read_fd = ecf->fd;
372 if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_WRITE))
373 write_fd = ecf->fd;
374
375 ares_process_fd(info_channel, read_fd, write_fd);
376
377 return ECORE_CALLBACK_RENEW;
378}
379
380static int
381_ecore_con_info_fds_search(const Ecore_Con_FD *fd1,
382 const Ecore_Con_FD *fd2)
383{
384 return fd1->fd - fd2->fd;
385}
386
387static void
388_ecore_con_info_cares_state_cb(void *data EINA_UNUSED,
389 ares_socket_t fd,
390 int readable,
391 int writable)
392{
393 int flags = 0;
394 Ecore_Con_FD *search = NULL, *ecf = NULL;
395
396 search = eina_list_search_unsorted(info_fds,
397 (Eina_Compare_Cb)_ecore_con_info_fds_search, &ecf);
398
399 if (!(readable | writable))
400 {
401 ares_process_fd(info_channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
402 if (search)
403 {
404 info_fds = eina_list_remove(info_fds, search);
405 ecore_timer_del(search->timer);
406 ecore_main_fd_handler_del(search->handler);
407 free(search);
408 }
409 return;
410 }
411
412 if (!search)
413 {
414 search = malloc(sizeof(Ecore_Con_FD));
415 EINA_SAFETY_ON_NULL_RETURN(search);
416
417 search->fd = fd;
418 search->handler = ecore_main_fd_handler_add(fd, ECORE_FD_WRITE | ECORE_FD_READ,
419 (Ecore_Fd_Cb)_ecore_con_info_cares_fd_cb, search, NULL, NULL);
420 /* c-ares default timeout is 5 seconds */
421 search->timer = ecore_timer_add(5, _ecore_con_info_cares_timeout_cb, NULL);
422 info_fds = eina_list_append(info_fds, search);
423 }
424
425 if (readable) flags |= ECORE_FD_READ;
426 if (writable) flags |= ECORE_FD_WRITE;
427 ecore_main_fd_handler_active_set(search->handler, flags);
428}
429
430static void
431_ecore_con_info_ares_host_cb(Ecore_Con_CAres *arg,
432 int status,
433 int timeouts EINA_UNUSED,
434 struct hostent *hostent)
435{
436 struct sockaddr *addr;
437 Efl_Network_Server_Data *svr;
438 int addrlen;
439
440 svr = eo_data_scope_get(arg->svr, EFL_NETWORK_SERVER_CLASS);
441
442 /* Found something ? */
443 switch (status)
444 {
445 case ARES_SUCCESS:
446 if (!hostent->h_addr_list[0])
447 {
448 ERR("No IP found");
449 goto on_error;
450 }
451
452 switch (hostent->h_addrtype)
453 {
454 case AF_INET:
455 {
456 struct sockaddr_in *addri;
457
458 addrlen = sizeof(struct sockaddr_in);
459 addri = malloc(addrlen);
460
461 if (!addri)
462 goto on_mem_error;
463
464 addri->sin_family = AF_INET;
465 addri->sin_port = htons(svr->ecs ? svr->ecs->port : svr->port);
466
467 memcpy(&addri->sin_addr.s_addr,
468 hostent->h_addr_list[0], sizeof(struct in_addr));
469
470 addr = (struct sockaddr *)addri;
471 break;
472 }
473
474#ifdef HAVE_IPV6
475 case AF_INET6:
476 {
477 struct sockaddr_in6 *addri6;
478
479 addrlen = sizeof(struct sockaddr_in6);
480 addri6 = malloc(addrlen);
481
482 if (!addri6)
483 goto on_mem_error;
484
485 addri6->sin6_family = AF_INET6;
486 addri6->sin6_port = htons(svr->ecs ? svr->ecs->port : svr->port);
487 addri6->sin6_flowinfo = 0;
488 addri6->sin6_scope_id = 0;
489
490 memcpy(&addri6->sin6_addr.s6_addr,
491 hostent->h_addr_list[0], sizeof(struct in6_addr));
492
493 addr = (struct sockaddr *)addri6;
494 break;
495 }
496
497#endif
498 default:
499 ERR("Unknown addrtype %i", hostent->h_addrtype);
500 goto on_error;
501 }
502
503 if (!_ecore_con_info_ares_getnameinfo(arg, hostent->h_addrtype,
504 hostent->h_name,
505 addr, addrlen))
506 goto on_error;
507
508 break;
509
510 case ARES_ENOTFOUND: /* address notfound */
511 if (arg->byaddr)
512 {
513#ifdef HAVE_IPV6
514 /* This happen when host doesn't have a reverse. */
515 if (arg->isv6)
516 {
517 struct sockaddr_in6 *addri6;
518
519 addrlen = sizeof(struct sockaddr_in6);
520 addri6 = malloc(addrlen);
521
522 if (!addri6)
523 goto on_mem_error;
524
525 addri6->sin6_family = AF_INET6;
526 addri6->sin6_port = htons(svr->ecs ? svr->ecs->port : svr->port);
527 addri6->sin6_flowinfo = 0;
528 addri6->sin6_scope_id = 0;
529
530 memcpy(&addri6->sin6_addr.s6_addr,
531 &arg->addr.v6, sizeof(struct in6_addr));
532
533 addr = (struct sockaddr *)addri6;
534 }
535 else
536#endif
537 {
538 struct sockaddr_in *addri;
539
540 addrlen = sizeof(struct sockaddr_in);
541 addri = malloc(addrlen);
542
543 if (!addri)
544 goto on_mem_error;
545
546 addri->sin_family = AF_INET;
547 addri->sin_port = htons(svr->ecs ? svr->ecs->port : svr->port);
548
549 memcpy(&addri->sin_addr.s_addr,
550 &arg->addr.v4, sizeof(struct in_addr));
551
552 addr = (struct sockaddr *)addri;
553 }
554
555 if (!_ecore_con_info_ares_getnameinfo(arg,
556#ifdef HAVE_IPV6
557 arg->isv6 ? AF_INET6 :
558#endif
559 AF_INET,
560 NULL, addr,
561 addrlen))
562 goto on_error;
563
564 break;
565 }
566
567 case ARES_ENOTIMP: /* unknown family */
568 case ARES_EBADNAME: /* not a valid internet address */
569 case ARES_ENOMEM: /* not enough memory */
570 case ARES_EDESTRUCTION: /* request canceled, shuting down */
571 case ARES_ENODATA: /* no data returned */
572 case ARES_ECONNREFUSED: /* connection refused */
573 case ARES_ETIMEOUT: /* connection timed out */
574 ecore_con_event_server_error(arg->svr, ares_strerror(status));
575 goto on_error;
576
577 default:
578 ERR("Unknown status returned by c-ares: %i assuming error", status);
579 ecore_con_event_server_error(arg->svr, ares_strerror(status));
580 goto on_error;
581 }
582
583 return;
584
585on_mem_error:
586 ERR("Not enough memory");
587
588on_error:
589 if (arg->data)
590 {
591 ecore_con_server_infos_del(arg->data, arg);
592 arg->done_cb(arg->data, NULL);
593 }
594 free(arg);
595}
596
597static void
598_ecore_con_info_ares_nameinfo(Ecore_Con_CAres *arg,
599 int status,
600 int timeouts EINA_UNUSED,
601 char *node,
602 char *service)
603{
604 switch (status)
605 {
606 case ARES_SUCCESS:
607 if (node)
608 strcpy(arg->result->ip, node);
609 else
610 *arg->result->ip = '\0';
611
612 if (service)
613 strcpy(arg->result->service, service);
614 else
615 *arg->result->service = '\0';
616
617 if (arg->data) arg->done_cb(arg->data, arg->result);
618 break;
619
620 case ARES_ENOTIMP:
621 case ARES_ENOTFOUND:
622 case ARES_ENOMEM:
623 case ARES_EDESTRUCTION:
624 case ARES_EBADFLAGS:
625 ecore_con_event_server_error(arg->svr, ares_strerror(status));
626 if (arg->data) arg->done_cb(arg->data, NULL);
627 break;
628 }
629
630 free(arg->result->info.ai_addr);
631 free(arg->result);
632 if (arg->data) ecore_con_server_infos_del(arg->data, arg);
633 free(arg);
634}
635
diff --git a/src/lib/ecore_con/ecore_con_dns.c b/src/lib/ecore_con/ecore_con_dns.c
deleted file mode 100644
index e1a4cc5f33..0000000000
--- a/src/lib/ecore_con/ecore_con_dns.c
+++ /dev/null
@@ -1,351 +0,0 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5/*
6 * This version of ecore_con_info uses dns.c to provide asynchronous dns lookup.
7 *
8 * dns.c is written by William Ahern:
9 * http://25thandclement.com/~william/projects/dns.c.html
10 */
11
12#include <string.h>
13#include <sys/types.h>
14#include <errno.h> /* for EAGAIN */
15#include <netinet/in.h>
16#include <arpa/inet.h>
17
18#include "dns.h"
19
20#include "Ecore.h"
21#include "Ecore_Con.h"
22#include "ecore_con_private.h"
23
24typedef struct dns_addrinfo dns_addrinfo;
25typedef struct dns_resolv_conf dns_resolv_conf;
26typedef struct dns_resolver dns_resolver;
27typedef struct dns_hosts dns_hosts;
28
29typedef struct _Ecore_Con_DNS Ecore_Con_DNS;
30
31struct _Ecore_Con_DNS
32{
33 Ecore_Con_Server *svr;
34 Ecore_Con_Info_Cb done_cb;
35 void *data;
36 dns_addrinfo *ai;
37 dns_resolver *resolv;
38 struct addrinfo hints;
39 Ecore_Fd_Handler *fdh;
40 Ecore_Timer *timer;
41};
42
43static int _ecore_con_dns_init = 0;
44static dns_resolv_conf *resconf = NULL;
45static dns_hosts *hosts = NULL;
46
47static void
48_ecore_con_dns_free(Ecore_Con_DNS *dns)
49{
50 if (dns->timer) ecore_timer_del(dns->timer);
51 if (dns->fdh) ecore_main_fd_handler_del(dns->fdh);
52 if (dns->ai) dns_ai_close(dns->ai);
53 dns_res_close(dns_res_mortal(dns->resolv));
54 free(dns);
55}
56
57static void
58_ecore_con_dns_del(Ecore_Con_DNS *dns)
59{
60 if (dns->svr)
61 {
62 Efl_Network_Server_Data *svr;
63
64 svr = eo_data_scope_get(dns->svr, EFL_NETWORK_CLIENT_CLASS);
65 if ((svr) && (svr->infos))
66 svr->infos = eina_list_remove(svr->infos, dns);
67 }
68 _ecore_con_dns_free(dns);
69}
70
71static Eina_Bool
72_dns_addrinfo_get(Ecore_Con_DNS *dns, const char *addr, int port)
73{
74 int error = 0;
75 char service[NI_MAXSERV];
76
77 snprintf(service, sizeof(service), "%d", port);
78 dns->ai = dns_ai_open(addr, service, DNS_T_A, (const struct addrinfo *)&dns->hints, dns->resolv, &error);
79 return error;
80}
81
82static int
83_ecore_con_dns_check(Ecore_Con_DNS *dns)
84{
85 struct addrinfo *ent = NULL;
86 int error = 0;
87
88 error = dns_ai_nextent(&ent, dns->ai);
89
90 switch (error)
91 {
92 case 0:
93 break;
94
95 case EAGAIN:
96 return 1;
97
98 default:
99 DBG("resolve failed: %s", dns_strerror(error));
100 goto error;
101 }
102
103 {
104 Ecore_Con_Info result = {0, .ip = {0}, .service = {0}};
105#if 0
106 char pretty[512];
107 dns_ai_print(pretty, sizeof(pretty), ent, dns->ai);
108 printf("%s\n", pretty);
109#endif
110 result.size = 0;
111 dns_inet_ntop(dns_sa_family(ent->ai_addr), dns_sa_addr(dns_sa_family(ent->ai_addr), ent->ai_addr), result.ip, sizeof(result.ip));
112 snprintf(result.service, sizeof(result.service), "%u", ntohs(*dns_sa_port(dns_sa_family(ent->ai_addr), ent->ai_addr)));
113 memcpy(&result.info, ent, sizeof(result.info));
114 if (dns->fdh) ecore_main_fd_handler_del(dns->fdh);
115 dns->fdh = NULL;
116 dns->done_cb(dns->data, &result);
117 free(ent);
118 _ecore_con_dns_del(dns);
119 }
120
121 return 0;
122error:
123 dns->done_cb(dns->data, NULL);
124 _ecore_con_dns_del(dns);
125 return -1;
126}
127
128static Eina_Bool
129_dns_fd_cb(Ecore_Con_DNS *dns, Ecore_Fd_Handler *fdh EINA_UNUSED)
130{
131 if (_ecore_con_dns_check(dns) != 1) return ECORE_CALLBACK_RENEW;
132 if (ecore_main_fd_handler_fd_get(dns->fdh) != dns_ai_pollfd(dns->ai))
133 {
134 ecore_main_fd_handler_del(dns->fdh);
135 dns->fdh = ecore_main_fd_handler_add(dns_ai_pollfd(dns->ai), dns_ai_events(dns->ai), (Ecore_Fd_Cb)_dns_fd_cb, dns, NULL, NULL);
136 }
137 else
138 ecore_main_fd_handler_active_set(dns->fdh, dns_ai_events(dns->ai));
139 return ECORE_CALLBACK_RENEW;
140}
141
142static Eina_Bool
143_dns_timer_cb(Ecore_Con_DNS *dns)
144{
145 dns->done_cb(dns->data, NULL);
146 _ecore_con_dns_del(dns);
147 return EINA_FALSE;
148}
149
150int
151ecore_con_info_init(void)
152{
153 int err;
154 if (_ecore_con_dns_init) return ++_ecore_con_dns_init;
155
156 resconf = dns_resconf_local(&err);
157 if (!resconf)
158 {
159 ERR("resconf_open: %s", dns_strerror(err));
160 return 0;
161 }
162 hosts = dns_hosts_local(&err);
163 if (!hosts)
164 {
165 ERR("hosts_open: %s", dns_strerror(err));
166 dns_resconf_close(resconf);
167 resconf = NULL;
168 return 0;
169 }
170 /* this is super slow don't do it */
171 //resconf->options.recurse = 1;
172 return ++_ecore_con_dns_init;
173}
174
175int
176ecore_con_info_shutdown(void)
177{
178 if (!_ecore_con_dns_init) return 0;
179 if (--_ecore_con_dns_init) return _ecore_con_dns_init;
180 dns_resconf_close(resconf);
181 resconf = NULL;
182 dns_hosts_close(hosts);
183 hosts = NULL;
184 return 0;
185}
186
187void
188ecore_con_info_data_clear(void *info)
189{
190 if (info)
191 _ecore_con_dns_free(info);
192}
193
194int
195ecore_con_info_tcp_connect(Ecore_Con_Server *svr,
196 Ecore_Con_Info_Cb done_cb,
197 void *data)
198{
199 struct addrinfo hints;
200
201 memset(&hints, 0, sizeof(struct addrinfo));
202#ifdef HAVE_IPV6
203 hints.ai_family = AF_INET6;
204#else
205 hints.ai_family = AF_INET;
206#endif
207 hints.ai_socktype = SOCK_STREAM;
208 hints.ai_flags = AI_CANONNAME;
209 hints.ai_protocol = IPPROTO_TCP;
210
211 return ecore_con_info_get(svr, done_cb, data, &hints);
212}
213
214int
215ecore_con_info_tcp_listen(Ecore_Con_Server *svr,
216 Ecore_Con_Info_Cb done_cb,
217 void *data)
218{
219 struct addrinfo hints;
220
221 memset(&hints, 0, sizeof(struct addrinfo));
222#ifdef HAVE_IPV6
223 hints.ai_family = AF_INET6;
224#else
225 hints.ai_family = AF_INET;
226#endif
227 hints.ai_socktype = SOCK_STREAM;
228 hints.ai_flags = AI_PASSIVE;
229 hints.ai_protocol = IPPROTO_TCP;
230
231 return ecore_con_info_get(svr, done_cb, data, &hints);
232}
233
234int
235ecore_con_info_udp_connect(Ecore_Con_Server *svr,
236 Ecore_Con_Info_Cb done_cb,
237 void *data)
238{
239 struct addrinfo hints;
240
241 memset(&hints, 0, sizeof(struct addrinfo));
242#ifdef HAVE_IPV6
243 hints.ai_family = AF_INET6;
244#else
245 hints.ai_family = AF_INET;
246#endif
247 hints.ai_socktype = SOCK_DGRAM;
248 hints.ai_flags = AI_CANONNAME;
249 hints.ai_protocol = IPPROTO_UDP;
250
251 return ecore_con_info_get(svr, done_cb, data, &hints);
252}
253
254int
255ecore_con_info_udp_listen(Ecore_Con_Server *svr,
256 Ecore_Con_Info_Cb done_cb,
257 void *data)
258{
259 struct addrinfo hints;
260
261 memset(&hints, 0, sizeof(struct addrinfo));
262#ifdef HAVE_IPV6
263 hints.ai_family = AF_INET6;
264#else
265 hints.ai_family = AF_INET;
266#endif
267 hints.ai_socktype = SOCK_DGRAM;
268 hints.ai_flags = AI_PASSIVE;
269 hints.ai_protocol = IPPROTO_UDP;
270
271 return ecore_con_info_get(svr, done_cb, data, &hints);
272}
273
274int
275ecore_con_info_mcast_listen(Ecore_Con_Server *svr,
276 Ecore_Con_Info_Cb done_cb,
277 void *data)
278{
279 struct addrinfo hints;
280
281 memset(&hints, 0, sizeof(struct addrinfo));
282#ifdef HAVE_IPV6
283 hints.ai_family = AF_INET6;
284#else
285 hints.ai_family = AF_INET;
286#endif
287 hints.ai_socktype = SOCK_DGRAM;
288 hints.ai_protocol = IPPROTO_UDP;
289
290 return ecore_con_info_get(svr, done_cb, data, &hints);
291}
292
293EAPI int
294ecore_con_info_get(Ecore_Con_Server *obj,
295 Ecore_Con_Info_Cb done_cb,
296 void *data,
297 struct addrinfo *hints)
298{
299 Efl_Network_Server_Data *svr = eo_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS);
300 Ecore_Con_DNS *dns;
301 int error = 0;
302
303 if (!svr)
304 return 0;
305
306 dns = calloc(1, sizeof(Ecore_Con_DNS));
307 if (!dns) return 0;
308
309 dns->svr = obj;
310 dns->done_cb = done_cb;
311 dns->data = data;
312
313 if (hints)
314 memcpy(&dns->hints, hints, sizeof(struct addrinfo));
315
316 if (!(dns->resolv = dns_res_open(resconf, hosts, dns_hints_mortal(dns_hints_local(resconf, &error)), NULL, dns_opts(), &error)))
317 {
318 ERR("res_open: %s", dns_strerror(error));
319 goto reserr;
320 }
321
322 error = _dns_addrinfo_get(dns, svr->ecs ? svr->ecs->ip : svr->name, svr->ecs ? svr->ecs->port : svr->port);
323 if (error && (error != EAGAIN))
324 {
325 ERR("resolver: %s", dns_strerror(error));
326 goto seterr;
327 }
328
329 switch (_ecore_con_dns_check(dns))
330 {
331 case 0:
332 break;
333
334 case 1:
335 dns->fdh = ecore_main_fd_handler_add(dns_ai_pollfd(dns->ai), dns_ai_events(dns->ai), (Ecore_Fd_Cb)_dns_fd_cb, dns, NULL, NULL);
336 svr->infos = eina_list_append(svr->infos, dns);
337 dns->timer = ecore_timer_add(5.0, (Ecore_Task_Cb)_dns_timer_cb, dns);
338 break;
339
340 default:
341 return 0;
342 }
343
344 return 1;
345seterr:
346 if (dns->resolv) dns_res_close(dns_res_mortal(dns->resolv));
347reserr:
348 free(dns);
349 return 0;
350}
351
diff --git a/src/lib/ecore_con/ecore_con_info.c b/src/lib/ecore_con/ecore_con_info.c
index c89ad24e6a..d70eb064cc 100644
--- a/src/lib/ecore_con/ecore_con_info.c
+++ b/src/lib/ecore_con/ecore_con_info.c
@@ -23,14 +23,21 @@
23#include <unistd.h> 23#include <unistd.h>
24#include <fcntl.h> 24#include <fcntl.h>
25#include <ctype.h> 25#include <ctype.h>
26#include <sys/socket.h> 26#ifdef HAVE_SYS_SOCKET_H
27# include <sys/socket.h>
28#endif
27#ifdef __OpenBSD__ 29#ifdef __OpenBSD__
28# include <sys/types.h> 30# include <sys/types.h>
29#endif 31#endif
30#include <netinet/in.h> 32#ifdef HAVE_NETINET_IN_H
31#include <arpa/inet.h> 33# include <netinet/in.h>
32#include <arpa/nameser.h> 34#endif
33 35#ifdef HAVE_ARPA_INET_H
36# include <arpa/inet.h>
37#endif
38#ifdef HAVE_ARPA_NAMESER_H
39# include <arpa/nameser.h>
40#endif
34#ifdef HAVE_NETDB_H 41#ifdef HAVE_NETDB_H
35# include <netdb.h> 42# include <netdb.h>
36#endif 43#endif
@@ -48,21 +55,20 @@ struct _CB_Data
48 EINA_INLIST; 55 EINA_INLIST;
49 Ecore_Con_Info_Cb cb_done; 56 Ecore_Con_Info_Cb cb_done;
50 void *data; 57 void *data;
51 Ecore_Fd_Handler *fdh; 58 Ecore_Thread *thread;
52 pid_t pid; 59 struct addrinfo hints;
53 Ecore_Event_Handler *handler; 60 Ecore_Con_Info *result;
54 int fd2; 61 int error;
62 char service[NI_MAXSERV];
63 char name[NI_MAXHOST];
55}; 64};
56 65
57static void _ecore_con_info_readdata(CB_Data *cbdata); 66static void _ecore_con_info_slave_free (CB_Data *cbdata);
58static void _ecore_con_info_slave_free(CB_Data *cbdata); 67static void _ecore_con_info_slave_result(void *data, Ecore_Thread *th);
59static Eina_Bool _ecore_con_info_data_handler(void *data, 68static void _ecore_con_info_slave_cancel(void *data, Ecore_Thread *th);
60 Ecore_Fd_Handler *fd_handler); 69static void _ecore_con_info_slave_lookup(void *data, Ecore_Thread *th);
61static Eina_Bool _ecore_con_info_exit_handler(void *data,
62 int type EINA_UNUSED,
63 void *event);
64 70
65static int info_init = 0; 71static int info_init = 0;
66static CB_Data *info_slaves = NULL; 72static CB_Data *info_slaves = NULL;
67 73
68int 74int
@@ -77,28 +83,38 @@ ecore_con_info_shutdown(void)
77{ 83{
78 info_init--; 84 info_init--;
79 if (info_init == 0) 85 if (info_init == 0)
80 while (info_slaves) 86 {
81 _ecore_con_info_slave_free(info_slaves); 87 while (info_slaves)
88 {
89 CB_Data *cbdata;
82 90
91 cbdata = info_slaves;
92 info_slaves = (CB_Data *)eina_inlist_remove
93 (EINA_INLIST_GET(info_slaves), EINA_INLIST_GET(info_slaves));
94 ecore_thread_cancel(cbdata->thread);
95 }
96 }
83 return info_init; 97 return info_init;
84} 98}
85 99
100static void
101_hints_fill(struct addrinfo *hints, int flags, int proto)
102{
103 memset(hints, 0, sizeof(struct addrinfo));
104 hints->ai_family = AF_UNSPEC;
105 hints->ai_flags = flags;
106 if (proto == IPPROTO_TCP) hints->ai_socktype = SOCK_STREAM;
107 else hints->ai_socktype = SOCK_DGRAM;
108 hints->ai_protocol = proto;
109}
110
86int 111int
87ecore_con_info_tcp_connect(Ecore_Con_Server *svr, 112ecore_con_info_tcp_connect(Ecore_Con_Server *svr,
88 Ecore_Con_Info_Cb done_cb, 113 Ecore_Con_Info_Cb done_cb,
89 void *data) 114 void *data)
90{ 115{
91 struct addrinfo hints; 116 struct addrinfo hints;
92 117 _hints_fill(&hints, AI_CANONNAME, IPPROTO_TCP);
93 memset(&hints, 0, sizeof(struct addrinfo));
94 hints.ai_family = AF_UNSPEC;
95 hints.ai_socktype = SOCK_STREAM;
96 hints.ai_flags = AI_CANONNAME;
97 hints.ai_protocol = IPPROTO_TCP;
98 hints.ai_canonname = NULL;
99 hints.ai_next = NULL;
100 hints.ai_addr = NULL;
101
102 return ecore_con_info_get(svr, done_cb, data, &hints); 118 return ecore_con_info_get(svr, done_cb, data, &hints);
103} 119}
104 120
@@ -108,16 +124,7 @@ ecore_con_info_tcp_listen(Ecore_Con_Server *svr,
108 void *data) 124 void *data)
109{ 125{
110 struct addrinfo hints; 126 struct addrinfo hints;
111 127 _hints_fill(&hints, AI_PASSIVE, IPPROTO_TCP);
112 memset(&hints, 0, sizeof(struct addrinfo));
113 hints.ai_family = AF_UNSPEC;
114 hints.ai_socktype = SOCK_STREAM;
115 hints.ai_flags = AI_PASSIVE;
116 hints.ai_protocol = IPPROTO_TCP;
117 hints.ai_canonname = NULL;
118 hints.ai_next = NULL;
119 hints.ai_addr = NULL;
120
121 return ecore_con_info_get(svr, done_cb, data, &hints); 128 return ecore_con_info_get(svr, done_cb, data, &hints);
122} 129}
123 130
@@ -127,16 +134,7 @@ ecore_con_info_udp_connect(Ecore_Con_Server *svr,
127 void *data) 134 void *data)
128{ 135{
129 struct addrinfo hints; 136 struct addrinfo hints;
130 137 _hints_fill(&hints, AI_CANONNAME, IPPROTO_UDP);
131 memset(&hints, 0, sizeof(struct addrinfo));
132 hints.ai_family = AF_UNSPEC;
133 hints.ai_socktype = SOCK_DGRAM;
134 hints.ai_flags = AI_CANONNAME;
135 hints.ai_protocol = IPPROTO_UDP;
136 hints.ai_canonname = NULL;
137 hints.ai_next = NULL;
138 hints.ai_addr = NULL;
139
140 return ecore_con_info_get(svr, done_cb, data, &hints); 138 return ecore_con_info_get(svr, done_cb, data, &hints);
141} 139}
142 140
@@ -146,16 +144,7 @@ ecore_con_info_udp_listen(Ecore_Con_Server *svr,
146 void *data) 144 void *data)
147{ 145{
148 struct addrinfo hints; 146 struct addrinfo hints;
149 147 _hints_fill(&hints, AI_PASSIVE, IPPROTO_UDP);
150 memset(&hints, 0, sizeof(struct addrinfo));
151 hints.ai_family = AF_UNSPEC;
152 hints.ai_socktype = SOCK_DGRAM;
153 hints.ai_flags = AI_PASSIVE;
154 hints.ai_protocol = IPPROTO_UDP;
155 hints.ai_canonname = NULL;
156 hints.ai_next = NULL;
157 hints.ai_addr = NULL;
158
159 return ecore_con_info_get(svr, done_cb, data, &hints); 148 return ecore_con_info_get(svr, done_cb, data, &hints);
160} 149}
161 150
@@ -165,151 +154,44 @@ ecore_con_info_mcast_listen(Ecore_Con_Server *svr,
165 void *data) 154 void *data)
166{ 155{
167 struct addrinfo hints; 156 struct addrinfo hints;
168 157 _hints_fill(&hints, 0, IPPROTO_UDP);
169 memset(&hints, 0, sizeof(struct addrinfo));
170 hints.ai_family = AF_UNSPEC;
171 hints.ai_socktype = SOCK_DGRAM;
172 hints.ai_flags = 0;
173 hints.ai_protocol = IPPROTO_UDP;
174 hints.ai_canonname = NULL;
175 hints.ai_next = NULL;
176 hints.ai_addr = NULL;
177
178 return ecore_con_info_get(svr, done_cb, data, &hints); 158 return ecore_con_info_get(svr, done_cb, data, &hints);
179} 159}
180 160
181static void
182_ecore_con_fd_close_on_exec(int fd)
183{
184#ifdef HAVE_FCNTL
185 int flags;
186
187 flags = fcntl(fd, F_GETFD);
188 if (flags == -1) return;
189 flags |= FD_CLOEXEC;
190 if (fcntl(fd, F_SETFD, flags) == -1) return;
191#else
192 (void)fd;
193#endif
194}
195
196EAPI int 161EAPI int
197ecore_con_info_get(Ecore_Con_Server *svr, 162ecore_con_info_get(Ecore_Con_Server *obj,
198 Ecore_Con_Info_Cb done_cb, 163 Ecore_Con_Info_Cb done_cb,
199 void *data, 164 void *data,
200 struct addrinfo *hints) 165 struct addrinfo *hints)
201{ 166{
167 Efl_Network_Server_Data *svr = eo_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS);
202 CB_Data *cbdata; 168 CB_Data *cbdata;
203 int fd[2];
204
205 if (pipe(fd) < 0)
206 {
207 ecore_con_event_server_error(svr, strerror(errno));
208 return 0;
209 }
210
211 _ecore_con_fd_close_on_exec(fd[0]);
212 _ecore_con_fd_close_on_exec(fd[1]);
213 169
170 if (!svr) return 0;
214 cbdata = calloc(1, sizeof(CB_Data)); 171 cbdata = calloc(1, sizeof(CB_Data));
215 if (!cbdata) 172 if (!cbdata)
216 { 173 {
217 close(fd[0]); 174 ecore_con_event_server_error(obj, "Memory allocation failure");
218 close(fd[1]);
219 return 0; 175 return 0;
220 } 176 }
221 177
222 cbdata->cb_done = done_cb; 178 cbdata->cb_done = done_cb;
223 cbdata->data = data; 179 cbdata->data = data;
224 cbdata->fd2 = fd[1]; 180 cbdata->hints = *hints;
225 if (!(cbdata->fdh = ecore_main_fd_handler_add(fd[0], ECORE_FD_READ, 181 cbdata->thread = ecore_thread_run(_ecore_con_info_slave_lookup,
226 _ecore_con_info_data_handler, 182 _ecore_con_info_slave_result,
227 cbdata, 183 _ecore_con_info_slave_cancel,
228 NULL, NULL))) 184 cbdata);
185 if (!cbdata->thread)
229 { 186 {
230 ecore_con_event_server_error(svr, "Memory allocation failure");
231 free(cbdata); 187 free(cbdata);
232 close(fd[0]); 188 ecore_con_event_server_error(obj, "Memory allocation failure");
233 close(fd[1]);
234 return 0; 189 return 0;
235 } 190 }
236 191 eina_convert_itoa(svr->ecs ? svr->ecs->port : svr->port, cbdata->service);
237 if ((cbdata->pid = fork()) == 0) 192 strncpy(cbdata->name, svr->ecs ? svr->ecs->ip : svr->name, NI_MAXHOST - 1);
238 { 193 cbdata->name[NI_MAXHOST - 1] = 0;
239 Ecore_Con_Info *container; 194 info_slaves = (CB_Data *)eina_inlist_append(EINA_INLIST_GET(info_slaves),
240 struct addrinfo *result = NULL;
241 char service[NI_MAXSERV] = {0};
242 char hbuf[NI_MAXHOST] = {0};
243 char sbuf[NI_MAXSERV] = {0};
244 unsigned char *tosend = NULL;
245 int tosend_len;
246 int canonname_len = 0;
247
248 eina_convert_itoa(svr->ecs ? svr->ecs->port : svr->port, service);
249 /* CHILD */
250 if (!getaddrinfo(svr->ecs ? svr->ecs->ip : svr->name, service, hints, &result) && result)
251 {
252 if (result->ai_canonname)
253 canonname_len = strlen(result->ai_canonname) + 1;
254
255 tosend_len = sizeof(Ecore_Con_Info) + result->ai_addrlen +
256 canonname_len;
257
258 tosend = alloca(tosend_len);
259 memset(tosend, 0, tosend_len);
260
261 container = (Ecore_Con_Info *)tosend;
262 container->size = tosend_len;
263
264 memcpy(&container->info,
265 result,
266 sizeof(struct addrinfo));
267 memcpy(tosend + sizeof(Ecore_Con_Info),
268 result->ai_addr,
269 result->ai_addrlen);
270 if (result->ai_canonname) /* FIXME: else... */
271 memcpy(tosend + sizeof(Ecore_Con_Info) + result->ai_addrlen,
272 result->ai_canonname,
273 canonname_len);
274
275 if (!getnameinfo(result->ai_addr, result->ai_addrlen,
276 hbuf, sizeof(hbuf), sbuf, sizeof(sbuf),
277 NI_NUMERICHOST | NI_NUMERICSERV))
278 {
279 memcpy(container->ip, hbuf, sizeof(container->ip));
280 memcpy(container->service, sbuf, sizeof(container->service));
281 }
282
283 if (write(fd[1], tosend, tosend_len) < 0) perror("write");
284 }
285
286 if (result)
287 freeaddrinfo(result);
288
289 if (write(fd[1], "", 1) < 0) perror("write");
290 close(fd[1]);
291#if defined(__USE_ISOC99) && !defined(__UCLIBC__)
292 _Exit(0);
293#else
294 _exit(0);
295#endif
296 }
297
298 /* PARENT */
299 cbdata->handler =
300 ecore_event_handler_add(ECORE_EXE_EVENT_DEL, _ecore_con_info_exit_handler,
301 cbdata);
302 close(fd[1]);
303 if (!cbdata->handler)
304 {
305 ecore_main_fd_handler_del(cbdata->fdh);
306 free(cbdata);
307 close(fd[0]);
308 return 0;
309 }
310
311 info_slaves = (CB_Data *)eina_inlist_append(EINA_INLIST_GET(
312 info_slaves),
313 EINA_INLIST_GET(cbdata)); 195 EINA_INLIST_GET(cbdata));
314 svr->infos = eina_list_append(svr->infos, cbdata); 196 svr->infos = eina_list_append(svr->infos, cbdata);
315 return 1; 197 return 1;
@@ -323,127 +205,92 @@ ecore_con_info_data_clear(void *info)
323} 205}
324 206
325static void 207static void
326_ecore_con_info_readdata(CB_Data *cbdata) 208_ecore_con_info_slave_free(CB_Data *cbdata)
327{ 209{
328 Ecore_Con_Info container; 210 info_slaves = (CB_Data *)eina_inlist_remove(EINA_INLIST_GET(info_slaves),
329 Ecore_Con_Info *recv_info; 211 EINA_INLIST_GET(cbdata));
330 unsigned char *torecv; 212 if (cbdata->result) free(cbdata->result);
331 int torecv_len; 213 cbdata->result = NULL;
214 if (cbdata->data) ecore_con_server_infos_del(cbdata->data, cbdata);
215 cbdata->data = NULL;
216 free(cbdata);
217}
332 218
333 ssize_t size; 219static void
220_ecore_con_info_slave_result(void *data, Ecore_Thread *th EINA_UNUSED)
221{
222 CB_Data *cbdata = data;
334 223
335 size = read(ecore_main_fd_handler_fd_get(cbdata->fdh), &container, 224 if (cbdata->result) // lookup ok
336 sizeof(Ecore_Con_Info));
337 if (size == sizeof(Ecore_Con_Info))
338 { 225 {
339 torecv_len = container.size; 226 if (cbdata->data) cbdata->cb_done(cbdata->data, cbdata->result);
340 torecv = malloc(torecv_len);
341
342 memcpy(torecv, &container, sizeof(Ecore_Con_Info));
343
344 size = read(ecore_main_fd_handler_fd_get(cbdata->fdh),
345 torecv + sizeof(Ecore_Con_Info),
346 torecv_len - sizeof(Ecore_Con_Info));
347 if ((size > 0) &&
348 ((size_t)size == torecv_len - sizeof(Ecore_Con_Info)))
349 {
350 recv_info = (Ecore_Con_Info *)torecv;
351
352 recv_info->info.ai_addr =
353 (struct sockaddr *)(torecv + sizeof(Ecore_Con_Info));
354 if ((size_t)torecv_len !=
355 (sizeof(Ecore_Con_Info) + recv_info->info.ai_addrlen))
356 recv_info->info.ai_canonname = (char *)
357 (torecv + sizeof(Ecore_Con_Info) + recv_info->info.ai_addrlen);
358 else
359 recv_info->info.ai_canonname = NULL;
360
361 recv_info->info.ai_next = NULL;
362
363 if (cbdata->data)
364 {
365 cbdata->cb_done(cbdata->data, recv_info);
366 ecore_con_server_infos_del(cbdata->data, cbdata);
367 }
368
369 free(torecv);
370 }
371 else
372 {
373 if (cbdata->data)
374 {
375 cbdata->cb_done(cbdata->data, NULL);
376 ecore_con_server_infos_del(cbdata->data, cbdata);
377 }
378 }
379 } 227 }
380 else 228 else // an error occured
381 { 229 {
382 if (cbdata->data) 230 if (cbdata->data)
383 { 231 {
384 ecore_con_event_server_error(cbdata->data, strerror(errno)); 232 char *str = strerror(cbdata->error);
233 ecore_con_event_server_error(cbdata->data, str);
385 cbdata->cb_done(cbdata->data, NULL); 234 cbdata->cb_done(cbdata->data, NULL);
386 ecore_con_server_infos_del(cbdata->data, cbdata);
387 } 235 }
388 } 236 }
389 237 if (cbdata->data) ecore_con_server_infos_del(cbdata->data, cbdata);
390 cbdata->cb_done = NULL; 238 cbdata->data = NULL;
239 _ecore_con_info_slave_free(cbdata);
391} 240}
392 241
393static void 242static void
394_ecore_con_info_slave_free(CB_Data *cbdata) 243_ecore_con_info_slave_cancel(void *data, Ecore_Thread *th EINA_UNUSED)
395{ 244{
396 info_slaves = (CB_Data *)eina_inlist_remove(EINA_INLIST_GET(info_slaves), 245 CB_Data *cbdata = data;
397 EINA_INLIST_GET(cbdata)); 246 _ecore_con_info_slave_free(cbdata);
398 ecore_main_fd_handler_del(cbdata->fdh);
399 ecore_event_handler_del(cbdata->handler);
400 close(ecore_main_fd_handler_fd_get(cbdata->fdh));
401 if (cbdata->data) ecore_con_server_infos_del(cbdata->data, cbdata);
402 free(cbdata);
403} 247}
404 248
405static Eina_Bool 249static void
406_ecore_con_info_data_handler(void *data, 250_ecore_con_info_slave_lookup(void *data, Ecore_Thread *th EINA_UNUSED)
407 Ecore_Fd_Handler *fd_handler)
408{ 251{
409 CB_Data *cbdata; 252 CB_Data *cbdata = data;
253 struct addrinfo *result = NULL;
410 254
411 cbdata = data; 255 // do lookup, fill cbdata
412 if (cbdata->cb_done) 256 if ((!getaddrinfo(cbdata->name, cbdata->service, &(cbdata->hints), &result))
257 && (result))
413 { 258 {
414 if (ecore_main_fd_handler_active_get(fd_handler, 259 Ecore_Con_Info *info;
415 ECORE_FD_READ)) 260 unsigned int canonname_size = 0, size;
416 _ecore_con_info_readdata(cbdata); 261
417 else 262 if (result->ai_canonname)
263 canonname_size = strlen(result->ai_canonname) + 1;
264 size = sizeof(Ecore_Con_Info) + result->ai_addrlen + canonname_size;
265 info = calloc(1, size);
266 if (info)
418 { 267 {
419 if (cbdata->data) 268 char hbuf[NI_MAXHOST] = { 0 }, sbuf[NI_MAXSERV] = { 0 }, *p;
269
270 info->size = size;
271 memcpy(&(info->info), result, sizeof(struct addrinfo));
272 p = ((char *)info) + sizeof(Ecore_Con_Info);
273 memcpy(p, result->ai_addr, result->ai_addrlen);
274 info->info.ai_addr = (struct sockaddr *)p;
275 if (result->ai_canonname)
276 {
277 p = ((char *)info) + sizeof(Ecore_Con_Info) + result->ai_addrlen;
278 memcpy(p, result->ai_canonname, canonname_size);
279 info->info.ai_canonname = p;
280 }
281 // we don't care about multiple entries - take first one then
282 info->info.ai_next = NULL;
283 if (!getnameinfo(result->ai_addr, result->ai_addrlen,
284 hbuf, sizeof(hbuf), sbuf, sizeof(sbuf),
285 NI_NUMERICHOST | NI_NUMERICSERV))
420 { 286 {
421 cbdata->cb_done(cbdata->data, NULL); 287 memcpy(info->ip, hbuf, sizeof(info->ip));
422 cbdata->cb_done = NULL; 288 memcpy(info->service, sbuf, sizeof(info->service));
423 ecore_con_server_infos_del(cbdata->data, cbdata);
424 } 289 }
290 cbdata->result = info;
425 } 291 }
292 if (!cbdata->result) free(info);
426 } 293 }
427 294 if (!cbdata->result) cbdata->error = errno;
428 _ecore_con_info_slave_free(cbdata); 295 if (result) freeaddrinfo(result);
429 return ECORE_CALLBACK_CANCEL;
430}
431
432static Eina_Bool
433_ecore_con_info_exit_handler(void *data,
434 int type EINA_UNUSED,
435 void *event)
436{
437 CB_Data *cbdata;
438 Ecore_Exe_Event_Del *ev;
439
440 ev = event;
441 cbdata = data;
442 if (cbdata->pid != ev->pid)
443 return ECORE_CALLBACK_RENEW;
444
445 return ECORE_CALLBACK_CANCEL; /* FIXME: Woot ??? */
446 _ecore_con_info_slave_free(cbdata);
447 return ECORE_CALLBACK_CANCEL;
448} 296}
449
diff --git a/src/static_libs/dns/dns.c b/src/static_libs/dns/dns.c
deleted file mode 100644
index a426a53476..0000000000
--- a/src/static_libs/dns/dns.c
+++ /dev/null
@@ -1,8701 +0,0 @@
1/* ==========================================================================
2 * dns.c - Recursive, Reentrant DNS Resolver.
3 * --------------------------------------------------------------------------
4 * Copyright (c) 2008, 2009, 2010, 2012, 2013 William Ahern
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to permit
11 * persons to whom the Software is furnished to do so, subject to the
12 * following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
20 * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
21 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
23 * USE OR OTHER DEALINGS IN THE SOFTWARE.
24 * ==========================================================================
25 */
26#if !defined(__FreeBSD__) && !defined(__sun)
27#ifndef _XOPEN_SOURCE
28#define _XOPEN_SOURCE 600
29#endif
30
31#undef _DEFAULT_SOURCE
32#define _DEFAULT_SOURCE
33
34#undef _BSD_SOURCE
35#define _BSD_SOURCE
36
37#undef _DARWIN_C_SOURCE
38#define _DARWIN_C_SOURCE
39
40#undef _NETBSD_SOURCE
41#define _NETBSD_SOURCE
42#endif
43
44#include <stddef.h> /* offsetof() */
45#ifdef _WIN32
46#define uint32_t unsigned int
47#else
48#include <stdint.h> /* uint32_t */
49#endif
50#include <stdlib.h> /* malloc(3) realloc(3) free(3) rand(3) random(3) arc4random(3) */
51#include <stdio.h> /* FILE fopen(3) fclose(3) getc(3) rewind(3) */
52
53#include <string.h> /* memcpy(3) strlen(3) memmove(3) memchr(3) memcmp(3) strchr(3) strsep(3) strcspn(3) */
54#include <strings.h> /* strcasecmp(3) strncasecmp(3) */
55
56#include <ctype.h> /* isspace(3) isdigit(3) */
57
58#include <time.h> /* time_t time(2) difftime(3) */
59
60#include <signal.h> /* SIGPIPE sigemptyset(3) sigaddset(3) sigpending(2) sigprocmask(2) pthread_sigmask(3) sigtimedwait(2) */
61
62#include <errno.h> /* errno EINVAL ENOENT */
63
64#undef NDEBUG
65#include <assert.h> /* assert(3) */
66
67#if _WIN32
68#ifndef FD_SETSIZE
69#define FD_SETSIZE 256
70#endif
71#include <winsock2.h>
72#include <ws2tcpip.h>
73#else
74#include <sys/types.h> /* FD_SETSIZE socklen_t */
75#include <sys/select.h> /* FD_ZERO FD_SET fd_set select(2) */
76#include <sys/socket.h> /* AF_INET AF_INET6 AF_UNIX struct sockaddr struct sockaddr_in struct sockaddr_in6 socket(2) */
77
78#if defined(AF_UNIX)
79#include <sys/un.h> /* struct sockaddr_un */
80#endif
81
82#include <fcntl.h> /* F_SETFD F_GETFL F_SETFL O_NONBLOCK fcntl(2) */
83
84#include <unistd.h> /* _POSIX_THREADS gethostname(3) close(2) */
85
86#include <poll.h> /* POLLIN POLLOUT */
87
88#include <netinet/in.h> /* struct sockaddr_in struct sockaddr_in6 */
89
90#include <arpa/inet.h> /* inet_pton(3) inet_ntop(3) htons(3) ntohs(3) */
91
92#include <netdb.h> /* struct addrinfo */
93#endif
94
95#include "dns.h"
96
97
98/*
99 * C O M P I L E R A N N O T A T I O N S
100 *
101 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
102
103#if __GNUC__
104#define DNS_NOTUSED __attribute__((unused))
105#else
106#define DNS_NOTUSED
107#endif
108
109#if __clang__
110#pragma clang diagnostic push
111#pragma clang diagnostic ignored "-Wunused-parameter"
112#elif (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4
113#pragma GCC diagnostic push
114#pragma GCC diagnostic ignored "-Wunused-parameter"
115#endif
116
117
118/*
119 * S T A N D A R D M A C R O S
120 *
121 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
122
123#ifndef MIN
124#define MIN(a, b) (((a) < (b))? (a) : (b))
125#endif
126
127
128#ifndef MAX
129#define MAX(a, b) (((a) > (b))? (a) : (b))
130#endif
131
132
133#ifndef lengthof
134#define lengthof(a) (sizeof (a) / sizeof (a)[0])
135#endif
136
137#ifndef endof
138#define endof(a) (&(a)[lengthof((a))])
139#endif
140
141
142/*
143 * M I S C E L L A N E O U S C O M P A T
144 *
145 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
146
147#if _WIN32 || _WIN64
148#define PRIuZ "Iu"
149#else
150#define PRIuZ "zu"
151#endif
152
153#ifndef DNS_THREAD_SAFE
154#if (defined _REENTRANT || defined _THREAD_SAFE) && _POSIX_THREADS > 0
155#define DNS_THREAD_SAFE 1
156#else
157#define DNS_THREAD_SAFE 0
158#endif
159#endif
160
161
162/*
163 * D E B U G M A C R O S
164 *
165 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
166
167int dns_debug = 0;
168
169#if DNS_DEBUG
170
171#undef DNS_DEBUG
172#define DNS_DEBUG dns_debug
173
174#define DNS_SAY_(fmt, ...) \
175 do { if (DNS_DEBUG > 0) fprintf(stderr, fmt "%.1s", __func__, __LINE__, __VA_ARGS__); } while (0)
176#define DNS_SAY(...) DNS_SAY_("@@ (%s:%d) " __VA_ARGS__, "\n")
177#define DNS_HAI DNS_SAY("HAI")
178
179#define DNS_SHOW_(P, fmt, ...) do { \
180 if (DNS_DEBUG > 1) { \
181 fprintf(stderr, "@@ BEGIN * * * * * * * * * * * *\n"); \
182 fprintf(stderr, "@@ " fmt "%.0s\n", __VA_ARGS__); \
183 dns_p_dump((P), stderr); \
184 fprintf(stderr, "@@ END * * * * * * * * * * * * *\n\n"); \
185 } \
186} while (0)
187
188#define DNS_SHOW(...) DNS_SHOW_(__VA_ARGS__, "")
189
190#else /* !DNS_DEBUG */
191
192#undef DNS_DEBUG
193#define DNS_DEBUG 0
194
195#define DNS_SAY(...)
196#define DNS_HAI
197#define DNS_SHOW(...)
198
199#endif /* DNS_DEBUG */
200
201
202/*
203 * V E R S I O N R O U T I N E S
204 *
205 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
206
207const char *dns_vendor(void) {
208 return DNS_VENDOR;
209} /* dns_vendor() */
210
211
212int dns_v_rel(void) {
213 return DNS_V_REL;
214} /* dns_v_rel() */
215
216
217int dns_v_abi(void) {
218 return DNS_V_ABI;
219} /* dns_v_abi() */
220
221
222int dns_v_api(void) {
223 return DNS_V_API;
224} /* dns_v_api() */
225
226
227/*
228 * E R R O R R O U T I N E S
229 *
230 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
231
232#if _WIN32
233
234#define DNS_EINTR WSAEINTR
235#define DNS_EINPROGRESS WSAEINPROGRESS
236#define DNS_EISCONN WSAEISCONN
237#define DNS_EWOULDBLOCK WSAEWOULDBLOCK
238#define DNS_EALREADY WSAEALREADY
239#define DNS_EAGAIN EAGAIN
240#define DNS_ETIMEDOUT WSAETIMEDOUT
241
242#define dns_syerr() ((int)GetLastError())
243#define dns_soerr() ((int)WSAGetLastError())
244
245#else
246
247#define DNS_EINTR EINTR
248#define DNS_EINPROGRESS EINPROGRESS
249#define DNS_EISCONN EISCONN
250#define DNS_EWOULDBLOCK EWOULDBLOCK
251#define DNS_EALREADY EALREADY
252#define DNS_EAGAIN EAGAIN
253#define DNS_ETIMEDOUT ETIMEDOUT
254
255#define dns_syerr() errno
256#define dns_soerr() errno
257
258#endif
259
260
261const char *dns_strerror(int error) {
262 switch (error) {
263 case DNS_ENOBUFS:
264 return "DNS packet buffer too small";
265 case DNS_EILLEGAL:
266 return "Illegal DNS RR name or data";
267 case DNS_EORDER:
268 return "Attempt to push RR out of section order";
269 case DNS_ESECTION:
270 return "Invalid section specified";
271 case DNS_EUNKNOWN:
272 return "Unknown DNS error";
273 case DNS_EADDRESS:
274 return "Invalid textual address form";
275 default:
276 return strerror(error);
277 } /* switch() */
278} /* dns_strerror() */
279
280
281/*
282 * A T O M I C R O U T I N E S
283 *
284 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
285
286DNS_NOTUSED static void dns_atomic_fence(void) {
287 return;
288} /* dns_atomic_fence() */
289
290
291static unsigned dns_atomic_inc(dns_atomic_t *i) {
292 return (*i)++;
293} /* dns_atomic_inc() */
294
295
296static unsigned dns_atomic_dec(dns_atomic_t *i) {
297 return (*i)--;
298} /* dns_atomic_dec() */
299
300
301static unsigned dns_atomic_load(dns_atomic_t *i) {
302 return *i;
303} /* dns_atomic_load() */
304
305
306DNS_NOTUSED static unsigned dns_atomic_store(dns_atomic_t *i, unsigned n) {
307 unsigned o;
308
309 o = dns_atomic_load(i);
310 *i = n;
311 return o;
312} /* dns_atomic_store() */
313
314
315/*
316 * C R Y P T O R O U T I N E S
317 *
318 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
319
320/*
321 * P R N G
322 */
323
324#ifndef DNS_RANDOM
325#if defined(HAVE_ARC4RANDOM) \
326 || defined(__OpenBSD__) \
327 || defined(__FreeBSD__) \
328 || defined(__NetBSD__) \
329 || defined(__APPLE__)
330#define DNS_RANDOM arc4random
331#elif __linux
332#define DNS_RANDOM random
333#else
334#define DNS_RANDOM rand
335#endif
336#endif
337
338#define DNS_RANDOM_arc4random 1
339#define DNS_RANDOM_random 2
340#define DNS_RANDOM_rand 3
341#define DNS_RANDOM_RAND_bytes 4
342
343#define DNS_RANDOM_OPENSSL (DNS_RANDOM_RAND_bytes == DNS_PP_XPASTE(DNS_RANDOM_, DNS_RANDOM))
344
345#if DNS_RANDOM_OPENSSL
346#include <openssl/rand.h>
347#endif
348
349static unsigned dns_random_(void) {
350#if DNS_RANDOM_OPENSSL
351 unsigned r;
352
353 assert(1 == RAND_bytes((unsigned char *)&r, sizeof r));
354
355 return r;
356#else
357 return DNS_RANDOM();
358#endif
359} /* dns_random_() */
360
361unsigned (*dns_random)(void) __attribute__((weak)) = &dns_random_;
362
363
364/*
365 * P E R M U T A T I O N G E N E R A T O R
366 */
367
368#define DNS_K_TEA_KEY_SIZE 16
369#define DNS_K_TEA_BLOCK_SIZE 8
370#define DNS_K_TEA_CYCLES 32
371#define DNS_K_TEA_MAGIC 0x9E3779B9U
372
373struct dns_k_tea {
374 uint32_t key[DNS_K_TEA_KEY_SIZE / sizeof (uint32_t)];
375 unsigned cycles;
376}; /* struct dns_k_tea */
377
378
379static void dns_k_tea_init(struct dns_k_tea *tea, uint32_t key[], unsigned cycles) {
380 memcpy(tea->key, key, sizeof tea->key);
381
382 tea->cycles = (cycles)? cycles : DNS_K_TEA_CYCLES;
383} /* dns_k_tea_init() */
384
385
386static void dns_k_tea_encrypt(struct dns_k_tea *tea, uint32_t v[], uint32_t *w) {
387 uint32_t y, z, sum, n;
388
389 y = v[0];
390 z = v[1];
391 sum = 0;
392
393 for (n = 0; n < tea->cycles; n++) {
394 sum += DNS_K_TEA_MAGIC;
395 y += ((z << 4) + tea->key[0]) ^ (z + sum) ^ ((z >> 5) + tea->key[1]);
396 z += ((y << 4) + tea->key[2]) ^ (y + sum) ^ ((y >> 5) + tea->key[3]);
397 }
398
399 w[0] = y;
400 w[1] = z;
401
402 return /* void */;
403} /* dns_k_tea_encrypt() */
404
405
406/*
407 * Permutation generator, based on a Luby-Rackoff Feistel construction.
408 *
409 * Specifically, this is a generic balanced Feistel block cipher using TEA
410 * (another block cipher) as the pseudo-random function, F. At best it's as
411 * strong as F (TEA), notwithstanding the seeding. F could be AES, SHA-1, or
412 * perhaps Bernstein's Salsa20 core; I am naively trying to keep things
413 * simple.
414 *
415 * The generator can create a permutation of any set of numbers, as long as
416 * the size of the set is an even power of 2. This limitation arises either
417 * out of an inherent property of balanced Feistel constructions, or by my
418 * own ignorance. I'll tackle an unbalanced construction after I wrap my
419 * head around Schneier and Kelsey's paper.
420 *
421 * CAVEAT EMPTOR. IANAC.
422 */
423#define DNS_K_PERMUTOR_ROUNDS 8
424
425struct dns_k_permutor {
426 unsigned stepi, length, limit;
427 unsigned shift, mask, rounds;
428
429 struct dns_k_tea tea;
430}; /* struct dns_k_permutor */
431
432
433static inline unsigned dns_k_permutor_powof(unsigned n) {
434 unsigned m, i = 0;
435
436 for (m = 1; m < n; m <<= 1, i++)
437 ;;
438
439 return i;
440} /* dns_k_permutor_powof() */
441
442static void dns_k_permutor_init(struct dns_k_permutor *p, unsigned low, unsigned high) {
443 uint32_t key[DNS_K_TEA_KEY_SIZE / sizeof (uint32_t)];
444 unsigned width, i;
445
446 p->stepi = 0;
447
448 p->length = (high - low) + 1;
449 p->limit = high;
450
451 width = dns_k_permutor_powof(p->length);
452 width += width % 2;
453
454 p->shift = width / 2;
455 p->mask = (1U << p->shift) - 1;
456 p->rounds = DNS_K_PERMUTOR_ROUNDS;
457
458 for (i = 0; i < lengthof(key); i++)
459 key[i] = dns_random();
460
461 dns_k_tea_init(&p->tea, key, 0);
462
463 return /* void */;
464} /* dns_k_permutor_init() */
465
466
467static unsigned dns_k_permutor_F(struct dns_k_permutor *p, unsigned k, unsigned x) {
468 uint32_t in[DNS_K_TEA_BLOCK_SIZE / sizeof (uint32_t)], out[DNS_K_TEA_BLOCK_SIZE / sizeof (uint32_t)];
469
470 memset(in, '\0', sizeof in);
471
472 in[0] = k;
473 in[1] = x;
474
475 dns_k_tea_encrypt(&p->tea, in, out);
476
477 return p->mask & out[0];
478} /* dns_k_permutor_F() */
479
480
481static unsigned dns_k_permutor_E(struct dns_k_permutor *p, unsigned n) {
482 unsigned l[2], r[2];
483 unsigned i;
484
485 i = 0;
486 l[i] = p->mask & (n >> p->shift);
487 r[i] = p->mask & (n >> 0);
488
489 do {
490 l[(i + 1) % 2] = r[i % 2];
491 r[(i + 1) % 2] = l[i % 2] ^ dns_k_permutor_F(p, i, r[i % 2]);
492
493 i++;
494 } while (i < p->rounds - 1);
495
496 return ((l[i % 2] & p->mask) << p->shift) | ((r[i % 2] & p->mask) << 0);
497} /* dns_k_permutor_E() */
498
499
500DNS_NOTUSED static unsigned dns_k_permutor_D(struct dns_k_permutor *p, unsigned n) {
501 unsigned l[2], r[2];
502 unsigned i;
503
504 i = p->rounds - 1;
505 l[i % 2] = p->mask & (n >> p->shift);
506 r[i % 2] = p->mask & (n >> 0);
507
508 do {
509 i--;
510
511 r[i % 2] = l[(i + 1) % 2];
512 l[i % 2] = r[(i + 1) % 2] ^ dns_k_permutor_F(p, i, l[(i + 1) % 2]);
513 } while (i > 0);
514
515 return ((l[i % 2] & p->mask) << p->shift) | ((r[i % 2] & p->mask) << 0);
516} /* dns_k_permutor_D() */
517
518
519static unsigned dns_k_permutor_step(struct dns_k_permutor *p) {
520 unsigned n;
521
522 do {
523 n = dns_k_permutor_E(p, p->stepi++);
524 } while (n >= p->length);
525
526 return n + (p->limit + 1 - p->length);
527} /* dns_k_permutor_step() */
528
529
530/*
531 * Simple permutation box. Useful for shuffling rrsets from an iterator.
532 * Uses AES s-box to provide good diffusion.
533 *
534 * Seems to pass muster under runs test.
535 *
536 * $ for i in 0 1 2 3 4 5 6 7 8 9; do ./dns shuffle-16 > /tmp/out; done
537 * $ R -q -f /dev/stdin 2>/dev/null <<-EOF | awk '/p-value/{ print $8 }'
538 * library(lawstat)
539 * runs.test(scan(file="/tmp/out"))
540 * EOF
541 */
542static unsigned short dns_k_shuffle16(unsigned short n, unsigned s) {
543 static const unsigned char sbox[256] =
544 { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
545 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
546 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
547 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
548 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,
549 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
550 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a,
551 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
552 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
553 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
554 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,
555 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
556 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,
557 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
558 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
559 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
560 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17,
561 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
562 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88,
563 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
564 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
565 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
566 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9,
567 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
568 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,
569 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
570 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
571 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
572 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94,
573 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
574 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68,
575 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 };
576 unsigned char a, b;
577 unsigned i;
578
579 a = 0xff & (n >> 0);
580 b = 0xff & (n >> 8);
581
582 for (i = 0; i < 4; i++) {
583 a ^= 0xff & s;
584 a = sbox[a] ^ b;
585 b = sbox[b] ^ a;
586 s >>= 8;
587 }
588
589 return ((0xff00 & (a << 8)) | (0x00ff & (b << 0)));
590} /* dns_k_shuffle16() */
591
592
593/*
594 * U T I L I T Y R O U T I N E S
595 *
596 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
597
598#define DNS_MAXINTERVAL 300
599
600struct dns_clock {
601 time_t sample, elapsed;
602}; /* struct dns_clock */
603
604static void dns_begin(struct dns_clock *clk) {
605 clk->sample = time(0);
606 clk->elapsed = 0;
607} /* dns_begin() */
608
609static time_t dns_elapsed(struct dns_clock *clk) {
610 time_t curtime;
611
612 if ((time_t)-1 == time(&curtime))
613 return clk->elapsed;
614
615 if (curtime > clk->sample)
616 clk->elapsed += (time_t)MIN(difftime(curtime, clk->sample), DNS_MAXINTERVAL);
617
618 clk->sample = curtime;
619
620 return clk->elapsed;
621} /* dns_elapsed() */
622
623
624static size_t dns_af_len(int af) {
625 static const size_t table[AF_MAX] = {
626 [AF_INET6] = sizeof (struct sockaddr_in6),
627 [AF_INET] = sizeof (struct sockaddr_in),
628#if defined(AF_UNIX) && !defined(_WIN32)
629 [AF_UNIX] = sizeof (struct sockaddr_un),
630#endif
631 };
632
633 return table[af];
634} /* dns_af_len() */
635
636#define dns_sa_len(sa) dns_af_len(dns_sa_family(sa))
637
638
639#define DNS_SA_NOPORT &dns_sa_noport
640static unsigned short dns_sa_noport;
641
642unsigned short *dns_sa_port(int af, void *sa) {
643 switch (af) {
644 case AF_INET6:
645 return &((struct sockaddr_in6 *)sa)->sin6_port;
646 case AF_INET:
647 return &((struct sockaddr_in *)sa)->sin_port;
648 default:
649 return DNS_SA_NOPORT;
650 }
651} /* dns_sa_port() */
652
653
654void *dns_sa_addr(int af, void *sa) {
655 switch (af) {
656 case AF_INET6:
657 return &((struct sockaddr_in6 *)sa)->sin6_addr;
658 case AF_INET:
659 return &((struct sockaddr_in *)sa)->sin_addr;
660 default:
661 return 0;
662 }
663} /* dns_sa_addr() */
664
665
666#if _WIN32
667static int dns_inet_pton(int af, const void *src, void *dst) {
668 union { struct sockaddr_in sin; struct sockaddr_in6 sin6; } u;
669
670 u.sin.sin_family = af;
671
672 if (0 != WSAStringToAddressA((void *)src, af, (void *)0, (struct sockaddr *)&u, &(int){ sizeof u }))
673 return -1;
674
675 switch (af) {
676 case AF_INET6:
677 *(struct in6_addr *)dst = u.sin6.sin6_addr;
678
679 return 1;
680 case AF_INET:
681 *(struct in_addr *)dst = u.sin.sin_addr;
682
683 return 1;
684 default:
685 return 0;
686 }
687} /* dns_inet_pton() */
688
689const char *dns_inet_ntop(int af, const void *src, void *dst, unsigned long lim) {
690 union { struct sockaddr_in sin; struct sockaddr_in6 sin6; } u;
691
692 /* NOTE: WSAAddressToString will print .sin_port unless zeroed. */
693 memset(&u, 0, sizeof u);
694
695 u.sin.sin_family = af;
696
697 switch (af) {
698 case AF_INET6:
699 u.sin6.sin6_addr = *(struct in6_addr *)src;
700 break;
701 case AF_INET:
702 u.sin.sin_addr = *(struct in_addr *)src;
703
704 break;
705 default:
706 return 0;
707 }
708
709 if (0 != WSAAddressToStringA((struct sockaddr *)&u, dns_sa_len(&u), (void *)0, dst, &lim))
710 return 0;
711
712 return dst;
713} /* dns_inet_ntop() */
714#endif
715
716
717static dns_error_t dns_pton(int af, const void *src, void *dst) {
718 switch (dns_inet_pton(af, src, dst)) {
719 case 1:
720 return 0;
721 case -1:
722 return dns_soerr();
723 default:
724 return DNS_EADDRESS;
725 }
726} /* dns_pton() */
727
728
729static dns_error_t dns_ntop(int af, const void *src, void *dst, unsigned long lim) {
730 return (dns_inet_ntop(af, src, dst, lim))? 0 : dns_soerr();
731} /* dns_ntop() */
732
733
734size_t dns_strlcpy(char *dst, const char *src, size_t lim) {
735 char *d = dst;
736 char *e = &dst[lim];
737 const char *s = src;
738
739 if (d < e) {
740 do {
741 if ('\0' == (*d++ = *s++))
742 return s - src - 1;
743 } while (d < e);
744
745 d[-1] = '\0';
746 }
747
748 while (*s++ != '\0')
749 ;;
750
751 return s - src - 1;
752} /* dns_strlcpy() */
753
754
755size_t dns_strlcat(char *dst, const char *src, size_t lim) {
756 char *d = memchr(dst, '\0', lim);
757 char *e = &dst[lim];
758 const char *s = src;
759 const char *p;
760
761 if (d && d < e) {
762 do {
763 if ('\0' == (*d++ = *s++))
764 return d - dst - 1;
765 } while (d < e);
766
767 d[-1] = '\0';
768 }
769
770 p = s;
771
772 while (*s++ != '\0')
773 ;;
774
775 return lim + (s - p - 1);
776} /* dns_strlcat() */
777
778
779#if _WIN32
780
781static char *dns_strsep(char **sp, const char *delim) {
782 char *p;
783
784 if (!(p = *sp))
785 return 0;
786
787 *sp += strcspn(p, delim);
788
789 if (**sp != '\0') {
790 **sp = '\0';
791 ++*sp;
792 } else
793 *sp = NULL;
794
795 return p;
796} /* dns_strsep() */
797
798#else
799#define dns_strsep(...) strsep(__VA_ARGS__)
800#endif
801
802
803#if _WIN32
804#define strcasecmp(...) _stricmp(__VA_ARGS__)
805#define strncasecmp(...) _strnicmp(__VA_ARGS__)
806#endif
807
808
809static int dns_poll(int fd, short events, int timeout) {
810 fd_set rset, wset;
811
812 if (!events)
813 return 0;
814
815 assert(fd >= 0 && (unsigned)fd < FD_SETSIZE);
816
817 FD_ZERO(&rset);
818 FD_ZERO(&wset);
819
820 if (events & DNS_POLLIN)
821 FD_SET(fd, &rset);
822
823 if (events & DNS_POLLOUT)
824 FD_SET(fd, &wset);
825
826 select(fd + 1, &rset, &wset, 0, (timeout >= 0)? &(struct timeval){ timeout, 0 } : NULL);
827
828 return 0;
829} /* dns_poll() */
830
831
832#if !_WIN32
833DNS_NOTUSED static int dns_sigmask(int how, const sigset_t *set, sigset_t *oset) {
834#if DNS_THREAD_SAFE
835 return pthread_sigmask(how, set, oset);
836#else
837 return (0 == sigprocmask(how, set, oset))? 0 : errno;
838#endif
839} /* dns_sigmask() */
840#endif
841
842
843static long dns_send(int fd, const void *src, size_t lim, int flags) {
844#if _WIN32 || !defined SIGPIPE || defined SO_NOSIGPIPE
845 return send(fd, src, lim, flags);
846#elif defined MSG_NOSIGNAL
847 return send(fd, src, lim, flags|MSG_NOSIGNAL);
848#elif _POSIX_REALTIME_SIGNALS > 0 /* require sigtimedwait */
849 /*
850 * SIGPIPE handling similar to the approach described in
851 * http://krokisplace.blogspot.com/2010/02/suppressing-sigpipe-in-library.html
852 */
853 sigset_t pending, blocked, piped;
854 long count;
855 int saved, error;
856
857 sigemptyset(&pending);
858 sigpending(&pending);
859
860 if (!sigismember(&pending, SIGPIPE)) {
861 sigemptyset(&piped);
862 sigaddset(&piped, SIGPIPE);
863 sigemptyset(&blocked);
864
865 if ((error = dns_sigmask(SIG_BLOCK, &piped, &blocked)))
866 goto error;
867 }
868
869 count = send(fd, src, lim, flags);
870
871 if (!sigismember(&pending, SIGPIPE)) {
872 saved = errno;
873
874 if (count == -1 && errno == EPIPE) {
875 while (-1 == sigtimedwait(&piped, NULL, &(struct timespec){ 0, 0 }) && errno == EINTR)
876 ;;
877 }
878
879 if ((error = dns_sigmask(SIG_SETMASK, &blocked, NULL)))
880 goto error;
881
882 errno = saved;
883 }
884
885 return count;
886error:
887 errno = error;
888
889 return -1;
890#else
891#error "unable to suppress SIGPIPE"
892 return send(fd, src, lim, flags);
893#endif
894} /* dns_send() */
895
896
897/*
898 * P A C K E T R O U T I N E S
899 *
900 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
901
902unsigned dns_p_count(struct dns_packet *P, enum dns_section section) {
903 unsigned count;
904
905 switch (section) {
906 case DNS_S_QD:
907 return ntohs(dns_header(P)->qdcount);
908 case DNS_S_AN:
909 return ntohs(dns_header(P)->ancount);
910 case DNS_S_NS:
911 return ntohs(dns_header(P)->nscount);
912 case DNS_S_AR:
913 return ntohs(dns_header(P)->arcount);
914 default:
915 count = 0;
916
917 if (section & DNS_S_QD)
918 count += ntohs(dns_header(P)->qdcount);
919 if (section & DNS_S_AN)
920 count += ntohs(dns_header(P)->ancount);
921 if (section & DNS_S_NS)
922 count += ntohs(dns_header(P)->nscount);
923 if (section & DNS_S_AR)
924 count += ntohs(dns_header(P)->arcount);
925
926 return count;
927 }
928} /* dns_p_count() */
929
930
931struct dns_packet *dns_p_init(struct dns_packet *P, size_t size) {
932 if (!P)
933 return 0;
934
935 assert(size >= offsetof(struct dns_packet, data) + 12);
936
937 memset(P, 0, sizeof *P);
938 P->size = size - offsetof(struct dns_packet, data);
939 P->end = 12;
940
941 memset(P->data, '\0', 12);
942
943 return P;
944} /* dns_p_init() */
945
946
947static unsigned short dns_p_qend(struct dns_packet *P) {
948 unsigned short qend = 12;
949 unsigned i, count = dns_p_count(P, DNS_S_QD);
950
951 for (i = 0; i < count && qend < P->end; i++) {
952 if (P->end == (qend = dns_d_skip(qend, P)))
953 goto invalid;
954
955 if (P->end - qend < 4)
956 goto invalid;
957
958 qend += 4;
959 }
960
961 return MIN(qend, P->end);
962invalid:
963 return P->end;
964} /* dns_p_qend() */
965
966
967struct dns_packet *dns_p_make(size_t len, int *error) {
968 struct dns_packet *P;
969 size_t size = dns_p_calcsize(len);
970
971 if (!(P = dns_p_init(malloc(size), size)))
972 *error = dns_syerr();
973
974 return P;
975} /* dns_p_make() */
976
977
978int dns_p_grow(struct dns_packet **P) {
979 struct dns_packet *tmp;
980 size_t size;
981 int error;
982
983 if (!*P) {
984 if (!(*P = dns_p_make(DNS_P_QBUFSIZ, &error)))
985 return error;
986
987 return 0;
988 }
989
990 size = dns_p_sizeof(*P);
991 size |= size >> 1;
992 size |= size >> 2;
993 size |= size >> 4;
994 size |= size >> 8;
995 size++;
996
997 if (size > 65536)
998 return DNS_ENOBUFS;
999
1000 if (!(tmp = realloc(*P, dns_p_calcsize(size))))
1001 return dns_syerr();
1002
1003 tmp->size = size;
1004 *P = tmp;
1005
1006 return 0;
1007} /* dns_p_grow() */
1008
1009
1010struct dns_packet *dns_p_copy(struct dns_packet *P, const struct dns_packet *P0) {
1011 if (!P)
1012 return 0;
1013
1014 P->end = MIN(P->size, P0->end);
1015
1016 memcpy(P->data, P0->data, P->end);
1017
1018 return P;
1019} /* dns_p_copy() */
1020
1021
1022struct dns_packet *dns_p_merge(struct dns_packet *A, enum dns_section Amask, struct dns_packet *B, enum dns_section Bmask, int *error_) {
1023 size_t bufsiz = MIN(65535, ((A)? A->end : 0) + ((B)? B->end : 0));
1024 struct dns_packet *M;
1025 enum dns_section section;
1026 struct dns_rr rr, mr;
1027 int error, copy;
1028
1029 if (!A && B) {
1030 A = B;
1031 Amask = Bmask;
1032 B = 0;
1033 }
1034
1035merge:
1036 if (!(M = dns_p_make(bufsiz, &error)))
1037 goto error;
1038
1039 for (section = DNS_S_QD; (DNS_S_ALL & section); section <<= 1) {
1040 if (A && (section & Amask)) {
1041 dns_rr_foreach(&rr, A, .section = section) {
1042 if ((error = dns_rr_copy(M, &rr, A)))
1043 goto error;
1044 }
1045 }
1046
1047 if (B && (section & Bmask)) {
1048 dns_rr_foreach(&rr, B, .section = section) {
1049 copy = 1;
1050
1051 dns_rr_foreach(&mr, M, .type = rr.type, .section = DNS_S_ALL) {
1052 if (!(copy = dns_rr_cmp(&rr, B, &mr, M)))
1053 break;
1054 }
1055
1056 if (copy && (error = dns_rr_copy(M, &rr, B)))
1057 goto error;
1058 }
1059 }
1060 }
1061
1062 return M;
1063error:
1064 free(M); M = 0;
1065
1066 if (error == DNS_ENOBUFS && bufsiz < 65535) {
1067 bufsiz = MIN(65535, bufsiz * 2);
1068
1069 goto merge;
1070 }
1071
1072 *error_ = error;
1073
1074 return 0;
1075} /* dns_p_merge() */
1076
1077
1078static unsigned short dns_l_skip(unsigned short, const unsigned char *, size_t);
1079
1080void dns_p_dictadd(struct dns_packet *P, unsigned short dn) {
1081 unsigned short lp, lptr, i;
1082
1083 lp = dn;
1084
1085 while (lp < P->end) {
1086 if (0xc0 == (0xc0 & P->data[lp]) && P->end - lp >= 2 && lp != dn) {
1087 lptr = ((0x3f & P->data[lp + 0]) << 8)
1088 | ((0xff & P->data[lp + 1]) << 0);
1089
1090 for (i = 0; i < lengthof(P->dict) && P->dict[i]; i++) {
1091 if (P->dict[i] == lptr) {
1092 P->dict[i] = dn;
1093
1094 return;
1095 }
1096 }
1097 }
1098
1099 lp = dns_l_skip(lp, P->data, P->end);
1100 }
1101
1102 for (i = 0; i < lengthof(P->dict); i++) {
1103 if (!P->dict[i]) {
1104 P->dict[i] = dn;
1105
1106 break;
1107 }
1108 }
1109} /* dns_p_dictadd() */
1110
1111
1112int dns_p_push(struct dns_packet *P, enum dns_section section, const void *dn, size_t dnlen, enum dns_type type, enum dns_class class, unsigned ttl, const void *any) {
1113 size_t end = P->end;
1114 int error;
1115
1116 if ((error = dns_d_push(P, dn, dnlen)))
1117 goto error;
1118
1119 if (P->size - P->end < 4)
1120 goto nobufs;
1121
1122 P->data[P->end++] = 0xff & (type >> 8);
1123 P->data[P->end++] = 0xff & (type >> 0);
1124
1125 P->data[P->end++] = 0xff & (class >> 8);
1126 P->data[P->end++] = 0xff & (class >> 0);
1127
1128 if (section == DNS_S_QD)
1129 goto update;
1130
1131 if (P->size - P->end < 6)
1132 goto nobufs;
1133
1134 P->data[P->end++] = 0x7f & (ttl >> 24);
1135 P->data[P->end++] = 0xff & (ttl >> 16);
1136 P->data[P->end++] = 0xff & (ttl >> 8);
1137 P->data[P->end++] = 0xff & (ttl >> 0);
1138
1139 if ((error = dns_any_push(P, (union dns_any *)any, type)))
1140 goto error;
1141
1142update:
1143 switch (section) {
1144 case DNS_S_QD:
1145 if (dns_p_count(P, DNS_S_AN|DNS_S_NS|DNS_S_AR))
1146 goto order;
1147
1148 if (!P->qd.base && (error = dns_p_study(P)))
1149 goto error;
1150
1151 dns_header(P)->qdcount = htons(ntohs(dns_header(P)->qdcount) + 1);
1152
1153 P->qd.end = P->end;
1154 P->an.base = P->end;
1155 P->an.end = P->end;
1156 P->ns.base = P->end;
1157 P->ns.end = P->end;
1158 P->ar.base = P->end;
1159 P->ar.end = P->end;
1160
1161 break;
1162 case DNS_S_AN:
1163 if (dns_p_count(P, DNS_S_NS|DNS_S_AR))
1164 goto order;
1165
1166 if (!P->an.base && (error = dns_p_study(P)))
1167 goto error;
1168
1169 dns_header(P)->ancount = htons(ntohs(dns_header(P)->ancount) + 1);
1170
1171 P->an.end = P->end;
1172 P->ns.base = P->end;
1173 P->ns.end = P->end;
1174 P->ar.base = P->end;
1175 P->ar.end = P->end;
1176
1177 break;
1178 case DNS_S_NS:
1179 if (dns_p_count(P, DNS_S_AR))
1180 goto order;
1181
1182 if (!P->ns.base && (error = dns_p_study(P)))
1183 goto error;
1184
1185 dns_header(P)->nscount = htons(ntohs(dns_header(P)->nscount) + 1);
1186
1187 P->ns.end = P->end;
1188 P->ar.base = P->end;
1189 P->ar.end = P->end;
1190
1191 break;
1192 case DNS_S_AR:
1193 if (!P->ar.base && (error = dns_p_study(P)))
1194 goto error;
1195
1196 dns_header(P)->arcount = htons(ntohs(dns_header(P)->arcount) + 1);
1197
1198 P->ar.end = P->end;
1199
1200 break;
1201 default:
1202 error = DNS_ESECTION;
1203
1204 goto error;
1205 } /* switch() */
1206
1207 return 0;
1208nobufs:
1209 error = DNS_ENOBUFS;
1210
1211 goto error;
1212order:
1213 error = DNS_EORDER;
1214
1215 goto error;
1216error:
1217 P->end = end;
1218
1219 return error;
1220} /* dns_p_push() */
1221
1222
1223static void dns_p_dump3(struct dns_packet *P, struct dns_rr_i *I, FILE *fp) {
1224 enum dns_section section;
1225 struct dns_rr rr;
1226 int error;
1227 union dns_any any;
1228 char pretty[sizeof any * 2];
1229 size_t len;
1230
1231 fputs(";; [HEADER]\n", fp);
1232 fprintf(fp, ";; qr : %s(%d)\n", (dns_header(P)->qr)? "RESPONSE" : "QUERY", dns_header(P)->qr);
1233 fprintf(fp, ";; opcode : %s(%d)\n", dns_stropcode(dns_header(P)->opcode), dns_header(P)->opcode);
1234 fprintf(fp, ";; aa : %s(%d)\n", (dns_header(P)->aa)? "AUTHORITATIVE" : "NON-AUTHORITATIVE", dns_header(P)->aa);
1235 fprintf(fp, ";; tc : %s(%d)\n", (dns_header(P)->tc)? "TRUNCATED" : "NOT-TRUNCATED", dns_header(P)->tc);
1236 fprintf(fp, ";; rd : %s(%d)\n", (dns_header(P)->rd)? "RECURSION-DESIRED" : "RECURSION-NOT-DESIRED", dns_header(P)->rd);
1237 fprintf(fp, ";; ra : %s(%d)\n", (dns_header(P)->ra)? "RECURSION-ALLOWED" : "RECURSION-NOT-ALLOWED", dns_header(P)->ra);
1238 fprintf(fp, ";; rcode : %s(%d)\n", dns_strrcode(dns_header(P)->rcode), dns_header(P)->rcode);
1239
1240 section = 0;
1241
1242 while (dns_rr_grep(&rr, 1, I, P, &error)) {
1243 if (section != rr.section)
1244 fprintf(fp, "\n;; [%s:%d]\n", dns_strsection(rr.section), dns_p_count(P, rr.section));
1245
1246 if ((len = dns_rr_print(pretty, sizeof pretty, &rr, P, &error)))
1247 fprintf(fp, "%s\n", pretty);
1248
1249 section = rr.section;
1250 }
1251} /* dns_p_dump3() */
1252
1253
1254void dns_p_dump(struct dns_packet *P, FILE *fp) {
1255 dns_p_dump3(P, dns_rr_i_new(P, .section = 0), fp);
1256} /* dns_p_dump() */
1257
1258
1259static void dns_s_unstudy(struct dns_s_memo *m)
1260 { m->base = 0; m->end = 0; }
1261
1262static void dns_p_unstudy(struct dns_packet *P) {
1263 dns_s_unstudy(&P->qd);
1264 dns_s_unstudy(&P->an);
1265 dns_s_unstudy(&P->ns);
1266 dns_s_unstudy(&P->ar);
1267} /* dns_p_unstudy() */
1268
1269static int dns_s_study(struct dns_s_memo *m, enum dns_section section, unsigned base, struct dns_packet *P) {
1270 unsigned short count, rp;
1271
1272 count = dns_p_count(P, section);
1273
1274 for (rp = base; count && rp < P->end; count--)
1275 rp = dns_rr_skip(rp, P);
1276
1277 m->base = base;
1278 m->end = rp;
1279
1280 return 0;
1281} /* dns_s_study() */
1282
1283int dns_p_study(struct dns_packet *P) {
1284 int error;
1285
1286 if ((error = dns_s_study(&P->qd, DNS_S_QD, 12, P)))
1287 goto error;
1288
1289 if ((error = dns_s_study(&P->an, DNS_S_AN, P->qd.end, P)))
1290 goto error;
1291
1292 if ((error = dns_s_study(&P->ns, DNS_S_NS, P->an.end, P)))
1293 goto error;
1294
1295 if ((error = dns_s_study(&P->ar, DNS_S_AR, P->ns.end, P)))
1296 goto error;
1297
1298 return 0;
1299error:
1300 dns_p_unstudy(P);
1301
1302 return error;
1303} /* dns_p_study() */
1304
1305
1306/*
1307 * D O M A I N N A M E R O U T I N E S
1308 *
1309 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1310
1311#ifndef DNS_D_MAXPTRS
1312#define DNS_D_MAXPTRS 127 /* Arbitrary; possible, valid depth is something like packet size / 2 + fudge. */
1313#endif
1314
1315static size_t dns_l_expand(unsigned char *dst, size_t lim, unsigned short src, unsigned short *nxt, const unsigned char *data, size_t end) {
1316 unsigned short len;
1317 unsigned nptrs = 0;
1318
1319retry:
1320 if (src >= end)
1321 goto invalid;
1322
1323 switch (0x03 & (data[src] >> 6)) {
1324 case 0x00:
1325 len = (0x3f & (data[src++]));
1326
1327 if (end - src < len)
1328 goto invalid;
1329
1330 if (lim > 0) {
1331 memcpy(dst, &data[src], MIN(lim, len));
1332
1333 dst[MIN(lim - 1, len)] = '\0';
1334 }
1335
1336 *nxt = src + len;
1337
1338 return len;
1339 case 0x01:
1340 goto invalid;
1341 case 0x02:
1342 goto invalid;
1343 case 0x03:
1344 if (++nptrs > DNS_D_MAXPTRS)
1345 goto invalid;
1346
1347 if (end - src < 2)
1348 goto invalid;
1349
1350 src = ((0x3f & data[src + 0]) << 8)
1351 | ((0xff & data[src + 1]) << 0);
1352
1353 goto retry;
1354 } /* switch() */
1355
1356 /* NOT REACHED */
1357invalid:
1358 *nxt = end;
1359
1360 return 0;
1361} /* dns_l_expand() */
1362
1363
1364static unsigned short dns_l_skip(unsigned short src, const unsigned char *data, size_t end) {
1365 unsigned short len;
1366
1367 if (src >= end)
1368 goto invalid;
1369
1370 switch (0x03 & (data[src] >> 6)) {
1371 case 0x00:
1372 len = (0x3f & (data[src++]));
1373
1374 if (end - src < len)
1375 goto invalid;
1376
1377 return (len)? src + len : end;
1378 case 0x01:
1379 goto invalid;
1380 case 0x02:
1381 goto invalid;
1382 case 0x03:
1383 return end;
1384 } /* switch() */
1385
1386 /* NOT REACHED */
1387invalid:
1388 return end;
1389} /* dns_l_skip() */
1390
1391
1392size_t dns_d_trim(void *dst_, size_t lim, const void *src_, size_t len, int flags) {
1393 unsigned char *dst = dst_;
1394 const unsigned char *src = src_;
1395 size_t dp = 0, sp = 0;
1396 int lc;
1397
1398 /* trim any leading dot(s) */
1399 while (sp < len && src[sp] == '.')
1400 sp++;
1401
1402 for (lc = 0; sp < len; lc = src[sp++]) {
1403 /* trim extra dot(s) */
1404 if (src[sp] == '.' && lc == '.')
1405 continue;
1406
1407 if (dp < lim)
1408 dst[dp] = src[sp];
1409
1410 dp++;
1411 }
1412
1413 if ((flags & DNS_D_ANCHOR) && lc != '.') {
1414 if (dp < lim)
1415 dst[dp] = '.';
1416
1417 dp++;
1418 }
1419
1420 if (lim > 0)
1421 dst[MIN(dp, lim - 1)] = '\0';
1422
1423 return dp;
1424} /* dns_d_trim() */
1425
1426
1427char *dns_d_init(void *dst, size_t lim, const void *src, size_t len, int flags) {
1428 if (flags & DNS_D_TRIM) {
1429 dns_d_trim(dst, lim, src, len, flags);
1430 } if (flags & DNS_D_ANCHOR) {
1431 dns_d_anchor(dst, lim, src, len);
1432 } else {
1433 memmove(dst, src, MIN(lim, len));
1434
1435 if (lim > 0)
1436 ((char *)dst)[MIN(len, lim - 1)] = '\0';
1437 }
1438
1439 return dst;
1440} /* dns_d_init() */
1441
1442
1443size_t dns_d_anchor(void *dst, size_t lim, const void *src, size_t len) {
1444 if (len == 0)
1445 return 0;
1446
1447 memmove(dst, src, MIN(lim, len));
1448
1449 if (((const char *)src)[len - 1] != '.') {
1450 if (len < lim)
1451 ((char *)dst)[len] = '.';
1452 len++;
1453 }
1454
1455 if (lim > 0)
1456 ((char *)dst)[MIN(lim - 1, len)] = '\0';
1457
1458 return len;
1459} /* dns_d_anchor() */
1460
1461
1462size_t dns_d_cleave(void *dst, size_t lim, const void *src, size_t len) {
1463 const char *dot;
1464
1465 /* XXX: Skip any leading dot. Handles cleaving root ".". */
1466 if (len == 0 || !(dot = memchr((const char *)src + 1, '.', len - 1)))
1467 return 0;
1468
1469 len -= dot - (const char *)src;
1470
1471 /* XXX: Unless root, skip the label's trailing dot. */
1472 if (len > 1) {
1473 src = ++dot;
1474 len--;
1475 } else
1476 src = dot;
1477
1478 memmove(dst, src, MIN(lim, len));
1479
1480 if (lim > 0)
1481 ((char *)dst)[MIN(lim - 1, len)] = '\0';
1482
1483 return len;
1484} /* dns_d_cleave() */
1485
1486
1487size_t dns_d_comp(void *dst_, size_t lim, const void *src_, size_t len, struct dns_packet *P, int *error DNS_NOTUSED) {
1488 struct { unsigned char *b; size_t p, x; } dst, src;
1489 unsigned char ch = '.';
1490
1491 dst.b = dst_;
1492 dst.p = 0;
1493 dst.x = 1;
1494
1495 src.b = (unsigned char *)src_;
1496 src.p = 0;
1497 src.x = 0;
1498
1499 while (src.x < len) {
1500 ch = src.b[src.x];
1501
1502 if (ch == '.') {
1503 if (dst.p < lim)
1504 dst.b[dst.p] = (0x3f & (src.x - src.p));
1505
1506 dst.p = dst.x++;
1507 src.p = ++src.x;
1508 } else {
1509 if (dst.x < lim)
1510 dst.b[dst.x] = ch;
1511
1512 dst.x++;
1513 src.x++;
1514 }
1515 } /* while() */
1516
1517 if (src.x > src.p) {
1518 if (dst.p < lim)
1519 dst.b[dst.p] = (0x3f & (src.x - src.p));
1520
1521 dst.p = dst.x;
1522 }
1523
1524 if (dst.p > 1) {
1525 if (dst.p < lim)
1526 dst.b[dst.p] = 0x00;
1527
1528 dst.p++;
1529 }
1530
1531#if 1
1532 if (dst.p < lim) {
1533 struct { unsigned char label[DNS_D_MAXLABEL + 1]; size_t len; unsigned short p, x, y; } a, b;
1534 unsigned i;
1535
1536 a.p = 0;
1537
1538 while ((a.len = dns_l_expand(a.label, sizeof a.label, a.p, &a.x, dst.b, lim))) {
1539 for (i = 0; i < lengthof(P->dict) && P->dict[i]; i++) {
1540 b.p = P->dict[i];
1541
1542 while ((b.len = dns_l_expand(b.label, sizeof b.label, b.p, &b.x, P->data, P->end))) {
1543 a.y = a.x;
1544 b.y = b.x;
1545
1546 while (a.len && b.len && 0 == strcasecmp((char *)a.label, (char *)b.label)) {
1547 a.len = dns_l_expand(a.label, sizeof a.label, a.y, &a.y, dst.b, lim);
1548 b.len = dns_l_expand(b.label, sizeof b.label, b.y, &b.y, P->data, P->end);
1549 }
1550
1551 if (a.len == 0 && b.len == 0 && b.p <= 0x3fff) {
1552 dst.b[a.p++] = 0xc0
1553 | (0x3f & (b.p >> 8));
1554 dst.b[a.p++] = (0xff & (b.p >> 0));
1555
1556 return a.p;
1557 }
1558
1559 b.p = b.x;
1560 } /* while() */
1561 } /* for() */
1562
1563 a.p = a.x;
1564 } /* while() */
1565 } /* if () */
1566#endif
1567
1568 return dst.p;
1569} /* dns_d_comp() */
1570
1571
1572unsigned short dns_d_skip(unsigned short src, struct dns_packet *P) {
1573 unsigned short len;
1574
1575 while (src < P->end) {
1576 switch (0x03 & (P->data[src] >> 6)) {
1577 case 0x00: /* FOLLOWS */
1578 len = (0x3f & P->data[src++]);
1579
1580 if (0 == len) {
1581/* success ==> */ return src;
1582 } else if (P->end - src > len) {
1583 src += len;
1584
1585 break;
1586 } else
1587 goto invalid;
1588
1589 /* NOT REACHED */
1590 case 0x01: /* RESERVED */
1591 goto invalid;
1592 case 0x02: /* RESERVED */
1593 goto invalid;
1594 case 0x03: /* POINTER */
1595 if (P->end - src < 2)
1596 goto invalid;
1597
1598 src += 2;
1599
1600/* success ==> */ return src;
1601 } /* switch() */
1602 } /* while() */
1603
1604invalid:
1605//assert(0);
1606 return P->end;
1607} /* dns_d_skip() */
1608
1609
1610#include <stdio.h>
1611
1612size_t dns_d_expand(void *dst, size_t lim, unsigned short src, struct dns_packet *P, int *error) {
1613 size_t dstp = 0;
1614 unsigned nptrs = 0;
1615 unsigned char len;
1616
1617 while (src < P->end) {
1618 switch ((0x03 & (P->data[src] >> 6))) {
1619 case 0x00: /* FOLLOWS */
1620 len = (0x3f & P->data[src]);
1621
1622 if (0 == len) {
1623 if (dstp == 0) {
1624 if (dstp < lim)
1625 ((unsigned char *)dst)[dstp] = '.';
1626
1627 dstp++;
1628 }
1629
1630 /* NUL terminate */
1631 if (lim > 0)
1632 ((unsigned char *)dst)[MIN(dstp, lim - 1)] = '\0';
1633
1634/* success ==> */ return dstp;
1635 }
1636
1637 src++;
1638
1639 if (P->end - src < len)
1640 goto toolong;
1641
1642 if (dstp < lim)
1643 memcpy(&((unsigned char *)dst)[dstp], &P->data[src], MIN(len, lim - dstp));
1644
1645 src += len;
1646 dstp += len;
1647
1648 if (dstp < lim)
1649 ((unsigned char *)dst)[dstp] = '.';
1650
1651 dstp++;
1652
1653 nptrs = 0;
1654
1655 continue;
1656 case 0x01: /* RESERVED */
1657 goto reserved;
1658 case 0x02: /* RESERVED */
1659 goto reserved;
1660 case 0x03: /* POINTER */
1661 if (++nptrs > DNS_D_MAXPTRS)
1662 goto toolong;
1663
1664 if (P->end - src < 2)
1665 goto toolong;
1666
1667 src = ((0x3f & P->data[src + 0]) << 8)
1668 | ((0xff & P->data[src + 1]) << 0);
1669
1670 continue;
1671 } /* switch() */
1672 } /* while() */
1673
1674toolong:
1675 *error = DNS_EILLEGAL;
1676
1677 if (lim > 0)
1678 ((unsigned char *)dst)[MIN(dstp, lim - 1)] = '\0';
1679
1680 return 0;
1681reserved:
1682 *error = DNS_EILLEGAL;
1683
1684 if (lim > 0)
1685 ((unsigned char *)dst)[MIN(dstp, lim - 1)] = '\0';
1686
1687 return 0;
1688} /* dns_d_expand() */
1689
1690
1691int dns_d_push(struct dns_packet *P, const void *dn, size_t len) {
1692 size_t lim = P->size - P->end;
1693 unsigned dp = P->end;
1694 int error;
1695
1696 len = dns_d_comp(&P->data[dp], lim, dn, len, P, &error);
1697
1698 if (len == 0)
1699 return error;
1700 if (len > lim)
1701 return DNS_ENOBUFS;
1702
1703 P->end += len;
1704
1705 dns_p_dictadd(P, dp);
1706
1707 return 0;
1708} /* dns_d_push() */
1709
1710
1711size_t dns_d_cname(void *dst, size_t lim, const void *dn, size_t len, struct dns_packet *P, int *error_) {
1712 char host[DNS_D_MAXNAME + 1];
1713 struct dns_rr_i i;
1714 struct dns_rr rr;
1715 unsigned depth;
1716 int error;
1717
1718 if (sizeof host <= dns_d_anchor(host, sizeof host, dn, len))
1719 { error = ENAMETOOLONG; goto error; }
1720
1721 for (depth = 0; depth < 7; depth++) {
1722 dns_rr_i_init(memset(&i, 0, sizeof i), P);
1723
1724 i.section = DNS_S_ALL & ~DNS_S_QD;
1725 i.name = host;
1726 i.type = DNS_T_CNAME;
1727
1728 if (!dns_rr_grep(&rr, 1, &i, P, &error))
1729 break;
1730
1731 if ((error = dns_cname_parse((struct dns_cname *)host, &rr, P)))
1732 goto error;
1733 }
1734
1735 return dns_strlcpy(dst, host, lim);
1736error:
1737 *error_ = error;
1738
1739 return 0;
1740} /* dns_d_cname() */
1741
1742
1743/*
1744 * R E S O U R C E R E C O R D R O U T I N E S
1745 *
1746 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1747
1748int dns_rr_copy(struct dns_packet *P, struct dns_rr *rr, struct dns_packet *Q) {
1749 unsigned char dn[DNS_D_MAXNAME + 1];
1750 union dns_any any;
1751 size_t len;
1752 int error;
1753
1754 if (!(len = dns_d_expand(dn, sizeof dn, rr->dn.p, Q, &error)))
1755 return error;
1756 else if (len >= sizeof dn)
1757 return DNS_EILLEGAL;
1758
1759 if (rr->section != DNS_S_QD && (error = dns_any_parse(dns_any_init(&any, sizeof any), rr, Q)))
1760 return error;
1761
1762 return dns_p_push(P, rr->section, dn, len, rr->type, rr->class, rr->ttl, &any);
1763} /* dns_rr_copy() */
1764
1765
1766int dns_rr_parse(struct dns_rr *rr, unsigned short src, struct dns_packet *P) {
1767 unsigned short p = src;
1768
1769 if (src >= P->end)
1770 goto invalid;
1771
1772 rr->dn.p = p;
1773 rr->dn.len = (p = dns_d_skip(p, P)) - rr->dn.p;
1774
1775 if (P->end - p < 4)
1776 goto invalid;
1777
1778 rr->type = ((0xff & P->data[p + 0]) << 8)
1779 | ((0xff & P->data[p + 1]) << 0);
1780
1781 rr->class = ((0xff & P->data[p + 2]) << 8)
1782 | ((0xff & P->data[p + 3]) << 0);
1783
1784 p += 4;
1785
1786 if (src < dns_p_qend(P)) {
1787 rr->section = DNS_S_QUESTION;
1788
1789 rr->ttl = 0;
1790 rr->rd.p = 0;
1791 rr->rd.len = 0;
1792
1793 return 0;
1794 }
1795
1796 if (P->end - p < 4)
1797 goto invalid;
1798
1799 rr->ttl = ((0x7f & P->data[p + 0]) << 24)
1800 | ((0xff & P->data[p + 1]) << 16)
1801 | ((0xff & P->data[p + 2]) << 8)
1802 | ((0xff & P->data[p + 3]) << 0);
1803
1804 p += 4;
1805
1806 if (P->end - p < 2)
1807 goto invalid;
1808
1809 rr->rd.len = ((0xff & P->data[p + 0]) << 8)
1810 | ((0xff & P->data[p + 1]) << 0);
1811 rr->rd.p = p + 2;
1812
1813 p += 2;
1814
1815 if (P->end - p < rr->rd.len)
1816 goto invalid;
1817
1818 return 0;
1819invalid:
1820//assert(0);
1821 return DNS_EILLEGAL;
1822} /* dns_rr_parse() */
1823
1824
1825static unsigned short dns_rr_len(const unsigned short src, struct dns_packet *P) {
1826 unsigned short rp, rdlen;
1827
1828 rp = dns_d_skip(src, P);
1829
1830 if (P->end - rp < 4)
1831 return P->end - src;
1832
1833 rp += 4; /* TYPE, CLASS */
1834
1835 if (rp <= dns_p_qend(P))
1836 return rp - src;
1837
1838 if (P->end - rp < 6)
1839 return P->end - src;
1840
1841 rp += 6; /* TTL, RDLEN */
1842
1843 rdlen = ((0xff & P->data[rp - 2]) << 8)
1844 | ((0xff & P->data[rp - 1]) << 0);
1845
1846 if (P->end - rp < rdlen)
1847 return P->end - src;
1848
1849 rp += rdlen;
1850
1851 return rp - src;
1852} /* dns_rr_len() */
1853
1854
1855unsigned short dns_rr_skip(unsigned short src, struct dns_packet *P) {
1856 return src + dns_rr_len(src, P);
1857} /* dns_rr_skip() */
1858
1859
1860static enum dns_section dns_rr_section(unsigned short src, struct dns_packet *P) {
1861 enum dns_section section;
1862 unsigned count, ind;
1863 unsigned short rp;
1864
1865 if (src >= P->qd.base && src < P->qd.end)
1866 return DNS_S_QD;
1867 if (src >= P->an.base && src < P->an.end)
1868 return DNS_S_AN;
1869 if (src >= P->ns.base && src < P->ns.end)
1870 return DNS_S_NS;
1871 if (src >= P->ar.base && src < P->ar.end)
1872 return DNS_S_AR;
1873
1874 /* NOTE: Possibly bad memoization. Try it the hard-way. */
1875
1876 for (rp = 12, ind = 0; rp < src && rp < P->end; ind++)
1877 rp = dns_rr_skip(rp, P);
1878
1879 section = DNS_S_QD;
1880 count = dns_p_count(P, section);
1881
1882 while (ind >= count && section <= DNS_S_AR) {
1883 section <<= 1;
1884 count += dns_p_count(P, section);
1885 }
1886
1887 return DNS_S_ALL & section;
1888} /* dns_rr_section() */
1889
1890
1891static enum dns_type dns_rr_type(unsigned short src, struct dns_packet *P) {
1892 struct dns_rr rr;
1893 int error;
1894
1895 if ((error = dns_rr_parse(&rr, src, P)))
1896 return 0;
1897
1898 return rr.type;
1899} /* dns_rr_type() */
1900
1901
1902int dns_rr_cmp(struct dns_rr *r0, struct dns_packet *P0, struct dns_rr *r1, struct dns_packet *P1) {
1903 char host0[DNS_D_MAXNAME + 1], host1[DNS_D_MAXNAME + 1];
1904 union dns_any any0, any1;
1905 int cmp, error;
1906 size_t len;
1907
1908 if ((cmp = r0->type - r1->type))
1909 return cmp;
1910
1911 if ((cmp = r0->class - r1->class))
1912 return cmp;
1913
1914 /*
1915 * FIXME: Do label-by-label comparison to handle illegally long names?
1916 */
1917
1918 if (!(len = dns_d_expand(host0, sizeof host0, r0->dn.p, P0, &error))
1919 || len >= sizeof host0)
1920 return -1;
1921
1922 if (!(len = dns_d_expand(host1, sizeof host1, r1->dn.p, P1, &error))
1923 || len >= sizeof host1)
1924 return 1;
1925
1926 if ((cmp = strcasecmp(host0, host1)))
1927 return cmp;
1928
1929 if (DNS_S_QD & (r0->section | r1->section)) {
1930 if (r0->section == r1->section)
1931 return 0;
1932
1933 return (r0->section == DNS_S_QD)? -1 : 1;
1934 }
1935
1936 if ((error = dns_any_parse(&any0, r0, P0)))
1937 return -1;
1938
1939 if ((error = dns_any_parse(&any1, r1, P1)))
1940 return 1;
1941
1942 return dns_any_cmp(&any0, r0->type, &any1, r1->type);
1943} /* dns_rr_cmp() */
1944
1945
1946static _Bool dns_rr_exists(struct dns_rr *rr0, struct dns_packet *P0, struct dns_packet *P1) {
1947 struct dns_rr rr1;
1948
1949 dns_rr_foreach(&rr1, P1, .section = rr0->section, .type = rr0->type) {
1950 if (0 == dns_rr_cmp(rr0, P0, &rr1, P1))
1951 return 1;
1952 }
1953
1954 return 0;
1955} /* dns_rr_exists() */
1956
1957
1958static unsigned short dns_rr_offset(struct dns_rr *rr) {
1959 return rr->dn.p;
1960} /* dns_rr_offset() */
1961
1962
1963static _Bool dns_rr_i_match(struct dns_rr *rr, struct dns_rr_i *i, struct dns_packet *P) {
1964 if (i->section && !(rr->section & i->section))
1965 return 0;
1966
1967 if (i->type && rr->type != i->type && i->type != DNS_T_ALL)
1968 return 0;
1969
1970 if (i->class && rr->class != i->class && i->class != DNS_C_ANY)
1971 return 0;
1972
1973 if (i->name) {
1974 char dn[DNS_D_MAXNAME + 1];
1975 size_t len;
1976 int error;
1977
1978 if (!(len = dns_d_expand(dn, sizeof dn, rr->dn.p, P, &error))
1979 || len >= sizeof dn)
1980 return 0;
1981
1982 if (0 != strcasecmp(dn, i->name))
1983 return 0;
1984 }
1985
1986 if (i->data && i->type && rr->section > DNS_S_QD) {
1987 union dns_any rd;
1988 int error;
1989
1990 if ((error = dns_any_parse(&rd, rr, P)))
1991 return 0;
1992
1993 if (0 != dns_any_cmp(&rd, rr->type, i->data, i->type))
1994 return 0;
1995 }
1996
1997 return 1;
1998} /* dns_rr_i_match() */
1999
2000
2001static unsigned short dns_rr_i_start(struct dns_rr_i *i, struct dns_packet *P) {
2002 unsigned short rp;
2003 struct dns_rr r0, rr;
2004 int error;
2005
2006 if ((i->section & DNS_S_QD) && P->qd.base)
2007 rp = P->qd.base;
2008 else if ((i->section & DNS_S_AN) && P->an.base)
2009 rp = P->an.base;
2010 else if ((i->section & DNS_S_NS) && P->ns.base)
2011 rp = P->ns.base;
2012 else if ((i->section & DNS_S_AR) && P->ar.base)
2013 rp = P->ar.base;
2014 else
2015 rp = 12;
2016
2017 for (; rp < P->end; rp = dns_rr_skip(rp, P)) {
2018 if ((error = dns_rr_parse(&rr, rp, P)))
2019 continue;
2020
2021 rr.section = dns_rr_section(rp, P);
2022
2023 if (!dns_rr_i_match(&rr, i, P))
2024 continue;
2025
2026 r0 = rr;
2027
2028 goto lower;
2029 }
2030
2031 return P->end;
2032lower:
2033 if (i->sort == &dns_rr_i_packet)
2034 return dns_rr_offset(&r0);
2035
2036 while ((rp = dns_rr_skip(rp, P)) < P->end) {
2037 if ((error = dns_rr_parse(&rr, rp, P)))
2038 continue;
2039
2040 rr.section = dns_rr_section(rp, P);
2041
2042 if (!dns_rr_i_match(&rr, i, P))
2043 continue;
2044
2045 if (i->sort(&rr, &r0, i, P) < 0)
2046 r0 = rr;
2047 }
2048
2049 return dns_rr_offset(&r0);
2050} /* dns_rr_i_start() */
2051
2052
2053static unsigned short dns_rr_i_skip(unsigned short rp, struct dns_rr_i *i, struct dns_packet *P) {
2054 struct dns_rr r0, r1, rr;
2055 int error;
2056
2057 if ((error = dns_rr_parse(&r0, rp, P)))
2058 return P->end;
2059
2060 r0.section = dns_rr_section(rp, P);
2061
2062 rp = (i->sort == &dns_rr_i_packet)? dns_rr_skip(rp, P) : 12;
2063
2064 for (; rp < P->end; rp = dns_rr_skip(rp, P)) {
2065 if ((error = dns_rr_parse(&rr, rp, P)))
2066 continue;
2067
2068 rr.section = dns_rr_section(rp, P);
2069
2070 if (!dns_rr_i_match(&rr, i, P))
2071 continue;
2072
2073 if (i->sort(&rr, &r0, i, P) <= 0)
2074 continue;
2075
2076 r1 = rr;
2077
2078 goto lower;
2079 }
2080
2081 return P->end;
2082lower:
2083 if (i->sort == &dns_rr_i_packet)
2084 return dns_rr_offset(&r1);
2085
2086 while ((rp = dns_rr_skip(rp, P)) < P->end) {
2087 if ((error = dns_rr_parse(&rr, rp, P)))
2088 continue;
2089
2090 rr.section = dns_rr_section(rp, P);
2091
2092 if (!dns_rr_i_match(&rr, i, P))
2093 continue;
2094
2095 if (i->sort(&rr, &r0, i, P) <= 0)
2096 continue;
2097
2098 if (i->sort(&rr, &r1, i, P) >= 0)
2099 continue;
2100
2101 r1 = rr;
2102 }
2103
2104 return dns_rr_offset(&r1);
2105} /* dns_rr_i_skip() */
2106
2107
2108int dns_rr_i_packet(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i DNS_NOTUSED, struct dns_packet *P DNS_NOTUSED) {
2109 return (int)a->dn.p - (int)b->dn.p;
2110} /* dns_rr_i_packet() */
2111
2112
2113int dns_rr_i_order(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i DNS_NOTUSED, struct dns_packet *P) {
2114 int cmp;
2115
2116 if ((cmp = a->section - b->section))
2117 return cmp;
2118
2119 if (a->type != b->type)
2120 return (int)a->dn.p - (int)b->dn.p;
2121
2122 return dns_rr_cmp(a, P, b, P);
2123} /* dns_rr_i_order() */
2124
2125
2126int dns_rr_i_shuffle(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i, struct dns_packet *P DNS_NOTUSED) {
2127 int cmp;
2128
2129 while (!i->state.regs[0])
2130 i->state.regs[0] = dns_random();
2131
2132 if ((cmp = a->section - b->section))
2133 return cmp;
2134
2135 return dns_k_shuffle16(a->dn.p, i->state.regs[0]) - dns_k_shuffle16(b->dn.p, i->state.regs[0]);
2136} /* dns_rr_i_shuffle() */
2137
2138
2139struct dns_rr_i *dns_rr_i_init(struct dns_rr_i *i, struct dns_packet *P DNS_NOTUSED) {
2140 static const struct dns_rr_i i_initializer;
2141
2142 i->state = i_initializer.state;
2143 i->saved = i->state;
2144
2145 return i;
2146} /* dns_rr_i_init() */
2147
2148
2149unsigned dns_rr_grep(struct dns_rr *rr, unsigned lim, struct dns_rr_i *i, struct dns_packet *P, int *error_) {
2150 unsigned count = 0;
2151 int error;
2152
2153 switch (i->state.exec) {
2154 case 0:
2155 if (!i->sort)
2156 i->sort = &dns_rr_i_packet;
2157
2158 i->state.next = dns_rr_i_start(i, P);
2159 i->state.exec++;
2160
2161 /* FALL THROUGH */
2162 case 1:
2163 while (count < lim && i->state.next < P->end) {
2164 if ((error = dns_rr_parse(rr, i->state.next, P)))
2165 goto error;
2166
2167 rr->section = dns_rr_section(i->state.next, P);
2168
2169 rr++;
2170 count++;
2171 i->state.count++;
2172
2173 i->state.next = dns_rr_i_skip(i->state.next, i, P);
2174 } /* while() */
2175
2176 break;
2177 } /* switch() */
2178
2179 return count;
2180error:
2181 *error_ = error;
2182
2183 return count;
2184} /* dns_rr_grep() */
2185
2186
2187static size_t dns__printchar(void *dst, size_t lim, size_t cp, unsigned char ch) {
2188 if (cp < lim)
2189 ((unsigned char *)dst)[cp] = ch;