Line | Count | Source (jump to first uncovered line) |
1 | | /* dnsmasq is Copyright (c) 2000-2025 Simon Kelley |
2 | | |
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. |
7 | | |
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. |
12 | | |
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/>. |
15 | | */ |
16 | | |
17 | | #include "dnsmasq.h" |
18 | | |
19 | | #ifdef HAVE_LOOP |
20 | | static ssize_t loop_make_probe(u32 uid); |
21 | | |
22 | | void loop_send_probes(void) |
23 | 0 | { |
24 | 0 | struct server *serv; |
25 | 0 | struct randfd_list *rfds = NULL; |
26 | | |
27 | 0 | if (!option_bool(OPT_LOOP_DETECT)) |
28 | 0 | return; |
29 | | |
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 | 0 | for (serv = daemon->servers; serv; serv = serv->next) |
33 | 0 | if (strlen(serv->domain) == 0 && |
34 | 0 | !(serv->flags & (SERV_FOR_NODOTS))) |
35 | 0 | { |
36 | 0 | ssize_t len = loop_make_probe(serv->uid); |
37 | 0 | int fd; |
38 | | |
39 | 0 | serv->flags &= ~SERV_LOOP; |
40 | |
|
41 | 0 | if ((fd = allocate_rfd(&rfds, serv)) == -1) |
42 | 0 | continue; |
43 | | |
44 | 0 | while (retry_send(sendto(fd, daemon->packet, len, 0, |
45 | 0 | &serv->addr.sa, sa_len(&serv->addr)))); |
46 | 0 | } |
47 | |
|
48 | 0 | free_rfds(&rfds); |
49 | 0 | } |
50 | | |
51 | | static ssize_t loop_make_probe(u32 uid) |
52 | 0 | { |
53 | 0 | struct dns_header *header = (struct dns_header *)daemon->packet; |
54 | 0 | unsigned char *p = (unsigned char *)(header+1); |
55 | | |
56 | | /* packet buffer overwritten */ |
57 | 0 | daemon->srv_save = NULL; |
58 | | |
59 | 0 | header->id = rand16(); |
60 | 0 | header->ancount = header->nscount = header->arcount = htons(0); |
61 | 0 | header->qdcount = htons(1); |
62 | 0 | header->hb3 = HB3_RD; |
63 | 0 | header->hb4 = 0; |
64 | 0 | SET_OPCODE(header, QUERY); |
65 | |
|
66 | 0 | *p++ = 8; |
67 | 0 | sprintf((char *)p, "%.8x", uid); |
68 | 0 | p += 8; |
69 | 0 | *p++ = strlen(LOOP_TEST_DOMAIN); |
70 | 0 | strcpy((char *)p, LOOP_TEST_DOMAIN); /* Add terminating zero */ |
71 | 0 | p += strlen(LOOP_TEST_DOMAIN) + 1; |
72 | |
|
73 | 0 | PUTSHORT(LOOP_TEST_TYPE, p); |
74 | 0 | PUTSHORT(C_IN, p); |
75 | |
|
76 | 0 | return p - (unsigned char *)header; |
77 | 0 | } |
78 | | |
79 | | |
80 | | int detect_loop(char *query, int type) |
81 | 0 | { |
82 | 0 | int i; |
83 | 0 | u32 uid; |
84 | 0 | struct server *serv; |
85 | | |
86 | 0 | if (!option_bool(OPT_LOOP_DETECT)) |
87 | 0 | return 0; |
88 | | |
89 | 0 | if (type != LOOP_TEST_TYPE || |
90 | 0 | strlen(LOOP_TEST_DOMAIN) + 9 != strlen(query) || |
91 | 0 | strstr(query, LOOP_TEST_DOMAIN) != query + 9) |
92 | 0 | return 0; |
93 | | |
94 | 0 | for (i = 0; i < 8; i++) |
95 | 0 | if (!isxdigit((unsigned char)query[i])) |
96 | 0 | return 0; |
97 | | |
98 | 0 | uid = strtol(query, NULL, 16); |
99 | |
|
100 | 0 | for (serv = daemon->servers; serv; serv = serv->next) |
101 | 0 | if (strlen(serv->domain) == 0 && |
102 | 0 | !(serv->flags & SERV_LOOP) && |
103 | 0 | uid == serv->uid) |
104 | 0 | { |
105 | 0 | serv->flags |= SERV_LOOP; |
106 | 0 | check_servers(1); /* log new state - don't send more probes. */ |
107 | 0 | return 1; |
108 | 0 | } |
109 | | |
110 | 0 | return 0; |
111 | 0 | } |
112 | | |
113 | | #endif |