mirror of
http://thekelleys.org.uk/git/dnsmasq.git
synced 2026-11-06 15:51:41 +00:00
Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d05dd58de1 | ||
|
|
f7443d76f7 | ||
|
|
f344dbc622 |
No files matched your search
@@ -22,6 +22,15 @@ version 2.76
|
|||||||
reading a hosts-file fails. Thanks to André Glüpker
|
reading a hosts-file fails. Thanks to André Glüpker
|
||||||
for the patch.
|
for the patch.
|
||||||
|
|
||||||
|
Fix wrong answer to simple name query when --domain-needed
|
||||||
|
set, but no upstream servers configured. Dnsmasq returned
|
||||||
|
REFUSED, in this case, when it should be the same as when
|
||||||
|
upstream servers are configured - NOERROR. Thanks to
|
||||||
|
Allain Legacy for spotting the problem.
|
||||||
|
|
||||||
|
Return REFUSED when running out of forwarding table slots,
|
||||||
|
not SERVFAIL.
|
||||||
|
|
||||||
|
|
||||||
version 2.75
|
version 2.75
|
||||||
Fix reversion on 2.74 which caused 100% CPU use when a
|
Fix reversion on 2.74 which caused 100% CPU use when a
|
||||||
|
|||||||
+125
-37
@@ -249,9 +249,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||||||
(void)do_bit;
|
(void)do_bit;
|
||||||
|
|
||||||
/* may be no servers available. */
|
/* may be no servers available. */
|
||||||
if (!daemon->servers)
|
if (forward || (hash && (forward = lookup_frec_by_sender(ntohs(header->id), udpaddr, hash))))
|
||||||
forward = NULL;
|
|
||||||
else if (forward || (hash && (forward = lookup_frec_by_sender(ntohs(header->id), udpaddr, hash))))
|
|
||||||
{
|
{
|
||||||
/* If we didn't get an answer advertising a maximal packet in EDNS,
|
/* If we didn't get an answer advertising a maximal packet in EDNS,
|
||||||
fall back to 1280, which should work everywhere on IPv6.
|
fall back to 1280, which should work everywhere on IPv6.
|
||||||
@@ -331,12 +329,12 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||||||
|
|
||||||
#ifdef HAVE_DNSSEC
|
#ifdef HAVE_DNSSEC
|
||||||
do_dnssec = type & SERV_DO_DNSSEC;
|
do_dnssec = type & SERV_DO_DNSSEC;
|
||||||
type &= ~SERV_DO_DNSSEC;
|
#endif
|
||||||
#endif
|
type &= ~SERV_DO_DNSSEC;
|
||||||
|
|
||||||
if (!flags && !(forward = get_new_frec(now, NULL, 0)))
|
if (daemon->servers && !flags)
|
||||||
/* table full - server failure. */
|
forward = get_new_frec(now, NULL, 0);
|
||||||
flags = F_NEG;
|
/* table full - flags == 0, return REFUSED */
|
||||||
|
|
||||||
if (forward)
|
if (forward)
|
||||||
{
|
{
|
||||||
@@ -923,7 +921,7 @@ void reply_query(int fd, int family, time_t now)
|
|||||||
status = STAT_ABANDONED;
|
status = STAT_ABANDONED;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int fd, type;
|
int fd, type = SERV_DO_DNSSEC;
|
||||||
struct frec *next = new->next;
|
struct frec *next = new->next;
|
||||||
char *domain;
|
char *domain;
|
||||||
|
|
||||||
@@ -936,7 +934,7 @@ void reply_query(int fd, int family, time_t now)
|
|||||||
servers for domains are involved. */
|
servers for domains are involved. */
|
||||||
if (search_servers(now, NULL, F_QUERY, daemon->keyname, &type, &domain, NULL) == 0)
|
if (search_servers(now, NULL, F_QUERY, daemon->keyname, &type, &domain, NULL) == 0)
|
||||||
{
|
{
|
||||||
struct server *start = server;
|
struct server *start = server, *new_server = NULL;
|
||||||
type &= ~SERV_DO_DNSSEC;
|
type &= ~SERV_DO_DNSSEC;
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
@@ -945,8 +943,12 @@ void reply_query(int fd, int family, time_t now)
|
|||||||
(type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) &&
|
(type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) &&
|
||||||
!(start->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
|
!(start->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
|
||||||
{
|
{
|
||||||
server = start;
|
new_server = start;
|
||||||
break;
|
if (server == start)
|
||||||
|
{
|
||||||
|
new_server = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(start = start->next))
|
if (!(start = start->next))
|
||||||
@@ -954,7 +956,11 @@ void reply_query(int fd, int family, time_t now)
|
|||||||
if (start == server)
|
if (start == server)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (new_server)
|
||||||
|
server = new_server;
|
||||||
}
|
}
|
||||||
|
|
||||||
new->sentto = server;
|
new->sentto = server;
|
||||||
|
|
||||||
new->rfd4 = NULL;
|
new->rfd4 = NULL;
|
||||||
@@ -1010,6 +1016,15 @@ void reply_query(int fd, int family, time_t now)
|
|||||||
|
|
||||||
if (fd != -1)
|
if (fd != -1)
|
||||||
{
|
{
|
||||||
|
#ifdef HAVE_CONNTRACK
|
||||||
|
/* Copy connection mark of incoming query to outgoing connection. */
|
||||||
|
if (option_bool(OPT_CONNTRACK))
|
||||||
|
{
|
||||||
|
unsigned int mark;
|
||||||
|
if (get_incoming_mark(&orig->source, &orig->dest, 0, &mark))
|
||||||
|
setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
while (retry_send(sendto(fd, (char *)header, nn, 0,
|
while (retry_send(sendto(fd, (char *)header, nn, 0,
|
||||||
&server->addr.sa,
|
&server->addr.sa,
|
||||||
sa_len(&server->addr))));
|
sa_len(&server->addr))));
|
||||||
@@ -1072,7 +1087,7 @@ void reply_query(int fd, int family, time_t now)
|
|||||||
else
|
else
|
||||||
header->hb4 &= ~HB4_CD;
|
header->hb4 &= ~HB4_CD;
|
||||||
|
|
||||||
if ((nn = process_reply(header, now, server, (size_t)n, check_rebind, no_cache_dnssec, cache_secure, bogusanswer,
|
if ((nn = process_reply(header, now, forward->sentto, (size_t)n, check_rebind, no_cache_dnssec, cache_secure, bogusanswer,
|
||||||
forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION,
|
forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION,
|
||||||
forward->flags & FREC_ADDED_PHEADER, forward->flags & FREC_HAS_SUBNET, &forward->source)))
|
forward->flags & FREC_ADDED_PHEADER, forward->flags & FREC_HAS_SUBNET, &forward->source)))
|
||||||
{
|
{
|
||||||
@@ -1433,20 +1448,24 @@ void receive_query(struct listener *listen, time_t now)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_DNSSEC
|
#ifdef HAVE_DNSSEC
|
||||||
|
/* Recurse up the key heirarchy */
|
||||||
static int tcp_key_recurse(time_t now, int status, struct dns_header *header, size_t n,
|
static int tcp_key_recurse(time_t now, int status, struct dns_header *header, size_t n,
|
||||||
int class, char *name, char *keyname, struct server *server, int *keycount)
|
int class, char *name, char *keyname, struct server *server,
|
||||||
|
int have_mark, unsigned int mark, int *keycount)
|
||||||
{
|
{
|
||||||
/* Recurse up the key heirarchy */
|
|
||||||
int new_status;
|
int new_status;
|
||||||
unsigned char *packet = NULL;
|
unsigned char *packet = NULL;
|
||||||
size_t m;
|
|
||||||
unsigned char *payload = NULL;
|
unsigned char *payload = NULL;
|
||||||
struct dns_header *new_header = NULL;
|
struct dns_header *new_header = NULL;
|
||||||
u16 *length = NULL;
|
u16 *length = NULL;
|
||||||
unsigned char c1, c2;
|
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
|
int type = SERV_DO_DNSSEC;
|
||||||
|
char *domain;
|
||||||
|
size_t m;
|
||||||
|
unsigned char c1, c2;
|
||||||
|
|
||||||
/* limit the amount of work we do, to avoid cycling forever on loops in the DNS */
|
/* limit the amount of work we do, to avoid cycling forever on loops in the DNS */
|
||||||
if (--(*keycount) == 0)
|
if (--(*keycount) == 0)
|
||||||
new_status = STAT_ABANDONED;
|
new_status = STAT_ABANDONED;
|
||||||
@@ -1480,6 +1499,67 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
|
|||||||
new_status == STAT_NEED_KEY ? T_DNSKEY : T_DS, &server->addr, server->edns_pktsz);
|
new_status == STAT_NEED_KEY ? T_DNSKEY : T_DS, &server->addr, server->edns_pktsz);
|
||||||
|
|
||||||
*length = htons(m);
|
*length = htons(m);
|
||||||
|
|
||||||
|
/* Find server to forward to. This will normally be the
|
||||||
|
same as for the original query, but may be another if
|
||||||
|
servers for domains are involved. */
|
||||||
|
if (search_servers(now, NULL, F_QUERY, keyname, &type, &domain, NULL) == 0)
|
||||||
|
{
|
||||||
|
struct server *start = server, *new_server = NULL;
|
||||||
|
type &= ~SERV_DO_DNSSEC;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
if (type == (start->flags & SERV_TYPE) &&
|
||||||
|
(type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) &&
|
||||||
|
!(start->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
|
||||||
|
{
|
||||||
|
new_server = start;
|
||||||
|
if (server == start)
|
||||||
|
{
|
||||||
|
new_server = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(start = start->next))
|
||||||
|
start = daemon->servers;
|
||||||
|
if (start == server)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (new_server)
|
||||||
|
{
|
||||||
|
server = new_server;
|
||||||
|
/* may need to make new connection. */
|
||||||
|
if (server->tcpfd == -1)
|
||||||
|
{
|
||||||
|
if ((server->tcpfd = socket(server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
|
||||||
|
{
|
||||||
|
new_status = STAT_ABANDONED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_CONNTRACK
|
||||||
|
/* Copy connection mark of incoming query to outgoing connection. */
|
||||||
|
if (have_mark)
|
||||||
|
setsockopt(server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!local_bind(server->tcpfd, &server->source_addr, server->interface, 1) ||
|
||||||
|
connect(server->tcpfd, &server->addr.sa, sa_len(&server->addr)) == -1)
|
||||||
|
{
|
||||||
|
close(server->tcpfd);
|
||||||
|
server->tcpfd = -1;
|
||||||
|
new_status = STAT_ABANDONED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!read_write(server->tcpfd, packet, m + sizeof(u16), 0) ||
|
if (!read_write(server->tcpfd, packet, m + sizeof(u16), 0) ||
|
||||||
!read_write(server->tcpfd, &c1, 1, 1) ||
|
!read_write(server->tcpfd, &c1, 1, 1) ||
|
||||||
@@ -1492,7 +1572,7 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
|
|||||||
|
|
||||||
m = (c1 << 8) | c2;
|
m = (c1 << 8) | c2;
|
||||||
|
|
||||||
new_status = tcp_key_recurse(now, new_status, new_header, m, class, name, keyname, server, keycount);
|
new_status = tcp_key_recurse(now, new_status, new_header, m, class, name, keyname, server, have_mark, mark, keycount);
|
||||||
|
|
||||||
if (new_status != STAT_OK)
|
if (new_status != STAT_OK)
|
||||||
break;
|
break;
|
||||||
@@ -1536,10 +1616,31 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
socklen_t peer_len = sizeof(union mysockaddr);
|
socklen_t peer_len = sizeof(union mysockaddr);
|
||||||
int query_count = 0;
|
int query_count = 0;
|
||||||
unsigned char *pheader;
|
unsigned char *pheader;
|
||||||
|
unsigned int mark = 0;
|
||||||
|
int have_mark = 0;
|
||||||
|
|
||||||
|
(void)mark;
|
||||||
|
(void)have_mark;
|
||||||
|
|
||||||
if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
|
if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
|
||||||
return packet;
|
return packet;
|
||||||
|
|
||||||
|
#ifdef HAVE_CONNTRACK
|
||||||
|
/* Get connection mark of incoming query to set on outgoing connections. */
|
||||||
|
if (option_bool(OPT_CONNTRACK))
|
||||||
|
{
|
||||||
|
struct all_addr local;
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
if (local_addr->sa.sa_family == AF_INET6)
|
||||||
|
local.addr.addr6 = local_addr->in6.sin6_addr;
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
local.addr.addr4 = local_addr->in.sin_addr;
|
||||||
|
|
||||||
|
have_mark = get_incoming_mark(&peer_addr, &local, 1, &mark);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* We can be configured to only accept queries from at-most-one-hop-away addresses. */
|
/* We can be configured to only accept queries from at-most-one-hop-away addresses. */
|
||||||
if (option_bool(OPT_LOCAL_SERVICE))
|
if (option_bool(OPT_LOCAL_SERVICE))
|
||||||
{
|
{
|
||||||
@@ -1665,7 +1766,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
{
|
{
|
||||||
unsigned int flags = 0;
|
unsigned int flags = 0;
|
||||||
struct all_addr *addrp = NULL;
|
struct all_addr *addrp = NULL;
|
||||||
int type = 0;
|
int type = SERV_DO_DNSSEC;
|
||||||
char *domain = NULL;
|
char *domain = NULL;
|
||||||
size_t new_size = add_edns0_config(header, size, ((unsigned char *) header) + 65536, &peer_addr, now, &check_subnet);
|
size_t new_size = add_edns0_config(header, size, ((unsigned char *) header) + 65536, &peer_addr, now, &check_subnet);
|
||||||
|
|
||||||
@@ -1678,9 +1779,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
if (gotname)
|
if (gotname)
|
||||||
flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
|
flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
|
||||||
|
|
||||||
#ifdef HAVE_DNSSEC
|
|
||||||
type &= ~SERV_DO_DNSSEC;
|
type &= ~SERV_DO_DNSSEC;
|
||||||
#endif
|
|
||||||
|
|
||||||
if (type != 0 || option_bool(OPT_ORDER) || !daemon->last_server)
|
if (type != 0 || option_bool(OPT_ORDER) || !daemon->last_server)
|
||||||
last_server = daemon->servers;
|
last_server = daemon->servers;
|
||||||
@@ -1728,20 +1827,8 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
|
|
||||||
#ifdef HAVE_CONNTRACK
|
#ifdef HAVE_CONNTRACK
|
||||||
/* Copy connection mark of incoming query to outgoing connection. */
|
/* Copy connection mark of incoming query to outgoing connection. */
|
||||||
if (option_bool(OPT_CONNTRACK))
|
if (have_mark)
|
||||||
{
|
setsockopt(last_server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
|
||||||
unsigned int mark;
|
|
||||||
struct all_addr local;
|
|
||||||
#ifdef HAVE_IPV6
|
|
||||||
if (local_addr->sa.sa_family == AF_INET6)
|
|
||||||
local.addr.addr6 = local_addr->in6.sin6_addr;
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
local.addr.addr4 = local_addr->in.sin_addr;
|
|
||||||
|
|
||||||
if (get_incoming_mark(&peer_addr, &local, 1, &mark))
|
|
||||||
setsockopt(last_server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if ((!local_bind(last_server->tcpfd, &last_server->source_addr, last_server->interface, 1) ||
|
if ((!local_bind(last_server->tcpfd, &last_server->source_addr, last_server->interface, 1) ||
|
||||||
@@ -1802,7 +1889,8 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
if (option_bool(OPT_DNSSEC_VALID) && !checking_disabled && (last_server->flags & SERV_DO_DNSSEC))
|
if (option_bool(OPT_DNSSEC_VALID) && !checking_disabled && (last_server->flags & SERV_DO_DNSSEC))
|
||||||
{
|
{
|
||||||
int keycount = DNSSEC_WORK; /* Limit to number of DNSSEC questions, to catch loops and avoid filling cache. */
|
int keycount = DNSSEC_WORK; /* Limit to number of DNSSEC questions, to catch loops and avoid filling cache. */
|
||||||
int status = tcp_key_recurse(now, STAT_OK, header, m, 0, daemon->namebuff, daemon->keyname, last_server, &keycount);
|
int status = tcp_key_recurse(now, STAT_OK, header, m, 0, daemon->namebuff, daemon->keyname,
|
||||||
|
last_server, have_mark, mark, &keycount);
|
||||||
char *result, *domain = "result";
|
char *result, *domain = "result";
|
||||||
|
|
||||||
if (status == STAT_ABANDONED)
|
if (status == STAT_ABANDONED)
|
||||||
|
|||||||
+1
-3
@@ -896,9 +896,7 @@ size_t setup_reply(struct dns_header *header, size_t qlen,
|
|||||||
header->nscount = htons(0);
|
header->nscount = htons(0);
|
||||||
header->arcount = htons(0);
|
header->arcount = htons(0);
|
||||||
header->ancount = htons(0); /* no answers unless changed below */
|
header->ancount = htons(0); /* no answers unless changed below */
|
||||||
if (flags == F_NEG)
|
if (flags == F_NOERR)
|
||||||
SET_RCODE(header, SERVFAIL); /* couldn't get memory */
|
|
||||||
else if (flags == F_NOERR)
|
|
||||||
SET_RCODE(header, NOERROR); /* empty domain */
|
SET_RCODE(header, NOERROR); /* empty domain */
|
||||||
else if (flags == F_NXDOMAIN)
|
else if (flags == F_NXDOMAIN)
|
||||||
SET_RCODE(header, NXDOMAIN);
|
SET_RCODE(header, NXDOMAIN);
|
||||||
|
|||||||
Reference in new issue
Block a user