mirror of
http://thekelleys.org.uk/git/dnsmasq.git
synced 2026-11-10 16:31:00 +00:00
Compare commits
2
Commits
v2.77test2
...
v2.77test3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
05da782f8f | ||
|
|
361dfe5158 |
No files matched your search
@@ -65,6 +65,11 @@ version 2.77
|
|||||||
Thanks to Kevin Darbyshire-Bryant and Eric Luehrsen
|
Thanks to Kevin Darbyshire-Bryant and Eric Luehrsen
|
||||||
for pushing this.
|
for pushing this.
|
||||||
|
|
||||||
|
Improve connection handling when talking to TCP upsteam
|
||||||
|
servers. Specifically, be prepared to open a new TCP
|
||||||
|
connection when we want to make multiple queries
|
||||||
|
but the upstream server accepts fewer queries per connection.
|
||||||
|
|
||||||
|
|
||||||
version 2.76
|
version 2.76
|
||||||
Include 0.0.0.0/8 in DNS rebind checks. This range
|
Include 0.0.0.0/8 in DNS rebind checks. This range
|
||||||
|
|||||||
@@ -485,6 +485,7 @@ union mysockaddr {
|
|||||||
#define SERV_FROM_FILE 4096 /* read from --servers-file */
|
#define SERV_FROM_FILE 4096 /* read from --servers-file */
|
||||||
#define SERV_LOOP 8192 /* server causes forwarding loop */
|
#define SERV_LOOP 8192 /* server causes forwarding loop */
|
||||||
#define SERV_DO_DNSSEC 16384 /* Validate DNSSEC when using this server */
|
#define SERV_DO_DNSSEC 16384 /* Validate DNSSEC when using this server */
|
||||||
|
#define SERV_GOT_TCP 32768 /* Got some data from the TCP connection */
|
||||||
|
|
||||||
struct serverfd {
|
struct serverfd {
|
||||||
int fd;
|
int fd;
|
||||||
|
|||||||
+99
-82
@@ -1466,6 +1466,7 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
|
|||||||
char *domain;
|
char *domain;
|
||||||
size_t m;
|
size_t m;
|
||||||
unsigned char c1, c2;
|
unsigned char c1, c2;
|
||||||
|
struct server *firstsendto = NULL;
|
||||||
|
|
||||||
/* 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)
|
||||||
@@ -1504,76 +1505,81 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
|
|||||||
/* Find server to forward to. This will normally be the
|
/* Find server to forward to. This will normally be the
|
||||||
same as for the original query, but may be another if
|
same as for the original query, but may be another if
|
||||||
servers for domains are involved. */
|
servers for domains are involved. */
|
||||||
if (search_servers(now, NULL, F_QUERY, keyname, &type, &domain, NULL) == 0)
|
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) ||
|
|
||||||
!read_write(server->tcpfd, &c1, 1, 1) ||
|
|
||||||
!read_write(server->tcpfd, &c2, 1, 1) ||
|
|
||||||
!read_write(server->tcpfd, payload, (c1 << 8) | c2, 1))
|
|
||||||
{
|
{
|
||||||
new_status = STAT_ABANDONED;
|
new_status = STAT_ABANDONED;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
m = (c1 << 8) | c2;
|
type &= ~SERV_DO_DNSSEC;
|
||||||
|
|
||||||
new_status = tcp_key_recurse(now, new_status, new_header, m, class, name, keyname, server, have_mark, mark, keycount);
|
while (1)
|
||||||
|
{
|
||||||
|
if (!firstsendto)
|
||||||
|
firstsendto = server;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!(server = server->next))
|
||||||
|
server = daemon->servers;
|
||||||
|
if (server == firstsendto)
|
||||||
|
{
|
||||||
|
/* can't find server to accept our query. */
|
||||||
|
new_status = STAT_ABANDONED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type != (server->flags & SERV_TYPE) ||
|
||||||
|
(type == SERV_HAS_DOMAIN && !hostname_isequal(domain, server->domain)) ||
|
||||||
|
(server->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
retry:
|
||||||
|
/* may need to make new connection. */
|
||||||
|
if (server->tcpfd == -1)
|
||||||
|
{
|
||||||
|
if ((server->tcpfd = socket(server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
|
||||||
|
continue; /* No good, next server */
|
||||||
|
|
||||||
|
#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;
|
||||||
|
continue; /* No good, next server */
|
||||||
|
}
|
||||||
|
|
||||||
|
server->flags &= ~SERV_GOT_TCP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!read_write(server->tcpfd, packet, m + sizeof(u16), 0) ||
|
||||||
|
!read_write(server->tcpfd, &c1, 1, 1) ||
|
||||||
|
!read_write(server->tcpfd, &c2, 1, 1) ||
|
||||||
|
!read_write(server->tcpfd, payload, (c1 << 8) | c2, 1))
|
||||||
|
{
|
||||||
|
close(server->tcpfd);
|
||||||
|
server->tcpfd = -1;
|
||||||
|
/* We get data then EOF, reopen connection to same server,
|
||||||
|
else try next. This avoids DoS from a server which accepts
|
||||||
|
connections and then closes them. */
|
||||||
|
if (server->flags & SERV_GOT_TCP)
|
||||||
|
goto retry;
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
server->flags |= SERV_GOT_TCP;
|
||||||
|
|
||||||
|
m = (c1 << 8) | c2;
|
||||||
|
new_status = tcp_key_recurse(now, new_status, new_header, m, class, name, keyname, server, have_mark, mark, keycount);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (new_status != STAT_OK)
|
if (new_status != STAT_OK)
|
||||||
break;
|
break;
|
||||||
@@ -1821,6 +1827,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
(last_server->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
|
(last_server->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
retry:
|
||||||
if (last_server->tcpfd == -1)
|
if (last_server->tcpfd == -1)
|
||||||
{
|
{
|
||||||
if ((last_server->tcpfd = socket(last_server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
|
if ((last_server->tcpfd = socket(last_server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
|
||||||
@@ -1840,25 +1847,27 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_DNSSEC
|
last_server->flags &= ~SERV_GOT_TCP;
|
||||||
if (option_bool(OPT_DNSSEC_VALID) && (last_server->flags & SERV_DO_DNSSEC))
|
|
||||||
{
|
|
||||||
new_size = add_do_bit(header, size, ((unsigned char *) header) + 65536);
|
|
||||||
|
|
||||||
if (size != new_size)
|
|
||||||
{
|
|
||||||
added_pheader = 1;
|
|
||||||
size = new_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* For debugging, set Checking Disabled, otherwise, have the upstream check too,
|
|
||||||
this allows it to select auth servers when one is returning bad data. */
|
|
||||||
if (option_bool(OPT_DNSSEC_DEBUG))
|
|
||||||
header->hb4 |= HB4_CD;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_DNSSEC
|
||||||
|
if (option_bool(OPT_DNSSEC_VALID) && (last_server->flags & SERV_DO_DNSSEC))
|
||||||
|
{
|
||||||
|
new_size = add_do_bit(header, size, ((unsigned char *) header) + 65536);
|
||||||
|
|
||||||
|
if (size != new_size)
|
||||||
|
{
|
||||||
|
added_pheader = 1;
|
||||||
|
size = new_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For debugging, set Checking Disabled, otherwise, have the upstream check too,
|
||||||
|
this allows it to select auth servers when one is returning bad data. */
|
||||||
|
if (option_bool(OPT_DNSSEC_DEBUG))
|
||||||
|
header->hb4 |= HB4_CD;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
*length = htons(size);
|
*length = htons(size);
|
||||||
|
|
||||||
/* get query name again for logging - may have been overwritten */
|
/* get query name again for logging - may have been overwritten */
|
||||||
@@ -1872,9 +1881,17 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
{
|
{
|
||||||
close(last_server->tcpfd);
|
close(last_server->tcpfd);
|
||||||
last_server->tcpfd = -1;
|
last_server->tcpfd = -1;
|
||||||
continue;
|
/* We get data then EOF, reopen connection to same server,
|
||||||
|
else try next. This avoids DoS from a server which accepts
|
||||||
|
connections and then closes them. */
|
||||||
|
if (last_server->flags & SERV_GOT_TCP)
|
||||||
|
goto retry;
|
||||||
|
else
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
last_server->flags |= SERV_GOT_TCP;
|
||||||
|
|
||||||
m = (c1 << 8) | c2;
|
m = (c1 << 8) | c2;
|
||||||
|
|
||||||
if (last_server->addr.sa.sa_family == AF_INET)
|
if (last_server->addr.sa.sa_family == AF_INET)
|
||||||
|
|||||||
+2
-1
@@ -1,9 +1,10 @@
|
|||||||
# The root DNSSEC trust anchor, valid as at 30/01/2014
|
# The root DNSSEC trust anchor, valid as at 10/02/2017
|
||||||
|
|
||||||
# Note that this is a DS record (ie a hash of the root Zone Signing Key)
|
# Note that this is a DS record (ie a hash of the root Zone Signing Key)
|
||||||
# If was downloaded from https://data.iana.org/root-anchors/root-anchors.xml
|
# If was downloaded from https://data.iana.org/root-anchors/root-anchors.xml
|
||||||
|
|
||||||
trust-anchor=.,19036,8,2,49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5
|
trust-anchor=.,19036,8,2,49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5
|
||||||
|
trust-anchor=.,20326,8,2,E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC683457104237C7F8EC8D
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Reference in new issue
Block a user