mirror of
http://thekelleys.org.uk/git/dnsmasq.git
synced 2026-11-04 13:48:30 +00:00
Compare commits
49
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9ad74926d4 | ||
|
|
a6069da373 | ||
|
|
14f53171ca | ||
|
|
8fd06d2cc0 | ||
|
|
d152e81e42 | ||
|
|
e0bec3342b | ||
|
|
dd707937d5 | ||
|
|
c5f46412a3 | ||
|
|
cd04c0ce20 | ||
|
|
0630a45ae1 | ||
|
|
3ea905b98b | ||
|
|
ca509cb611 | ||
|
|
8ceb8ee9b5 | ||
|
|
1c4a97edb5 | ||
|
|
9e3e0465cd | ||
|
|
b12a9249f6 | ||
|
|
9dec84ca42 | ||
|
|
68c149e9dd | ||
|
|
5ea054b264 | ||
|
|
b95d5a2577 | ||
|
|
5be5dc1f16 | ||
|
|
48348a2d77 | ||
|
|
b4a0663654 | ||
|
|
53313014b5 | ||
|
|
cf08eeee12 | ||
|
|
0597828b74 | ||
|
|
c8168e888e | ||
|
|
3a052d55fb | ||
|
|
1eab169173 | ||
|
|
4070a74862 | ||
|
|
65adc53130 | ||
|
|
66d9658f5f | ||
|
|
ca30c82647 | ||
|
|
32a54fc8a5 | ||
|
|
3f2bfca3df | ||
|
|
e4d0bb4579 | ||
|
|
84415a87be | ||
|
|
1537645e8f | ||
|
|
ceab392c60 | ||
|
|
5f0f6aa9b1 | ||
|
|
578ea08391 | ||
|
|
fbfcf87f8b | ||
|
|
19f3e06e7a | ||
|
|
40d1152059 | ||
|
|
3c830c4f1c | ||
|
|
e9f400dd37 | ||
|
|
870f14108f | ||
|
|
714d36229a | ||
|
|
60e90e2224 |
No files matched your search
@@ -24,6 +24,16 @@ version 2.93
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
Modify the inotify implementation so that inotify watches are
|
||||
only created after dnsmasq has changed permissions and userid.
|
||||
This means that the permissions used when creating the watches
|
||||
are the same as used for accessing watched files, which makes
|
||||
more sense and avoids odd and confusing error conditions.
|
||||
|
||||
|
||||
version 2.92
|
||||
Redesign the interaction between DNSSEC validation and per-domain
|
||||
|
||||
+5
-3
@@ -1515,7 +1515,7 @@ The normal default DNS server (the same address as the DHCP server)
|
||||
will not be appropriate when there is no route bewteen the
|
||||
two, so this will have to be explicitly configured.
|
||||
.TP
|
||||
.B \-U, --dhcp-vendorclass=set:<tag>,[enterprise:<IANA-enterprise number>,]<vendor-class>
|
||||
.B \-U, --dhcp-vendorclass=set:<tag>,[enterprise:<IANA-enterprise number>,][<vendor-class>]
|
||||
Map from a vendor-class string to a tag. Most DHCP clients provide a
|
||||
"vendor class" which represents, in some sense, the type of host. This option
|
||||
maps vendor classes to tags, so that DHCP options may be selectively delivered
|
||||
@@ -1529,9 +1529,11 @@ allow fuzzy matching. The set: prefix is optional but allowed for
|
||||
consistency.
|
||||
|
||||
Note that in IPv6 only, vendorclasses are namespaced with an
|
||||
IANA-allocated enterprise number. This is given with enterprise:
|
||||
IANA-allocated enterprise number. This may be given with an enterprise:
|
||||
keyword and specifies that only vendorclasses matching the specified
|
||||
number should be searched.
|
||||
number should be searched. Similarly, an enterprise number may be given
|
||||
with no vendor-class string. This always matches vendorclasses with
|
||||
the given enterprise number.
|
||||
.TP
|
||||
.B \-j, --dhcp-userclass=set:<tag>,<user-class>
|
||||
Map from a user-class string to a tag (with substring
|
||||
|
||||
+7
-7
@@ -591,7 +591,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
if (auth && zone)
|
||||
{
|
||||
char *authname;
|
||||
int newoffset, offset = 0;
|
||||
int newoffset = ansp - (unsigned char *)header, offset = 0;
|
||||
|
||||
if (!subnet)
|
||||
authname = zone->domain;
|
||||
@@ -631,8 +631,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
}
|
||||
|
||||
/* handle NS and SOA in auth section or for explicit queries */
|
||||
newoffset = ansp - (unsigned char *)header;
|
||||
if (((anscount == 0 && !ns) || soa) &&
|
||||
if (((anscount == 0 && !ns) || soa) &&
|
||||
add_resource_record(header, limit, &trunc, 0, &ansp,
|
||||
daemon->auth_ttl, NULL, T_SOA, C_IN, "ddlllll",
|
||||
authname, daemon->authserver, daemon->hostmaster,
|
||||
@@ -650,11 +649,10 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
if (anscount != 0 || ns)
|
||||
{
|
||||
struct name_list *secondary;
|
||||
|
||||
|
||||
/* Only include the machine running dnsmasq if it's acting as an auth server */
|
||||
if (daemon->authinterface)
|
||||
{
|
||||
newoffset = ansp - (unsigned char *)header;
|
||||
if (add_resource_record(header, limit, &trunc, -offset, &ansp,
|
||||
daemon->auth_ttl, NULL, T_NS, C_IN, "d", offset == 0 ? authname : NULL, daemon->authserver))
|
||||
{
|
||||
@@ -669,9 +667,11 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
|
||||
if (!subnet)
|
||||
for (secondary = daemon->secondary_forward_server; secondary; secondary = secondary->next)
|
||||
if (add_resource_record(header, limit, &trunc, offset, &ansp,
|
||||
daemon->auth_ttl, NULL, T_NS, C_IN, "d", secondary->name))
|
||||
if (add_resource_record(header, limit, &trunc, -offset, &ansp,
|
||||
daemon->auth_ttl, NULL, T_NS, C_IN, "d", offset == 0 ? authname : NULL, secondary->name))
|
||||
{
|
||||
if (offset == 0)
|
||||
offset = newoffset;
|
||||
if (ns)
|
||||
anscount++;
|
||||
else
|
||||
|
||||
+6
-8
@@ -193,22 +193,20 @@ void *blockdata_retrieve(struct blockdata *block, size_t len, void *data)
|
||||
{
|
||||
size_t blen;
|
||||
struct blockdata *b;
|
||||
uint8_t *new, *d;
|
||||
uint8_t *d;
|
||||
|
||||
static unsigned int buff_len = 0;
|
||||
static unsigned char *buff = NULL;
|
||||
|
||||
if (!data)
|
||||
{
|
||||
static unsigned int buff_len = 0;
|
||||
static unsigned char *buff = NULL;
|
||||
uint8_t *new;
|
||||
|
||||
if (len > buff_len)
|
||||
{
|
||||
blen = len + 1024;
|
||||
if (!(new = whine_malloc(blen)))
|
||||
if (!(new = whine_realloc(buff, blen)))
|
||||
return NULL;
|
||||
|
||||
if (buff)
|
||||
free(buff);
|
||||
|
||||
buff = new;
|
||||
buff_len = blen;
|
||||
}
|
||||
|
||||
+149
-102
@@ -17,13 +17,16 @@
|
||||
#include "dnsmasq.h"
|
||||
|
||||
static struct crec *cache_head = NULL, *cache_tail = NULL, **hash_table = NULL;
|
||||
#ifdef HAVE_DHCP
|
||||
static struct crec *dhcp_spare = NULL;
|
||||
#endif
|
||||
static struct crec *config_spare = NULL;
|
||||
static struct crec *new_chain = NULL;
|
||||
static int insert_error;
|
||||
static union bigname *big_free = NULL;
|
||||
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 struct crec *really_insert(char *name, union all_addr *addr, unsigned short class,
|
||||
@@ -192,6 +195,61 @@ void cache_init(void)
|
||||
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)
|
||||
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
|
||||
@@ -441,12 +499,14 @@ unsigned int cache_remove_uid(const unsigned int uid)
|
||||
if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) && crecp->uid == uid)
|
||||
{
|
||||
*up = tmp;
|
||||
free(crecp);
|
||||
free_config_crec(crecp);
|
||||
removed++;
|
||||
}
|
||||
else
|
||||
up = &crecp->hash_next;
|
||||
}
|
||||
|
||||
free_names(uid);
|
||||
|
||||
return removed;
|
||||
}
|
||||
@@ -1023,6 +1083,9 @@ int cache_recv_insert(time_t now, int fd)
|
||||
!read_write(fd, (unsigned char *)&validatecount, sizeof(validatecount), RW_READ) ||
|
||||
!read_write(fd, (unsigned char *)&validatecountp, sizeof(validatecountp), RW_READ)))
|
||||
return 0;
|
||||
|
||||
if (op == PIPE_OP_KILLED)
|
||||
my_syslog(LOG_INFO, _("TCP process for DNSSEC validation timed out"));
|
||||
|
||||
/* There's a tiny chance that the frec may have been freed
|
||||
and reused before the TCP process returns. Detect that with
|
||||
@@ -1261,7 +1324,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))))
|
||||
if ((lookup->flags & F_HOSTS) && memcmp(&lookup->addr, addr, addrlen) == 0)
|
||||
{
|
||||
free(cache);
|
||||
free_config_crec(cache);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1384,13 +1447,13 @@ int read_hostsfile(char *filename, unsigned int index, int cache_size, struct cr
|
||||
{
|
||||
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;
|
||||
domain_suffix = get_domain(addr.addr4);
|
||||
}
|
||||
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;
|
||||
domain_suffix = get_domain6(&addr.addr6);
|
||||
}
|
||||
@@ -1424,27 +1487,37 @@ int read_hostsfile(char *filename, unsigned int index, int cache_size, struct cr
|
||||
if ((canon = canonicalise(token, &nomem)))
|
||||
{
|
||||
/* If set, add a version of the name with a default domain appended */
|
||||
if (option_bool(OPT_EXPAND) && domain_suffix && !fqdn &&
|
||||
(cache = whine_malloc(SIZEOF_BARE_CREC + strlen(canon) + 2 + strlen(domain_suffix))))
|
||||
if (option_bool(OPT_EXPAND) && domain_suffix && !fqdn && (cache = get_config_crec()))
|
||||
{
|
||||
strcpy(cache->name.sname, canon);
|
||||
strcat(cache->name.sname, ".");
|
||||
strcat(cache->name.sname, domain_suffix);
|
||||
cache->flags = flags;
|
||||
cache->ttd = daemon->local_ttl;
|
||||
add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
|
||||
name_count++;
|
||||
names_done++;
|
||||
if (!(cache->name.namep = store_name(strlen(canon) + 2 + strlen(domain_suffix), index)))
|
||||
free_config_crec(cache);
|
||||
else
|
||||
{
|
||||
strcpy(cache->name.namep, canon);
|
||||
strcat(cache->name.namep, ".");
|
||||
strcat(cache->name.namep, domain_suffix);
|
||||
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);
|
||||
cache->flags = flags;
|
||||
cache->ttd = daemon->local_ttl;
|
||||
add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
|
||||
name_count++;
|
||||
names_done++;
|
||||
if (!(cache->name.namep = store_name(strlen(canon) + 1, index)))
|
||||
free_config_crec(cache);
|
||||
else
|
||||
{
|
||||
strcpy(cache->name.namep, canon);
|
||||
cache->flags = flags;
|
||||
cache->ttd = daemon->local_ttl;
|
||||
add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
|
||||
name_count++;
|
||||
names_done++;
|
||||
}
|
||||
}
|
||||
|
||||
free(canon);
|
||||
|
||||
}
|
||||
@@ -1495,7 +1568,7 @@ void cache_reload(void)
|
||||
if (cache->flags & (F_HOSTS | F_CONFIG))
|
||||
{
|
||||
*up = cache->hash_next;
|
||||
free(cache);
|
||||
free_config_crec(cache);
|
||||
}
|
||||
else if (!(cache->flags & F_DHCP))
|
||||
{
|
||||
@@ -1510,11 +1583,13 @@ void cache_reload(void)
|
||||
else
|
||||
up = &cache->hash_next;
|
||||
}
|
||||
|
||||
free_names(UID_NONE); /* free everything */
|
||||
|
||||
/* Add locally-configured CNAMEs to the cache */
|
||||
for (a = daemon->cnames; a; a = a->next)
|
||||
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->ttd = a->ttl;
|
||||
@@ -1528,25 +1603,30 @@ void cache_reload(void)
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
for (ds = daemon->ds; ds; ds = ds->next)
|
||||
if ((cache = whine_malloc(SIZEOF_POINTER_CREC)) &&
|
||||
(cache->addr.ds.keydata = blockdata_alloc(ds->digest, ds->digestlen)))
|
||||
if (ds->name && (cache = get_config_crec()))
|
||||
{
|
||||
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);
|
||||
if (!(cache->addr.ds.keydata = blockdata_alloc(ds->digest, ds->digestlen)))
|
||||
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
|
||||
|
||||
@@ -1561,7 +1641,7 @@ void cache_reload(void)
|
||||
for (nl = hr->names; nl; nl = nl->next)
|
||||
{
|
||||
if ((hr->flags & HR_4) &&
|
||||
(cache = whine_malloc(SIZEOF_POINTER_CREC)))
|
||||
(cache = get_config_crec()))
|
||||
{
|
||||
cache->name.namep = nl->name;
|
||||
cache->ttd = hr->ttl;
|
||||
@@ -1570,7 +1650,7 @@ void cache_reload(void)
|
||||
}
|
||||
|
||||
if ((hr->flags & HR_6) &&
|
||||
(cache = whine_malloc(SIZEOF_POINTER_CREC)))
|
||||
(cache = get_config_crec()))
|
||||
{
|
||||
cache->name.namep = nl->name;
|
||||
cache->ttd = hr->ttl;
|
||||
@@ -1662,8 +1742,7 @@ void cache_unhash_dhcp(void)
|
||||
if (cache->flags & F_DHCP)
|
||||
{
|
||||
*up = cache->hash_next;
|
||||
cache->next = dhcp_spare;
|
||||
dhcp_spare = cache;
|
||||
free_config_crec(cache);
|
||||
}
|
||||
else
|
||||
up = &cache->hash_next;
|
||||
@@ -1734,12 +1813,7 @@ void cache_add_dhcp_entry(char *host_name, int prot,
|
||||
else
|
||||
flags |= F_REVERSE;
|
||||
|
||||
if ((crec = dhcp_spare))
|
||||
dhcp_spare = dhcp_spare->next;
|
||||
else /* need new one */
|
||||
crec = whine_malloc(SIZEOF_POINTER_CREC);
|
||||
|
||||
if (crec) /* malloc may fail */
|
||||
if ((crec = get_config_crec()))
|
||||
{
|
||||
crec->flags = flags | F_NAMEP | F_DHCP | F_FORWARD;
|
||||
if (ttd == 0)
|
||||
@@ -1786,15 +1860,7 @@ static void make_non_terminals(struct crec *source)
|
||||
hostname_isequal(name, cache_get_name(crecp)))
|
||||
{
|
||||
*up = crecp->hash_next;
|
||||
#ifdef HAVE_DHCP
|
||||
if (type & F_DHCP)
|
||||
{
|
||||
crecp->next = dhcp_spare;
|
||||
dhcp_spare = crecp;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
free(crecp);
|
||||
free_config_crec(crecp);
|
||||
break;
|
||||
}
|
||||
else
|
||||
@@ -1827,17 +1893,7 @@ static void make_non_terminals(struct crec *source)
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
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)
|
||||
if ((crecp = get_config_crec()))
|
||||
{
|
||||
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))
|
||||
@@ -2166,9 +2222,9 @@ static char *querystr(char *desc, unsigned short type)
|
||||
unsigned int i;
|
||||
int len = 10; /* strlen("type=xxxxx") */
|
||||
const char *types = NULL;
|
||||
static char *buff = NULL;
|
||||
static int bufflen = 0;
|
||||
|
||||
static struct iovec buff = { NULL, 0 };
|
||||
char *buffp;
|
||||
|
||||
for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++)
|
||||
if (typestr[i].type == type)
|
||||
{
|
||||
@@ -2183,37 +2239,28 @@ static char *querystr(char *desc, unsigned short type)
|
||||
len += strlen(desc);
|
||||
}
|
||||
len++; /* terminator */
|
||||
|
||||
if (!buff || bufflen < len)
|
||||
{
|
||||
if (buff)
|
||||
free(buff);
|
||||
else if (len < 20)
|
||||
len = 20;
|
||||
|
||||
buff = whine_malloc(len);
|
||||
bufflen = len;
|
||||
}
|
||||
|
||||
if (buff)
|
||||
if (!expand_buf(&buff, len))
|
||||
return "";
|
||||
|
||||
buffp = buff.iov_base;
|
||||
|
||||
if (desc)
|
||||
{
|
||||
if (desc)
|
||||
{
|
||||
if (types)
|
||||
sprintf(buff, "%s[%s]", desc, types);
|
||||
else
|
||||
sprintf(buff, "%s[type=%d]", desc, type);
|
||||
}
|
||||
if (types)
|
||||
sprintf(buffp, "%s[%s]", desc, types);
|
||||
else
|
||||
{
|
||||
if (types)
|
||||
sprintf(buff, "<%s>", types);
|
||||
else
|
||||
sprintf(buff, "<type=%d>", type);
|
||||
}
|
||||
sprintf(buffp, "%s[type=%d]", desc, type);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (types)
|
||||
sprintf(buffp, "<%s>", types);
|
||||
else
|
||||
sprintf(buffp, "<type=%d>", type);
|
||||
}
|
||||
|
||||
return buff ? buff : "";
|
||||
return buffp;
|
||||
}
|
||||
|
||||
static char *edestr(int ede)
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#define TCP_BACKLOG 32 /* kernel backlog limit for TCP connections */
|
||||
#define EDNS_PKTSZ 1232 /* default max EDNS.0 UDP packet from from /dnsflagday.net/2020 */
|
||||
#define KEYBLOCK_LEN 40 /* choose to minimise fragmentation when storing DNSSEC keys */
|
||||
#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_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. */
|
||||
|
||||
+26
-7
@@ -93,7 +93,15 @@ static void null_hash_update(void *ctxv, size_t length, const uint8_t *src)
|
||||
memcpy(null_hash_buff + ctx->len, src, length);
|
||||
ctx->len += length;
|
||||
}
|
||||
|
||||
|
||||
/* The prototype changes in nettle 4.0 to omit the length argument */
|
||||
#if MIN_VERSION(4, 0)
|
||||
static void null_hash_digest(void *ctx, uint8_t *dst)
|
||||
{
|
||||
((struct null_hash_digest *)dst)->buff = null_hash_buff;
|
||||
((struct null_hash_digest *)dst)->len = ((struct null_hash_ctx *)ctx)->len;
|
||||
}
|
||||
#else
|
||||
static void null_hash_digest(void *ctx, size_t length, uint8_t *dst)
|
||||
{
|
||||
(void)length;
|
||||
@@ -101,6 +109,7 @@ static void null_hash_digest(void *ctx, size_t length, uint8_t *dst)
|
||||
((struct null_hash_digest *)dst)->buff = null_hash_buff;
|
||||
((struct null_hash_digest *)dst)->len = ((struct null_hash_ctx *)ctx)->len;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct nettle_hash null_hash = {
|
||||
"null_hash",
|
||||
@@ -126,20 +135,18 @@ int hash_init(const struct nettle_hash *hash, void **ctxp, unsigned char **diges
|
||||
|
||||
if (ctx_sz < hash->context_size)
|
||||
{
|
||||
if (!(new = whine_malloc(hash->context_size)))
|
||||
if (!(new = whine_realloc(ctx, hash->context_size)))
|
||||
return 0;
|
||||
if (ctx)
|
||||
free(ctx);
|
||||
|
||||
ctx = new;
|
||||
ctx_sz = hash->context_size;
|
||||
}
|
||||
|
||||
if (digest_sz < hash->digest_size)
|
||||
{
|
||||
if (!(new = whine_malloc(hash->digest_size)))
|
||||
if (!(new = whine_realloc(digest, hash->digest_size)))
|
||||
return 0;
|
||||
if (digest)
|
||||
free(digest);
|
||||
|
||||
digest = new;
|
||||
digest_sz = hash->digest_size;
|
||||
}
|
||||
@@ -503,4 +510,16 @@ const struct nettle_hash *hash_find(char *name)
|
||||
#endif
|
||||
}
|
||||
|
||||
/* The prototype changes in nettle 4.0 to omit the length argument */
|
||||
void nettle_digest_wrapper(const struct nettle_hash *hash, void *ctx, size_t length, uint8_t *dst)
|
||||
{
|
||||
#if MIN_VERSION(4, 0)
|
||||
(void)length;
|
||||
hash->digest(ctx, dst);
|
||||
#else
|
||||
hash->digest(ctx, length, dst);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#endif /* defined(HAVE_DNSSEC) */
|
||||
+7
-8
@@ -882,7 +882,7 @@ char *option_string(int prot, unsigned int opt, unsigned char *val, int opt_len,
|
||||
buf[j++] = c;
|
||||
}
|
||||
i = l;
|
||||
if (val[i] != 0 && j < buf_len)
|
||||
if (i < opt_len && val[i] != 0 && j < buf_len)
|
||||
buf[j++] = '.';
|
||||
}
|
||||
}
|
||||
@@ -892,24 +892,23 @@ char *option_string(int prot, unsigned int opt, unsigned char *val, int opt_len,
|
||||
unsigned char *p;
|
||||
|
||||
i = 0, j = 0;
|
||||
while (1)
|
||||
while (i + 2 <= opt_len)
|
||||
{
|
||||
p = &val[i];
|
||||
GETSHORT(len, p);
|
||||
if (i + 2 + len > opt_len)
|
||||
break; /* malformed: body extends beyond option */
|
||||
for (k = 0; k < len && j < buf_len; k++)
|
||||
{
|
||||
char c = *p++;
|
||||
if (isprint((unsigned char)c))
|
||||
buf[j++] = c;
|
||||
}
|
||||
i += len +2;
|
||||
if (i >= opt_len)
|
||||
break;
|
||||
|
||||
if (j < buf_len)
|
||||
i += len + 2;
|
||||
if (i < opt_len && j < buf_len)
|
||||
buf[j++] = ',';
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else if ((ot[o].size & (OT_DEC | OT_TIME)) && opt_len != 0)
|
||||
{
|
||||
|
||||
+1
-1
@@ -399,7 +399,7 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
if (mess->ciaddr.s_addr != 0)
|
||||
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. */
|
||||
if (is_relay_use_source)
|
||||
|
||||
+65
-25
@@ -199,7 +199,7 @@ int main (int argc, char **argv)
|
||||
/* Must have at least a root trust anchor, or the DNSSEC code
|
||||
can loop forever. */
|
||||
for (ds = daemon->ds; ds; ds = ds->next)
|
||||
if (ds->name[0] == 0)
|
||||
if (ds->name && ds->name[0] == 0)
|
||||
break;
|
||||
|
||||
if (!ds)
|
||||
@@ -437,14 +437,6 @@ int main (int argc, char **argv)
|
||||
daemon->tcp_pipes[i] = -1;
|
||||
}
|
||||
|
||||
#ifdef HAVE_INOTIFY
|
||||
if ((daemon->port != 0 && !option_bool(OPT_NO_RESOLV)) ||
|
||||
daemon->dynamic_dirs)
|
||||
inotify_dnsmasq_init();
|
||||
else
|
||||
daemon->inotifyfd = -1;
|
||||
#endif
|
||||
|
||||
if (daemon->dump_file)
|
||||
#ifdef HAVE_DUMPFILE
|
||||
dump_init();
|
||||
@@ -864,6 +856,14 @@ int main (int argc, char **argv)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_INOTIFY
|
||||
if ((daemon->port != 0 && !option_bool(OPT_NO_RESOLV)) ||
|
||||
daemon->dynamic_dirs)
|
||||
inotify_dnsmasq_init(err_pipe[1]);
|
||||
else
|
||||
daemon->inotifyfd = -1;
|
||||
#endif
|
||||
|
||||
/* Don't start logging malloc before logging is set up. */
|
||||
daemon->log_malloc = option_bool(OPT_LOG_MALLOC);
|
||||
|
||||
@@ -946,9 +946,27 @@ int main (int argc, char **argv)
|
||||
my_syslog(LOG_INFO, _("DNSSEC signature timestamps not checked until system time valid"));
|
||||
|
||||
for (ds = daemon->ds; ds; ds = ds->next)
|
||||
my_syslog(LOG_INFO,
|
||||
ds->digestlen == 0 ? _("configured with negative trust anchor for %s") : _("configured with trust anchor for %s keytag %u"),
|
||||
ds->name[0] == 0 ? "<root>" : ds->name, ds->keytag);
|
||||
{
|
||||
struct ds_config *ds1;
|
||||
|
||||
for (ds1 = ds->next; ds1; ds1 = ds1->next)
|
||||
if (strcmp(ds->name, ds1->name) == 0 &&
|
||||
ds->digestlen == ds1->digestlen &&
|
||||
(ds->digestlen == 0 ||
|
||||
(ds->algo == ds1->algo &&
|
||||
ds->keytag == ds1->keytag &&
|
||||
ds->digest_type == ds1->digest_type &&
|
||||
memcmp(ds->digest, ds1->digest, ds->digestlen) == 0)))
|
||||
{
|
||||
ds->name = NULL; /* Mark as duplicate */
|
||||
break;
|
||||
}
|
||||
|
||||
if (ds->name)
|
||||
my_syslog(LOG_INFO,
|
||||
ds->digestlen == 0 ? _("configured with negative trust anchor for %s") : _("configured with trust anchor for %s keytag %u"),
|
||||
ds->name[0] == 0 ? "<root>" : ds->name, ds->keytag);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1367,8 +1385,6 @@ static void sig_handler(int sig)
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)(&daemon->forward_to_tcp), sizeof(daemon->forward_to_tcp), RW_WRITE);
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)(&daemon->forward_to_tcp->uid), sizeof(daemon->forward_to_tcp->uid), RW_WRITE);
|
||||
|
||||
my_syslog(LOG_INFO, _("TCP process for DNSSEC validation timed out"));
|
||||
|
||||
_exit(0);
|
||||
}
|
||||
}
|
||||
@@ -1450,8 +1466,6 @@ void send_event(int fd, int event, int data, char *msg)
|
||||
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)
|
||||
{
|
||||
char *buf;
|
||||
@@ -1461,12 +1475,22 @@ static int read_event(int fd, struct event_desc *evp, char **msg)
|
||||
|
||||
*msg = NULL;
|
||||
|
||||
if (evp->msg_sz != 0 &&
|
||||
(buf = malloc(evp->msg_sz + 1)) &&
|
||||
read_write(fd, (unsigned char *)buf, evp->msg_sz, RW_READ))
|
||||
if (evp->msg_sz != 0)
|
||||
{
|
||||
buf[evp->msg_sz] = 0;
|
||||
*msg = buf;
|
||||
if (!(buf = whine_malloc(evp->msg_sz + 1)))
|
||||
{
|
||||
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;
|
||||
@@ -1519,6 +1543,26 @@ static void fatal_event(struct event_desc *ev, char *msg)
|
||||
/* fall through */
|
||||
case EVENT_TIME_ERR:
|
||||
die(_("cannot create timestamp file %s: %s" ), msg, EC_BADCONF);
|
||||
|
||||
/* fall through */
|
||||
case EVENT_LINK_ERR:
|
||||
die(_("cannot access path %s: %s" ), msg, EC_MISC);
|
||||
|
||||
/* fall through */
|
||||
case EVENT_INOTFY_ERR:
|
||||
die(_("failed to create inotify: %s" ), NULL, EC_MISC);
|
||||
|
||||
/* fall through */
|
||||
case EVENT_TMSL_ERR:
|
||||
die(_("too many symlinks following %s"), msg, EC_MISC);
|
||||
|
||||
/* fall through */
|
||||
case EVENT_RESOLV_ERR:
|
||||
die(_("directory %s for resolv-file is missing, cannot poll"), msg, EC_MISC);
|
||||
|
||||
/* fall through */
|
||||
case EVENT_IFILE_ERR:
|
||||
die(_("failed to create inotify for %s: %s"), msg, EC_MISC);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1529,9 +1573,6 @@ static void async_event(int pipe, time_t now)
|
||||
int wstatus, i, check = 0;
|
||||
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))
|
||||
switch (ev.event)
|
||||
{
|
||||
@@ -1637,7 +1678,6 @@ static void async_event(int pipe, time_t now)
|
||||
case EVENT_SCRIPT_LOG:
|
||||
my_syslog(MS_SCRIPT | LOG_DEBUG, "%s", msg ? msg : "");
|
||||
free(msg);
|
||||
msg = NULL;
|
||||
break;
|
||||
|
||||
/* necessary for fatal errors in helper */
|
||||
|
||||
+16
-5
@@ -201,6 +201,11 @@ struct event_desc {
|
||||
#define EVENT_TIME_ERR 24
|
||||
#define EVENT_SCRIPT_LOG 25
|
||||
#define EVENT_TIME 26
|
||||
#define EVENT_LINK_ERR 27
|
||||
#define EVENT_INOTFY_ERR 28
|
||||
#define EVENT_TMSL_ERR 29
|
||||
#define EVENT_RESOLV_ERR 30
|
||||
#define EVENT_IFILE_ERR 31
|
||||
|
||||
/* Exit codes. */
|
||||
#define EC_GOOD 0
|
||||
@@ -1468,6 +1473,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
|
||||
char *keyname, int class, int *validate_count);
|
||||
int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char *name,
|
||||
char *keyname, int class, int *validate_count);
|
||||
int cache_neg_ds(char *name, int flags, int class, time_t now, int neg_ttl);
|
||||
int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int *class,
|
||||
int check_unsigned, int *neganswer, int *prim_ok, int *nons, int *nsec_ttl, int *validate_count);
|
||||
int dnskey_keytag(int alg, int flags, unsigned char *key, int keylen);
|
||||
@@ -1484,6 +1490,7 @@ int verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig,
|
||||
char *ds_digest_name(int digest);
|
||||
char *algo_digest_name(int algo);
|
||||
char *nsec3_digest_name(int digest);
|
||||
void nettle_digest_wrapper(const struct nettle_hash *hash, void *ctx, size_t length, uint8_t *dst);
|
||||
|
||||
/* util.c */
|
||||
void rand_init(void);
|
||||
@@ -1497,12 +1504,18 @@ unsigned char *do_rfc1035_name(unsigned char *p, char *sval, char *limit);
|
||||
void *safe_malloc(size_t size);
|
||||
void safe_strncpy(char *dest, const char *src, size_t size);
|
||||
void safe_pipe(int *fd, int read_noblock);
|
||||
#define malloc_log(x, y) malloc_log_real(__func__, __LINE__, (x), (y))
|
||||
#define whine_malloc(x) whine_malloc_real(__func__, __LINE__, (x))
|
||||
#define whine_realloc(x, y) whine_realloc_real(__func__, __LINE__, (x), (y))
|
||||
#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 malloc_log_real(const char *func, unsigned int line, void *mem, size_t size);
|
||||
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 *func, unsigned int line, void *ptr, 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 sockaddr_isequal(const union mysockaddr *s1, const union mysockaddr *s2);
|
||||
int sockaddr_isnull(const union mysockaddr *s);
|
||||
@@ -1524,7 +1537,6 @@ int parse_hex(char *in, unsigned char *out, int maxlen,
|
||||
unsigned int *wildcard_mask, int *mac_type);
|
||||
int memcmp_masked(unsigned char *a, unsigned char *b, int len,
|
||||
unsigned int mask);
|
||||
int expand_buf(struct iovec *iov, size_t size);
|
||||
char *print_mac(char *buff, unsigned char *mac, int len);
|
||||
int read_write(int fd, unsigned char *packet, int size, int rw);
|
||||
int read_writev(int fd, struct iovec *iov, int iovcnt, int rw);
|
||||
@@ -1902,7 +1914,7 @@ int detect_loop(char *query, int type);
|
||||
|
||||
/* inotify.c */
|
||||
#ifdef HAVE_INOTIFY
|
||||
void inotify_dnsmasq_init(void);
|
||||
void inotify_dnsmasq_init(int errfd);
|
||||
int inotify_check(time_t now);
|
||||
void set_dynamic_inotify(int flag, int total_size, struct crec **rhash, int revhashsz);
|
||||
#endif
|
||||
@@ -1916,7 +1928,6 @@ int do_poll(int timeout);
|
||||
/* rrfilter.c */
|
||||
size_t rrfilter(struct dns_header *header, size_t *plen, int mode);
|
||||
short *rrfilter_desc(int type);
|
||||
int expand_workspace(unsigned char ***wkspc, int *szp, int new);
|
||||
int to_wire(char *name);
|
||||
void from_wire(char *name);
|
||||
/* modes. */
|
||||
|
||||
+26
-20
@@ -656,7 +656,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
||||
}
|
||||
}
|
||||
|
||||
hash->digest(ctx, hash->digest_size, digest);
|
||||
nettle_digest_wrapper(hash, ctx, hash->digest_size, digest);
|
||||
|
||||
/* namebuff used for workspace above, restore to leave unchanged on exit */
|
||||
p = (unsigned char*)(rrset[0]);
|
||||
@@ -836,7 +836,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
|
||||
rather then O(keys x DSs) */
|
||||
hash->update(ctx, (unsigned int)wire_len, (unsigned char *)name);
|
||||
hash->update(ctx, (unsigned int)rdlen, psave);
|
||||
hash->digest(ctx, hash->digest_size, digest);
|
||||
nettle_digest_wrapper(hash, ctx, hash->digest_size, digest);
|
||||
|
||||
from_wire(name);
|
||||
|
||||
@@ -1027,21 +1027,21 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
|
||||
(flags = in_arpa_name_2_addr(name, &a)) &&
|
||||
((flags == F_IPV6 && private_net6(&a.addr6, 0)) || (flags == F_IPV4 && private_net(a.addr4, 0))))
|
||||
{
|
||||
my_syslog(LOG_INFO, _("Insecure reply received for DS %s, assuming that's OK for a RFC-1918 address."), name);
|
||||
my_syslog(LOG_INFO, _("insecure reply received for DS %s, assuming that's OK for a RFC-1918 address"), name);
|
||||
neganswer = 1;
|
||||
nons = 0; /* If we're faking a DS, fake one with an NS. */
|
||||
neg_ttl = DNSSEC_ASSUMED_DS_TTL;
|
||||
}
|
||||
else if (lookup_domain(name, F_DOMAINSRV, NULL, NULL))
|
||||
{
|
||||
my_syslog(LOG_INFO, _("Insecure reply received for DS %s, assuming non-DNSSEC domain-specific server."), name);
|
||||
my_syslog(LOG_INFO, _("insecure reply received for DS %s, assuming non-DNSSEC domain-specific server"), name);
|
||||
neganswer = 1;
|
||||
nons = 0; /* If we're faking a DS, fake one with an NS. */
|
||||
neg_ttl = DNSSEC_ASSUMED_DS_TTL;
|
||||
}
|
||||
else
|
||||
{
|
||||
my_syslog(LOG_WARNING, _("Insecure DS reply received for %s, check domain configuration and upstream DNS server DNSSEC support"), name);
|
||||
my_syslog(LOG_WARNING, _("insecure DS reply received for %s, check domain configuration and upstream DNS server DNSSEC support"), name);
|
||||
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DS - not secure", 0);
|
||||
return STAT_BOGUS | DNSSEC_FAIL_INDET;
|
||||
}
|
||||
@@ -1141,44 +1141,47 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
|
||||
}
|
||||
|
||||
flags = F_FORWARD | F_DS | F_NEG | F_DNSSECOK;
|
||||
|
||||
|
||||
if (neganswer)
|
||||
{
|
||||
if (RCODE(header) == NXDOMAIN)
|
||||
flags |= F_NXDOMAIN;
|
||||
|
||||
/* We only cache validated DS records, DNSSECOK flag hijacked
|
||||
to store presence/absence of NS. */
|
||||
if (nons)
|
||||
{
|
||||
if (lookup_domain(name, F_DOMAINSRV, NULL, NULL))
|
||||
{
|
||||
my_syslog(LOG_WARNING, _("Negative DS reply without NS record received for %s, assuming non-DNSSEC domain-specific server."), name);
|
||||
my_syslog(LOG_WARNING, _("negative DS reply without NS record received for %s, assuming non-DNSSEC domain-specific server"), name);
|
||||
nons = 0;
|
||||
neg_ttl = DNSSEC_ASSUMED_DS_TTL;
|
||||
}
|
||||
else
|
||||
/* We only cache validated DS records, DNSSECOK flag hijacked
|
||||
to store presence/absence of NS. */
|
||||
flags &= ~F_DNSSECOK;
|
||||
}
|
||||
|
||||
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL,
|
||||
servfail ? "SERVFAIL" : (nons ? "no DS/cut" : "no DS"), 0);
|
||||
}
|
||||
|
||||
|
||||
return cache_neg_ds(name, flags, class, now, neg_ttl);
|
||||
|
||||
}
|
||||
|
||||
int cache_neg_ds(char *name, int flags, int class, time_t now, int ttl)
|
||||
{
|
||||
cache_start_insert();
|
||||
|
||||
/* Use TTL from NSEC for negative cache entries */
|
||||
if (!cache_insert(name, NULL, class, now, neg_ttl, flags))
|
||||
if (!cache_insert(name, NULL, class, now, ttl, flags))
|
||||
return STAT_ABANDONED;
|
||||
|
||||
cache_end_insert();
|
||||
|
||||
if (neganswer)
|
||||
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL,
|
||||
servfail ? "SERVFAIL" : (nons ? "no DS/cut" : "no DS"), 0);
|
||||
|
||||
return STAT_OK;
|
||||
}
|
||||
|
||||
|
||||
/* 4034 6.1 */
|
||||
static int hostname_cmp(const char *a, const char *b)
|
||||
{
|
||||
@@ -1385,13 +1388,13 @@ static int hash_name(char *in, unsigned char **out, struct nettle_hash const *ha
|
||||
|
||||
hash->update(ctx, to_wire(in), (unsigned char *)in);
|
||||
hash->update(ctx, salt_len, salt);
|
||||
hash->digest(ctx, hash->digest_size, digest);
|
||||
nettle_digest_wrapper(hash, ctx, hash->digest_size, digest);
|
||||
|
||||
for(i = 0; i < iterations; i++)
|
||||
{
|
||||
hash->update(ctx, hash->digest_size, digest);
|
||||
hash->update(ctx, salt_len, salt);
|
||||
hash->digest(ctx, hash->digest_size, digest);
|
||||
nettle_digest_wrapper(hash, ctx, hash->digest_size, digest);
|
||||
}
|
||||
|
||||
from_wire(in);
|
||||
@@ -1423,7 +1426,10 @@ static int base32_decode(char *in, unsigned char *out)
|
||||
oc |= 1;
|
||||
mask = mask >> 1;
|
||||
if (((++on) & 7) == 0)
|
||||
*p++ = oc;
|
||||
{
|
||||
*p++ = oc;
|
||||
oc = 0;
|
||||
}
|
||||
oc = oc << 1;
|
||||
}
|
||||
}
|
||||
@@ -1553,7 +1559,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
|
||||
{
|
||||
unsigned char *salt, *p, *digest;
|
||||
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;
|
||||
|
||||
if (nons)
|
||||
|
||||
+3
-1
@@ -79,7 +79,9 @@ void build_server_array(void)
|
||||
for (serv = daemon->local_domains; serv; serv = serv->next, count++)
|
||||
daemon->serverarray[count] = serv;
|
||||
|
||||
qsort(daemon->serverarray, daemon->serverarraysz, sizeof(struct server *), order_qsort);
|
||||
/* serverarray may be unallocated if we have no servers yet. */
|
||||
if (daemon->serverarray)
|
||||
qsort(daemon->serverarray, daemon->serverarraysz, sizeof(struct server *), order_qsort);
|
||||
|
||||
/* servers need the location in the array to find all the whole
|
||||
set of equivalent servers from a pointer to a single one. */
|
||||
|
||||
+7
-7
@@ -175,8 +175,8 @@ int is_rev_synth(int flag, union all_addr *addr, char *name)
|
||||
*p = '-';
|
||||
}
|
||||
|
||||
strncat(name, ".", MAXDNAME);
|
||||
strncat(name, c->domain, MAXDNAME);
|
||||
strncat(name, ".", MAXDNAME - strlen(name) - 1);
|
||||
strncat(name, c->domain, MAXDNAME - strlen(name) - 1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -201,16 +201,16 @@ int is_rev_synth(int flag, union all_addr *addr, char *name)
|
||||
for (i = 0; i < 16; i += 2)
|
||||
{
|
||||
sprintf(frag, "%s%02x%02x", i == 0 ? "" : "-", addr->addr6.s6_addr[i], addr->addr6.s6_addr[i+1]);
|
||||
strncat(name, frag, MAXDNAME);
|
||||
strncat(name, frag, MAXDNAME - strlen(name) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
strncat(name, ".", MAXDNAME);
|
||||
strncat(name, c->domain, MAXDNAME);
|
||||
|
||||
strncat(name, ".", MAXDNAME - strlen(name) - 1);
|
||||
strncat(name, c->domain, MAXDNAME - strlen(name) - 1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -85,7 +85,8 @@ void dump_init(void)
|
||||
/* count existing records */
|
||||
while (read_write(daemon->dumpfd, (void *)&pcap_header, sizeof(pcap_header), RW_READ))
|
||||
{
|
||||
lseek(daemon->dumpfd, pcap_header.incl_len, SEEK_CUR);
|
||||
if (lseek(daemon->dumpfd, pcap_header.incl_len, SEEK_CUR) == (off_t)-1)
|
||||
break;
|
||||
packet_count++;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-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,
|
||||
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;
|
||||
unsigned short flags = set_do ? 0x8000 : 0, rcode = 0;
|
||||
|
||||
@@ -469,6 +469,8 @@ int check_source(struct dns_header *header, size_t plen, unsigned char *pseudohe
|
||||
{
|
||||
GETSHORT(code, p);
|
||||
GETSHORT(len, p);
|
||||
if (i + 4 + len > rdlen)
|
||||
break; /* malformed: option body extends beyond RDATA */
|
||||
if (code == EDNS0_OPTION_CLIENT_SUBNET)
|
||||
{
|
||||
if (peer)
|
||||
|
||||
+38
-20
@@ -954,6 +954,7 @@ static void dnssec_validate(struct frec *forward, struct dns_header *header,
|
||||
/* As soon as anything returns BOGUS, we stop and unwind, to do otherwise
|
||||
would invite infinite loops, since the answers to DNSKEY and DS queries
|
||||
will not be cached, so they'll be repeated. */
|
||||
ds_retry:
|
||||
if (forward->flags & FREC_DNSKEY_QUERY)
|
||||
status = dnssec_validate_by_ds(now, header, plen, daemon->namebuff, daemon->keyname, forward->class, &orig->validate_counter);
|
||||
else if (forward->flags & FREC_DS_QUERY)
|
||||
@@ -1083,6 +1084,18 @@ static void dnssec_validate(struct frec *forward, struct dns_header *header,
|
||||
STAT_ISEQUAL(status, STAT_NEED_KEY) ? "dnssec-query[DNSKEY]" : "dnssec-query[DS]", 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* If there's no server for the parent of a domain-specific server's domain,
|
||||
assume that said server's contents it legitimately unsigned, as if the parent
|
||||
contained a negative DS record. This is part of the same logic that's found
|
||||
in dnssec_validate_ds() when it gets a negative DS repsonse. */
|
||||
if (STAT_ISEQUAL(status, STAT_NEED_DS) && serverind == -1 && lookup_domain(daemon->keyname, F_DOMAINSRV, NULL, NULL) &&
|
||||
cache_neg_ds(daemon->keyname, F_FORWARD | F_DS | F_NEG | F_DNSSECOK, forward->class, now, DNSSEC_ASSUMED_DS_TTL) == STAT_OK)
|
||||
{
|
||||
my_syslog(LOG_WARNING, _("no server for parent domain of %s, assuming unsigned domain"), daemon->keyname);
|
||||
blockdata_free(stash);
|
||||
goto ds_retry;
|
||||
}
|
||||
|
||||
/* error unwind */
|
||||
free_rfds(&rfds);
|
||||
@@ -1192,10 +1205,10 @@ void reply_query(int fd, time_t now)
|
||||
server = daemon->serverarray[serv];
|
||||
if (server->sfd && server->sfd->fd == fd)
|
||||
break;
|
||||
|
||||
if (serv == last)
|
||||
return;
|
||||
}
|
||||
|
||||
if (serv == last)
|
||||
return;
|
||||
}
|
||||
|
||||
/* spoof check: answer must come from known server, also
|
||||
@@ -2162,9 +2175,12 @@ static ssize_t tcp_talk(int first, int last, int start, struct dns_header *heade
|
||||
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)
|
||||
struct dns_header *header = (struct dns_header *)recvbuff->iov_base;
|
||||
p = (unsigned char *)(header+1);
|
||||
if (rsize < (unsigned int)sizeof(struct dns_header) || !(header->hb3 & HB3_QR) || ntohs(header->qdcount) != 1 ||
|
||||
extract_name(header, rsize, &p, daemon->namebuff, EXTR_NAME_COMPARE, 4) != 1)
|
||||
continue;
|
||||
|
||||
GETSHORT(rtype, p);
|
||||
GETSHORT(rclass, p);
|
||||
|
||||
@@ -2442,25 +2458,34 @@ void tcp_request(int confd, time_t now, struct iovec *bigbuff,
|
||||
break;
|
||||
|
||||
/* Now get the query into the normal UDP packet buffer.
|
||||
Ignore queries long than this. If we're answering locally,
|
||||
Ignore queries longer 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. */
|
||||
wants the query in different buffer from the reply.
|
||||
Note that we overwrote any saved UDP query - this only matters in debug mode. */
|
||||
daemon->srv_save = NULL;
|
||||
if (!read_write(confd, (unsigned char *)&tcp_len, sizeof(tcp_len), RW_READ) ||
|
||||
!(size = ntohs(tcp_len)) || size > (size_t)daemon->packet_buff_sz ||
|
||||
!read_write(confd, (unsigned char *)daemon->packet, size, RW_READ))
|
||||
break;
|
||||
|
||||
if (size < (int)sizeof(struct dns_header))
|
||||
/* header == query */
|
||||
header = (struct dns_header *)daemon->packet;
|
||||
|
||||
if (size < (int)sizeof(struct dns_header) || (header->hb3 & HB3_QR))
|
||||
continue;
|
||||
|
||||
/* Make sure we have a buffer big enough for the largest answer. */
|
||||
expand_buf(bigbuff, 65536 + MAXDNAME + RRFIXEDSZ);
|
||||
out_header = bigbuff->iov_base;
|
||||
|
||||
/* header == query */
|
||||
header = (struct dns_header *)daemon->packet;
|
||||
/* Add edns0 pheader to query */
|
||||
size = add_edns0_config(header, size, ((unsigned char *) header) + daemon->packet_buff_sz, &peer_addr, now, &cacheable);
|
||||
|
||||
/* 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);
|
||||
|
||||
query_count++;
|
||||
|
||||
/* log_query gets called indirectly all over the place, so
|
||||
@@ -2493,13 +2518,6 @@ void tcp_request(int confd, time_t now, struct iovec *bigbuff,
|
||||
do_bit = 1; /* do bit */
|
||||
}
|
||||
|
||||
size = add_edns0_config(header, size, ((unsigned char *) header) + daemon->edns_pktsz, &peer_addr, now, &cacheable);
|
||||
|
||||
/* 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,
|
||||
&peer_addr, NULL, qtype);
|
||||
|
||||
@@ -2552,7 +2570,7 @@ void tcp_request(int confd, time_t now, struct iovec *bigbuff,
|
||||
else if (!allowed)
|
||||
{
|
||||
ede = EDE_BLOCKED;
|
||||
m = answer_disallowed(header, size, (u32)mark, daemon->namebuff);
|
||||
m = answer_disallowed(out_header, size, (u32)mark, daemon->namebuff);
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_AUTH
|
||||
@@ -2568,7 +2586,7 @@ void tcp_request(int confd, time_t now, struct iovec *bigbuff,
|
||||
/* Do this by steam now we're not in the select() loop */
|
||||
check_log_writer(1);
|
||||
|
||||
if (m == 0 && ede == EDE_UNSET)
|
||||
if (!flags && m == 0 && ede == EDE_UNSET)
|
||||
{
|
||||
struct server *master;
|
||||
int start;
|
||||
|
||||
+3
-1
@@ -740,9 +740,11 @@ static unsigned char *grab_extradata_lua(unsigned char *buf, unsigned char *end,
|
||||
if (!buf || (buf == end))
|
||||
return NULL;
|
||||
|
||||
for (next = buf; *next != 0; next++)
|
||||
for (next = buf; ; next++)
|
||||
if (next == end)
|
||||
return NULL;
|
||||
else if (*next == 0)
|
||||
break;
|
||||
|
||||
if (next != buf)
|
||||
{
|
||||
|
||||
+25
-10
@@ -40,7 +40,7 @@ static char *inotify_buffer;
|
||||
points to, made absolute if relative.
|
||||
If path doesn't exist or is not a symlink, return NULL.
|
||||
Return value is malloc'ed */
|
||||
static char *my_readlink(char *path)
|
||||
static char *my_readlink(int errfd, char *path)
|
||||
{
|
||||
ssize_t rc, size = 64;
|
||||
char *buf;
|
||||
@@ -59,7 +59,10 @@ static char *my_readlink(char *path)
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
die(_("cannot access path %s: %s"), path, EC_MISC);
|
||||
{
|
||||
send_event(errfd, EVENT_LINK_ERR, errno, path);
|
||||
_exit(0);
|
||||
}
|
||||
}
|
||||
else if (rc < size-1)
|
||||
{
|
||||
@@ -85,15 +88,18 @@ static char *my_readlink(char *path)
|
||||
}
|
||||
}
|
||||
|
||||
void inotify_dnsmasq_init()
|
||||
void inotify_dnsmasq_init(int errfd)
|
||||
{
|
||||
struct resolvc *res;
|
||||
inotify_buffer = safe_malloc(INOTIFY_SZ);
|
||||
daemon->inotifyfd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
|
||||
|
||||
if (daemon->inotifyfd == -1)
|
||||
die(_("failed to create inotify: %s"), NULL, EC_MISC);
|
||||
|
||||
{
|
||||
send_event(errfd, EVENT_INOTFY_ERR, errno, NULL);
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
if (daemon->port == 0 || option_bool(OPT_NO_RESOLV))
|
||||
return;
|
||||
|
||||
@@ -105,10 +111,13 @@ void inotify_dnsmasq_init()
|
||||
strcpy(path, res->name);
|
||||
|
||||
/* Follow symlinks until we reach a non-symlink, or a non-existent file. */
|
||||
while ((new_path = my_readlink(path)))
|
||||
while ((new_path = my_readlink(errfd, path)))
|
||||
{
|
||||
if (links-- == 0)
|
||||
die(_("too many symlinks following %s"), res->name, EC_MISC);
|
||||
{
|
||||
send_event(errfd, EVENT_TMSL_ERR, 0, res->name);
|
||||
_exit(0);
|
||||
}
|
||||
free(path);
|
||||
path = new_path;
|
||||
}
|
||||
@@ -124,12 +133,18 @@ void inotify_dnsmasq_init()
|
||||
*d = '/';
|
||||
|
||||
if (res->wd == -1 && errno == ENOENT)
|
||||
die(_("directory %s for resolv-file is missing, cannot poll"), res->name, EC_MISC);
|
||||
{
|
||||
send_event(errfd, EVENT_RESOLV_ERR, 0, res->name);
|
||||
_exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (res->wd == -1)
|
||||
die(_("failed to create inotify for %s: %s"), res->name, EC_MISC);
|
||||
|
||||
{
|
||||
send_event(errfd, EVENT_IFILE_ERR, errno, res->name);
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+10
-2
@@ -73,7 +73,9 @@ static int read_leases(time_t now, FILE *leasestream)
|
||||
if (lease)
|
||||
{
|
||||
opt_len = parse_hex(daemon->packet, (unsigned char *)daemon->packet, 255, NULL, NULL);
|
||||
|
||||
if (opt_len < 0)
|
||||
continue;
|
||||
|
||||
if (strcmp(daemon->dhcp_buff3, "vendorclass") == 0)
|
||||
lease_set_vendorclass(lease, (unsigned char *)daemon->packet, opt_len);
|
||||
else if (strcmp(daemon->dhcp_buff3, "agent-info") == 0)
|
||||
@@ -99,6 +101,8 @@ static int read_leases(time_t now, FILE *leasestream)
|
||||
|
||||
|
||||
hw_len = parse_hex(daemon->dhcp_buff2, (unsigned char *)daemon->dhcp_buff2, DHCP_CHADDR_MAX, NULL, &hw_type);
|
||||
if (hw_len < 0)
|
||||
hw_len = 0;
|
||||
/* For backwards compatibility, no explicit MAC address type means ether. */
|
||||
if (hw_type == 0 && hw_len != 0)
|
||||
hw_type = ARPHRD_ETHER;
|
||||
@@ -131,7 +135,11 @@ static int read_leases(time_t now, FILE *leasestream)
|
||||
die (_("too many stored leases"), NULL, EC_MISC);
|
||||
|
||||
if (strcmp(daemon->packet, "*") != 0)
|
||||
clid_len = parse_hex(daemon->packet, (unsigned char *)daemon->packet, 255, NULL, NULL);
|
||||
{
|
||||
clid_len = parse_hex(daemon->packet, (unsigned char *)daemon->packet, 255, NULL, NULL);
|
||||
if (clid_len < 0)
|
||||
clid_len = 0;
|
||||
}
|
||||
|
||||
lease_set_hwaddr(lease, (unsigned char *)daemon->dhcp_buff2, (unsigned char *)daemon->packet,
|
||||
hw_len, hw_type, clid_len, now, 0);
|
||||
|
||||
+36
-31
@@ -23,6 +23,9 @@ static volatile int mem_recover = 0;
|
||||
static jmp_buf mem_jmp;
|
||||
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. */
|
||||
#ifdef HAVE_SOLARIS_NETWORK
|
||||
static const struct {
|
||||
@@ -655,13 +658,13 @@ static void unhide_metas(char *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;
|
||||
|
||||
if (mem_recover)
|
||||
{
|
||||
ret = whine_malloc(size);
|
||||
ret = whine_malloc_real(func, line, size);
|
||||
if (!ret)
|
||||
longjmp(mem_jmp, 1);
|
||||
}
|
||||
@@ -4577,39 +4580,41 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
only allowed for agent-options. */
|
||||
|
||||
arg = comma;
|
||||
if ((comma = split(arg)))
|
||||
if (option == 'U' && strstr(arg, "enterprise:") == arg)
|
||||
{
|
||||
if (option != 'U' || strstr(arg, "enterprise:") != arg)
|
||||
comma = split(arg);
|
||||
new->enterprise = atoi(arg+11);
|
||||
arg = comma;
|
||||
}
|
||||
|
||||
if (arg)
|
||||
{
|
||||
for (dig = 0, colon = 0, p = (unsigned char *)arg; *p; p++)
|
||||
if (isxdigit(*p))
|
||||
dig = 1;
|
||||
else if (*p == ':')
|
||||
colon = 1;
|
||||
else
|
||||
break;
|
||||
|
||||
unhide_metas(arg);
|
||||
if (option == 'U' || option == 'j' || *p || !dig || !colon)
|
||||
{
|
||||
free(new->netid.net);
|
||||
ret_err_free(gen_err, new);
|
||||
new->len = strlen(arg);
|
||||
new->data = opt_malloc(new->len);
|
||||
memcpy(new->data, arg, new->len);
|
||||
}
|
||||
else
|
||||
new->enterprise = atoi(arg+11);
|
||||
{
|
||||
new->len = parse_hex(comma, (unsigned char *)arg, strlen(arg), NULL, NULL);
|
||||
new->data = opt_malloc(new->len);
|
||||
memcpy(new->data, arg, new->len);
|
||||
}
|
||||
}
|
||||
else
|
||||
comma = arg;
|
||||
|
||||
for (dig = 0, colon = 0, p = (unsigned char *)comma; *p; p++)
|
||||
if (isxdigit(*p))
|
||||
dig = 1;
|
||||
else if (*p == ':')
|
||||
colon = 1;
|
||||
else
|
||||
break;
|
||||
|
||||
unhide_metas(comma);
|
||||
if (option == 'U' || option == 'j' || *p || !dig || !colon)
|
||||
else if (option != 'U' || new->enterprise == 0)
|
||||
{
|
||||
new->len = strlen(comma);
|
||||
new->data = opt_malloc(new->len);
|
||||
memcpy(new->data, comma, new->len);
|
||||
}
|
||||
else
|
||||
{
|
||||
new->len = parse_hex(comma, (unsigned char *)comma, strlen(comma), NULL, NULL);
|
||||
new->data = opt_malloc(new->len);
|
||||
memcpy(new->data, comma, new->len);
|
||||
free(new->netid.net);
|
||||
ret_err_free(gen_err, new);
|
||||
}
|
||||
|
||||
switch (option)
|
||||
@@ -4632,7 +4637,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
}
|
||||
new->next = daemon->dhcp_vendors;
|
||||
daemon->dhcp_vendors = new;
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -5734,7 +5739,7 @@ struct hostsfile *expand_filelist(struct hostsfile *list)
|
||||
struct dirent **namelist;
|
||||
|
||||
/* 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;
|
||||
|
||||
|
||||
+11
-3
@@ -317,7 +317,7 @@ unsigned char *skip_name(unsigned char *ansp, struct dns_header *header, size_t
|
||||
else if (label_type == 0x40)
|
||||
{
|
||||
/* Extended label type */
|
||||
unsigned int count;
|
||||
unsigned int count, llen;
|
||||
|
||||
if (!CHECK_LEN(header, ansp, plen, 2))
|
||||
return NULL;
|
||||
@@ -328,9 +328,12 @@ unsigned char *skip_name(unsigned char *ansp, struct dns_header *header, size_t
|
||||
count = *(ansp++); /* Bits in bitstring */
|
||||
|
||||
if (count == 0) /* count == 0 means 256 bits */
|
||||
ansp += 32;
|
||||
llen = 32;
|
||||
else
|
||||
ansp += ((count-1)>>3)+1;
|
||||
llen = ((count-1)>>3)+1;
|
||||
|
||||
if (!ADD_RDLEN(header, ansp, plen, llen))
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{ /* label type == 0 Bottom six bits is length */
|
||||
@@ -1427,6 +1430,11 @@ int check_for_ignored_address(struct dns_header *header, size_t qlen)
|
||||
return check_bad_address(header, qlen, daemon->ignore_addr, NULL, NULL);
|
||||
}
|
||||
|
||||
/* Nameoffset > 0 means that the name of the new record already exists at the given offset,
|
||||
so use a "jump" to that.
|
||||
Nameoffset == 0 means use the first variable argument as the name of the new record.
|
||||
nameoffset < 0 means use the first variable argument as the start of the new record name,
|
||||
then "jump" to -nameoffset to complete it. */
|
||||
int add_resource_record(struct dns_header *header, char *limit, int *truncp, int nameoffset, unsigned char **pp,
|
||||
unsigned long ttl, int *offset, unsigned short type, unsigned short class, char *format, ...)
|
||||
{
|
||||
|
||||
+2
-2
@@ -597,7 +597,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
if (mess->file[0])
|
||||
{
|
||||
memcpy(daemon->dhcp_buff2, mess->file, sizeof(mess->file));
|
||||
daemon->dhcp_buff2[sizeof(mess->file) + 1] = 0; /* ensure zero term. */
|
||||
daemon->dhcp_buff2[sizeof(mess->file)] = 0; /* ensure zero term. */
|
||||
id.net = (char *)daemon->dhcp_buff2;
|
||||
id.next = netid;
|
||||
netid = &id;
|
||||
@@ -3248,7 +3248,7 @@ unsigned int relay_reply4(struct dhcp_packet *mess, size_t sz, char *arrival_int
|
||||
|
||||
/* delete agent info before return RFC 3046 para 2.1 */
|
||||
*opt = OPTION_END;
|
||||
memset(opt + 1, 0, option_len(opt) + 2);
|
||||
memset(opt + 1, 0, option_len(opt) + 1);
|
||||
}
|
||||
}
|
||||
else if (mess->giaddr.s_addr == relay->local.addr4.s_addr)
|
||||
|
||||
+93
-111
@@ -21,7 +21,7 @@
|
||||
|
||||
struct state {
|
||||
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;
|
||||
struct dhcp_context *context;
|
||||
struct in6_addr *link_address, *fallback, *ll_addr, *ula_addr;
|
||||
@@ -34,13 +34,13 @@ struct state {
|
||||
};
|
||||
|
||||
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);
|
||||
static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbuff, size_t sz, 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, time_t now);
|
||||
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_quiet(struct state *state, char *type, struct in6_addr *addr, char *string);
|
||||
static void *opt6_find (uint8_t *opts, uint8_t *end, unsigned int search, unsigned int minsize);
|
||||
static void *opt6_next(uint8_t *opts, uint8_t *end);
|
||||
static void *opt6_find (uint8_t *opts, uint8_t *end, unsigned int search, int minsize);
|
||||
static void *opt6_first(uint8_t *opt, uint8_t *end);
|
||||
static unsigned int opt6_uint(unsigned char *opt, int offset, int size);
|
||||
static void get_context_tag(struct state *state, struct dhcp_context *context);
|
||||
static int check_ia(struct state *state, void *opt, void **endp, void **ia_option);
|
||||
@@ -62,6 +62,7 @@ static void calculate_times(struct dhcp_context *context, unsigned int *min_time
|
||||
#define opt6_len(opt) ((int)(opt6_uint(opt, -2, 2)))
|
||||
#define opt6_type(opt) (opt6_uint(opt, -4, 2))
|
||||
#define opt6_ptr(opt, i) ((void *)&(((uint8_t *)(opt))[4+(i)]))
|
||||
#define opt6_next(opt, end) (opt6_first(opt6_ptr((opt), opt6_len((opt))), (end)))
|
||||
|
||||
#define opt6_user_vendor_ptr(opt, i) ((void *)&(((uint8_t *)(opt))[2+(i)]))
|
||||
#define opt6_user_vendor_len(opt) ((int)(opt6_uint(opt, -4, 2)))
|
||||
@@ -80,6 +81,10 @@ unsigned short dhcp6_reply(struct dhcp_context *context, int multicast_dest, int
|
||||
return 0;
|
||||
|
||||
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 */
|
||||
for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
|
||||
@@ -87,7 +92,6 @@ unsigned short dhcp6_reply(struct dhcp_context *context, int multicast_dest, int
|
||||
|
||||
reset_counter();
|
||||
state.context = context;
|
||||
state.multicast_dest = multicast_dest;
|
||||
state.interface = interface;
|
||||
state.iface_name = iface_name;
|
||||
state.fallback = fallback;
|
||||
@@ -97,8 +101,7 @@ unsigned short dhcp6_reply(struct dhcp_context *context, int multicast_dest, int
|
||||
state.tags = NULL;
|
||||
state.link_address = NULL;
|
||||
|
||||
if (dhcp6_maybe_relay(&state, daemon->dhcp_packet.iov_base, sz, client_addr,
|
||||
IN6_IS_ADDR_MULTICAST(client_addr), now))
|
||||
if (dhcp6_maybe_relay(&state, daemon->dhcp_packet.iov_base, sz, client_addr, now))
|
||||
return msg_type == DHCP6RELAYFORW ? DHCPV6_SERVER_PORT : DHCPV6_CLIENT_PORT;
|
||||
|
||||
return 0;
|
||||
@@ -106,15 +109,22 @@ 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. */
|
||||
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 *opts = inbuff + 34;
|
||||
int msg_type = *inbuff;
|
||||
int msg_type;
|
||||
unsigned char *outmsgtypep;
|
||||
uint8_t *opt;
|
||||
struct dhcp_vendor *vendor;
|
||||
|
||||
/* must have at least msg_type+trans_id
|
||||
which is 1 + 3 = 4 */
|
||||
if (sz < 4)
|
||||
return 0;
|
||||
|
||||
msg_type = *inbuff;
|
||||
|
||||
/* if not an encapsulated relayed message, just do the stuff */
|
||||
if (msg_type != DHCP6RELAYFORW)
|
||||
{
|
||||
@@ -184,7 +194,7 @@ static int dhcp6_maybe_relay(struct state *state, unsigned char *inbuff, size_t
|
||||
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
|
||||
@@ -231,11 +241,8 @@ static int dhcp6_maybe_relay(struct state *state, unsigned char *inbuff, size_t
|
||||
memcpy(&state->mac[0], opt6_ptr(opt, 2), state->mac_len);
|
||||
}
|
||||
|
||||
for (opt = opts; opt; opt = opt6_next(opt, end))
|
||||
for (opt = opt6_first(opts, end); opt; opt = opt6_next(opt, end))
|
||||
{
|
||||
if ((uint8_t *)opt6_ptr(opt, 0) + opt6_len(opt) > end)
|
||||
return 0;
|
||||
|
||||
/* Don't copy MAC address into reply. */
|
||||
if (opt6_type(opt) != OPTION6_CLIENT_MAC)
|
||||
{
|
||||
@@ -250,9 +257,7 @@ static int dhcp6_maybe_relay(struct state *state, unsigned char *inbuff, size_t
|
||||
/* RFC6221 para 4 */
|
||||
if (!IN6_IS_ADDR_UNSPECIFIED(&align))
|
||||
state->link_address = &align;
|
||||
/* zero is_unicast since that is now known to refer to the
|
||||
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))
|
||||
if (!dhcp6_maybe_relay(state, opt6_ptr(opt, 0), opt6_len(opt), client_addr, now))
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
@@ -264,7 +269,7 @@ static int dhcp6_maybe_relay(struct state *state, unsigned char *inbuff, size_t
|
||||
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;
|
||||
int i, o, o1, start_opts, start_msg;
|
||||
@@ -290,7 +295,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbu
|
||||
state->hostname = NULL;
|
||||
state->client_hostname = NULL;
|
||||
state->fqdn_flags = 0x01; /* default to send if we receive no FQDN option */
|
||||
|
||||
|
||||
/* set tag with name == interface */
|
||||
iface_id.net = state->iface_name;
|
||||
iface_id.next = state->tags;
|
||||
@@ -340,22 +345,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);
|
||||
|
||||
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. */
|
||||
if (!state->multicast_dest)
|
||||
/* SOLICIT, CONFIRM and REBIND messages MUST NOT have a server-id. 3315 para 15.x */
|
||||
if (opt)
|
||||
return 0;
|
||||
|
||||
/* server-id must match except for SOLICIT, CONFIRM and REBIND messages, which MUST NOT
|
||||
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 ||
|
||||
memcmp(opt6_ptr(opt, 0), daemon->duid, daemon->duid_len) != 0))
|
||||
return 0;
|
||||
}
|
||||
else if (opt)
|
||||
}
|
||||
else if (msg_type == DHCP6IREQ)
|
||||
{
|
||||
/* If server-id provided in IREQ, it must match. */
|
||||
if (opt && (opt6_len(opt) != daemon->duid_len ||
|
||||
memcmp(opt6_ptr(opt, 0), daemon->duid, daemon->duid_len) != 0))
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
@@ -370,18 +370,6 @@ static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbu
|
||||
put_opt6(daemon->duid, daemon->duid_len);
|
||||
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 */
|
||||
for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
|
||||
{
|
||||
@@ -404,13 +392,26 @@ static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbu
|
||||
if (opt6_len(opt) < 4)
|
||||
continue;
|
||||
|
||||
if (vendor->enterprise != opt6_uint(opt, 0, 4))
|
||||
if (vendor->enterprise != 0 && vendor->enterprise != opt6_uint(opt, 0, 4))
|
||||
continue;
|
||||
|
||||
|
||||
/* matching enterprise, no string match. */
|
||||
if (vendor->enterprise != 0 && vendor->len == 0)
|
||||
{
|
||||
vendor->netid.next = state->tags;
|
||||
state->tags = &vendor->netid;
|
||||
break;
|
||||
}
|
||||
|
||||
offset = 4;
|
||||
|
||||
/* If we're going to search the strings below, there must be at least one empty string to search
|
||||
I think a vendor_class option with just the enterprise number is valid. */
|
||||
if (opt6_len(opt) < 6)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Note that format if user/vendor classes is different to DHCP options - no option types. */
|
||||
|
||||
/* Note that format if user/vendor classes is different to DHCP options - no option types. */
|
||||
for (enc_opt = opt6_ptr(opt, offset); enc_opt; enc_opt = opt6_user_vendor_next(enc_opt, enc_end))
|
||||
for (i = 0; i <= (opt6_user_vendor_len(enc_opt) - vendor->len); i++)
|
||||
if (memcmp(vendor->data, opt6_user_vendor_ptr(enc_opt, i), vendor->len) == 0)
|
||||
@@ -674,7 +675,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbu
|
||||
for (c = state->context; c; c = c->current)
|
||||
c->flags &= ~CONTEXT_CONF_USED;
|
||||
|
||||
for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
|
||||
for (opt = opt6_first(state->packet_options, state->end); opt; opt = opt6_next(opt, state->end))
|
||||
{
|
||||
void *ia_option, *ia_end;
|
||||
unsigned int min_time = 0xffffffff;
|
||||
@@ -838,7 +839,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbu
|
||||
if (ignore)
|
||||
return 0;
|
||||
|
||||
for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
|
||||
for (opt = opt6_first(state->packet_options, state->end); opt; opt = opt6_next(opt, state->end))
|
||||
{
|
||||
void *ia_option, *ia_end;
|
||||
unsigned int min_time = 0xffffffff;
|
||||
@@ -949,7 +950,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbu
|
||||
|
||||
log6_quiet(state, msg_type == DHCP6RENEW ? "DHCPRENEW" : "DHCPREBIND", NULL, NULL);
|
||||
|
||||
for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
|
||||
for (opt = opt6_first(state->packet_options, state->end); opt; opt = opt6_next(opt, state->end))
|
||||
{
|
||||
void *ia_option, *ia_end;
|
||||
unsigned int min_time = 0xffffffff;
|
||||
@@ -1084,7 +1085,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbu
|
||||
|
||||
log6_quiet(state, "DHCPCONFIRM", NULL, NULL);
|
||||
|
||||
for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
|
||||
for (opt = opt6_first(state->packet_options, state->end); opt; opt = opt6_next(opt, state->end))
|
||||
{
|
||||
void *ia_option, *ia_end;
|
||||
|
||||
@@ -1160,7 +1161,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbu
|
||||
|
||||
log6_quiet(state, "DHCPRELEASE", NULL, NULL);
|
||||
|
||||
for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
|
||||
for (opt = opt6_first(state->packet_options, state->end); opt; opt = opt6_next(opt, state->end))
|
||||
{
|
||||
void *ia_option, *ia_end;
|
||||
int made_ia = 0;
|
||||
@@ -1225,7 +1226,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbu
|
||||
|
||||
log6_quiet(state, "DHCPDECLINE", NULL, NULL);
|
||||
|
||||
for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
|
||||
for (opt = opt6_first(state->packet_options, state->end); opt; opt = opt6_next(opt, state->end))
|
||||
{
|
||||
void *ia_option, *ia_end;
|
||||
int made_ia = 0;
|
||||
@@ -1304,7 +1305,6 @@ static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbu
|
||||
|
||||
log_tags(tagif, state->xid);
|
||||
|
||||
done:
|
||||
/* Fill in the message type. Note that we store the offset,
|
||||
not a direct pointer, since the packet memory may have been
|
||||
reallocated. */
|
||||
@@ -1598,10 +1598,7 @@ static int check_ia(struct state *state, void *opt, void **endp, void **ia_optio
|
||||
{
|
||||
*ia_option = NULL;
|
||||
|
||||
/* must be a minimal option to check without stepping outside received packet. */
|
||||
if (opt6_ptr(opt, 4) > state->end)
|
||||
return 0;
|
||||
|
||||
/* callee ensures packet is long enough for opt6_len(opt) to be valid and believe-able. */
|
||||
state->ia_type = opt6_type(opt);
|
||||
|
||||
if (state->ia_type != OPTION6_IA_NA && state->ia_type != OPTION6_IA_TA)
|
||||
@@ -1613,10 +1610,7 @@ static int check_ia(struct state *state, void *opt, void **endp, void **ia_optio
|
||||
if (state->ia_type == OPTION6_IA_TA && opt6_len(opt) < 4)
|
||||
return 0;
|
||||
|
||||
/* Check we don't overflow the received packet. */
|
||||
if ((*endp = opt6_ptr(opt, opt6_len(opt))) > state->end)
|
||||
return 0;
|
||||
|
||||
*endp = opt6_ptr(opt, opt6_len(opt));
|
||||
state->iaid = opt6_uint(opt, 0, 4);
|
||||
*ia_option = opt6_find(opt6_ptr(opt, state->ia_type == OPTION6_IA_NA ? 12 : 4), *endp, OPTION6_IAADDR, 24);
|
||||
|
||||
@@ -1931,10 +1925,10 @@ static void update_leases(struct state *state, struct dhcp_context *context, str
|
||||
lease_add_extradata(lease, (unsigned char *)daemon->dhcp_buff2, strlen(daemon->dhcp_buff2), 0);
|
||||
|
||||
if (opt6_len(opt) >= 6)
|
||||
for (enc_opt = opt6_ptr(opt, 4); enc_opt; enc_opt = opt6_next(enc_opt, enc_end))
|
||||
for (enc_opt = opt6_ptr(opt, 4); enc_opt; enc_opt = opt6_user_vendor_next(enc_opt, enc_end))
|
||||
{
|
||||
lease->vendorclass_count++;
|
||||
lease_add_extradata(lease, opt6_ptr(enc_opt, 0), opt6_len(enc_opt), 0);
|
||||
lease_add_extradata(lease, opt6_user_vendor_ptr(enc_opt, 0), opt6_user_vendor_len(enc_opt), 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1991,8 +1985,8 @@ static void update_leases(struct state *state, struct dhcp_context *context, str
|
||||
if ((opt = opt6_find(state->packet_options, state->end, OPTION6_USER_CLASS, 2)))
|
||||
{
|
||||
void *enc_opt, *enc_end = opt6_ptr(opt, opt6_len(opt));
|
||||
for (enc_opt = opt6_ptr(opt, 0); enc_opt; enc_opt = opt6_next(enc_opt, enc_end))
|
||||
lease_add_extradata(lease, opt6_ptr(enc_opt, 0), opt6_len(enc_opt), 0);
|
||||
for (enc_opt = opt6_ptr(opt, 0); enc_opt; enc_opt = opt6_user_vendor_next(enc_opt, enc_end))
|
||||
lease_add_extradata(lease, opt6_user_vendor_ptr(enc_opt, 0), opt6_user_vendor_len(enc_opt), 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -2007,10 +2001,10 @@ static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_op
|
||||
void *opt;
|
||||
char *desc = nest ? "nest" : "sent";
|
||||
|
||||
if (!option_bool(OPT_LOG_OPTS) || start_opts == end_opts)
|
||||
if (!option_bool(OPT_LOG_OPTS))
|
||||
return;
|
||||
|
||||
for (opt = start_opts; opt; opt = opt6_next(opt, end_opts))
|
||||
for (opt = opt6_first(start_opts, end_opts); opt; opt = opt6_next(opt, end_opts))
|
||||
{
|
||||
int type = opt6_type(opt);
|
||||
void *ia_options = NULL;
|
||||
@@ -2043,9 +2037,15 @@ static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_op
|
||||
}
|
||||
else if (type == OPTION6_STATUS_CODE)
|
||||
{
|
||||
int len = sprintf(daemon->namebuff, "%u ", opt6_uint(opt, 0, 2));
|
||||
memcpy(daemon->namebuff + len, opt6_ptr(opt, 2), opt6_len(opt)-2);
|
||||
daemon->namebuff[len + opt6_len(opt) - 2] = 0;
|
||||
if (opt6_len(opt) >= 2)
|
||||
{
|
||||
int slen = opt6_len(opt) - 2;
|
||||
int len = sprintf(daemon->namebuff, "%u ", opt6_uint(opt, 0, 2));
|
||||
if (slen > (MAXDNAME * 2) - len - 1)
|
||||
slen = (MAXDNAME * 2) - len - 1;
|
||||
memcpy(daemon->namebuff + len, opt6_ptr(opt, 2), slen);
|
||||
daemon->namebuff[len + slen] = 0;
|
||||
}
|
||||
optname = "status";
|
||||
}
|
||||
else
|
||||
@@ -2104,49 +2104,31 @@ static void log6_packet(struct state *state, char *type, struct in6_addr *addr,
|
||||
string ? string : "");
|
||||
}
|
||||
|
||||
static void *opt6_find (uint8_t *opts, uint8_t *end, unsigned int search, unsigned int minsize)
|
||||
static void *opt6_find(uint8_t *opts, uint8_t *end, unsigned int search, int minsize)
|
||||
{
|
||||
u16 opt, opt_len;
|
||||
void *start;
|
||||
|
||||
if (!opts)
|
||||
return NULL;
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (end - opts < 4)
|
||||
return NULL;
|
||||
|
||||
start = opts;
|
||||
GETSHORT(opt, opts);
|
||||
GETSHORT(opt_len, opts);
|
||||
|
||||
if (opt_len > (end - opts))
|
||||
return NULL;
|
||||
|
||||
if (opt == search && (opt_len >= minsize))
|
||||
return start;
|
||||
|
||||
opts += opt_len;
|
||||
}
|
||||
for (opts = opt6_first(opts, end); opts; opts = opt6_next(opts, end))
|
||||
if (opt6_type(opts) == search && opt6_len(opts) >= minsize)
|
||||
return opts;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *opt6_next(uint8_t *opts, uint8_t *end)
|
||||
static void *opt6_first(uint8_t *opt, uint8_t *end)
|
||||
{
|
||||
u16 opt_len;
|
||||
|
||||
if (end - opts < 4)
|
||||
if (!opt)
|
||||
return NULL;
|
||||
|
||||
opts += 2;
|
||||
GETSHORT(opt_len, opts);
|
||||
|
||||
if (opt_len >= (end - opts))
|
||||
return NULL;
|
||||
|
||||
return opts + opt_len;
|
||||
}
|
||||
|
||||
/* make sure we have option number and length. */
|
||||
if ((uint8_t *)opt6_ptr(opt, 0) > end)
|
||||
return NULL;
|
||||
|
||||
/* make sure we have bytes promised by length. */
|
||||
if ((uint8_t *)opt6_ptr(opt, opt6_len(opt)) > end)
|
||||
return NULL;
|
||||
|
||||
return opt;
|
||||
}
|
||||
|
||||
static unsigned int opt6_uint(unsigned char *opt, int offset, int size)
|
||||
{
|
||||
/* this worries about unaligned data and byte order */
|
||||
|
||||
@@ -337,27 +337,6 @@ short *rrfilter_desc(int type)
|
||||
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.
|
||||
Also map UC -> LC.
|
||||
Note that using extract_name to get presentation format
|
||||
|
||||
+7
-2
@@ -545,8 +545,13 @@ static struct tftp_file *check_tftp_fileperm(char *packet, ssize_t *len, char *p
|
||||
int fd = -1;
|
||||
|
||||
/* trick to ban moving out of the subtree */
|
||||
if (prefix && strstr(namebuff, "/../"))
|
||||
goto perm;
|
||||
if (prefix)
|
||||
{
|
||||
char *suspect = strstr(namebuff, "/..");
|
||||
|
||||
if (suspect && (suspect[3] == '/' || suspect[3] == 0))
|
||||
goto perm;
|
||||
}
|
||||
|
||||
if ((fd = open(namebuff, O_RDONLY)) == -1)
|
||||
{
|
||||
|
||||
+64
-34
@@ -105,8 +105,6 @@ u32 rand32(void)
|
||||
|
||||
u64 rand64(void)
|
||||
{
|
||||
static int outleft = 0;
|
||||
|
||||
if (outleft < 2)
|
||||
{
|
||||
if (!++in[0]) if (!++in[1]) if (!++in[2]) ++in[3];
|
||||
@@ -266,6 +264,10 @@ char *canonicalise(char *in, int *nomem)
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* IDN library doesnt call our malloc wrapper, so log this by steam */
|
||||
if (ret)
|
||||
malloc_log(ret, strlen(ret)+1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -323,13 +325,15 @@ void *safe_malloc(size_t size)
|
||||
}
|
||||
|
||||
/* Ensure limited size string is always terminated.
|
||||
* Can be replaced by (void)strlcpy() on some platforms */
|
||||
Can be replaced by (void)strlcpy() on some platforms.
|
||||
src may be NULL in which case we return an empty string. */
|
||||
void safe_strncpy(char *dest, const char *src, size_t size)
|
||||
{
|
||||
if (size != 0)
|
||||
{
|
||||
dest[size-1] = '\0';
|
||||
strncpy(dest, src, size-1);
|
||||
dest[0] = dest[size-1] = '\0';
|
||||
if (src)
|
||||
strncpy(dest, src, size-1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -575,6 +579,7 @@ void prettyprint_time(char *buf, unsigned int t)
|
||||
else
|
||||
{
|
||||
unsigned int x, p = 0;
|
||||
buf[0] = '\0';
|
||||
if ((x = t/86400))
|
||||
p += sprintf(&buf[p], "%ud", x);
|
||||
if ((x = (t/3600)%24))
|
||||
@@ -672,32 +677,6 @@ int memcmp_masked(unsigned char *a, unsigned char *b, int len, unsigned int mask
|
||||
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 *p = buff;
|
||||
@@ -790,7 +769,7 @@ int read_writev(int fd, struct iovec *iov, int iovcnt, int rw)
|
||||
return 0;
|
||||
|
||||
done += n;
|
||||
while ((size_t)done >= iov[cur].iov_len)
|
||||
while (cur < iovcnt && (size_t)done >= iov[cur].iov_len)
|
||||
done -= iov[cur++].iov_len;
|
||||
}
|
||||
|
||||
@@ -961,7 +940,7 @@ void *whine_malloc_real(const char *func, unsigned int line, size_t size)
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *whine_realloc_real(const char *func, unsigned int line, void *ptr, size_t size)
|
||||
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);
|
||||
@@ -969,11 +948,62 @@ void *whine_realloc_real(const char *func, unsigned int line, void *ptr, size_t
|
||||
if (!ret)
|
||||
my_syslog(LOG_ERR, _("failed to reallocate %d bytes"), (int) size);
|
||||
else if (daemon->log_malloc)
|
||||
my_syslog(LOG_INFO, _("realloc: %s:%u %zu bytes from %x to %x"), func, line, size, old, hash_ptr(ret));
|
||||
{
|
||||
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) * sizeof(unsigned char *));
|
||||
|
||||
*wkspc = p;
|
||||
*szp = new;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void malloc_log_real(const char *func, unsigned int line, void *mem, size_t size)
|
||||
{
|
||||
if (mem && daemon->log_malloc)
|
||||
my_syslog(LOG_INFO, _("malloc: %s:%u %zu bytes at %x"), func, line, size, hash_ptr(mem));
|
||||
}
|
||||
|
||||
#undef free
|
||||
void free_real(const char *func, unsigned int line, void *ptr)
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user