mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 10:18:25 +00:00
Tidy-up of TCP-child pipe handling code.
Functionality is unchanged, but the code is easier to read and understand. Also fix memory leak of blocks when cache insert fails.
This commit is contained in:
360
src/cache.c
360
src/cache.c
@@ -779,7 +779,14 @@ void cache_end_insert(void)
|
||||
{
|
||||
if (insert_error)
|
||||
return;
|
||||
|
||||
|
||||
/* signal start of cache insert transaction to master process */
|
||||
if (daemon->pipe_to_parent != -1)
|
||||
{
|
||||
unsigned char op = PIPE_OP_INSERT;
|
||||
read_write(daemon->pipe_to_parent, &op, sizeof(op), RW_WRITE);
|
||||
}
|
||||
|
||||
while (new_chain)
|
||||
{
|
||||
struct crec *tmp = new_chain->next;
|
||||
@@ -799,12 +806,10 @@ void cache_end_insert(void)
|
||||
char *name = cache_get_name(new_chain);
|
||||
ssize_t m = strlen(name);
|
||||
unsigned int flags = new_chain->flags;
|
||||
unsigned char op = PIPE_OP_RR;
|
||||
#ifdef HAVE_DNSSEC
|
||||
u16 class = new_chain->uid;
|
||||
#endif
|
||||
|
||||
read_write(daemon->pipe_to_parent, &op, sizeof(op), RW_WRITE);
|
||||
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);
|
||||
@@ -818,7 +823,7 @@ void cache_end_insert(void)
|
||||
blockdata_write(new_chain->addr.rrblock.rrdata, new_chain->addr.rrblock.datalen, daemon->pipe_to_parent);
|
||||
}
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (flags & F_DNSKEY)
|
||||
else if (flags & F_DNSKEY)
|
||||
{
|
||||
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);
|
||||
@@ -840,8 +845,8 @@ void cache_end_insert(void)
|
||||
/* signal end of cache insert in master process */
|
||||
if (daemon->pipe_to_parent != -1)
|
||||
{
|
||||
unsigned char op = PIPE_OP_END;
|
||||
read_write(daemon->pipe_to_parent, &op, sizeof(op), RW_WRITE);
|
||||
ssize_t m = -1;
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&m, sizeof(m), RW_WRITE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -874,195 +879,204 @@ void cache_send_ipset(unsigned char op, struct ipsets *sets, int flags, union al
|
||||
}
|
||||
#endif
|
||||
|
||||
/* A marshalled cache entry arrives on fd, read, unmarshall and insert into cache of master process. */
|
||||
/* Retrieve and handle a result from child TCP-handler.
|
||||
Return 0 when pipe is closed by far end. */
|
||||
int cache_recv_insert(time_t now, int fd)
|
||||
{
|
||||
ssize_t m;
|
||||
union all_addr addr;
|
||||
unsigned long ttl;
|
||||
time_t ttd;
|
||||
unsigned int flags;
|
||||
struct crec *crecp = NULL;
|
||||
unsigned char op;
|
||||
|
||||
cache_start_insert();
|
||||
if (!read_write(fd, &op, sizeof(op), RW_READ))
|
||||
return 0;
|
||||
|
||||
while (1)
|
||||
switch (op)
|
||||
{
|
||||
if (!read_write(fd, &op, sizeof(op), RW_READ))
|
||||
return 0;
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case PIPE_OP_END:
|
||||
cache_end_insert();
|
||||
return 1;
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
case PIPE_OP_STATS:
|
||||
{
|
||||
/* Sneak in possibly updated crypto HWM. */
|
||||
unsigned int val;
|
||||
case PIPE_OP_INSERT:
|
||||
{
|
||||
/* A marshalled set if cache entries arrives on fd, read, unmarshall and insert into cache of master process. */
|
||||
ssize_t m;
|
||||
union all_addr addr;
|
||||
unsigned long ttl;
|
||||
time_t ttd;
|
||||
unsigned int flags;
|
||||
struct crec *crecp = NULL;
|
||||
|
||||
if (!read_write(fd, (unsigned char *)&val, sizeof(val), RW_READ))
|
||||
return 0;
|
||||
if (val > daemon->metrics[METRIC_CRYPTO_HWM])
|
||||
daemon->metrics[METRIC_CRYPTO_HWM] = val;
|
||||
if (!read_write(fd, (unsigned char *)&val, sizeof(val), RW_READ))
|
||||
return 0;
|
||||
if (val > daemon->metrics[METRIC_SIG_FAIL_HWM])
|
||||
daemon->metrics[METRIC_SIG_FAIL_HWM] = val;
|
||||
if (!read_write(fd, (unsigned char *)&val, sizeof(val), RW_READ))
|
||||
return 0;
|
||||
if (val > daemon->metrics[METRIC_WORK_HWM])
|
||||
daemon->metrics[METRIC_WORK_HWM] = val;
|
||||
return 1;
|
||||
}
|
||||
|
||||
case PIPE_OP_RESULT:
|
||||
cache_start_insert();
|
||||
|
||||
/* loop reading RRs, since we don't want to go back to the poll() loop
|
||||
and start processing other queries which might pollute the insertion
|
||||
chain. The child will never block between the first OP_RR and the
|
||||
minus-one length marking the end. */
|
||||
while (1)
|
||||
{
|
||||
/* UDP validation moved to TCP to avoid truncation.
|
||||
Restart UDP validation process with the returned result. */
|
||||
int status, uid, keycount, validatecount;
|
||||
int *keycountp, *validatecountp;
|
||||
size_t ret_len;
|
||||
|
||||
struct frec *forward;
|
||||
|
||||
if (!read_write(fd, (unsigned char *)&status, sizeof(status), RW_READ))
|
||||
return 0;
|
||||
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, RW_READ))
|
||||
return 0;
|
||||
if (!read_write(fd, (unsigned char *)&forward, sizeof(forward), RW_READ))
|
||||
return 0;
|
||||
if (!read_write(fd, (unsigned char *)&uid, sizeof(uid), RW_READ))
|
||||
return 0;
|
||||
if (!read_write(fd, (unsigned char *)&keycount, sizeof(keycount), RW_READ))
|
||||
return 0;
|
||||
if (!read_write(fd, (unsigned char *)&keycountp, sizeof(keycountp), RW_READ))
|
||||
return 0;
|
||||
if (!read_write(fd, (unsigned char *)&validatecount, sizeof(validatecount), RW_READ))
|
||||
return 0;
|
||||
if (!read_write(fd, (unsigned char *)&validatecountp, sizeof(validatecountp), RW_READ))
|
||||
if (!read_write(fd, (unsigned char *)&m, sizeof(m), RW_READ))
|
||||
return 0;
|
||||
|
||||
/* There's a tiny chance that the frec may have been freed
|
||||
and reused before the TCP process returns. Detect that with
|
||||
the uid field which is unique modulo 2^32 for each use. */
|
||||
if (uid == forward->uid)
|
||||
if (m == -1)
|
||||
{
|
||||
/* repatriate the work counters from the child process. */
|
||||
*keycountp = keycount;
|
||||
*validatecountp = validatecount;
|
||||
|
||||
if (!forward->dependent)
|
||||
return_reply(now, forward, (struct dns_header *)daemon->packet, ret_len, status);
|
||||
else
|
||||
pop_and_retry_query(forward, status, now);
|
||||
cache_end_insert();
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
case PIPE_OP_RR:
|
||||
if (!read_write(fd, (unsigned char *)&m, sizeof(m), RW_READ) ||
|
||||
!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;
|
||||
|
||||
ttl = difftime(ttd, now);
|
||||
|
||||
if (flags & F_CNAME)
|
||||
{
|
||||
struct crec *newc = really_insert(daemon->namebuff, NULL, C_IN, now, ttl, flags);
|
||||
/* This relies on the fact that the target of a CNAME immediately precedes
|
||||
it because of the order of extraction in extract_addresses, and
|
||||
the order reversal on the new_chain. */
|
||||
if (newc)
|
||||
{
|
||||
newc->addr.cname.is_name_ptr = 0;
|
||||
|
||||
if (!crecp)
|
||||
newc->addr.cname.target.cache = NULL;
|
||||
else
|
||||
{
|
||||
next_uid(crecp);
|
||||
newc->addr.cname.target.cache = crecp;
|
||||
newc->addr.cname.uid = crecp->uid;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned short class = C_IN;
|
||||
|
||||
if ((flags & F_RR) && !(flags & F_NEG) && (flags & F_KEYTAG)
|
||||
&& !(addr.rrblock.rrdata = blockdata_read(fd, addr.rrblock.datalen)))
|
||||
return 0;
|
||||
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;
|
||||
|
||||
ttl = difftime(ttd, now);
|
||||
|
||||
if (flags & F_CNAME)
|
||||
{
|
||||
struct crec *newc = really_insert(daemon->namebuff, NULL, C_IN, now, ttl, flags);
|
||||
/* This relies on the fact that the target of a CNAME immediately precedes
|
||||
it because of the order of extraction in extract_addresses, and
|
||||
the order reversal on the new_chain. */
|
||||
if (newc)
|
||||
{
|
||||
newc->addr.cname.is_name_ptr = 0;
|
||||
|
||||
if (!crecp)
|
||||
newc->addr.cname.target.cache = NULL;
|
||||
else
|
||||
{
|
||||
next_uid(crecp);
|
||||
newc->addr.cname.target.cache = crecp;
|
||||
newc->addr.cname.uid = crecp->uid;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned short class = C_IN;
|
||||
struct blockdata *block = NULL;
|
||||
|
||||
if ((flags & F_RR) && !(flags & F_NEG) && (flags & F_KEYTAG)
|
||||
&& !(block = addr.rrblock.rrdata = blockdata_read(fd, addr.rrblock.datalen)))
|
||||
continue;
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (flags & F_DNSKEY)
|
||||
{
|
||||
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), RW_READ) ||
|
||||
(!(flags & F_NEG) && !(addr.key.keydata = blockdata_read(fd, addr.key.keylen))))
|
||||
return 0;
|
||||
}
|
||||
else if (flags & F_DNSKEY)
|
||||
{
|
||||
if (!read_write(fd, (unsigned char *)&class, sizeof(class), RW_READ))
|
||||
return 0;
|
||||
if (!(block = addr.key.keydata = blockdata_read(fd, addr.key.keylen)))
|
||||
continue;
|
||||
}
|
||||
else if (flags & F_DS)
|
||||
{
|
||||
if (!read_write(fd, (unsigned char *)&class, sizeof(class), RW_READ))
|
||||
return 0;
|
||||
if (!(flags & F_NEG) && !(block = addr.ds.keydata = blockdata_read(fd, addr.ds.keylen)))
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
crecp = really_insert(daemon->namebuff, &addr, class, now, ttl, flags);
|
||||
}
|
||||
|
||||
/* loop reading RRs, since we don't want to go back to the poll() loop
|
||||
and start processing other queries which might pollute the insertion
|
||||
chain. The child will never block between the first OP_RR and the OP_END */
|
||||
continue;
|
||||
|
||||
if (!(crecp = really_insert(daemon->namebuff, &addr, class, now, ttl, flags)))
|
||||
blockdata_free(block);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
case PIPE_OP_STATS:
|
||||
{
|
||||
/* Sneak in possibly updated crypto HWM. */
|
||||
unsigned int val;
|
||||
|
||||
if (!read_write(fd, (unsigned char *)&val, sizeof(val), RW_READ))
|
||||
return 0;
|
||||
if (val > daemon->metrics[METRIC_CRYPTO_HWM])
|
||||
daemon->metrics[METRIC_CRYPTO_HWM] = val;
|
||||
if (!read_write(fd, (unsigned char *)&val, sizeof(val), RW_READ))
|
||||
return 0;
|
||||
if (val > daemon->metrics[METRIC_SIG_FAIL_HWM])
|
||||
daemon->metrics[METRIC_SIG_FAIL_HWM] = val;
|
||||
if (!read_write(fd, (unsigned char *)&val, sizeof(val), RW_READ))
|
||||
return 0;
|
||||
if (val > daemon->metrics[METRIC_WORK_HWM])
|
||||
daemon->metrics[METRIC_WORK_HWM] = val;
|
||||
return 1;
|
||||
}
|
||||
|
||||
case PIPE_OP_RESULT:
|
||||
{
|
||||
/* UDP validation moved to TCP to avoid truncation.
|
||||
Restart UDP validation process with the returned result. */
|
||||
int status, uid, keycount, validatecount;
|
||||
int *keycountp, *validatecountp;
|
||||
size_t ret_len;
|
||||
|
||||
struct frec *forward;
|
||||
|
||||
if (!read_write(fd, (unsigned char *)&status, sizeof(status), RW_READ) ||
|
||||
!read_write(fd, (unsigned char *)&ret_len, sizeof(ret_len), RW_READ) ||
|
||||
!read_write(fd, (unsigned char *)daemon->packet, ret_len, RW_READ) ||
|
||||
!read_write(fd, (unsigned char *)&forward, sizeof(forward), RW_READ) ||
|
||||
!read_write(fd, (unsigned char *)&uid, sizeof(uid), RW_READ) ||
|
||||
!read_write(fd, (unsigned char *)&keycount, sizeof(keycount), RW_READ) ||
|
||||
!read_write(fd, (unsigned char *)&keycountp, sizeof(keycountp), RW_READ) ||
|
||||
!read_write(fd, (unsigned char *)&validatecount, sizeof(validatecount), RW_READ) ||
|
||||
!read_write(fd, (unsigned char *)&validatecountp, sizeof(validatecountp), RW_READ))
|
||||
return 0;
|
||||
|
||||
/* There's a tiny chance that the frec may have been freed
|
||||
and reused before the TCP process returns. Detect that with
|
||||
the uid field which is unique modulo 2^32 for each use. */
|
||||
if (uid == forward->uid)
|
||||
{
|
||||
/* repatriate the work counters from the child process. */
|
||||
*keycountp = keycount;
|
||||
*validatecountp = validatecount;
|
||||
|
||||
if (!forward->dependent)
|
||||
return_reply(now, forward, (struct dns_header *)daemon->packet, ret_len, status);
|
||||
else
|
||||
pop_and_retry_query(forward, status, now);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_IPSET) || defined(HAVE_NFTSET)
|
||||
case PIPE_OP_IPSET:
|
||||
case PIPE_OP_NFTSET:
|
||||
{
|
||||
struct ipsets *sets;
|
||||
char **sets_cur;
|
||||
|
||||
if (!read_write(fd, (unsigned char *)&sets, sizeof(sets), RW_READ) ||
|
||||
!read_write(fd, (unsigned char *)&flags, sizeof(flags), RW_READ) ||
|
||||
!read_write(fd, (unsigned char *)&addr, sizeof(addr), RW_READ))
|
||||
return 0;
|
||||
|
||||
for (sets_cur = sets->sets; *sets_cur; sets_cur++)
|
||||
{
|
||||
int rc = -1;
|
||||
|
||||
case PIPE_OP_IPSET:
|
||||
case PIPE_OP_NFTSET:
|
||||
{
|
||||
struct ipsets *sets;
|
||||
char **sets_cur;
|
||||
unsigned int flags;
|
||||
union all_addr addr;
|
||||
|
||||
if (!read_write(fd, (unsigned char *)&sets, sizeof(sets), RW_READ) ||
|
||||
!read_write(fd, (unsigned char *)&flags, sizeof(flags), RW_READ) ||
|
||||
!read_write(fd, (unsigned char *)&addr, sizeof(addr), RW_READ))
|
||||
return 0;
|
||||
|
||||
for (sets_cur = sets->sets; *sets_cur; sets_cur++)
|
||||
{
|
||||
int rc = -1;
|
||||
|
||||
#ifdef HAVE_IPSET
|
||||
if (op == PIPE_OP_IPSET)
|
||||
rc = add_to_ipset(*sets_cur, &addr, flags, 0);
|
||||
if (op == PIPE_OP_IPSET)
|
||||
rc = add_to_ipset(*sets_cur, &addr, flags, 0);
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HAVE_NFTSET
|
||||
if (op == PIPE_OP_NFTSET)
|
||||
rc = add_to_nftset(*sets_cur, &addr, flags, 0);
|
||||
if (op == PIPE_OP_NFTSET)
|
||||
rc = add_to_nftset(*sets_cur, &addr, flags, 0);
|
||||
#endif
|
||||
|
||||
if (rc == 0)
|
||||
log_query((flags & (F_IPV4 | F_IPV6)) | F_IPSET, sets->domain, &addr, *sets_cur, op == PIPE_OP_IPSET);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (rc == 0)
|
||||
log_query((flags & (F_IPV4 | F_IPV6)) | F_IPSET, sets->domain, &addr, *sets_cur, op == PIPE_OP_IPSET);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cache_find_non_terminal(char *name, time_t now)
|
||||
|
||||
Reference in New Issue
Block a user