mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 18:28:25 +00:00
Finesse TCP timeouts for upstream connections.
Timeouts for TCP connections to non-responive servers are very long. This in not appropriate for DNS connections. Set timeouts for connection setup, sending data and recieving data. The timeouts for connection setup and sending data are set at 5 seconds. For recieving the reply this is doubled, to take into account the time for usptream to actually get the answer. Thanks to Petr Menšík for pointing out this problem, and finding a better and more portable solution than the one in place heretofore.
This commit is contained in:
@@ -101,7 +101,7 @@ static struct blockdata *blockdata_alloc_real(int fd, char *data, size_t len)
|
||||
memcpy(block->key, data, blen);
|
||||
data += blen;
|
||||
}
|
||||
else if (!read_write(fd, block->key, blen, 1))
|
||||
else if (!read_write(fd, block->key, blen, RW_READ))
|
||||
{
|
||||
/* failed read free partial chain */
|
||||
blockdata_free(ret);
|
||||
@@ -228,7 +228,7 @@ void blockdata_write(struct blockdata *block, size_t len, int fd)
|
||||
for (; len > 0 && block; block = block->next)
|
||||
{
|
||||
size_t blen = len > KEYBLOCK_LEN ? KEYBLOCK_LEN : len;
|
||||
read_write(fd, block->key, blen, 0);
|
||||
read_write(fd, block->key, blen, RW_WRITE);
|
||||
len -= blen;
|
||||
}
|
||||
}
|
||||
|
||||
60
src/cache.c
60
src/cache.c
@@ -798,11 +798,11 @@ void cache_end_insert(void)
|
||||
u16 class = new_chain->uid;
|
||||
#endif
|
||||
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&m, sizeof(m), 0);
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)name, m, 0);
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->ttd, sizeof(new_chain->ttd), 0);
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&flags, sizeof(flags), 0);
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr, sizeof(new_chain->addr), 0);
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&m, sizeof(m), RW_WRITE);
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)name, m, RW_WRITE);
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->ttd, sizeof(new_chain->ttd), RW_WRITE);
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&flags, sizeof(flags), RW_WRITE);
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr, sizeof(new_chain->addr), RW_WRITE);
|
||||
|
||||
if (flags & F_RR)
|
||||
{
|
||||
@@ -813,12 +813,12 @@ void cache_end_insert(void)
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (flags & F_DNSKEY)
|
||||
{
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&class, sizeof(class), 0);
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&class, sizeof(class), RW_WRITE);
|
||||
blockdata_write(new_chain->addr.key.keydata, new_chain->addr.key.keylen, daemon->pipe_to_parent);
|
||||
}
|
||||
else if (flags & F_DS)
|
||||
{
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&class, sizeof(class), 0);
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&class, sizeof(class), RW_WRITE);
|
||||
/* A negative DS entry is possible and has no data, obviously. */
|
||||
if (!(flags & F_NEG))
|
||||
blockdata_write(new_chain->addr.ds.keydata, new_chain->addr.ds.keylen, daemon->pipe_to_parent);
|
||||
@@ -835,16 +835,16 @@ void cache_end_insert(void)
|
||||
{
|
||||
ssize_t m = -1;
|
||||
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&m, sizeof(m), 0);
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&m, sizeof(m), RW_WRITE);
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
/* Sneak out possibly updated crypto HWM values. */
|
||||
m = daemon->metrics[METRIC_CRYPTO_HWM];
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&m, sizeof(m), 0);
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&m, sizeof(m), RW_WRITE);
|
||||
m = daemon->metrics[METRIC_SIG_FAIL_HWM];
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&m, sizeof(m), 0);
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&m, sizeof(m), RW_WRITE);
|
||||
m = daemon->metrics[METRIC_WORK_HWM];
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&m, sizeof(m), 0);
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&m, sizeof(m), RW_WRITE);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -867,22 +867,22 @@ int cache_recv_insert(time_t now, int fd)
|
||||
while (1)
|
||||
{
|
||||
|
||||
if (!read_write(fd, (unsigned char *)&m, sizeof(m), 1))
|
||||
if (!read_write(fd, (unsigned char *)&m, sizeof(m), RW_READ))
|
||||
return 0;
|
||||
|
||||
if (m == -1)
|
||||
{
|
||||
#ifdef HAVE_DNSSEC
|
||||
/* Sneak in possibly updated crypto HWM. */
|
||||
if (!read_write(fd, (unsigned char *)&m, sizeof(m), 1))
|
||||
if (!read_write(fd, (unsigned char *)&m, sizeof(m), RW_READ))
|
||||
return 0;
|
||||
if (m > daemon->metrics[METRIC_CRYPTO_HWM])
|
||||
daemon->metrics[METRIC_CRYPTO_HWM] = m;
|
||||
if (!read_write(fd, (unsigned char *)&m, sizeof(m), 1))
|
||||
if (!read_write(fd, (unsigned char *)&m, sizeof(m), RW_READ))
|
||||
return 0;
|
||||
if (m > daemon->metrics[METRIC_SIG_FAIL_HWM])
|
||||
daemon->metrics[METRIC_SIG_FAIL_HWM] = m;
|
||||
if (!read_write(fd, (unsigned char *)&m, sizeof(m), 1))
|
||||
if (!read_write(fd, (unsigned char *)&m, sizeof(m), RW_READ))
|
||||
return 0;
|
||||
if (m > daemon->metrics[METRIC_WORK_HWM])
|
||||
daemon->metrics[METRIC_WORK_HWM] = m;
|
||||
@@ -902,23 +902,23 @@ int cache_recv_insert(time_t now, int fd)
|
||||
|
||||
struct frec *forward;
|
||||
|
||||
if (!read_write(fd, (unsigned char *)&status, sizeof(status), 1))
|
||||
if (!read_write(fd, (unsigned char *)&status, sizeof(status), RW_READ))
|
||||
return 0;
|
||||
if (!read_write(fd, (unsigned char *)&ret_len, sizeof(ret_len), 1))
|
||||
if (!read_write(fd, (unsigned char *)&ret_len, sizeof(ret_len), RW_READ))
|
||||
return 0;
|
||||
if (!read_write(fd, (unsigned char *)daemon->packet, ret_len, 1))
|
||||
if (!read_write(fd, (unsigned char *)daemon->packet, ret_len, RW_READ))
|
||||
return 0;
|
||||
if (!read_write(fd, (unsigned char *)&forward, sizeof(forward), 1))
|
||||
if (!read_write(fd, (unsigned char *)&forward, sizeof(forward), RW_READ))
|
||||
return 0;
|
||||
if (!read_write(fd, (unsigned char *)&uid, sizeof(uid), 1))
|
||||
if (!read_write(fd, (unsigned char *)&uid, sizeof(uid), RW_READ))
|
||||
return 0;
|
||||
if (!read_write(fd, (unsigned char *)&keycount, sizeof(keycount), 1))
|
||||
if (!read_write(fd, (unsigned char *)&keycount, sizeof(keycount), RW_READ))
|
||||
return 0;
|
||||
if (!read_write(fd, (unsigned char *)&keycountp, sizeof(keycountp), 1))
|
||||
if (!read_write(fd, (unsigned char *)&keycountp, sizeof(keycountp), RW_READ))
|
||||
return 0;
|
||||
if (!read_write(fd, (unsigned char *)&validatecount, sizeof(validatecount), 1))
|
||||
if (!read_write(fd, (unsigned char *)&validatecount, sizeof(validatecount), RW_READ))
|
||||
return 0;
|
||||
if (!read_write(fd, (unsigned char *)&validatecountp, sizeof(validatecountp), 1))
|
||||
if (!read_write(fd, (unsigned char *)&validatecountp, sizeof(validatecountp), RW_READ))
|
||||
return 0;
|
||||
|
||||
/* There's a tiny chance that the frec may have been freed
|
||||
@@ -940,10 +940,10 @@ int cache_recv_insert(time_t now, int fd)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!read_write(fd, (unsigned char *)daemon->namebuff, m, 1) ||
|
||||
!read_write(fd, (unsigned char *)&ttd, sizeof(ttd), 1) ||
|
||||
!read_write(fd, (unsigned char *)&flags, sizeof(flags), 1) ||
|
||||
!read_write(fd, (unsigned char *)&addr, sizeof(addr), 1))
|
||||
if (!read_write(fd, (unsigned char *)daemon->namebuff, m, RW_READ) ||
|
||||
!read_write(fd, (unsigned char *)&ttd, sizeof(ttd), RW_READ) ||
|
||||
!read_write(fd, (unsigned char *)&flags, sizeof(flags), RW_READ) ||
|
||||
!read_write(fd, (unsigned char *)&addr, sizeof(addr), RW_READ))
|
||||
return 0;
|
||||
|
||||
daemon->namebuff[m] = 0;
|
||||
@@ -980,13 +980,13 @@ int cache_recv_insert(time_t now, int fd)
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (flags & F_DNSKEY)
|
||||
{
|
||||
if (!read_write(fd, (unsigned char *)&class, sizeof(class), 1) ||
|
||||
if (!read_write(fd, (unsigned char *)&class, sizeof(class), RW_READ) ||
|
||||
!(addr.key.keydata = blockdata_read(fd, addr.key.keylen)))
|
||||
return 0;
|
||||
}
|
||||
else if (flags & F_DS)
|
||||
{
|
||||
if (!read_write(fd, (unsigned char *)&class, sizeof(class), 1) ||
|
||||
if (!read_write(fd, (unsigned char *)&class, sizeof(class), RW_READ) ||
|
||||
(!(flags & F_NEG) && !(addr.key.keydata = blockdata_read(fd, addr.key.keylen))))
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#define MAX_PROCS 20 /* default max no children for TCP requests */
|
||||
#define CHILD_LIFETIME 150 /* secs 'till terminated (RFC1035 suggests > 120s) */
|
||||
#define TCP_MAX_QUERIES 100 /* Maximum number of queries per incoming TCP connection */
|
||||
#define TCP_TIMEOUT 5 /* timeout waiting to connect to an upstream server - double this for answer */
|
||||
#define TCP_BACKLOG 32 /* kernel backlog limit for TCP connections */
|
||||
#define EDNS_PKTSZ 1232 /* default max EDNS.0 UDP packet from from /dnsflagday.net/2020 */
|
||||
#define KEYBLOCK_LEN 40 /* choose to minimise fragmentation when storing DNSSEC keys */
|
||||
|
||||
@@ -683,7 +683,7 @@ int main (int argc, char **argv)
|
||||
if (getuid() == 0 && ent_pw && ent_pw->pw_uid != 0 && fchown(fd, ent_pw->pw_uid, ent_pw->pw_gid) == -1)
|
||||
chown_warn = errno;
|
||||
|
||||
if (!read_write(fd, (unsigned char *)daemon->namebuff, strlen(daemon->namebuff), 0))
|
||||
if (!read_write(fd, (unsigned char *)daemon->namebuff, strlen(daemon->namebuff), RW_WRITE))
|
||||
err = 1;
|
||||
else
|
||||
{
|
||||
@@ -1396,14 +1396,14 @@ static int read_event(int fd, struct event_desc *evp, char **msg)
|
||||
{
|
||||
char *buf;
|
||||
|
||||
if (!read_write(fd, (unsigned char *)evp, sizeof(struct event_desc), 1))
|
||||
if (!read_write(fd, (unsigned char *)evp, sizeof(struct event_desc), RW_READ))
|
||||
return 0;
|
||||
|
||||
*msg = NULL;
|
||||
|
||||
if (evp->msg_sz != 0 &&
|
||||
(buf = malloc(evp->msg_sz + 1)) &&
|
||||
read_write(fd, (unsigned char *)buf, evp->msg_sz, 1))
|
||||
read_write(fd, (unsigned char *)buf, evp->msg_sz, RW_READ))
|
||||
{
|
||||
buf[evp->msg_sz] = 0;
|
||||
*msg = buf;
|
||||
@@ -1977,7 +1977,7 @@ static void check_dns_listeners(time_t now)
|
||||
netlink socket. */
|
||||
|
||||
unsigned char a;
|
||||
read_write(pipefd[0], &a, 1, 1);
|
||||
read_write(pipefd[0], &a, 1, RW_READ);
|
||||
#endif
|
||||
|
||||
/* i holds index of free slot */
|
||||
@@ -2025,7 +2025,7 @@ static void check_dns_listeners(time_t now)
|
||||
unsigned char a = 0;
|
||||
|
||||
close(daemon->netlinkfd);
|
||||
read_write(pipefd[1], &a, 1, 0);
|
||||
read_write(pipefd[1], &a, 1, RW_WRITE);
|
||||
#endif
|
||||
alarm(CHILD_LIFETIME);
|
||||
close(pipefd[0]); /* close read end in child. */
|
||||
@@ -2118,7 +2118,7 @@ int swap_to_tcp(struct frec *forward, time_t now, int status, struct dns_header
|
||||
single byte comes back up the pipe, which
|
||||
is sent by the child after it has closed the
|
||||
netlink socket. */
|
||||
read_write(pipefd[0], &a, 1, 1);
|
||||
read_write(pipefd[0], &a, 1, RW_READ);
|
||||
#endif
|
||||
|
||||
/* i holds index of free slot */
|
||||
@@ -2140,7 +2140,7 @@ int swap_to_tcp(struct frec *forward, time_t now, int status, struct dns_header
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
/* See comment above re: netlink socket. */
|
||||
close(daemon->netlinkfd);
|
||||
read_write(pipefd[1], &a, 1, 0);
|
||||
read_write(pipefd[1], &a, 1, RW_WRITE);
|
||||
#endif
|
||||
close(pipefd[0]); /* close read end in child. */
|
||||
daemon->pipe_to_parent = pipefd[1];
|
||||
@@ -2164,16 +2164,16 @@ int swap_to_tcp(struct frec *forward, time_t now, int status, struct dns_header
|
||||
ssize_t m = -2;
|
||||
|
||||
/* tell our parent we're done, and what the result was then exit. */
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&m, sizeof(m), 0);
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&status, sizeof(status), 0);
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)plen, sizeof(*plen), 0);
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)header, *plen, 0);
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&forward, sizeof(forward), 0);
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&forward->uid, sizeof(forward->uid), 0);
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)keycount, sizeof(*keycount), 0);
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&keycount, sizeof(keycount), 0);
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)validatecount, sizeof(*validatecount), 0);
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&validatecount, sizeof(validatecount), 0);
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&m, sizeof(m), RW_WRITE);
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&status, sizeof(status), RW_WRITE);
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)plen, sizeof(*plen), RW_WRITE);
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)header, *plen, RW_WRITE);
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&forward, sizeof(forward), RW_WRITE);
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&forward->uid, sizeof(forward->uid), RW_WRITE);
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)keycount, sizeof(*keycount), RW_WRITE);
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&keycount, sizeof(keycount), RW_WRITE);
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)validatecount, sizeof(*validatecount), RW_WRITE);
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&validatecount, sizeof(validatecount), RW_WRITE);
|
||||
close(daemon->pipe_to_parent);
|
||||
|
||||
flush_log();
|
||||
|
||||
@@ -453,6 +453,11 @@ struct host_record {
|
||||
#define INP4 4
|
||||
#define INP6 8
|
||||
|
||||
#define RW_WRITE 0
|
||||
#define RW_READ 1
|
||||
#define RW_WRITE_ONCE 2
|
||||
#define RW_READ_ONCE 3
|
||||
|
||||
struct interface_name {
|
||||
char *name; /* domain name */
|
||||
char *intr; /* interface name */
|
||||
|
||||
14
src/dump.c
14
src/dump.c
@@ -64,18 +64,18 @@ void dump_init(void)
|
||||
|
||||
if (errno != ENOENT ||
|
||||
(daemon->dumpfd = creat(daemon->dump_file, S_IRUSR | S_IWUSR)) == -1 ||
|
||||
!read_write(daemon->dumpfd, (void *)&header, sizeof(header), 0))
|
||||
!read_write(daemon->dumpfd, (void *)&header, sizeof(header), RW_WRITE))
|
||||
die(_("cannot create %s: %s"), daemon->dump_file, EC_FILE);
|
||||
}
|
||||
else if ((daemon->dumpfd = open(daemon->dump_file, O_APPEND | O_RDWR)) == -1 ||
|
||||
!read_write(daemon->dumpfd, (void *)&header, sizeof(header), 1))
|
||||
!read_write(daemon->dumpfd, (void *)&header, sizeof(header), RW_READ))
|
||||
die(_("cannot access %s: %s"), daemon->dump_file, EC_FILE);
|
||||
else if (header.magic_number != 0xa1b2c3d4)
|
||||
die(_("bad header in %s"), daemon->dump_file, EC_FILE);
|
||||
else
|
||||
{
|
||||
/* count existing records */
|
||||
while (read_write(daemon->dumpfd, (void *)&pcap_header, sizeof(pcap_header), 1))
|
||||
while (read_write(daemon->dumpfd, (void *)&pcap_header, sizeof(pcap_header), RW_READ))
|
||||
{
|
||||
lseek(daemon->dumpfd, pcap_header.incl_len, SEEK_CUR);
|
||||
packet_count++;
|
||||
@@ -280,10 +280,10 @@ static void do_dump_packet(int mask, void *packet, size_t len,
|
||||
pcap_header.ts_usec = time.tv_usec;
|
||||
|
||||
if (rc == -1 ||
|
||||
!read_write(daemon->dumpfd, (void *)&pcap_header, sizeof(pcap_header), 0) ||
|
||||
!read_write(daemon->dumpfd, iphdr, ipsz, 0) ||
|
||||
(proto == IPPROTO_UDP && !read_write(daemon->dumpfd, (void *)&udp, sizeof(udp), 0)) ||
|
||||
!read_write(daemon->dumpfd, (void *)packet, len, 0))
|
||||
!read_write(daemon->dumpfd, (void *)&pcap_header, sizeof(pcap_header), RW_WRITE) ||
|
||||
!read_write(daemon->dumpfd, iphdr, ipsz, RW_WRITE) ||
|
||||
(proto == IPPROTO_UDP && !read_write(daemon->dumpfd, (void *)&udp, sizeof(udp), RW_WRITE)) ||
|
||||
!read_write(daemon->dumpfd, (void *)packet, len, RW_WRITE))
|
||||
my_syslog(LOG_ERR, _("failed to write packet dump"));
|
||||
else if (option_bool(OPT_EXTRALOG) && (mask & 0x00ff))
|
||||
my_syslog(LOG_INFO, _("%u dumping packet %u mask 0x%04x"), daemon->log_display_id, ++packet_count, mask);
|
||||
|
||||
@@ -1879,11 +1879,11 @@ static ssize_t tcp_talk(int first, int last, int start, unsigned char *packet,
|
||||
u16 *length = (u16 *)packet;
|
||||
unsigned char *payload = &packet[2];
|
||||
struct dns_header *header = (struct dns_header *)payload;
|
||||
unsigned char c1, c2;
|
||||
unsigned int rsize;
|
||||
int class, rclass, type, rtype;
|
||||
unsigned char *p;
|
||||
struct blockdata *saved_question;
|
||||
struct timeval tv;
|
||||
|
||||
(void)mark;
|
||||
(void)have_mark;
|
||||
@@ -1901,7 +1901,7 @@ static ssize_t tcp_talk(int first, int last, int start, unsigned char *packet,
|
||||
|
||||
while (1)
|
||||
{
|
||||
int data_sent = 0, timedout = 0;
|
||||
int data_sent = 0, fatal = 0;
|
||||
struct server *serv;
|
||||
|
||||
if (firstsendto == -1)
|
||||
@@ -1942,12 +1942,17 @@ static ssize_t tcp_talk(int first, int last, int start, unsigned char *packet,
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef TCP_SYNCNT
|
||||
#if defined(SO_SNDTIMEO) && defined(SO_RCVTIMEO)
|
||||
/* TCP connections by default take ages to time out.
|
||||
At least on Linux, we can reduce that to only two attempts
|
||||
to get a reply. For DNS, that's more sensible. */
|
||||
mark = 2;
|
||||
setsockopt(serv->tcpfd, IPPROTO_TCP, TCP_SYNCNT, &mark, sizeof(unsigned int));
|
||||
Set shorter timeouts more appropriate for a DNS server.
|
||||
We set the recieve timeout as twice the send timeout; we
|
||||
want to fail quickly on a non-responsive server, but give it time to get an
|
||||
answer. */
|
||||
tv.tv_sec = TCP_TIMEOUT;
|
||||
tv.tv_usec = 0;
|
||||
setsockopt(serv->tcpfd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
|
||||
tv.tv_sec += TCP_TIMEOUT;
|
||||
setsockopt(serv->tcpfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
|
||||
#endif
|
||||
|
||||
#ifdef MSG_FASTOPEN
|
||||
@@ -1955,13 +1960,13 @@ static ssize_t tcp_talk(int first, int last, int start, unsigned char *packet,
|
||||
|
||||
if (errno == 0)
|
||||
data_sent = 1;
|
||||
else if (errno == ETIMEDOUT || errno == EHOSTUNREACH)
|
||||
timedout = 1;
|
||||
else if (errno == ETIMEDOUT || errno == EHOSTUNREACH || errno == EINPROGRESS || errno == ECONNREFUSED)
|
||||
fatal = 1;
|
||||
#endif
|
||||
|
||||
/* If fastopen failed due to lack of reply, then there's no point in
|
||||
trying again in non-FASTOPEN mode. */
|
||||
if (timedout || (!data_sent && connect(serv->tcpfd, &serv->addr.sa, sa_len(&serv->addr)) == -1))
|
||||
if (fatal || (!data_sent && connect(serv->tcpfd, &serv->addr.sa, sa_len(&serv->addr)) == -1))
|
||||
{
|
||||
close(serv->tcpfd);
|
||||
serv->tcpfd = -1;
|
||||
@@ -1972,10 +1977,11 @@ static ssize_t tcp_talk(int first, int last, int start, unsigned char *packet,
|
||||
serv->flags &= ~SERV_GOT_TCP;
|
||||
}
|
||||
|
||||
if ((!data_sent && !read_write(serv->tcpfd, packet, qsize + sizeof(u16), 0)) ||
|
||||
!read_write(serv->tcpfd, &c1, 1, 1) ||
|
||||
!read_write(serv->tcpfd, &c2, 1, 1) ||
|
||||
!read_write(serv->tcpfd, payload, (rsize = (c1 << 8) | c2), 1))
|
||||
/* We us the _ONCE veriant of read_write() here because we've set a timeout on the tcp socket
|
||||
and wish to abort if the whole data is not read/written within the timeout. */
|
||||
if ((!data_sent && !read_write(serv->tcpfd, (unsigned char *)packet, qsize + sizeof(u16), RW_WRITE_ONCE)) ||
|
||||
!read_write(serv->tcpfd, (unsigned char *)length, sizeof (*length), RW_READ_ONCE) ||
|
||||
!read_write(serv->tcpfd, payload, (rsize = ntohs(*length)), RW_READ_ONCE))
|
||||
{
|
||||
close(serv->tcpfd);
|
||||
serv->tcpfd = -1;
|
||||
@@ -2210,7 +2216,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
/* Max TCP packet + slop + size */
|
||||
unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16));
|
||||
unsigned char *payload = &packet[2];
|
||||
unsigned char c1, c2;
|
||||
u16 tcp_len;
|
||||
/* largest field in header is 16-bits, so this is still sufficiently aligned */
|
||||
struct dns_header *header = (struct dns_header *)payload;
|
||||
u16 *length = (u16 *)packet;
|
||||
@@ -2283,9 +2289,9 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
if (query_count >= TCP_MAX_QUERIES)
|
||||
break;
|
||||
|
||||
if (!read_write(confd, &c1, 1, 1) || !read_write(confd, &c2, 1, 1) ||
|
||||
!(size = c1 << 8 | c2) ||
|
||||
!read_write(confd, payload, size, 1))
|
||||
if (!read_write(confd, (unsigned char *)&tcp_len, sizeof(tcp_len), RW_READ) ||
|
||||
!(size = ntohs(tcp_len)) ||
|
||||
!read_write(confd, payload, size, RW_READ))
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2584,7 +2590,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
if (option_bool(OPT_CMARK_ALST_EN) && have_mark && ((u32)mark & daemon->allowlist_mask))
|
||||
report_addresses(header, m, mark);
|
||||
#endif
|
||||
if (!read_write(confd, packet, m + sizeof(u16), 0))
|
||||
if (!read_write(confd, packet, m + sizeof(u16), RW_WRITE))
|
||||
break;
|
||||
|
||||
/* If we answered with stale data, this process will now try and get fresh data into
|
||||
|
||||
@@ -196,7 +196,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
}
|
||||
|
||||
/* we read zero bytes when pipe closed: this is our signal to exit */
|
||||
if (!read_write(pipefd[0], (unsigned char *)&data, sizeof(data), 1))
|
||||
if (!read_write(pipefd[0], (unsigned char *)&data, sizeof(data), RW_READ))
|
||||
{
|
||||
#ifdef HAVE_LUASCRIPT
|
||||
if (daemon->luascript)
|
||||
@@ -258,7 +258,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
continue;
|
||||
|
||||
if (!read_write(pipefd[0], buf,
|
||||
data.hostname_len + data.ed_len + data.clid_len, 1))
|
||||
data.hostname_len + data.ed_len + data.clid_len, RW_READ))
|
||||
continue;
|
||||
|
||||
/* CLID into packet */
|
||||
|
||||
@@ -845,7 +845,7 @@ static ssize_t get_block(char *packet, struct tftp_transfer *transfer)
|
||||
mess->block = htons((unsigned short)(transfer->block));
|
||||
|
||||
if (lseek(transfer->file->fd, transfer->offset, SEEK_SET) == (off_t)-1 ||
|
||||
!read_write(transfer->file->fd, mess->data, size, 1))
|
||||
!read_write(transfer->file->fd, mess->data, size, RW_READ))
|
||||
return -1;
|
||||
|
||||
transfer->expansion = 0;
|
||||
|
||||
26
src/util.c
26
src/util.c
@@ -46,8 +46,8 @@ void rand_init()
|
||||
int fd = open(RANDFILE, O_RDONLY);
|
||||
|
||||
if (fd == -1 ||
|
||||
!read_write(fd, (unsigned char *)&seed, sizeof(seed), 1) ||
|
||||
!read_write(fd, (unsigned char *)&in, sizeof(in), 1))
|
||||
!read_write(fd, (unsigned char *)&seed, sizeof(seed), RW_READ) ||
|
||||
!read_write(fd, (unsigned char *)&in, sizeof(in), RW_READ))
|
||||
die(_("failed to seed the random number generator: %s"), NULL, EC_MISC);
|
||||
|
||||
close(fd);
|
||||
@@ -765,6 +765,14 @@ int retry_send(ssize_t rc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* rw = 0 -> write
|
||||
rw = 1 -> read
|
||||
rw = 2 -> read once
|
||||
rw = 3 -> write once
|
||||
|
||||
"once" fail if all the data doesn't arrive/go in a single read/write.
|
||||
This indicates a timeout of a TCP socket.
|
||||
*/
|
||||
int read_write(int fd, unsigned char *packet, int size, int rw)
|
||||
{
|
||||
ssize_t n, done;
|
||||
@@ -772,7 +780,7 @@ int read_write(int fd, unsigned char *packet, int size, int rw)
|
||||
for (done = 0; done < size; done += n)
|
||||
{
|
||||
do {
|
||||
if (rw)
|
||||
if (rw & 1)
|
||||
n = read(fd, &packet[done], (size_t)(size - done));
|
||||
else
|
||||
n = write(fd, &packet[done], (size_t)(size - done));
|
||||
@@ -780,9 +788,17 @@ int read_write(int fd, unsigned char *packet, int size, int rw)
|
||||
if (n == 0)
|
||||
return 0;
|
||||
|
||||
} while (retry_send(n) || errno == ENOMEM || errno == ENOBUFS);
|
||||
if (n == -1 && errno == EINTR)
|
||||
continue;
|
||||
|
||||
if (errno != 0)
|
||||
/* "once" variant */
|
||||
if ((rw & 2) && n != size)
|
||||
return 0;
|
||||
|
||||
} while (n == -1 && (errno == EINTR || errno == ENOMEM || errno == ENOBUFS ||
|
||||
errno == EAGAIN || errno == EWOULDBLOCK));
|
||||
|
||||
if (n == -1)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user