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
114
115
116
117
|
#include "byte.h"
#include "dnsresolv.h"
#include "env.h"
#include "ip.h"
#include "readclose.h"
#include "socket_if.h"
#include "taia.h"
/**
@file dns_rcip.c
@author djb, fefe, feh
@source ucspi-tcp
@brief DNS receive for query
*/
static stralloc data = {0};
static stralloc ifname = {0};
static int init(char ip[QUERY_MAXIPLEN], uint32 sid[QUERY_MAXNS])
{
int i;
int j;
int k = 0;
int iplen = 0;
char *x;
char ip4[4];
/* Read (compactified) IPv4|v6 addresses of resolvers
Store them in array IP with fixed length:
ip(64) -> 16 IPv4 addresses (not used anymore)
ip(512) -> 16*2 IPv6 addresses (we use IPv4 mapped IPv6 addresses)
sid(32) -> the scope for the respective IPv6 or 0
*/
for (i = 0; i < QUERY_MAXNS; ++i) sid[i] = 0;
x = env_get("DNSCACHEIP");
if (x) {
while (iplen <= 240 && *x != '\0') {
if (*x == ' ') {
++x;
} else if ((i = ip6_ifscan(x, ip + iplen, &ifname))) {
if (ifname.len > 2) sid[k] = socket_getifidx(ifname.s);
iplen += 16;
k++;
if (*(x += i) == '\0') break;
}
}
}
if (!iplen) {
i = openreadclose("/etc/resolv.conf", &data, 64);
if (i == -1) return DNS_INT;
if (i) {
if (!stralloc_append(&data, "\n")) return DNS_MEM;
i = 0;
for (j = 0; j < data.len; ++j) {
if (data.s[j] == '\n') {
if (byte_equal("nameserver ", 11, data.s + i) || byte_equal("nameserver\t", 11, data.s + i)) {
i += 10;
while ((data.s[i] == ' ') || (data.s[i] == '\t')) i++;
if (iplen <= 240) {
data.s[j] = '\0'; /* ip6_ifscan needs terminated string on input */
if (ip4_scan(data.s + i, ip4)) {
if (byte_equal(ip4, 4, "\0\0\0\0")) byte_copy(ip4, 4, "\177\0\0\1");
byte_copy(ip + iplen, 12, V4mappedprefix);
byte_copy(ip + iplen + 12, 4, ip4);
sid[k] = 0;
iplen += 16;
k++;
} else if (ip6_ifscan(data.s + i, ip + iplen, &ifname)) {
if (ifname.len > 2) sid[k] = socket_getifidx(ifname.s);
iplen += 16;
k++;
}
}
}
i = j + 1;
}
}
}
}
if (!iplen) {
byte_copy(ip, 16, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1");
iplen = 16;
}
byte_zero(ip + iplen, QUERY_MAXIPLEN - iplen);
return 0;
}
static int ok = 0;
static unsigned int uses;
static struct taia deadline;
static char ip[QUERY_MAXIPLEN]; /* defined if ok */
static uint32 scopes[QUERY_MAXNS];
int dns_resolvconfip(char s[QUERY_MAXIPLEN], uint32 scope[QUERY_MAXNS])
{
struct taia now;
taia_now(&now);
if (taia_less(&deadline, &now)) ok = 0;
if (!uses) ok = 0;
if (!ok) {
if (init(ip, scopes) < 0) return DNS_INT;
taia_uint(&deadline, 600);
taia_add(&deadline, &now, &deadline);
uses = 10000;
ok = 1;
}
--uses;
byte_copy(s, QUERY_MAXIPLEN, ip);
byte_copy(scope, 128, scopes);
return 0;
}
|