1 /* dnsmasq is Copyright (c) 2000-2022 Simon Kelley
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; version 2 dated June, 1991, or
6 (at your option) version 3 dated 29 June, 2007.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
13 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 static ssize_t loop_make_probe(u32 uid);
22 void loop_send_probes()
25 struct randfd_list *rfds = NULL;
27 if (!option_bool(OPT_LOOP_DETECT))
30 /* Loop through all upstream servers not for particular domains, and send a query to that server which is
31 identifiable, via the uid. If we see that query back again, then the server is looping, and we should not use it. */
32 for (serv = daemon->servers; serv; serv = serv->next)
33 if (strlen(serv->domain) == 0 &&
34 !(serv->flags & (SERV_FOR_NODOTS)))
36 ssize_t len = loop_make_probe(serv->uid);
39 serv->flags &= ~SERV_LOOP;
41 if ((fd = allocate_rfd(&rfds, serv)) == -1)
44 while (retry_send(sendto(fd, daemon->packet, len, 0,
45 &serv->addr.sa, sa_len(&serv->addr))));
51 static ssize_t loop_make_probe(u32 uid)
53 struct dns_header *header = (struct dns_header *)daemon->packet;
54 unsigned char *p = (unsigned char *)(header+1);
56 /* packet buffer overwritten */
57 daemon->srv_save = NULL;
59 header->id = rand16();
60 header->ancount = header->nscount = header->arcount = htons(0);
61 header->qdcount = htons(1);
64 SET_OPCODE(header, QUERY);
67 sprintf((char *)p, "%.8x", uid);
69 *p++ = strlen(LOOP_TEST_DOMAIN);
70 strcpy((char *)p, LOOP_TEST_DOMAIN); /* Add terminating zero */
71 p += strlen(LOOP_TEST_DOMAIN) + 1;
73 PUTSHORT(LOOP_TEST_TYPE, p);
76 return p - (unsigned char *)header;
80 int detect_loop(char *query, int type)
86 if (!option_bool(OPT_LOOP_DETECT))
89 if (type != LOOP_TEST_TYPE ||
90 strlen(LOOP_TEST_DOMAIN) + 9 != strlen(query) ||
91 strstr(query, LOOP_TEST_DOMAIN) != query + 9)
94 for (i = 0; i < 8; i++)
95 if (!isxdigit(query[i]))
98 uid = strtol(query, NULL, 16);
100 for (serv = daemon->servers; serv; serv = serv->next)
101 if (strlen(serv->domain) == 0 &&
102 !(serv->flags & SERV_LOOP) &&
105 serv->flags |= SERV_LOOP;
106 check_servers(1); /* log new state - don't send more probes. */