mirror of
http://thekelleys.org.uk/git/dnsmasq.git
synced 2026-11-14 19:03:37 +00:00
Compare commits
20
Commits
v2.93test1
...
v2.93test4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e4d0bb4579 | ||
|
|
84415a87be | ||
|
|
1537645e8f | ||
|
|
ceab392c60 | ||
|
|
5f0f6aa9b1 | ||
|
|
578ea08391 | ||
|
|
fbfcf87f8b | ||
|
|
19f3e06e7a | ||
|
|
40d1152059 | ||
|
|
3c830c4f1c | ||
|
|
e9f400dd37 | ||
|
|
870f14108f | ||
|
|
714d36229a | ||
|
|
60e90e2224 | ||
|
|
ed2ba5b07a | ||
|
|
729c16a8ac | ||
|
|
80acb76f46 | ||
|
|
f1fa05d754 | ||
|
|
b148ba4752 | ||
|
|
81f619612e |
No files matched your search
@@ -24,6 +24,10 @@ version 2.93
|
|||||||
accepts a signed CNAME reply to a DS query as proof that no DS
|
accepts a signed CNAME reply to a DS query as proof that no DS
|
||||||
exists at the domain. This fixes the DS/zone break detection logic.
|
exists at the domain. This fixes the DS/zone break detection logic.
|
||||||
|
|
||||||
|
Fix regression in 2.92 release which broke DHCPv6 when a DHCP
|
||||||
|
relay is in use. Many thanks to Jørgen Søvik for help
|
||||||
|
finding this bug.
|
||||||
|
|
||||||
|
|
||||||
version 2.92
|
version 2.92
|
||||||
Redesign the interaction between DNSSEC validation and per-domain
|
Redesign the interaction between DNSSEC validation and per-domain
|
||||||
|
|||||||
+9
-7
@@ -193,20 +193,22 @@ void *blockdata_retrieve(struct blockdata *block, size_t len, void *data)
|
|||||||
{
|
{
|
||||||
size_t blen;
|
size_t blen;
|
||||||
struct blockdata *b;
|
struct blockdata *b;
|
||||||
uint8_t *new, *d;
|
uint8_t *d;
|
||||||
|
|
||||||
static unsigned int buff_len = 0;
|
|
||||||
static unsigned char *buff = NULL;
|
|
||||||
|
|
||||||
if (!data)
|
if (!data)
|
||||||
{
|
{
|
||||||
|
static unsigned int buff_len = 0;
|
||||||
|
static unsigned char *buff = NULL;
|
||||||
|
uint8_t *new;
|
||||||
|
|
||||||
if (len > buff_len)
|
if (len > buff_len)
|
||||||
{
|
{
|
||||||
if (!(new = whine_malloc(len)))
|
blen = len + 1024;
|
||||||
|
if (!(new = whine_realloc(buff, blen)))
|
||||||
return NULL;
|
return NULL;
|
||||||
if (buff)
|
|
||||||
free(buff);
|
|
||||||
buff = new;
|
buff = new;
|
||||||
|
buff_len = blen;
|
||||||
}
|
}
|
||||||
data = buff;
|
data = buff;
|
||||||
}
|
}
|
||||||
|
|||||||
+143
-99
@@ -17,13 +17,16 @@
|
|||||||
#include "dnsmasq.h"
|
#include "dnsmasq.h"
|
||||||
|
|
||||||
static struct crec *cache_head = NULL, *cache_tail = NULL, **hash_table = NULL;
|
static struct crec *cache_head = NULL, *cache_tail = NULL, **hash_table = NULL;
|
||||||
#ifdef HAVE_DHCP
|
static struct crec *config_spare = NULL;
|
||||||
static struct crec *dhcp_spare = NULL;
|
|
||||||
#endif
|
|
||||||
static struct crec *new_chain = NULL;
|
static struct crec *new_chain = NULL;
|
||||||
static int insert_error;
|
static int insert_error;
|
||||||
static union bigname *big_free = NULL;
|
static union bigname *big_free = NULL;
|
||||||
static int bignames_left, hash_size;
|
static int bignames_left, hash_size;
|
||||||
|
struct nameblock {
|
||||||
|
struct nameblock *next;
|
||||||
|
unsigned int last, index;
|
||||||
|
char data[NAMEBLOCK_CHARS];
|
||||||
|
} *hostblocks = NULL;
|
||||||
|
|
||||||
static void make_non_terminals(struct crec *source);
|
static void make_non_terminals(struct crec *source);
|
||||||
static struct crec *really_insert(char *name, union all_addr *addr, unsigned short class,
|
static struct crec *really_insert(char *name, union all_addr *addr, unsigned short class,
|
||||||
@@ -192,6 +195,61 @@ void cache_init(void)
|
|||||||
rehash(daemon->cachesize);
|
rehash(daemon->cachesize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct crec *get_config_crec(void)
|
||||||
|
{
|
||||||
|
struct crec *ret;
|
||||||
|
|
||||||
|
if (config_spare)
|
||||||
|
{
|
||||||
|
ret = config_spare;
|
||||||
|
config_spare = config_spare->next;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ret = whine_malloc(SIZEOF_POINTER_CREC);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void free_config_crec(struct crec *p)
|
||||||
|
{
|
||||||
|
p->next = config_spare;
|
||||||
|
config_spare = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *store_name(unsigned int namelen, unsigned int index)
|
||||||
|
{
|
||||||
|
struct nameblock *block;
|
||||||
|
char *ret = NULL;
|
||||||
|
|
||||||
|
for (block = hostblocks; block; block = block->next)
|
||||||
|
if (block->index == index && NAMEBLOCK_CHARS - block->last >= namelen)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!block && ((block = whine_malloc(sizeof(struct nameblock)))))
|
||||||
|
{
|
||||||
|
block->next = hostblocks;
|
||||||
|
block->index = index;
|
||||||
|
hostblocks = block;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (block && NAMEBLOCK_CHARS - block->last >= namelen)
|
||||||
|
{
|
||||||
|
ret = &block->data[block->last];
|
||||||
|
block->last += namelen;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void free_names(unsigned int index)
|
||||||
|
{
|
||||||
|
struct nameblock *block;
|
||||||
|
|
||||||
|
for (block = hostblocks; block; block = block->next)
|
||||||
|
if (index == UID_NONE || block->index == index)
|
||||||
|
block->last = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* In most cases, we create the hash table once here by calling this with (hash_table == NULL)
|
/* In most cases, we create the hash table once here by calling this with (hash_table == NULL)
|
||||||
but if the hosts file(s) are big (some people have 50000 ad-block entries), the table
|
but if the hosts file(s) are big (some people have 50000 ad-block entries), the table
|
||||||
will be much too small, so the hosts reading code calls rehash every 1000 addresses, to
|
will be much too small, so the hosts reading code calls rehash every 1000 addresses, to
|
||||||
@@ -441,13 +499,15 @@ unsigned int cache_remove_uid(const unsigned int uid)
|
|||||||
if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) && crecp->uid == uid)
|
if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) && crecp->uid == uid)
|
||||||
{
|
{
|
||||||
*up = tmp;
|
*up = tmp;
|
||||||
free(crecp);
|
free_config_crec(crecp);
|
||||||
removed++;
|
removed++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
up = &crecp->hash_next;
|
up = &crecp->hash_next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free_names(uid);
|
||||||
|
|
||||||
return removed;
|
return removed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1261,7 +1321,7 @@ static void add_hosts_entry(struct crec *cache, union all_addr *addr, int addrle
|
|||||||
while ((lookup = cache_find_by_name(lookup, cache_get_name(cache), 0, cache->flags & (F_IPV4 | F_IPV6))))
|
while ((lookup = cache_find_by_name(lookup, cache_get_name(cache), 0, cache->flags & (F_IPV4 | F_IPV6))))
|
||||||
if ((lookup->flags & F_HOSTS) && memcmp(&lookup->addr, addr, addrlen) == 0)
|
if ((lookup->flags & F_HOSTS) && memcmp(&lookup->addr, addr, addrlen) == 0)
|
||||||
{
|
{
|
||||||
free(cache);
|
free_config_crec(cache);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1384,13 +1444,13 @@ int read_hostsfile(char *filename, unsigned int index, int cache_size, struct cr
|
|||||||
{
|
{
|
||||||
if (inet_pton(AF_INET, token, &addr) > 0)
|
if (inet_pton(AF_INET, token, &addr) > 0)
|
||||||
{
|
{
|
||||||
flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
|
flags = F_NAMEP | F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
|
||||||
addrlen = INADDRSZ;
|
addrlen = INADDRSZ;
|
||||||
domain_suffix = get_domain(addr.addr4);
|
domain_suffix = get_domain(addr.addr4);
|
||||||
}
|
}
|
||||||
else if (inet_pton(AF_INET6, token, &addr) > 0)
|
else if (inet_pton(AF_INET6, token, &addr) > 0)
|
||||||
{
|
{
|
||||||
flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6;
|
flags = F_NAMEP | F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6;
|
||||||
addrlen = IN6ADDRSZ;
|
addrlen = IN6ADDRSZ;
|
||||||
domain_suffix = get_domain6(&addr.addr6);
|
domain_suffix = get_domain6(&addr.addr6);
|
||||||
}
|
}
|
||||||
@@ -1424,27 +1484,37 @@ int read_hostsfile(char *filename, unsigned int index, int cache_size, struct cr
|
|||||||
if ((canon = canonicalise(token, &nomem)))
|
if ((canon = canonicalise(token, &nomem)))
|
||||||
{
|
{
|
||||||
/* If set, add a version of the name with a default domain appended */
|
/* If set, add a version of the name with a default domain appended */
|
||||||
if (option_bool(OPT_EXPAND) && domain_suffix && !fqdn &&
|
if (option_bool(OPT_EXPAND) && domain_suffix && !fqdn && (cache = get_config_crec()))
|
||||||
(cache = whine_malloc(SIZEOF_BARE_CREC + strlen(canon) + 2 + strlen(domain_suffix))))
|
|
||||||
{
|
{
|
||||||
strcpy(cache->name.sname, canon);
|
if (!(cache->name.namep = store_name(strlen(canon) + 2 + strlen(domain_suffix), index)))
|
||||||
strcat(cache->name.sname, ".");
|
free_config_crec(cache);
|
||||||
strcat(cache->name.sname, domain_suffix);
|
else
|
||||||
cache->flags = flags;
|
{
|
||||||
cache->ttd = daemon->local_ttl;
|
strcpy(cache->name.namep, canon);
|
||||||
add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
|
strcat(cache->name.namep, ".");
|
||||||
name_count++;
|
strcat(cache->name.namep, domain_suffix);
|
||||||
names_done++;
|
cache->flags = flags;
|
||||||
|
cache->ttd = daemon->local_ttl;
|
||||||
|
add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
|
||||||
|
name_count++;
|
||||||
|
names_done++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if ((cache = whine_malloc(SIZEOF_BARE_CREC + strlen(canon) + 1)))
|
if ((cache = get_config_crec()))
|
||||||
{
|
{
|
||||||
strcpy(cache->name.sname, canon);
|
if (!(cache->name.namep = store_name(strlen(canon) + 1, index)))
|
||||||
cache->flags = flags;
|
free_config_crec(cache);
|
||||||
cache->ttd = daemon->local_ttl;
|
else
|
||||||
add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
|
{
|
||||||
name_count++;
|
strcpy(cache->name.namep, canon);
|
||||||
names_done++;
|
cache->flags = flags;
|
||||||
|
cache->ttd = daemon->local_ttl;
|
||||||
|
add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
|
||||||
|
name_count++;
|
||||||
|
names_done++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
free(canon);
|
free(canon);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1495,7 +1565,7 @@ void cache_reload(void)
|
|||||||
if (cache->flags & (F_HOSTS | F_CONFIG))
|
if (cache->flags & (F_HOSTS | F_CONFIG))
|
||||||
{
|
{
|
||||||
*up = cache->hash_next;
|
*up = cache->hash_next;
|
||||||
free(cache);
|
free_config_crec(cache);
|
||||||
}
|
}
|
||||||
else if (!(cache->flags & F_DHCP))
|
else if (!(cache->flags & F_DHCP))
|
||||||
{
|
{
|
||||||
@@ -1511,10 +1581,12 @@ void cache_reload(void)
|
|||||||
up = &cache->hash_next;
|
up = &cache->hash_next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free_names(UID_NONE); /* free everything */
|
||||||
|
|
||||||
/* Add locally-configured CNAMEs to the cache */
|
/* Add locally-configured CNAMEs to the cache */
|
||||||
for (a = daemon->cnames; a; a = a->next)
|
for (a = daemon->cnames; a; a = a->next)
|
||||||
if (a->alias[1] != '*' &&
|
if (a->alias[1] != '*' &&
|
||||||
((cache = whine_malloc(SIZEOF_POINTER_CREC))))
|
((cache = get_config_crec())))
|
||||||
{
|
{
|
||||||
cache->flags = F_FORWARD | F_NAMEP | F_CNAME | F_IMMORTAL | F_CONFIG;
|
cache->flags = F_FORWARD | F_NAMEP | F_CNAME | F_IMMORTAL | F_CONFIG;
|
||||||
cache->ttd = a->ttl;
|
cache->ttd = a->ttl;
|
||||||
@@ -1528,25 +1600,30 @@ void cache_reload(void)
|
|||||||
|
|
||||||
#ifdef HAVE_DNSSEC
|
#ifdef HAVE_DNSSEC
|
||||||
for (ds = daemon->ds; ds; ds = ds->next)
|
for (ds = daemon->ds; ds; ds = ds->next)
|
||||||
if ((cache = whine_malloc(SIZEOF_POINTER_CREC)) &&
|
if ((cache = get_config_crec()))
|
||||||
(cache->addr.ds.keydata = blockdata_alloc(ds->digest, ds->digestlen)))
|
|
||||||
{
|
{
|
||||||
cache->flags = F_FORWARD | F_IMMORTAL | F_DS | F_CONFIG | F_NAMEP;
|
|
||||||
cache->ttd = daemon->local_ttl;
|
|
||||||
cache->name.namep = ds->name;
|
|
||||||
cache->uid = ds->class;
|
|
||||||
if (ds->digestlen != 0)
|
|
||||||
{
|
|
||||||
cache->addr.ds.keylen = ds->digestlen;
|
|
||||||
cache->addr.ds.algo = ds->algo;
|
|
||||||
cache->addr.ds.keytag = ds->keytag;
|
|
||||||
cache->addr.ds.digest = ds->digest_type;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
cache->flags |= F_NEG | F_DNSSECOK | F_NO_RR;
|
|
||||||
|
|
||||||
cache_hash(cache);
|
if (!(cache->addr.ds.keydata = blockdata_alloc(ds->digest, ds->digestlen)))
|
||||||
make_non_terminals(cache);
|
free_config_crec(cache);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cache->flags = F_FORWARD | F_IMMORTAL | F_DS | F_CONFIG | F_NAMEP;
|
||||||
|
cache->ttd = daemon->local_ttl;
|
||||||
|
cache->name.namep = ds->name;
|
||||||
|
cache->uid = ds->class;
|
||||||
|
if (ds->digestlen != 0)
|
||||||
|
{
|
||||||
|
cache->addr.ds.keylen = ds->digestlen;
|
||||||
|
cache->addr.ds.algo = ds->algo;
|
||||||
|
cache->addr.ds.keytag = ds->keytag;
|
||||||
|
cache->addr.ds.digest = ds->digest_type;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
cache->flags |= F_NEG | F_DNSSECOK | F_NO_RR;
|
||||||
|
|
||||||
|
cache_hash(cache);
|
||||||
|
make_non_terminals(cache);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -1561,7 +1638,7 @@ void cache_reload(void)
|
|||||||
for (nl = hr->names; nl; nl = nl->next)
|
for (nl = hr->names; nl; nl = nl->next)
|
||||||
{
|
{
|
||||||
if ((hr->flags & HR_4) &&
|
if ((hr->flags & HR_4) &&
|
||||||
(cache = whine_malloc(SIZEOF_POINTER_CREC)))
|
(cache = get_config_crec()))
|
||||||
{
|
{
|
||||||
cache->name.namep = nl->name;
|
cache->name.namep = nl->name;
|
||||||
cache->ttd = hr->ttl;
|
cache->ttd = hr->ttl;
|
||||||
@@ -1570,7 +1647,7 @@ void cache_reload(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((hr->flags & HR_6) &&
|
if ((hr->flags & HR_6) &&
|
||||||
(cache = whine_malloc(SIZEOF_POINTER_CREC)))
|
(cache = get_config_crec()))
|
||||||
{
|
{
|
||||||
cache->name.namep = nl->name;
|
cache->name.namep = nl->name;
|
||||||
cache->ttd = hr->ttl;
|
cache->ttd = hr->ttl;
|
||||||
@@ -1662,8 +1739,7 @@ void cache_unhash_dhcp(void)
|
|||||||
if (cache->flags & F_DHCP)
|
if (cache->flags & F_DHCP)
|
||||||
{
|
{
|
||||||
*up = cache->hash_next;
|
*up = cache->hash_next;
|
||||||
cache->next = dhcp_spare;
|
free_config_crec(cache);
|
||||||
dhcp_spare = cache;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
up = &cache->hash_next;
|
up = &cache->hash_next;
|
||||||
@@ -1734,12 +1810,7 @@ void cache_add_dhcp_entry(char *host_name, int prot,
|
|||||||
else
|
else
|
||||||
flags |= F_REVERSE;
|
flags |= F_REVERSE;
|
||||||
|
|
||||||
if ((crec = dhcp_spare))
|
if ((crec = get_config_crec()))
|
||||||
dhcp_spare = dhcp_spare->next;
|
|
||||||
else /* need new one */
|
|
||||||
crec = whine_malloc(SIZEOF_POINTER_CREC);
|
|
||||||
|
|
||||||
if (crec) /* malloc may fail */
|
|
||||||
{
|
{
|
||||||
crec->flags = flags | F_NAMEP | F_DHCP | F_FORWARD;
|
crec->flags = flags | F_NAMEP | F_DHCP | F_FORWARD;
|
||||||
if (ttd == 0)
|
if (ttd == 0)
|
||||||
@@ -1786,15 +1857,7 @@ static void make_non_terminals(struct crec *source)
|
|||||||
hostname_isequal(name, cache_get_name(crecp)))
|
hostname_isequal(name, cache_get_name(crecp)))
|
||||||
{
|
{
|
||||||
*up = crecp->hash_next;
|
*up = crecp->hash_next;
|
||||||
#ifdef HAVE_DHCP
|
free_config_crec(crecp);
|
||||||
if (type & F_DHCP)
|
|
||||||
{
|
|
||||||
crecp->next = dhcp_spare;
|
|
||||||
dhcp_spare = crecp;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
free(crecp);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -1827,17 +1890,7 @@ static void make_non_terminals(struct crec *source)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_DHCP
|
if ((crecp = get_config_crec()))
|
||||||
if ((source->flags & F_DHCP) && dhcp_spare)
|
|
||||||
{
|
|
||||||
crecp = dhcp_spare;
|
|
||||||
dhcp_spare = dhcp_spare->next;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
crecp = whine_malloc(SIZEOF_POINTER_CREC);
|
|
||||||
|
|
||||||
if (crecp)
|
|
||||||
{
|
{
|
||||||
crecp->flags = (source->flags | F_NAMEP) & ~(F_IPV4 | F_IPV6 | F_CNAME | F_RR | F_DNSKEY | F_DS | F_REVERSE);
|
crecp->flags = (source->flags | F_NAMEP) & ~(F_IPV4 | F_IPV6 | F_CNAME | F_RR | F_DNSKEY | F_DS | F_REVERSE);
|
||||||
if (!(crecp->flags & F_IMMORTAL))
|
if (!(crecp->flags & F_IMMORTAL))
|
||||||
@@ -2166,8 +2219,8 @@ static char *querystr(char *desc, unsigned short type)
|
|||||||
unsigned int i;
|
unsigned int i;
|
||||||
int len = 10; /* strlen("type=xxxxx") */
|
int len = 10; /* strlen("type=xxxxx") */
|
||||||
const char *types = NULL;
|
const char *types = NULL;
|
||||||
static char *buff = NULL;
|
static struct iovec buff = { NULL, 0 };
|
||||||
static int bufflen = 0;
|
char *buffp;
|
||||||
|
|
||||||
for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++)
|
for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++)
|
||||||
if (typestr[i].type == type)
|
if (typestr[i].type == type)
|
||||||
@@ -2184,36 +2237,27 @@ static char *querystr(char *desc, unsigned short type)
|
|||||||
}
|
}
|
||||||
len++; /* terminator */
|
len++; /* terminator */
|
||||||
|
|
||||||
if (!buff || bufflen < len)
|
if (!expand_buf(&buff, len))
|
||||||
{
|
return "";
|
||||||
if (buff)
|
|
||||||
free(buff);
|
|
||||||
else if (len < 20)
|
|
||||||
len = 20;
|
|
||||||
|
|
||||||
buff = whine_malloc(len);
|
buffp = buff.iov_base;
|
||||||
bufflen = len;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buff)
|
if (desc)
|
||||||
{
|
{
|
||||||
if (desc)
|
if (types)
|
||||||
{
|
sprintf(buffp, "%s[%s]", desc, types);
|
||||||
if (types)
|
|
||||||
sprintf(buff, "%s[%s]", desc, types);
|
|
||||||
else
|
|
||||||
sprintf(buff, "%s[type=%d]", desc, type);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
sprintf(buffp, "%s[type=%d]", desc, type);
|
||||||
if (types)
|
}
|
||||||
sprintf(buff, "<%s>", types);
|
else
|
||||||
else
|
{
|
||||||
sprintf(buff, "<type=%d>", type);
|
if (types)
|
||||||
}
|
sprintf(buffp, "<%s>", types);
|
||||||
|
else
|
||||||
|
sprintf(buffp, "<type=%d>", type);
|
||||||
}
|
}
|
||||||
|
|
||||||
return buff ? buff : "";
|
return buffp;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *edestr(int ede)
|
static char *edestr(int ede)
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#define TCP_BACKLOG 32 /* kernel backlog limit for TCP connections */
|
#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 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 */
|
#define KEYBLOCK_LEN 40 /* choose to minimise fragmentation when storing DNSSEC keys */
|
||||||
|
#define NAMEBLOCK_CHARS 1500 /* quantum of memory allocation for names from /etc/hosts */
|
||||||
#define DNSSEC_LIMIT_WORK 40 /* Max number of queries to validate one question */
|
#define DNSSEC_LIMIT_WORK 40 /* Max number of queries to validate one question */
|
||||||
#define DNSSEC_LIMIT_SIG_FAIL 20 /* Number of signature that can fail to validate in one answer */
|
#define DNSSEC_LIMIT_SIG_FAIL 20 /* Number of signature that can fail to validate in one answer */
|
||||||
#define DNSSEC_LIMIT_CRYPTO 200 /* max no. of crypto operations to validate one query. */
|
#define DNSSEC_LIMIT_CRYPTO 200 /* max no. of crypto operations to validate one query. */
|
||||||
|
|||||||
+4
-6
@@ -126,20 +126,18 @@ int hash_init(const struct nettle_hash *hash, void **ctxp, unsigned char **diges
|
|||||||
|
|
||||||
if (ctx_sz < hash->context_size)
|
if (ctx_sz < hash->context_size)
|
||||||
{
|
{
|
||||||
if (!(new = whine_malloc(hash->context_size)))
|
if (!(new = whine_realloc(ctx, hash->context_size)))
|
||||||
return 0;
|
return 0;
|
||||||
if (ctx)
|
|
||||||
free(ctx);
|
|
||||||
ctx = new;
|
ctx = new;
|
||||||
ctx_sz = hash->context_size;
|
ctx_sz = hash->context_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (digest_sz < hash->digest_size)
|
if (digest_sz < hash->digest_size)
|
||||||
{
|
{
|
||||||
if (!(new = whine_malloc(hash->digest_size)))
|
if (!(new = whine_realloc(digest, hash->digest_size)))
|
||||||
return 0;
|
return 0;
|
||||||
if (digest)
|
|
||||||
free(digest);
|
|
||||||
digest = new;
|
digest = new;
|
||||||
digest_sz = hash->digest_size;
|
digest_sz = hash->digest_size;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -399,7 +399,7 @@ void dhcp_packet(time_t now, int pxe_fd)
|
|||||||
if (mess->ciaddr.s_addr != 0)
|
if (mess->ciaddr.s_addr != 0)
|
||||||
dest.sin_addr = mess->ciaddr;
|
dest.sin_addr = mess->ciaddr;
|
||||||
}
|
}
|
||||||
if ((is_relay_use_source || mess->giaddr.s_addr) && !is_relay_reply)
|
else if ((is_relay_use_source || mess->giaddr.s_addr) && !is_relay_reply)
|
||||||
{
|
{
|
||||||
/* Send to BOOTP relay. */
|
/* Send to BOOTP relay. */
|
||||||
if (is_relay_use_source)
|
if (is_relay_use_source)
|
||||||
|
|||||||
+21
-16
@@ -864,6 +864,9 @@ int main (int argc, char **argv)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Don't start logging malloc before logging is set up. */
|
||||||
|
daemon->log_malloc = option_bool(OPT_LOG_MALLOC);
|
||||||
|
|
||||||
if (daemon->port == 0)
|
if (daemon->port == 0)
|
||||||
my_syslog(LOG_INFO, _("started, version %s DNS disabled"), VERSION);
|
my_syslog(LOG_INFO, _("started, version %s DNS disabled"), VERSION);
|
||||||
else
|
else
|
||||||
@@ -1447,8 +1450,6 @@ void send_event(int fd, int event, int data, char *msg)
|
|||||||
while (writev(fd, iov, msg ? 2 : 1) == -1 && errno == EINTR);
|
while (writev(fd, iov, msg ? 2 : 1) == -1 && errno == EINTR);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NOTE: the memory used to return msg is leaked: use msgs in events only
|
|
||||||
to describe fatal errors. */
|
|
||||||
static int read_event(int fd, struct event_desc *evp, char **msg)
|
static int read_event(int fd, struct event_desc *evp, char **msg)
|
||||||
{
|
{
|
||||||
char *buf;
|
char *buf;
|
||||||
@@ -1458,12 +1459,22 @@ static int read_event(int fd, struct event_desc *evp, char **msg)
|
|||||||
|
|
||||||
*msg = NULL;
|
*msg = NULL;
|
||||||
|
|
||||||
if (evp->msg_sz != 0 &&
|
if (evp->msg_sz != 0)
|
||||||
(buf = malloc(evp->msg_sz + 1)) &&
|
|
||||||
read_write(fd, (unsigned char *)buf, evp->msg_sz, RW_READ))
|
|
||||||
{
|
{
|
||||||
buf[evp->msg_sz] = 0;
|
if (!(buf = whine_malloc(evp->msg_sz + 1)))
|
||||||
*msg = buf;
|
{
|
||||||
|
int i;
|
||||||
|
unsigned char a;
|
||||||
|
|
||||||
|
/* Keep the stream synchronised if malloc fails. */
|
||||||
|
for (i = 0; i < evp->msg_sz; i++)
|
||||||
|
read_write(fd, &a, 1, RW_READ);
|
||||||
|
}
|
||||||
|
else if (read_write(fd, (unsigned char *)buf, evp->msg_sz, RW_READ))
|
||||||
|
{
|
||||||
|
buf[evp->msg_sz] = 0;
|
||||||
|
*msg = buf;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@@ -1526,9 +1537,6 @@ static void async_event(int pipe, time_t now)
|
|||||||
int wstatus, i, check = 0;
|
int wstatus, i, check = 0;
|
||||||
char *msg;
|
char *msg;
|
||||||
|
|
||||||
/* NOTE: the memory used to return msg is leaked: use msgs in events only
|
|
||||||
to describe fatal errors. */
|
|
||||||
|
|
||||||
if (read_event(pipe, &ev, &msg))
|
if (read_event(pipe, &ev, &msg))
|
||||||
switch (ev.event)
|
switch (ev.event)
|
||||||
{
|
{
|
||||||
@@ -1634,7 +1642,6 @@ static void async_event(int pipe, time_t now)
|
|||||||
case EVENT_SCRIPT_LOG:
|
case EVENT_SCRIPT_LOG:
|
||||||
my_syslog(MS_SCRIPT | LOG_DEBUG, "%s", msg ? msg : "");
|
my_syslog(MS_SCRIPT | LOG_DEBUG, "%s", msg ? msg : "");
|
||||||
free(msg);
|
free(msg);
|
||||||
msg = NULL;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* necessary for fatal errors in helper */
|
/* necessary for fatal errors in helper */
|
||||||
@@ -1977,11 +1984,11 @@ static void do_tcp_connection(struct listener *listener, time_t now, int slot)
|
|||||||
pid_t p;
|
pid_t p;
|
||||||
union mysockaddr tcp_addr;
|
union mysockaddr tcp_addr;
|
||||||
socklen_t tcp_len = sizeof(union mysockaddr);
|
socklen_t tcp_len = sizeof(union mysockaddr);
|
||||||
unsigned char *buff;
|
|
||||||
struct server *s;
|
struct server *s;
|
||||||
int flags, auth_dns = 0;
|
int flags, auth_dns = 0;
|
||||||
struct in_addr netmask;
|
struct in_addr netmask;
|
||||||
int pipefd[2];
|
int pipefd[2];
|
||||||
|
struct iovec tcpbuff;
|
||||||
#ifdef HAVE_LINUX_NETWORK
|
#ifdef HAVE_LINUX_NETWORK
|
||||||
unsigned char a = 0;
|
unsigned char a = 0;
|
||||||
#endif
|
#endif
|
||||||
@@ -2156,10 +2163,8 @@ static void do_tcp_connection(struct listener *listener, time_t now, int slot)
|
|||||||
if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
|
if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
|
||||||
while(retry_send(fcntl(confd, F_SETFL, flags & ~O_NONBLOCK)));
|
while(retry_send(fcntl(confd, F_SETFL, flags & ~O_NONBLOCK)));
|
||||||
|
|
||||||
buff = tcp_request(confd, now, &tcp_addr, netmask, auth_dns);
|
tcp_request(confd, now, &tcpbuff, &tcp_addr, netmask, auth_dns);
|
||||||
|
free(tcpbuff.iov_base);
|
||||||
if (buff)
|
|
||||||
free(buff);
|
|
||||||
|
|
||||||
for (s = daemon->servers; s; s = s->next)
|
for (s = daemon->servers; s; s = s->next)
|
||||||
if (s->tcpfd != -1)
|
if (s->tcpfd != -1)
|
||||||
|
|||||||
+16
-7
@@ -290,7 +290,8 @@ struct event_desc {
|
|||||||
#define OPT_AUTH_LOG 76
|
#define OPT_AUTH_LOG 76
|
||||||
#define OPT_LEASEQUERY 77
|
#define OPT_LEASEQUERY 77
|
||||||
#define OPT_LOG_ONLY_FAILED 78
|
#define OPT_LOG_ONLY_FAILED 78
|
||||||
#define OPT_LAST 79
|
#define OPT_LOG_MALLOC 79
|
||||||
|
#define OPT_LAST 80
|
||||||
|
|
||||||
#define OPTION_BITS (sizeof(unsigned int)*8)
|
#define OPTION_BITS (sizeof(unsigned int)*8)
|
||||||
#define OPTION_SIZE ( (OPT_LAST/OPTION_BITS)+((OPT_LAST%OPTION_BITS)!=0) )
|
#define OPTION_SIZE ( (OPT_LAST/OPTION_BITS)+((OPT_LAST%OPTION_BITS)!=0) )
|
||||||
@@ -1207,6 +1208,7 @@ extern struct daemon {
|
|||||||
int log_fac; /* log facility */
|
int log_fac; /* log facility */
|
||||||
char *log_file; /* optional log file */
|
char *log_file; /* optional log file */
|
||||||
int max_logs; /* queue limit */
|
int max_logs; /* queue limit */
|
||||||
|
int log_malloc; /* log malloc/realloc/free */
|
||||||
int randport_limit; /* Maximum number of source ports for query. */
|
int randport_limit; /* Maximum number of source ports for query. */
|
||||||
int cachesize, ftabsize;
|
int cachesize, ftabsize;
|
||||||
int port, query_port, min_port, max_port;
|
int port, query_port, min_port, max_port;
|
||||||
@@ -1495,8 +1497,16 @@ unsigned char *do_rfc1035_name(unsigned char *p, char *sval, char *limit);
|
|||||||
void *safe_malloc(size_t size);
|
void *safe_malloc(size_t size);
|
||||||
void safe_strncpy(char *dest, const char *src, size_t size);
|
void safe_strncpy(char *dest, const char *src, size_t size);
|
||||||
void safe_pipe(int *fd, int read_noblock);
|
void safe_pipe(int *fd, int read_noblock);
|
||||||
void *whine_malloc(size_t size);
|
#define whine_malloc(x) whine_malloc_real(__func__, __LINE__, (x))
|
||||||
void *whine_realloc(void *ptr, size_t size);
|
#define whine_realloc(x, y) whine_realloc_real(NULL, __func__, __LINE__, (x), (y))
|
||||||
|
#define expand_buf(x, y) expand_buf_real(__func__, __LINE__, (x), (y))
|
||||||
|
#define expand_workspace(x, y, z) expand_workspace_real(__func__, __LINE__, (x), (y), (z))
|
||||||
|
#define free(x) free_real(__func__, __LINE__, (x))
|
||||||
|
void free_real(const char *func, unsigned int line, void *ptr);
|
||||||
|
void *whine_malloc_real(const char *func, unsigned int line, size_t size);
|
||||||
|
void *whine_realloc_real(const char *wrapper, const char *func, unsigned int line, void *ptr, size_t size);
|
||||||
|
int expand_buf_real(const char *func, unsigned int line, struct iovec *iov, size_t size);
|
||||||
|
int expand_workspace_real(const char *func, unsigned int line, unsigned char ***wkspc, int *szp, int new);
|
||||||
int sa_len(union mysockaddr *addr);
|
int sa_len(union mysockaddr *addr);
|
||||||
int sockaddr_isequal(const union mysockaddr *s1, const union mysockaddr *s2);
|
int sockaddr_isequal(const union mysockaddr *s1, const union mysockaddr *s2);
|
||||||
int sockaddr_isnull(const union mysockaddr *s);
|
int sockaddr_isnull(const union mysockaddr *s);
|
||||||
@@ -1518,9 +1528,9 @@ int parse_hex(char *in, unsigned char *out, int maxlen,
|
|||||||
unsigned int *wildcard_mask, int *mac_type);
|
unsigned int *wildcard_mask, int *mac_type);
|
||||||
int memcmp_masked(unsigned char *a, unsigned char *b, int len,
|
int memcmp_masked(unsigned char *a, unsigned char *b, int len,
|
||||||
unsigned int mask);
|
unsigned int mask);
|
||||||
int expand_buf(struct iovec *iov, size_t size);
|
|
||||||
char *print_mac(char *buff, unsigned char *mac, int len);
|
char *print_mac(char *buff, unsigned char *mac, int len);
|
||||||
int read_write(int fd, unsigned char *packet, int size, int rw);
|
int read_write(int fd, unsigned char *packet, int size, int rw);
|
||||||
|
int read_writev(int fd, struct iovec *iov, int iovcnt, int rw);
|
||||||
void close_fds(long max_fd, int spare1, int spare2, int spare3);
|
void close_fds(long max_fd, int spare1, int spare2, int spare3);
|
||||||
int wildcard_match(const char* wildcard, const char* match);
|
int wildcard_match(const char* wildcard, const char* match);
|
||||||
int wildcard_matchn(const char* wildcard, const char* match, int num);
|
int wildcard_matchn(const char* wildcard, const char* match, int num);
|
||||||
@@ -1563,8 +1573,8 @@ int tcp_from_udp(time_t now, int status, struct dns_header *header, ssize_t *n,
|
|||||||
int class, char *name, struct server *server,
|
int class, char *name, struct server *server,
|
||||||
int *keycount, int *validatecount);
|
int *keycount, int *validatecount);
|
||||||
#endif
|
#endif
|
||||||
unsigned char *tcp_request(int confd, time_t now,
|
void tcp_request(int confd, time_t now, struct iovec *bigbuff,
|
||||||
union mysockaddr *local_addr, struct in_addr netmask, int auth_dns);
|
union mysockaddr *local_addr, struct in_addr netmask, int auth_dns);
|
||||||
void server_gone(struct server *server);
|
void server_gone(struct server *server);
|
||||||
int send_from(int fd, int nowild, char *packet, size_t len,
|
int send_from(int fd, int nowild, char *packet, size_t len,
|
||||||
union mysockaddr *to, union all_addr *source,
|
union mysockaddr *to, union all_addr *source,
|
||||||
@@ -1909,7 +1919,6 @@ int do_poll(int timeout);
|
|||||||
/* rrfilter.c */
|
/* rrfilter.c */
|
||||||
size_t rrfilter(struct dns_header *header, size_t *plen, int mode);
|
size_t rrfilter(struct dns_header *header, size_t *plen, int mode);
|
||||||
short *rrfilter_desc(int type);
|
short *rrfilter_desc(int type);
|
||||||
int expand_workspace(unsigned char ***wkspc, int *szp, int new);
|
|
||||||
int to_wire(char *name);
|
int to_wire(char *name);
|
||||||
void from_wire(char *name);
|
void from_wire(char *name);
|
||||||
/* modes. */
|
/* modes. */
|
||||||
|
|||||||
+5
-2
@@ -1423,7 +1423,10 @@ static int base32_decode(char *in, unsigned char *out)
|
|||||||
oc |= 1;
|
oc |= 1;
|
||||||
mask = mask >> 1;
|
mask = mask >> 1;
|
||||||
if (((++on) & 7) == 0)
|
if (((++on) & 7) == 0)
|
||||||
*p++ = oc;
|
{
|
||||||
|
*p++ = oc;
|
||||||
|
oc = 0;
|
||||||
|
}
|
||||||
oc = oc << 1;
|
oc = oc << 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1553,7 +1556,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
|
|||||||
{
|
{
|
||||||
unsigned char *salt, *p, *digest;
|
unsigned char *salt, *p, *digest;
|
||||||
int digest_len, i, iterations, salt_len, base32_len, algo = 0;
|
int digest_len, i, iterations, salt_len, base32_len, algo = 0;
|
||||||
struct nettle_hash const *hash;
|
struct nettle_hash const *hash = NULL;
|
||||||
char *closest_encloser, *next_closest, *wildcard;
|
char *closest_encloser, *next_closest, *wildcard;
|
||||||
|
|
||||||
if (nons)
|
if (nons)
|
||||||
|
|||||||
+1
-1
@@ -103,7 +103,7 @@ unsigned char *find_pseudoheader(struct dns_header *header, size_t plen, size_t
|
|||||||
size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit,
|
size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit,
|
||||||
int optno, unsigned char *opt, size_t optlen, int set_do, int replace)
|
int optno, unsigned char *opt, size_t optlen, int set_do, int replace)
|
||||||
{
|
{
|
||||||
unsigned char *lenp, *datap, *p, *udp_len, *buff = NULL;
|
unsigned char *lenp = NULL, *datap = NULL, *p, *udp_len, *buff = NULL;
|
||||||
int rdlen = 0, is_sign, is_last;
|
int rdlen = 0, is_sign, is_last;
|
||||||
unsigned short flags = set_do ? 0x8000 : 0, rcode = 0;
|
unsigned short flags = set_do ? 0x8000 : 0, rcode = 0;
|
||||||
|
|
||||||
|
|||||||
+127
-126
@@ -135,9 +135,9 @@ static void log_query_mysockaddr(unsigned int flags, char *name, union mysockadd
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void server_send(struct server *server, int fd,
|
static void server_send(struct server *server, int fd,
|
||||||
const void *header, size_t plen, int flags)
|
const void *header, size_t plen)
|
||||||
{
|
{
|
||||||
while (retry_send(sendto(fd, header, plen, flags,
|
while (retry_send(sendto(fd, header, plen, 0,
|
||||||
&server->addr.sa,
|
&server->addr.sa,
|
||||||
sa_len(&server->addr))));
|
sa_len(&server->addr))));
|
||||||
}
|
}
|
||||||
@@ -1074,7 +1074,7 @@ static void dnssec_validate(struct frec *forward, struct dns_header *header,
|
|||||||
set_outgoing_mark(orig, fd);
|
set_outgoing_mark(orig, fd);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
server_send(server, fd, header, nn, 0);
|
server_send(server, fd, header, nn);
|
||||||
server->queries++;
|
server->queries++;
|
||||||
#ifdef HAVE_DUMPFILE
|
#ifdef HAVE_DUMPFILE
|
||||||
dump_packet_udp(DUMP_SEC_QUERY, (void *)header, (size_t)nn, NULL, &server->addr, fd);
|
dump_packet_udp(DUMP_SEC_QUERY, (void *)header, (size_t)nn, NULL, &server->addr, fd);
|
||||||
@@ -2018,20 +2018,21 @@ void receive_query(struct listener *listen, time_t now)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Send query in packet, qsize to a server determined by first,last,start and
|
/* Send query in header, qsize to a server determined by first,last,start and
|
||||||
get the reply. return reply size. */
|
get the reply into the buffer passed by outbuff. Return reply size. */
|
||||||
static ssize_t tcp_talk(int first, int last, int start, unsigned char *packet, size_t qsize,
|
static ssize_t tcp_talk(int first, int last, int start, struct dns_header *header, size_t qsize,
|
||||||
int have_mark, unsigned int mark, struct server **servp)
|
struct iovec *recvbuff, int have_mark, unsigned int mark, struct server **servp)
|
||||||
{
|
{
|
||||||
int firstsendto = -1;
|
int firstsendto = -1;
|
||||||
u16 *length = (u16 *)packet;
|
u16 length;
|
||||||
unsigned char *payload = &packet[2];
|
unsigned int rsize = 0;
|
||||||
struct dns_header *header = (struct dns_header *)payload;
|
|
||||||
unsigned int rsize;
|
|
||||||
int class, rclass, type, rtype;
|
int class, rclass, type, rtype;
|
||||||
unsigned char *p;
|
unsigned char *p;
|
||||||
struct blockdata *saved_question;
|
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
|
struct iovec sendio[2];
|
||||||
|
#ifdef MSG_FASTOPEN
|
||||||
|
struct msghdr msg;
|
||||||
|
#endif
|
||||||
|
|
||||||
(void)mark;
|
(void)mark;
|
||||||
(void)have_mark;
|
(void)have_mark;
|
||||||
@@ -2043,9 +2044,11 @@ static ssize_t tcp_talk(int first, int last, int start, unsigned char *packet,
|
|||||||
GETSHORT(type, p);
|
GETSHORT(type, p);
|
||||||
GETSHORT(class, p);
|
GETSHORT(class, p);
|
||||||
|
|
||||||
/* Save question for retry. */
|
length = htons(qsize);
|
||||||
if (!(saved_question = blockdata_alloc((char *)header, (size_t)qsize)))
|
sendio[0].iov_base = &length;
|
||||||
return 0;
|
sendio[0].iov_len = sizeof(length);
|
||||||
|
sendio[1].iov_base = header;
|
||||||
|
sendio[1].iov_len = qsize;
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
@@ -2068,10 +2071,6 @@ static ssize_t tcp_talk(int first, int last, int start, unsigned char *packet,
|
|||||||
*servp = serv = daemon->serverarray[start];
|
*servp = serv = daemon->serverarray[start];
|
||||||
|
|
||||||
retry:
|
retry:
|
||||||
blockdata_retrieve(saved_question, qsize, header);
|
|
||||||
|
|
||||||
*length = htons(qsize);
|
|
||||||
|
|
||||||
if (serv->tcpfd == -1)
|
if (serv->tcpfd == -1)
|
||||||
{
|
{
|
||||||
if ((serv->tcpfd = socket(serv->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
|
if ((serv->tcpfd = socket(serv->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
|
||||||
@@ -2102,9 +2101,16 @@ static ssize_t tcp_talk(int first, int last, int start, unsigned char *packet,
|
|||||||
tv.tv_sec += TCP_TIMEOUT;
|
tv.tv_sec += TCP_TIMEOUT;
|
||||||
setsockopt(serv->tcpfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
|
setsockopt(serv->tcpfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef MSG_FASTOPEN
|
#ifdef MSG_FASTOPEN
|
||||||
server_send(serv, serv->tcpfd, packet, qsize + sizeof(u16), MSG_FASTOPEN);
|
msg.msg_name = &serv->addr.sa;
|
||||||
|
msg.msg_namelen = sa_len(&serv->addr);
|
||||||
|
msg.msg_iov = sendio;
|
||||||
|
msg.msg_iovlen = 2;
|
||||||
|
msg.msg_control = NULL;
|
||||||
|
msg.msg_controllen = 0;
|
||||||
|
msg.msg_flags = 0;
|
||||||
|
|
||||||
|
while (retry_send(sendmsg(serv->tcpfd, &msg, MSG_FASTOPEN)));
|
||||||
|
|
||||||
if (errno == 0)
|
if (errno == 0)
|
||||||
data_sent = 1;
|
data_sent = 1;
|
||||||
@@ -2131,12 +2137,13 @@ static ssize_t tcp_talk(int first, int last, int start, unsigned char *packet,
|
|||||||
serv->flags &= ~SERV_GOT_TCP;
|
serv->flags &= ~SERV_GOT_TCP;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We us the _ONCE veriant of read_write() here because we've set a timeout on the tcp socket
|
/* We use the _ONCE variant 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. */
|
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)) ||
|
if ((!data_sent && !read_writev(serv->tcpfd, sendio, 2, RW_WRITE_ONCE)) ||
|
||||||
!read_write(serv->tcpfd, (unsigned char *)length, sizeof (*length), RW_READ_ONCE) ||
|
!read_write(serv->tcpfd, (unsigned char *)&length, sizeof(length), RW_READ_ONCE) ||
|
||||||
!read_write(serv->tcpfd, payload, (rsize = ntohs(*length)), RW_READ_ONCE))
|
!expand_buf(recvbuff, (rsize = ntohs(length))) ||
|
||||||
{
|
!read_write(serv->tcpfd, recvbuff->iov_base, rsize, RW_READ_ONCE))
|
||||||
|
{
|
||||||
/* We get data then EOF, reopen connection to same server,
|
/* We get data then EOF, reopen connection to same server,
|
||||||
else try next. This avoids DoS from a server which accepts
|
else try next. This avoids DoS from a server which accepts
|
||||||
connections and then closes them. */
|
connections and then closes them. */
|
||||||
@@ -2149,28 +2156,28 @@ static ssize_t tcp_talk(int first, int last, int start, unsigned char *packet,
|
|||||||
else
|
else
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* If the question section of the reply doesn't match the question we sent, then
|
||||||
|
someone might be attempting to insert bogus values into the cache by
|
||||||
|
sending replies containing questions and bogus answers.
|
||||||
|
Try another server, or give up */
|
||||||
|
p = (unsigned char *)(((struct dns_header *)recvbuff->iov_base)+1);
|
||||||
|
if (extract_name(((struct dns_header *)recvbuff->iov_base), rsize, &p, daemon->namebuff, EXTR_NAME_COMPARE, 4) != 1)
|
||||||
|
continue;
|
||||||
|
GETSHORT(rtype, p);
|
||||||
|
GETSHORT(rclass, p);
|
||||||
|
|
||||||
/* If the question section of the reply doesn't match the question we sent, then
|
if (type != rtype || class != rclass)
|
||||||
someone might be attempting to insert bogus values into the cache by
|
continue;
|
||||||
sending replies containing questions and bogus answers.
|
}
|
||||||
Try another server, or give up */
|
|
||||||
p = (unsigned char *)(header+1);
|
|
||||||
if (extract_name(header, rsize, &p, daemon->namebuff, EXTR_NAME_COMPARE, 4) != 1)
|
|
||||||
continue;
|
|
||||||
GETSHORT(rtype, p);
|
|
||||||
GETSHORT(rclass, p);
|
|
||||||
|
|
||||||
if (type != rtype || class != rclass)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
serv->flags |= SERV_GOT_TCP;
|
serv->flags |= SERV_GOT_TCP;
|
||||||
|
|
||||||
*servp = serv;
|
*servp = serv;
|
||||||
blockdata_free(saved_question);
|
|
||||||
return rsize;
|
return rsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
blockdata_free(saved_question);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2182,19 +2189,16 @@ int tcp_from_udp(time_t now, int status, struct dns_header *header, ssize_t *ple
|
|||||||
int class, char *name, struct server *server,
|
int class, char *name, struct server *server,
|
||||||
int *keycount, int *validatecount)
|
int *keycount, int *validatecount)
|
||||||
{
|
{
|
||||||
unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16));
|
|
||||||
struct dns_header *new_header = (struct dns_header *)&packet[2];
|
|
||||||
int start, first, last, new_status;
|
int start, first, last, new_status;
|
||||||
ssize_t n = *plenp;
|
ssize_t n = *plenp;
|
||||||
int log_save = daemon->log_display_id;
|
int log_save = daemon->log_display_id;
|
||||||
|
struct iovec recvbuff;
|
||||||
|
|
||||||
|
recvbuff.iov_len = 0;
|
||||||
|
recvbuff.iov_base = NULL;
|
||||||
|
|
||||||
*plenp = 0;
|
*plenp = 0;
|
||||||
|
|
||||||
if (!packet)
|
|
||||||
return STAT_ABANDONED;
|
|
||||||
|
|
||||||
memcpy(new_header, header, n);
|
|
||||||
|
|
||||||
/* Set TCP flag in logs. */
|
/* Set TCP flag in logs. */
|
||||||
daemon->log_display_id = -daemon->log_display_id;
|
daemon->log_display_id = -daemon->log_display_id;
|
||||||
|
|
||||||
@@ -2212,10 +2216,11 @@ int tcp_from_udp(time_t now, int status, struct dns_header *header, ssize_t *ple
|
|||||||
log_query_mysockaddr(F_NOEXTRA | F_DNSSEC | F_SERVER, name, &server->addr,
|
log_query_mysockaddr(F_NOEXTRA | F_DNSSEC | F_SERVER, name, &server->addr,
|
||||||
STAT_ISEQUAL(status, STAT_NEED_KEY) ? "dnssec-query[DNSKEY]" : "dnssec-query[DS]", 0);
|
STAT_ISEQUAL(status, STAT_NEED_KEY) ? "dnssec-query[DNSKEY]" : "dnssec-query[DS]", 0);
|
||||||
|
|
||||||
if ((n = tcp_talk(first, last, start, packet, n, 0, 0, &server)) == 0)
|
if ((n = tcp_talk(first, last, start, header, n, &recvbuff, 0, 0, &server)) == 0)
|
||||||
new_status = STAT_ABANDONED;
|
new_status = STAT_ABANDONED;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
struct dns_header *new_header = (struct dns_header *)recvbuff.iov_base;
|
||||||
new_status = tcp_key_recurse(now, status, new_header, n, class, daemon->namebuff, daemon->keyname, server, 0, 0, keycount, validatecount);
|
new_status = tcp_key_recurse(now, status, new_header, n, class, daemon->namebuff, daemon->keyname, server, 0, 0, keycount, validatecount);
|
||||||
|
|
||||||
if (STAT_ISEQUAL(status, STAT_OK))
|
if (STAT_ISEQUAL(status, STAT_OK))
|
||||||
@@ -2252,7 +2257,7 @@ int tcp_from_udp(time_t now, int status, struct dns_header *header, ssize_t *ple
|
|||||||
}
|
}
|
||||||
|
|
||||||
daemon->log_display_id = log_save;
|
daemon->log_display_id = log_save;
|
||||||
free(packet);
|
free(recvbuff.iov_base);
|
||||||
return new_status;
|
return new_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2262,8 +2267,11 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
|
|||||||
int have_mark, unsigned int mark, int *keycount, int *validatecount)
|
int have_mark, unsigned int mark, int *keycount, int *validatecount)
|
||||||
{
|
{
|
||||||
int first, last, start, new_status;
|
int first, last, start, new_status;
|
||||||
unsigned char *packet = NULL;
|
struct iovec new_packet;
|
||||||
struct dns_header *new_header = NULL;
|
struct dns_header *query_header = NULL, *new_header;
|
||||||
|
|
||||||
|
new_packet.iov_base = NULL;
|
||||||
|
new_packet.iov_len = 0;
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
@@ -2298,34 +2306,21 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Can't validate because we need a key/DS whose name now in keyname.
|
/* Can't validate because we need a key/DS whose name now in keyname.
|
||||||
Make query for same, and recurse to validate */
|
Make query for same in UDP packet buffer, recurse to validate*/
|
||||||
if (!packet)
|
query_header = (struct dns_header *)daemon->packet;
|
||||||
{
|
daemon->srv_save = NULL;
|
||||||
packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16));
|
|
||||||
new_header = (struct dns_header *)&packet[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!packet)
|
m = dnssec_generate_query(query_header, ((unsigned char *)query_header) + daemon->edns_pktsz, keyname, class, 0,
|
||||||
{
|
|
||||||
new_status = STAT_ABANDONED;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
m = dnssec_generate_query(new_header, ((unsigned char *) new_header) + 65536, keyname, class, 0,
|
|
||||||
STAT_ISEQUAL(new_status, STAT_NEED_KEY) ? T_DNSKEY : T_DS);
|
STAT_ISEQUAL(new_status, STAT_NEED_KEY) ? T_DNSKEY : T_DS);
|
||||||
|
|
||||||
if ((start = dnssec_server(server, keyname, STAT_ISEQUAL(new_status, STAT_NEED_DS), &first, &last)) == -1)
|
if ((start = dnssec_server(server, keyname, STAT_ISEQUAL(new_status, STAT_NEED_DS), &first, &last)) == -1 ||
|
||||||
{
|
(m = tcp_talk(first, last, start, query_header, m, &new_packet, have_mark, mark, &server)) == 0)
|
||||||
new_status = STAT_ABANDONED;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((m = tcp_talk(first, last, start, packet, m, have_mark, mark, &server)) == 0)
|
|
||||||
{
|
{
|
||||||
new_status = STAT_ABANDONED;
|
new_status = STAT_ABANDONED;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
new_header = new_packet.iov_base;
|
||||||
log_save = daemon->log_display_id;
|
log_save = daemon->log_display_id;
|
||||||
daemon->log_display_id = -(++daemon->log_id);
|
daemon->log_display_id = -(++daemon->log_id);
|
||||||
|
|
||||||
@@ -2342,8 +2337,7 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (packet)
|
free(new_packet.iov_base);
|
||||||
free(packet);
|
|
||||||
|
|
||||||
return new_status;
|
return new_status;
|
||||||
}
|
}
|
||||||
@@ -2353,11 +2347,11 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
|
|||||||
/* The daemon forks before calling this: it should deal with one connection,
|
/* The daemon forks before calling this: it should deal with one connection,
|
||||||
blocking as necessary, and then return. Note, need to be a bit careful
|
blocking as necessary, and then return. Note, need to be a bit careful
|
||||||
about resources for debug mode, when the fork is suppressed: that's
|
about resources for debug mode, when the fork is suppressed: that's
|
||||||
done by the caller. */
|
done by the caller, which also frees bigbuff. */
|
||||||
unsigned char *tcp_request(int confd, time_t now,
|
void tcp_request(int confd, time_t now, struct iovec *bigbuff,
|
||||||
union mysockaddr *local_addr, struct in_addr netmask, int auth_dns)
|
union mysockaddr *local_addr, struct in_addr netmask, int auth_dns)
|
||||||
{
|
{
|
||||||
size_t size = 0, saved_size = 0;
|
size_t size = 0;
|
||||||
int norebind = 0;
|
int norebind = 0;
|
||||||
#ifdef HAVE_CONNTRACK
|
#ifdef HAVE_CONNTRACK
|
||||||
int allowed = 1;
|
int allowed = 1;
|
||||||
@@ -2366,16 +2360,10 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
int local_auth = 0;
|
int local_auth = 0;
|
||||||
#endif
|
#endif
|
||||||
int checking_disabled, do_bit = 0, ad_reqd = 0, have_pseudoheader = 0;
|
int checking_disabled, do_bit = 0, ad_reqd = 0, have_pseudoheader = 0;
|
||||||
struct blockdata *saved_question = NULL;
|
|
||||||
unsigned short qtype;
|
unsigned short qtype;
|
||||||
unsigned int gotname = 0;
|
unsigned int gotname = 0;
|
||||||
/* Max TCP packet + slop + size */
|
u16 tcp_len, out_len;
|
||||||
unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16));
|
struct dns_header *header, *out_header;
|
||||||
unsigned char *payload = &packet[2];
|
|
||||||
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;
|
|
||||||
struct server *serv;
|
struct server *serv;
|
||||||
struct in_addr dst_addr_4;
|
struct in_addr dst_addr_4;
|
||||||
union mysockaddr peer_addr;
|
union mysockaddr peer_addr;
|
||||||
@@ -2385,9 +2373,13 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
unsigned int mark = 0;
|
unsigned int mark = 0;
|
||||||
int have_mark = 0;
|
int have_mark = 0;
|
||||||
int first, last, filtered, do_stale = 0;
|
int first, last, filtered, do_stale = 0;
|
||||||
|
struct iovec out_iov[2];
|
||||||
|
|
||||||
if (!packet || getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
|
bigbuff->iov_base = NULL;
|
||||||
return packet;
|
bigbuff->iov_len = 0;
|
||||||
|
|
||||||
|
if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
#ifdef HAVE_CONNTRACK
|
#ifdef HAVE_CONNTRACK
|
||||||
/* Get connection mark of incoming query to set on outgoing connections. */
|
/* Get connection mark of incoming query to set on outgoing connections. */
|
||||||
@@ -2431,7 +2423,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
{
|
{
|
||||||
prettyprint_addr(&peer_addr, daemon->addrbuff);
|
prettyprint_addr(&peer_addr, daemon->addrbuff);
|
||||||
my_syslog(LOG_WARNING, _("ignoring query from non-local network %s"), daemon->addrbuff);
|
my_syslog(LOG_WARNING, _("ignoring query from non-local network %s"), daemon->addrbuff);
|
||||||
return packet;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2449,18 +2441,26 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
if (query_count >= TCP_MAX_QUERIES)
|
if (query_count >= TCP_MAX_QUERIES)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
/* Now get the query into the normal UDP packet buffer.
|
||||||
|
Ignore queries long than this. If we're answering locally,
|
||||||
|
copy the query into the output buffer, but for forwarding, tcp_talk()
|
||||||
|
wants the query in a a different buffer from the reply.
|
||||||
|
Note that we overwrote any saved UDP query - this onlt matters in debug mode. */
|
||||||
|
daemon->srv_save = NULL;
|
||||||
if (!read_write(confd, (unsigned char *)&tcp_len, sizeof(tcp_len), RW_READ) ||
|
if (!read_write(confd, (unsigned char *)&tcp_len, sizeof(tcp_len), RW_READ) ||
|
||||||
!(size = ntohs(tcp_len)) ||
|
!(size = ntohs(tcp_len)) || size > (size_t)daemon->packet_buff_sz ||
|
||||||
!read_write(confd, payload, size, RW_READ))
|
!read_write(confd, (unsigned char *)daemon->packet, size, RW_READ))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (size < (int)sizeof(struct dns_header))
|
if (size < (int)sizeof(struct dns_header))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Clear buffer beyond request to avoid risk of
|
/* Make sure we have a buffer big enough for the largest answer. */
|
||||||
information disclosure. */
|
expand_buf(bigbuff, 65536 + MAXDNAME + RRFIXEDSZ);
|
||||||
memset(payload + size, 0, 65536 - size);
|
out_header = bigbuff->iov_base;
|
||||||
|
|
||||||
|
/* header == query */
|
||||||
|
header = (struct dns_header *)daemon->packet;
|
||||||
query_count++;
|
query_count++;
|
||||||
|
|
||||||
/* log_query gets called indirectly all over the place, so
|
/* log_query gets called indirectly all over the place, so
|
||||||
@@ -2479,9 +2479,6 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
ede = EDE_INVALID_DATA;
|
ede = EDE_INVALID_DATA;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (saved_question)
|
|
||||||
blockdata_free(saved_question);
|
|
||||||
|
|
||||||
do_bit = 0;
|
do_bit = 0;
|
||||||
|
|
||||||
if (find_pseudoheader(header, (size_t)size, NULL, &pheader, NULL, NULL))
|
if (find_pseudoheader(header, (size_t)size, NULL, &pheader, NULL, NULL))
|
||||||
@@ -2496,9 +2493,12 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
do_bit = 1; /* do bit */
|
do_bit = 1; /* do bit */
|
||||||
}
|
}
|
||||||
|
|
||||||
size = add_edns0_config(header, size, ((unsigned char *) header) + 65536, &peer_addr, now, &cacheable);
|
size = add_edns0_config(header, size, ((unsigned char *) header) + daemon->edns_pktsz, &peer_addr, now, &cacheable);
|
||||||
saved_question = blockdata_alloc((char *)header, (size_t)size);
|
|
||||||
saved_size = size;
|
/* Clear buffer to avoid risk of information disclosure. */
|
||||||
|
memset(bigbuff->iov_base, 0, bigbuff->iov_len);
|
||||||
|
/* Copy query into output buffer for local answering */
|
||||||
|
memcpy(out_header, header, size);
|
||||||
|
|
||||||
log_query_mysockaddr((auth_dns ? F_NOERR | F_AUTH : 0) | F_QUERY | F_FORWARD, daemon->namebuff,
|
log_query_mysockaddr((auth_dns ? F_NOERR | F_AUTH : 0) | F_QUERY | F_FORWARD, daemon->namebuff,
|
||||||
&peer_addr, NULL, qtype);
|
&peer_addr, NULL, qtype);
|
||||||
@@ -2557,10 +2557,10 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_AUTH
|
#ifdef HAVE_AUTH
|
||||||
else if (auth_dns)
|
else if (auth_dns)
|
||||||
m = answer_auth(header, ((char *) header) + 65536, (size_t)size, now, &peer_addr, local_auth);
|
m = answer_auth(out_header, ((char *) out_header) + 65536, (size_t)size, now, &peer_addr, local_auth);
|
||||||
#endif
|
#endif
|
||||||
else
|
else
|
||||||
m = answer_request(header, ((char *) header) + 65536, (size_t)size,
|
m = answer_request(out_header, ((char *) out_header) + 65536, (size_t)size,
|
||||||
dst_addr_4, netmask, now, ad_reqd, do_bit, !cacheable, &stale, &filtered);
|
dst_addr_4, netmask, now, ad_reqd, do_bit, !cacheable, &stale, &filtered);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2568,15 +2568,12 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
/* Do this by steam now we're not in the select() loop */
|
/* Do this by steam now we're not in the select() loop */
|
||||||
check_log_writer(1);
|
check_log_writer(1);
|
||||||
|
|
||||||
if (m == 0 && ede == EDE_UNSET && saved_question)
|
if (m == 0 && ede == EDE_UNSET)
|
||||||
{
|
{
|
||||||
struct server *master;
|
struct server *master;
|
||||||
int start;
|
int start;
|
||||||
int no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
|
int no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
|
||||||
|
|
||||||
blockdata_retrieve(saved_question, (size_t)saved_size, header);
|
|
||||||
size = saved_size;
|
|
||||||
|
|
||||||
/* save state of "cd" flag in query */
|
/* save state of "cd" flag in query */
|
||||||
checking_disabled = header->hb4 & HB4_CD;
|
checking_disabled = header->hb4 & HB4_CD;
|
||||||
|
|
||||||
@@ -2605,7 +2602,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
#ifdef HAVE_DNSSEC
|
#ifdef HAVE_DNSSEC
|
||||||
if (option_bool(OPT_DNSSEC_VALID))
|
if (option_bool(OPT_DNSSEC_VALID))
|
||||||
{
|
{
|
||||||
size = add_do_bit(header, size, ((unsigned char *) header) + 65536);
|
size = add_do_bit(header, size, ((unsigned char *) header) + daemon->edns_pktsz);
|
||||||
|
|
||||||
/* For debugging, set Checking Disabled, otherwise, have the upstream check too,
|
/* For debugging, set Checking Disabled, otherwise, have the upstream check too,
|
||||||
this allows it to select auth servers when one is returning bad data. */
|
this allows it to select auth servers when one is returning bad data. */
|
||||||
@@ -2615,12 +2612,14 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Loop round available servers until we succeed in connecting to one. */
|
/* Loop round available servers until we succeed in connecting to one. */
|
||||||
if ((m = tcp_talk(first, last, start, packet, size, have_mark, mark, &serv)) == 0)
|
if ((m = tcp_talk(first, last, start, header, size, bigbuff, have_mark, mark, &serv)) == 0)
|
||||||
ede = EDE_NETERR;
|
ede = EDE_NETERR;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
/* just in case tcp_talk() expanded buffer - should never happen */
|
||||||
|
out_header = bigbuff->iov_base;
|
||||||
/* get query name again for logging - may have been overwritten */
|
/* get query name again for logging - may have been overwritten */
|
||||||
if (!extract_name(header, (unsigned int)size, NULL, daemon->namebuff, EXTR_NAME_EXTRACT, 0))
|
if (!extract_name(out_header, (unsigned int)size, NULL, daemon->namebuff, EXTR_NAME_EXTRACT, 0))
|
||||||
strcpy(daemon->namebuff, "query");
|
strcpy(daemon->namebuff, "query");
|
||||||
log_query_mysockaddr(F_SERVER | F_FORWARD, daemon->namebuff, &serv->addr, NULL, 0);
|
log_query_mysockaddr(F_SERVER | F_FORWARD, daemon->namebuff, &serv->addr, NULL, 0);
|
||||||
|
|
||||||
@@ -2636,7 +2635,8 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
{
|
{
|
||||||
int keycount = daemon->limit[LIMIT_WORK]; /* Limit to number of DNSSEC questions, to catch loops and avoid filling cache. */
|
int keycount = daemon->limit[LIMIT_WORK]; /* Limit to number of DNSSEC questions, to catch loops and avoid filling cache. */
|
||||||
int validatecount = daemon->limit[LIMIT_CRYPTO];
|
int validatecount = daemon->limit[LIMIT_CRYPTO];
|
||||||
int status = tcp_key_recurse(now, STAT_OK, header, m, 0, daemon->namebuff, daemon->keyname,
|
/* tcp_key_recurse() may overwrite packetbuf, and thuse *header is now invalid */
|
||||||
|
int status = tcp_key_recurse(now, STAT_OK, out_header, m, 0, daemon->namebuff, daemon->keyname,
|
||||||
serv, have_mark, mark, &keycount, &validatecount);
|
serv, have_mark, mark, &keycount, &validatecount);
|
||||||
char *result, *domain = "result";
|
char *result, *domain = "result";
|
||||||
|
|
||||||
@@ -2662,7 +2662,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
no_cache_dnssec = 1;
|
no_cache_dnssec = 1;
|
||||||
bogusanswer = 1;
|
bogusanswer = 1;
|
||||||
|
|
||||||
if (extract_name(header, m, NULL, daemon->namebuff, EXTR_NAME_EXTRACT, 0))
|
if (extract_name(out_header, m, NULL, daemon->namebuff, EXTR_NAME_EXTRACT, 0))
|
||||||
domain = daemon->namebuff;
|
domain = daemon->namebuff;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2686,18 +2686,18 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
|
|
||||||
/* restore CD bit to the value in the query */
|
/* restore CD bit to the value in the query */
|
||||||
if (checking_disabled)
|
if (checking_disabled)
|
||||||
header->hb4 |= HB4_CD;
|
out_header->hb4 |= HB4_CD;
|
||||||
else
|
else
|
||||||
header->hb4 &= ~HB4_CD;
|
out_header->hb4 &= ~HB4_CD;
|
||||||
|
|
||||||
/* Never cache answers which are contingent on the source or MAC address EDSN0 option,
|
/* Never cache answers which are contingent on the source or MAC address EDSN0 option,
|
||||||
since the cache is ignorant of such things. */
|
since the cache is ignorant of such things. */
|
||||||
if (!cacheable)
|
if (!cacheable)
|
||||||
no_cache_dnssec = 1;
|
no_cache_dnssec = 1;
|
||||||
|
|
||||||
m = process_reply(header, now, serv, (unsigned int)m,
|
m = process_reply(out_header, now, serv, (unsigned int)m,
|
||||||
option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec, cache_secure, bogusanswer,
|
option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec, cache_secure, bogusanswer,
|
||||||
ad_reqd, do_bit, !have_pseudoheader, &peer_addr, ((unsigned char *)header) + 65536, ede);
|
ad_reqd, do_bit, !have_pseudoheader, &peer_addr, ((unsigned char *)out_header) + 65536, ede);
|
||||||
|
|
||||||
/* process_reply() adds pheader itself */
|
/* process_reply() adds pheader itself */
|
||||||
have_pseudoheader = 0;
|
have_pseudoheader = 0;
|
||||||
@@ -2712,8 +2712,8 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
/* In case of local answer or no connections made. */
|
/* In case of local answer or no connections made. */
|
||||||
if (m == 0)
|
if (m == 0)
|
||||||
{
|
{
|
||||||
if (!(m = make_local_answer(flags, gotname, size, header, daemon->namebuff,
|
if (!(m = make_local_answer(flags, gotname, size, out_header, daemon->namebuff,
|
||||||
((char *) header) + 65536, first, last, ede)))
|
((char *) out_header) + 65536, first, last, ede)))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if (ede == EDE_UNSET)
|
else if (ede == EDE_UNSET)
|
||||||
@@ -2729,15 +2729,13 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
u16 swap = htons((u16)ede);
|
u16 swap = htons((u16)ede);
|
||||||
|
|
||||||
if (ede != EDE_UNSET)
|
if (ede != EDE_UNSET)
|
||||||
m = add_pseudoheader(header, m, ((unsigned char *) header) + 65536, EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 0);
|
m = add_pseudoheader(out_header, m, ((unsigned char *) out_header) + 65536, EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 0);
|
||||||
else
|
else
|
||||||
m = add_pseudoheader(header, m, ((unsigned char *) header) + 65536, 0, NULL, 0, do_bit, 0);
|
m = add_pseudoheader(out_header, m, ((unsigned char *) out_header) + 65536, 0, NULL, 0, do_bit, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
check_log_writer(1);
|
check_log_writer(1);
|
||||||
|
|
||||||
*length = htons(m);
|
|
||||||
|
|
||||||
#if defined(HAVE_CONNTRACK) && defined(HAVE_UBUS)
|
#if defined(HAVE_CONNTRACK) && defined(HAVE_UBUS)
|
||||||
#ifdef HAVE_AUTH
|
#ifdef HAVE_AUTH
|
||||||
if (!auth_dns || local_auth)
|
if (!auth_dns || local_auth)
|
||||||
@@ -2746,7 +2744,13 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
report_addresses(header, m, mark);
|
report_addresses(header, m, mark);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!read_write(confd, packet, m + sizeof(u16), RW_WRITE))
|
/* use scatter-gather IO so that length doesn't end up in separate packet. */
|
||||||
|
out_len = htons(m);
|
||||||
|
out_iov[0].iov_len = sizeof(out_len);
|
||||||
|
out_iov[0].iov_base = &out_len;
|
||||||
|
out_iov[1].iov_len = m;
|
||||||
|
out_iov[1].iov_base = bigbuff->iov_base;
|
||||||
|
if (!read_writev(confd, out_iov, 2, RW_WRITE))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* If we answered with stale data, this process will now try and get fresh data into
|
/* If we answered with stale data, this process will now try and get fresh data into
|
||||||
@@ -2763,17 +2767,14 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we ran once to get fresh data, confd is already closed. */
|
/* If we ran once to get fresh data, confd is already closed. */
|
||||||
if (!do_stale)
|
if (!do_stale)
|
||||||
{
|
{
|
||||||
shutdown(confd, SHUT_RDWR);
|
shutdown(confd, SHUT_RDWR);
|
||||||
close(confd);
|
close(confd);
|
||||||
}
|
}
|
||||||
|
|
||||||
blockdata_free(saved_question);
|
|
||||||
check_log_writer(1);
|
check_log_writer(1);
|
||||||
|
|
||||||
return packet;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* return a UDP socket bound to a random port, have to cope with straying into
|
/* return a UDP socket bound to a random port, have to cope with straying into
|
||||||
@@ -3274,7 +3275,7 @@ void resend_query(void)
|
|||||||
{
|
{
|
||||||
if (daemon->srv_save)
|
if (daemon->srv_save)
|
||||||
server_send(daemon->srv_save, daemon->fd_save,
|
server_send(daemon->srv_save, daemon->fd_save,
|
||||||
daemon->packet, daemon->packet_len, 0);
|
daemon->packet, daemon->packet_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* A server record is going away, remove references to it */
|
/* A server record is going away, remove references to it */
|
||||||
|
|||||||
+9
-3
@@ -23,6 +23,9 @@ static volatile int mem_recover = 0;
|
|||||||
static jmp_buf mem_jmp;
|
static jmp_buf mem_jmp;
|
||||||
static int one_file(char *file, int hard_opt);
|
static int one_file(char *file, int hard_opt);
|
||||||
|
|
||||||
|
static void *opt_malloc_real(const char *func, unsigned int line, size_t size);
|
||||||
|
#define opt_malloc(x) opt_malloc_real(__func__, __LINE__, (x))
|
||||||
|
|
||||||
/* Solaris headers don't have facility names. */
|
/* Solaris headers don't have facility names. */
|
||||||
#ifdef HAVE_SOLARIS_NETWORK
|
#ifdef HAVE_SOLARIS_NETWORK
|
||||||
static const struct {
|
static const struct {
|
||||||
@@ -197,6 +200,7 @@ struct myoption {
|
|||||||
#define LOPT_DO_ENCODE 388
|
#define LOPT_DO_ENCODE 388
|
||||||
#define LOPT_LEASEQUERY 389
|
#define LOPT_LEASEQUERY 389
|
||||||
#define LOPT_SPLIT_RELAY 390
|
#define LOPT_SPLIT_RELAY 390
|
||||||
|
#define LOPT_LOG_MALLOC 391
|
||||||
|
|
||||||
#ifdef HAVE_GETOPT_LONG
|
#ifdef HAVE_GETOPT_LONG
|
||||||
static const struct option opts[] =
|
static const struct option opts[] =
|
||||||
@@ -398,6 +402,7 @@ static const struct myoption opts[] =
|
|||||||
{ "no-ident", 0, 0, LOPT_NO_IDENT },
|
{ "no-ident", 0, 0, LOPT_NO_IDENT },
|
||||||
{ "max-tcp-connections", 1, 0, LOPT_MAX_PROCS },
|
{ "max-tcp-connections", 1, 0, LOPT_MAX_PROCS },
|
||||||
{ "leasequery", 2, 0, LOPT_LEASEQUERY },
|
{ "leasequery", 2, 0, LOPT_LEASEQUERY },
|
||||||
|
{ "log-malloc", 0, 0, LOPT_LOG_MALLOC },
|
||||||
{ NULL, 0, 0, 0 }
|
{ NULL, 0, 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -606,6 +611,7 @@ static struct {
|
|||||||
{ LOPT_NO_IDENT, OPT_NO_IDENT, NULL, gettext_noop("Do not add CHAOS TXT records."), NULL },
|
{ LOPT_NO_IDENT, OPT_NO_IDENT, NULL, gettext_noop("Do not add CHAOS TXT records."), NULL },
|
||||||
{ LOPT_CACHE_RR, ARG_DUP, "<RR-type>", gettext_noop("Cache this DNS resource record type."), NULL },
|
{ LOPT_CACHE_RR, ARG_DUP, "<RR-type>", gettext_noop("Cache this DNS resource record type."), NULL },
|
||||||
{ LOPT_MAX_PROCS, ARG_ONE, "<integer>", gettext_noop("Maximum number of concurrent tcp connections."), NULL },
|
{ LOPT_MAX_PROCS, ARG_ONE, "<integer>", gettext_noop("Maximum number of concurrent tcp connections."), NULL },
|
||||||
|
{ LOPT_LOG_MALLOC, OPT_LOG_MALLOC, NULL, gettext_noop("Log memory allocation for debugging."), NULL },
|
||||||
{ 0, 0, NULL, NULL, NULL }
|
{ 0, 0, NULL, NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -652,13 +658,13 @@ static void unhide_metas(char *cp)
|
|||||||
*cp = unhide_meta(*cp);
|
*cp = unhide_meta(*cp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *opt_malloc(size_t size)
|
static void *opt_malloc_real(const char *func, unsigned int line, size_t size)
|
||||||
{
|
{
|
||||||
void *ret;
|
void *ret;
|
||||||
|
|
||||||
if (mem_recover)
|
if (mem_recover)
|
||||||
{
|
{
|
||||||
ret = whine_malloc(size);
|
ret = whine_malloc_real(func, line, size);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
longjmp(mem_jmp, 1);
|
longjmp(mem_jmp, 1);
|
||||||
}
|
}
|
||||||
@@ -5731,7 +5737,7 @@ struct hostsfile *expand_filelist(struct hostsfile *list)
|
|||||||
struct dirent **namelist;
|
struct dirent **namelist;
|
||||||
|
|
||||||
/* find largest used index */
|
/* find largest used index */
|
||||||
for (i = SRC_AH, ah = list; ah; ah = ah->next)
|
for (last = NULL, i = SRC_AH, ah = list; ah; ah = ah->next)
|
||||||
{
|
{
|
||||||
last = ah;
|
last = ah;
|
||||||
|
|
||||||
|
|||||||
+21
-39
@@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
struct state {
|
struct state {
|
||||||
unsigned char *clid;
|
unsigned char *clid;
|
||||||
int multicast_dest, clid_len, ia_type, interface, hostname_auth, lease_allocate;
|
int clid_len, ia_type, interface, hostname_auth, lease_allocate;
|
||||||
char *client_hostname, *hostname, *domain, *send_domain;
|
char *client_hostname, *hostname, *domain, *send_domain;
|
||||||
struct dhcp_context *context;
|
struct dhcp_context *context;
|
||||||
struct in6_addr *link_address, *fallback, *ll_addr, *ula_addr;
|
struct in6_addr *link_address, *fallback, *ll_addr, *ula_addr;
|
||||||
@@ -34,8 +34,8 @@ struct state {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static int dhcp6_maybe_relay(struct state *state, unsigned char *inbuff, size_t sz,
|
static int dhcp6_maybe_relay(struct state *state, unsigned char *inbuff, size_t sz,
|
||||||
struct in6_addr *client_addr, int is_unicast, time_t now);
|
struct in6_addr *client_addr, time_t now);
|
||||||
static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbuff, size_t sz, int is_unicast, time_t now);
|
static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbuff, size_t sz, time_t now);
|
||||||
static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_opts);
|
static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_opts);
|
||||||
static void log6_packet(struct state *state, char *type, struct in6_addr *addr, char *string);
|
static void log6_packet(struct state *state, char *type, struct in6_addr *addr, char *string);
|
||||||
static void log6_quiet(struct state *state, char *type, struct in6_addr *addr, char *string);
|
static void log6_quiet(struct state *state, char *type, struct in6_addr *addr, char *string);
|
||||||
@@ -81,13 +81,16 @@ unsigned short dhcp6_reply(struct dhcp_context *context, int multicast_dest, int
|
|||||||
|
|
||||||
msg_type = *((unsigned char *)daemon->dhcp_packet.iov_base);
|
msg_type = *((unsigned char *)daemon->dhcp_packet.iov_base);
|
||||||
|
|
||||||
|
/* request from a client must be multicast RFC-9915 section 16 */
|
||||||
|
if (msg_type != DHCP6RELAYFORW && !multicast_dest)
|
||||||
|
return 0;
|
||||||
|
|
||||||
/* Mark these so we only match each at most once, to avoid tangled linked lists */
|
/* Mark these so we only match each at most once, to avoid tangled linked lists */
|
||||||
for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
|
for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
|
||||||
vendor->netid.next = &vendor->netid;
|
vendor->netid.next = &vendor->netid;
|
||||||
|
|
||||||
reset_counter();
|
reset_counter();
|
||||||
state.context = context;
|
state.context = context;
|
||||||
state.multicast_dest = multicast_dest;
|
|
||||||
state.interface = interface;
|
state.interface = interface;
|
||||||
state.iface_name = iface_name;
|
state.iface_name = iface_name;
|
||||||
state.fallback = fallback;
|
state.fallback = fallback;
|
||||||
@@ -97,8 +100,7 @@ unsigned short dhcp6_reply(struct dhcp_context *context, int multicast_dest, int
|
|||||||
state.tags = NULL;
|
state.tags = NULL;
|
||||||
state.link_address = NULL;
|
state.link_address = NULL;
|
||||||
|
|
||||||
if (dhcp6_maybe_relay(&state, daemon->dhcp_packet.iov_base, sz, client_addr,
|
if (dhcp6_maybe_relay(&state, daemon->dhcp_packet.iov_base, sz, client_addr, now))
|
||||||
IN6_IS_ADDR_MULTICAST(client_addr), now))
|
|
||||||
return msg_type == DHCP6RELAYFORW ? DHCPV6_SERVER_PORT : DHCPV6_CLIENT_PORT;
|
return msg_type == DHCP6RELAYFORW ? DHCPV6_SERVER_PORT : DHCPV6_CLIENT_PORT;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -106,7 +108,7 @@ unsigned short dhcp6_reply(struct dhcp_context *context, int multicast_dest, int
|
|||||||
|
|
||||||
/* This cost me blood to write, it will probably cost you blood to understand - srk. */
|
/* This cost me blood to write, it will probably cost you blood to understand - srk. */
|
||||||
static int dhcp6_maybe_relay(struct state *state, unsigned char *inbuff, size_t sz,
|
static int dhcp6_maybe_relay(struct state *state, unsigned char *inbuff, size_t sz,
|
||||||
struct in6_addr *client_addr, int is_unicast, time_t now)
|
struct in6_addr *client_addr, time_t now)
|
||||||
{
|
{
|
||||||
uint8_t *end = inbuff + sz;
|
uint8_t *end = inbuff + sz;
|
||||||
uint8_t *opts = inbuff + 34;
|
uint8_t *opts = inbuff + 34;
|
||||||
@@ -184,7 +186,7 @@ static int dhcp6_maybe_relay(struct state *state, unsigned char *inbuff, size_t
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return dhcp6_no_relay(state, msg_type, inbuff, sz, is_unicast, now);
|
return dhcp6_no_relay(state, msg_type, inbuff, sz, now);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* must have at least msg_type+hopcount+link_address+peer_address+minimal size option
|
/* must have at least msg_type+hopcount+link_address+peer_address+minimal size option
|
||||||
@@ -250,9 +252,7 @@ static int dhcp6_maybe_relay(struct state *state, unsigned char *inbuff, size_t
|
|||||||
/* RFC6221 para 4 */
|
/* RFC6221 para 4 */
|
||||||
if (!IN6_IS_ADDR_UNSPECIFIED(&align))
|
if (!IN6_IS_ADDR_UNSPECIFIED(&align))
|
||||||
state->link_address = &align;
|
state->link_address = &align;
|
||||||
/* zero is_unicast since that is now known to refer to the
|
if (!dhcp6_maybe_relay(state, opt6_ptr(opt, 0), opt6_len(opt), client_addr, now))
|
||||||
relayed packet, not the original sent by the client */
|
|
||||||
if (!dhcp6_maybe_relay(state, opt6_ptr(opt, 0), opt6_len(opt), client_addr, 0, now))
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -264,7 +264,7 @@ static int dhcp6_maybe_relay(struct state *state, unsigned char *inbuff, size_t
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbuff, size_t sz, int is_unicast, time_t now)
|
static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbuff, size_t sz, time_t now)
|
||||||
{
|
{
|
||||||
void *opt;
|
void *opt;
|
||||||
int i, o, o1, start_opts, start_msg;
|
int i, o, o1, start_opts, start_msg;
|
||||||
@@ -340,22 +340,17 @@ static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbu
|
|||||||
|
|
||||||
opt = opt6_find(state->packet_options, state->end, OPTION6_SERVER_ID, 1);
|
opt = opt6_find(state->packet_options, state->end, OPTION6_SERVER_ID, 1);
|
||||||
|
|
||||||
if (msg_type == DHCP6SOLICIT || msg_type == DHCP6CONFIRM || msg_type == DHCP6REBIND || msg_type == DHCP6IREQ)
|
if (msg_type == DHCP6SOLICIT || msg_type == DHCP6CONFIRM || msg_type == DHCP6REBIND)
|
||||||
{
|
{
|
||||||
/* Above message types must be multicast 3315 Section 15. */
|
/* SOLICIT, CONFIRM and REBIND messages MUST NOT have a server-id. 3315 para 15.x */
|
||||||
if (!state->multicast_dest)
|
if (opt)
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
/* server-id must match except for SOLICIT, CONFIRM and REBIND messages, which MUST NOT
|
else if (msg_type == DHCP6IREQ)
|
||||||
have a server-id. 3315 para 15.x */
|
{
|
||||||
if (msg_type == DHCP6IREQ)
|
/* If server-id provided in IREQ, it must match. */
|
||||||
{
|
if (opt && (opt6_len(opt) != daemon->duid_len ||
|
||||||
/* If server-id provided in IREQ, it must match. */
|
memcmp(opt6_ptr(opt, 0), daemon->duid, daemon->duid_len) != 0))
|
||||||
if (opt && (opt6_len(opt) != daemon->duid_len ||
|
|
||||||
memcmp(opt6_ptr(opt, 0), daemon->duid, daemon->duid_len) != 0))
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else if (opt)
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -370,18 +365,6 @@ static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbu
|
|||||||
put_opt6(daemon->duid, daemon->duid_len);
|
put_opt6(daemon->duid, daemon->duid_len);
|
||||||
end_opt6(o);
|
end_opt6(o);
|
||||||
|
|
||||||
if (is_unicast &&
|
|
||||||
(msg_type == DHCP6REQUEST || msg_type == DHCP6RENEW || msg_type == DHCP6RELEASE || msg_type == DHCP6DECLINE))
|
|
||||||
|
|
||||||
{
|
|
||||||
outmsgtype = DHCP6REPLY;
|
|
||||||
o1 = new_opt6(OPTION6_STATUS_CODE);
|
|
||||||
put_opt6_short(DHCP6USEMULTI);
|
|
||||||
put_opt6_string("Use multicast");
|
|
||||||
end_opt6(o1);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* match vendor and user class options */
|
/* match vendor and user class options */
|
||||||
for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
|
for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
|
||||||
{
|
{
|
||||||
@@ -1304,7 +1287,6 @@ static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbu
|
|||||||
|
|
||||||
log_tags(tagif, state->xid);
|
log_tags(tagif, state->xid);
|
||||||
|
|
||||||
done:
|
|
||||||
/* Fill in the message type. Note that we store the offset,
|
/* Fill in the message type. Note that we store the offset,
|
||||||
not a direct pointer, since the packet memory may have been
|
not a direct pointer, since the packet memory may have been
|
||||||
reallocated. */
|
reallocated. */
|
||||||
|
|||||||
@@ -337,27 +337,6 @@ short *rrfilter_desc(int type)
|
|||||||
return p+1;
|
return p+1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int expand_workspace(unsigned char ***wkspc, int *szp, int new)
|
|
||||||
{
|
|
||||||
unsigned char **p;
|
|
||||||
int old = *szp;
|
|
||||||
|
|
||||||
if (old >= new+1)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
new += 5;
|
|
||||||
|
|
||||||
if (!(p = whine_realloc(*wkspc, new * sizeof(unsigned char *))))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
memset(p+old, 0, new-old);
|
|
||||||
|
|
||||||
*wkspc = p;
|
|
||||||
*szp = new;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Convert from presentation format to wire format, in place.
|
/* Convert from presentation format to wire format, in place.
|
||||||
Also map UC -> LC.
|
Also map UC -> LC.
|
||||||
Note that using extract_name to get presentation format
|
Note that using extract_name to get presentation format
|
||||||
|
|||||||
+120
-65
@@ -341,26 +341,6 @@ void safe_pipe(int *fd, int read_noblock)
|
|||||||
die(_("cannot create pipe: %s"), NULL, EC_MISC);
|
die(_("cannot create pipe: %s"), NULL, EC_MISC);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *whine_malloc(size_t size)
|
|
||||||
{
|
|
||||||
void *ret = calloc(1, size);
|
|
||||||
|
|
||||||
if (!ret)
|
|
||||||
my_syslog(LOG_ERR, _("failed to allocate %d bytes"), (int) size);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *whine_realloc(void *ptr, size_t size)
|
|
||||||
{
|
|
||||||
void *ret = realloc(ptr, size);
|
|
||||||
|
|
||||||
if (!ret)
|
|
||||||
my_syslog(LOG_ERR, _("failed to reallocate %d bytes"), (int) size);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int sockaddr_isequal(const union mysockaddr *s1, const union mysockaddr *s2)
|
int sockaddr_isequal(const union mysockaddr *s1, const union mysockaddr *s2)
|
||||||
{
|
{
|
||||||
if (s1->sa.sa_family == s2->sa.sa_family)
|
if (s1->sa.sa_family == s2->sa.sa_family)
|
||||||
@@ -692,32 +672,6 @@ int memcmp_masked(unsigned char *a, unsigned char *b, int len, unsigned int mask
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* _note_ may copy buffer */
|
|
||||||
int expand_buf(struct iovec *iov, size_t size)
|
|
||||||
{
|
|
||||||
void *new;
|
|
||||||
|
|
||||||
if (size <= (size_t)iov->iov_len)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
if (!(new = whine_malloc(size)))
|
|
||||||
{
|
|
||||||
errno = ENOMEM;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (iov->iov_base)
|
|
||||||
{
|
|
||||||
memcpy(new, iov->iov_base, iov->iov_len);
|
|
||||||
free(iov->iov_base);
|
|
||||||
}
|
|
||||||
|
|
||||||
iov->iov_base = new;
|
|
||||||
iov->iov_len = size;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *print_mac(char *buff, unsigned char *mac, int len)
|
char *print_mac(char *buff, unsigned char *mac, int len)
|
||||||
{
|
{
|
||||||
char *p = buff;
|
char *p = buff;
|
||||||
@@ -777,43 +731,60 @@ int retry_send(ssize_t rc)
|
|||||||
"once" fails on EAGAIN, as this a timeout.
|
"once" fails on EAGAIN, as this a timeout.
|
||||||
This indicates a timeout of a TCP socket.
|
This indicates a timeout of a TCP socket.
|
||||||
*/
|
*/
|
||||||
int read_write(int fd, unsigned char *packet, int size, int rw)
|
int read_writev(int fd, struct iovec *iov, int iovcnt, int rw)
|
||||||
{
|
{
|
||||||
ssize_t n, done;
|
int cur = 0;
|
||||||
|
ssize_t n, done = 0;
|
||||||
|
|
||||||
for (done = 0; done < size; done += n)
|
while (cur < iovcnt)
|
||||||
{
|
{
|
||||||
if (rw & 1)
|
iov[cur].iov_len -= done;
|
||||||
n = read(fd, &packet[done], (size_t)(size - done));
|
iov[cur].iov_base = ((char *)iov[cur].iov_base) + done;
|
||||||
else
|
|
||||||
n = write(fd, &packet[done], (size_t)(size - done));
|
|
||||||
|
|
||||||
if (n == 0)
|
if (rw & 1)
|
||||||
return 0;
|
n = readv(fd, &iov[cur], iovcnt - cur);
|
||||||
|
else
|
||||||
|
n = writev(fd, &iov[cur], iovcnt - cur);
|
||||||
|
|
||||||
|
iov[cur].iov_len += done;
|
||||||
|
iov[cur].iov_base = ((char *)iov[cur].iov_base) - done;
|
||||||
|
|
||||||
if (n == -1)
|
if (n == -1)
|
||||||
{
|
{
|
||||||
n = 0; /* don't mess with counter when we loop. */
|
|
||||||
|
|
||||||
if (errno == EINTR || errno == ENOMEM || errno == ENOBUFS)
|
if (errno == EINTR || errno == ENOMEM || errno == ENOBUFS)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
if (!(rw & 2) && (errno == EAGAIN || errno == EWOULDBLOCK))
|
||||||
{
|
continue;
|
||||||
/* "once" variant */
|
|
||||||
if (rw & 2)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (n == 0 && (rw & 1))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
done += n;
|
||||||
|
while (cur < iovcnt && (size_t)done >= iov[cur].iov_len)
|
||||||
|
done -= iov[cur++].iov_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int read_write(int fd, unsigned char *packet, int size, int rw)
|
||||||
|
{
|
||||||
|
struct iovec iov;
|
||||||
|
|
||||||
|
/* size == 0 is not an error, just a NOOP. */
|
||||||
|
if (size == 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
iov.iov_len = (size_t)size;
|
||||||
|
iov.iov_base = packet;
|
||||||
|
|
||||||
|
return read_writev(fd, &iov, 1, rw);
|
||||||
|
}
|
||||||
|
|
||||||
/* close all fds except STDIN, STDOUT and STDERR, spare1, spare2 and spare3 */
|
/* close all fds except STDIN, STDOUT and STDERR, spare1, spare2 and spare3 */
|
||||||
void close_fds(long max_fd, int spare1, int spare2, int spare3)
|
void close_fds(long max_fd, int spare1, int spare2, int spare3)
|
||||||
{
|
{
|
||||||
@@ -949,3 +920,87 @@ int kernel_version(void)
|
|||||||
return version * 256 + (split ? atoi(split) : 0);
|
return version * 256 + (split ? atoi(split) : 0);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define hash_ptr(x) (((unsigned int)(((char *)(x)) - ((char *)NULL))) & 0xffffff)
|
||||||
|
|
||||||
|
void *whine_malloc_real(const char *func, unsigned int line, size_t size)
|
||||||
|
{
|
||||||
|
void *ret = calloc(1, size);
|
||||||
|
|
||||||
|
if (!ret)
|
||||||
|
my_syslog(LOG_ERR, _("failed to allocate %d bytes"), (int) size);
|
||||||
|
else if (daemon->log_malloc)
|
||||||
|
my_syslog(LOG_INFO, _("malloc: %s:%u %zu bytes at %x"), func, line, size, hash_ptr(ret));
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *whine_realloc_real(const char *wrapper, const char *func, unsigned int line, void *ptr, size_t size)
|
||||||
|
{
|
||||||
|
unsigned int old = hash_ptr(ptr);
|
||||||
|
void *ret = realloc(ptr, size);
|
||||||
|
|
||||||
|
if (!ret)
|
||||||
|
my_syslog(LOG_ERR, _("failed to reallocate %d bytes"), (int) size);
|
||||||
|
else if (daemon->log_malloc)
|
||||||
|
{
|
||||||
|
if (!wrapper)
|
||||||
|
wrapper = "realloc";
|
||||||
|
my_syslog(LOG_INFO, _("%s: %s:%u %zu bytes from %x to %x"), wrapper, func, line, size, old, hash_ptr(ret));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* _note_ may copy buffer */
|
||||||
|
int expand_buf_real(const char *func, unsigned int line, struct iovec *iov, size_t size)
|
||||||
|
{
|
||||||
|
void *new;
|
||||||
|
|
||||||
|
if (size <= (size_t)iov->iov_len)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (!(new = whine_realloc_real("expand_buf", func, line, iov->iov_base, size)))
|
||||||
|
{
|
||||||
|
errno = ENOMEM;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
iov->iov_base = new;
|
||||||
|
iov->iov_len = size;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int expand_workspace_real(const char *func, unsigned int line, unsigned char ***wkspc, int *szp, int new)
|
||||||
|
{
|
||||||
|
unsigned char **p;
|
||||||
|
int old = *szp;
|
||||||
|
|
||||||
|
if (old >= new+1)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
new += 5;
|
||||||
|
|
||||||
|
if (!(p = whine_realloc_real("expand_workspace", func, line, *wkspc, new * sizeof(unsigned char *))))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
memset(p+old, 0, new-old);
|
||||||
|
|
||||||
|
*wkspc = p;
|
||||||
|
*szp = new;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef free
|
||||||
|
void free_real(const char *func, unsigned int line, void *ptr)
|
||||||
|
{
|
||||||
|
if (ptr)
|
||||||
|
{
|
||||||
|
if (daemon->log_malloc)
|
||||||
|
my_syslog(LOG_INFO, _("free: %s:%u block at %x"), func, line, hash_ptr(ptr));
|
||||||
|
|
||||||
|
free(ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user