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
|
/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 dated June, 1991, or
(at your option) version 3 dated 29 June, 2007.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "dnsmasq.h"
#ifdef HAVE_LOOP
static ssize_t loop_make_probe(u32 uid);
void loop_send_probes()
{
struct server *serv;
if (!option_bool(OPT_LOOP_DETECT))
return;
/* Loop through all upstream servers not for particular domains, and send a query to that server which is
identifiable, via the uid. If we see that query back again, then the server is looping, and we should not use it. */
for (serv = daemon->servers; serv; serv = serv->next)
if (!(serv->flags &
(SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_LOOP)))
{
ssize_t len = loop_make_probe(serv->uid);
int fd;
struct randfd *rfd = NULL;
if (serv->sfd)
fd = serv->sfd->fd;
else
{
if (!(rfd = allocate_rfd(serv->addr.sa.sa_family)))
continue;
fd = rfd->fd;
}
while (retry_send(sendto(fd, daemon->packet, len, 0,
&serv->addr.sa, sa_len(&serv->addr))));
free_rfd(rfd);
}
}
static ssize_t loop_make_probe(u32 uid)
{
struct dns_header *header = (struct dns_header *)daemon->packet;
unsigned char *p = (unsigned char *)(header+1);
/* packet buffer overwritten */
daemon->srv_save = NULL;
header->id = rand16();
header->ancount = header->nscount = header->arcount = htons(0);
header->qdcount = htons(1);
header->hb3 = HB3_RD;
header->hb4 = 0;
SET_OPCODE(header, QUERY);
*p++ = 8;
sprintf((char *)p, "%.8x", uid);
p += 8;
*p++ = strlen(LOOP_TEST_DOMAIN);
strcpy((char *)p, LOOP_TEST_DOMAIN); /* Add terminating zero */
p += strlen(LOOP_TEST_DOMAIN) + 1;
PUTSHORT(LOOP_TEST_TYPE, p);
PUTSHORT(C_IN, p);
return p - (unsigned char *)header;
}
int detect_loop(char *query, int type)
{
int i;
u32 uid;
struct server *serv;
if (!option_bool(OPT_LOOP_DETECT))
return 0;
if (type != LOOP_TEST_TYPE ||
strlen(LOOP_TEST_DOMAIN) + 9 != strlen(query) ||
strstr(query, LOOP_TEST_DOMAIN) != query + 9)
return 0;
for (i = 0; i < 8; i++)
if (!isxdigit(query[i]))
return 0;
uid = strtol(query, NULL, 16);
for (serv = daemon->servers; serv; serv = serv->next)
if (!(serv->flags &
(SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_LOOP)) &&
uid == serv->uid)
{
serv->flags |= SERV_LOOP;
check_servers(); /* log new state */
return 1;
}
return 0;
}
#endif
|