]>
git.ipfire.org Git - people/ms/dnsmasq.git/blob - src/loop.c
1 /* dnsmasq is Copyright (c) 2000-2014 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()
26 if (!option_bool(OPT_LOOP_DETECT
))
29 /* Loop through all upstream servers not for particular domains, and send a query to that server which is
30 identifiable, via the uid. If we see that query back again, then the server is looping, and we should not use it. */
31 for (serv
= daemon
->servers
; serv
; serv
= serv
->next
)
33 (SERV_LITERAL_ADDRESS
| SERV_NO_ADDR
| SERV_USE_RESOLV
| SERV_NO_REBIND
| SERV_HAS_DOMAIN
| SERV_FOR_NODOTS
| SERV_LOOP
)))
35 ssize_t len
= loop_make_probe(serv
->uid
);
37 struct randfd
*rfd
= NULL
;
43 if (!(rfd
= allocate_rfd(serv
->addr
.sa
.sa_family
)))
48 while (sendto(fd
, daemon
->packet
, len
, 0, &serv
->addr
.sa
, sa_len(&serv
->addr
)) == -1 && retry_send());
54 static ssize_t
loop_make_probe(u32 uid
)
56 struct dns_header
*header
= (struct dns_header
*)daemon
->packet
;
57 unsigned char *p
= (unsigned char *)(header
+1);
59 /* packet buffer overwritten */
60 daemon
->srv_save
= NULL
;
62 header
->id
= rand16();
63 header
->ancount
= header
->nscount
= header
->arcount
= htons(0);
64 header
->qdcount
= htons(1);
67 SET_OPCODE(header
, QUERY
);
70 sprintf((char *)p
, "%.8x", uid
);
72 *p
++ = strlen(LOOP_TEST_DOMAIN
);
73 strcpy((char *)p
, LOOP_TEST_DOMAIN
); /* Add terminating zero */
74 p
+= strlen(LOOP_TEST_DOMAIN
) + 1;
76 PUTSHORT(LOOP_TEST_TYPE
, p
);
79 return p
- (unsigned char *)header
;
83 int detect_loop(char *query
, int type
)
89 if (!option_bool(OPT_LOOP_DETECT
))
92 if (type
!= LOOP_TEST_TYPE
||
93 strlen(LOOP_TEST_DOMAIN
) + 9 != strlen(query
) ||
94 strstr(query
, LOOP_TEST_DOMAIN
) != query
+ 9)
97 for (i
= 0; i
< 8; i
++)
98 if (!isxdigit(query
[i
]))
101 uid
= strtol(query
, NULL
, 16);
103 for (serv
= daemon
->servers
; serv
; serv
= serv
->next
)
105 (SERV_LITERAL_ADDRESS
| SERV_NO_ADDR
| SERV_USE_RESOLV
| SERV_NO_REBIND
| SERV_HAS_DOMAIN
| SERV_FOR_NODOTS
| SERV_LOOP
)) &&
108 serv
->flags
|= SERV_LOOP
;
109 check_servers(); /* log new state */