-
Notifications
You must be signed in to change notification settings - Fork 39
/
Copy pathdns_prefetch_macos.c
113 lines (97 loc) · 3.87 KB
/
dns_prefetch_macos.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#include <dns_sd.h>
#include <fcntl.h>
#include <stdbool.h>
#include "libevent/util-internal.h"
#include "nn_features.h"
#include "log.h"
#include "network.h"
#include "dns_prefetch.h"
typedef struct {
DNSServiceRef sd;
char *host;
evutil_addrinfo *ai;
uint32_t min_ttl;
event *event;
network *n;
} dns_prefetch_request;
void dns_prefetch_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
DNSServiceErrorType errorCode, const char *fullname,
const sockaddr *address, uint32_t ttl, void *context)
{
dns_prefetch_request *request = (dns_prefetch_request*)context;
if (errorCode != 0) {
debug("%s host:%s errorCode:%d\n", __func__, request->host, errorCode);
return;
}
socklen_t addrlen = sockaddr_get_length(address);
evutil_addrinfo nullhints = {
.ai_family = address->sa_family,
.ai_socktype = SOCK_STREAM,
.ai_protocol = IPPROTO_TCP
};
evutil_addrinfo *a = evutil_new_addrinfo_((sockaddr*)address, addrlen, &nullhints);
debug("%s host:%s address:%s ttl:%d\n", __func__, request->host, sockaddr_str_addronly(a->ai_addr), ttl);
request->min_ttl = !request->min_ttl ? ttl : MIN(request->min_ttl, ttl);
request->ai = evutil_addrinfo_append_(request->ai, a);
if (!(flags & kDNSServiceFlagsMoreComing)) {
network *n = request->n;
// no more DNS responses immediately queued, go ahead and update result
network_async(n, ^{
dns_prefetch_store_result(n, request->ai, request->host, request->min_ttl);
});
}
}
void platform_dns_event_cb(evutil_socket_t fd, short what, void *arg)
{
dns_prefetch_request *request = (dns_prefetch_request*)arg;
if (what & EV_READ) {
// this arranges to call dns_prefetch_callback() above
// (the Apple DNS library lets you use your own event handler)
DNSServiceErrorType error = DNSServiceProcessResult(request->sd);
if (error != kDNSServiceErr_NoError) {
debug("%s: host:%s error:%d\n", __func__, request->host, error);
}
return;
}
if (what & EV_TIMEOUT) {
event_free(request->event);
DNSServiceRefDeallocate(request->sd);
evutil_freeaddrinfo(request->ai);
free(request->host);
free(request);
}
}
void platform_dns_prefetch(network *n, const char *host)
{
if (host == NULL || *host == '\0') {
return;
}
dns_prefetch_request *request = alloc(dns_prefetch_request);
request->host = strdup(host);
request->n = n;
// No matter which kinds of addresses we reaquest,
// DNSServiceGetAddrInfo won't return A records unless we have a
// routable IPv4 address, and won't return AAAA records unless we
// have a routable IPv6 address. This is great for initiating
// connections from the local host, not so great if we pass these
// addresses to a peer.
DNSServiceErrorType error = DNSServiceGetAddrInfo(&request->sd,
kDNSServiceFlagsTimeout,
0,
kDNSServiceProtocol_IPv4|kDNSServiceProtocol_IPv6,
host,
dns_prefetch_callback,
(void*)request);
if (error != kDNSServiceErr_NoError) {
debug("%s error:%d\n", __func__, error);
return;
}
evutil_socket_t fd = DNSServiceRefSockFD(request->sd);
evutil_make_socket_closeonexec(fd);
evutil_make_socket_nonblocking(fd);
// arrange for query results to be processed
request->event = event_new(n->evbase, fd, EV_READ|EV_TIMEOUT, platform_dns_event_cb, (void*)request);
timeval timeout = { 10, 0 }; // ten seconds
event_add(request->event, &timeout);
debug("%s queued request for %s\n", __func__, host);
}