mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 18:28:25 +00:00
First functional DNSSEC - highly alpha.
This commit is contained in:
75
src/cache.c
75
src/cache.c
@@ -56,6 +56,8 @@ static const struct {
|
|||||||
{ 38, "A6" },
|
{ 38, "A6" },
|
||||||
{ 39, "DNAME" },
|
{ 39, "DNAME" },
|
||||||
{ 41, "OPT" },
|
{ 41, "OPT" },
|
||||||
|
{ 43, "DS" },
|
||||||
|
{ 46, "RRSIG" },
|
||||||
{ 48, "DNSKEY" },
|
{ 48, "DNSKEY" },
|
||||||
{ 249, "TKEY" },
|
{ 249, "TKEY" },
|
||||||
{ 250, "TSIG" },
|
{ 250, "TSIG" },
|
||||||
@@ -916,12 +918,19 @@ void cache_reload(void)
|
|||||||
struct name_list *nl;
|
struct name_list *nl;
|
||||||
struct cname *a;
|
struct cname *a;
|
||||||
struct interface_name *intr;
|
struct interface_name *intr;
|
||||||
|
#ifdef HAVE_DNSSEC
|
||||||
|
struct dnskey *key;
|
||||||
|
#endif
|
||||||
|
|
||||||
cache_inserted = cache_live_freed = 0;
|
cache_inserted = cache_live_freed = 0;
|
||||||
|
|
||||||
for (i=0; i<hash_size; i++)
|
for (i=0; i<hash_size; i++)
|
||||||
for (cache = hash_table[i], up = &hash_table[i]; cache; cache = tmp)
|
for (cache = hash_table[i], up = &hash_table[i]; cache; cache = tmp)
|
||||||
{
|
{
|
||||||
|
#ifdef HAVE_DNSSEC
|
||||||
|
if (cache->flags & (F_DNSKEY | F_DS))
|
||||||
|
blockdata_free(cache->addr.key.keydata);
|
||||||
|
#endif
|
||||||
tmp = cache->hash_next;
|
tmp = cache->hash_next;
|
||||||
if (cache->flags & (F_HOSTS | F_CONFIG))
|
if (cache->flags & (F_HOSTS | F_CONFIG))
|
||||||
{
|
{
|
||||||
@@ -948,7 +957,7 @@ void cache_reload(void)
|
|||||||
if (hostname_isequal(a->target, intr->name) &&
|
if (hostname_isequal(a->target, intr->name) &&
|
||||||
((cache = whine_malloc(sizeof(struct crec)))))
|
((cache = whine_malloc(sizeof(struct 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 | F_DNSSECOK;
|
||||||
cache->name.namep = a->alias;
|
cache->name.namep = a->alias;
|
||||||
cache->addr.cname.target.int_name = intr;
|
cache->addr.cname.target.int_name = intr;
|
||||||
cache->addr.cname.uid = -1;
|
cache->addr.cname.uid = -1;
|
||||||
@@ -956,6 +965,20 @@ void cache_reload(void)
|
|||||||
add_hosts_cname(cache); /* handle chains */
|
add_hosts_cname(cache); /* handle chains */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_DNSSEC
|
||||||
|
for (key = daemon->dnskeys; key; key = key->next)
|
||||||
|
if ((cache = whine_malloc(sizeof(struct crec))) &&
|
||||||
|
(cache->addr.key.keydata = blockdata_alloc(key->key, key->keylen)))
|
||||||
|
{
|
||||||
|
cache->flags = F_FORWARD | F_IMMORTAL | F_DNSKEY | F_CONFIG | F_NAMEP;
|
||||||
|
cache->name.namep = key->name;
|
||||||
|
cache->uid = key->keylen;
|
||||||
|
cache->addr.key.algo = key->algo;
|
||||||
|
cache->addr.key.keytag = dnskey_keytag(key->algo, key->flags, (unsigned char *)key->key, key->keylen);
|
||||||
|
cache_hash(cache);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* borrow the packet buffer for a temporary by-address hash */
|
/* borrow the packet buffer for a temporary by-address hash */
|
||||||
memset(daemon->packet, 0, daemon->packet_buff_sz);
|
memset(daemon->packet, 0, daemon->packet_buff_sz);
|
||||||
revhashsz = daemon->packet_buff_sz / sizeof(struct crec *);
|
revhashsz = daemon->packet_buff_sz / sizeof(struct crec *);
|
||||||
@@ -1197,16 +1220,13 @@ void dump_cache(time_t now)
|
|||||||
for (i=0; i<hash_size; i++)
|
for (i=0; i<hash_size; i++)
|
||||||
for (cache = hash_table[i]; cache; cache = cache->hash_next)
|
for (cache = hash_table[i]; cache; cache = cache->hash_next)
|
||||||
{
|
{
|
||||||
char *a, *p = daemon->namebuff;
|
char *a = daemon->addrbuff, *p = daemon->namebuff, *n = cache_get_name(cache);
|
||||||
p += sprintf(p, "%-40.40s ", cache_get_name(cache));
|
*a = 0;
|
||||||
if ((cache->flags & F_NEG) && (cache->flags & F_FORWARD))
|
if (strlen(n) == 0)
|
||||||
a = "";
|
n = "<Root>";
|
||||||
else if (cache->flags & F_CNAME)
|
p += sprintf(p, "%-40.40s ", n);
|
||||||
{
|
if ((cache->flags & F_CNAME) && !is_outdated_cname_pointer(cache))
|
||||||
a = "";
|
|
||||||
if (!is_outdated_cname_pointer(cache))
|
|
||||||
a = cache_get_cname_target(cache);
|
a = cache_get_cname_target(cache);
|
||||||
}
|
|
||||||
#ifdef HAVE_DNSSEC
|
#ifdef HAVE_DNSSEC
|
||||||
else if (cache->flags & F_DNSKEY)
|
else if (cache->flags & F_DNSKEY)
|
||||||
{
|
{
|
||||||
@@ -1216,11 +1236,11 @@ void dump_cache(time_t now)
|
|||||||
else if (cache->flags & F_DS)
|
else if (cache->flags & F_DS)
|
||||||
{
|
{
|
||||||
a = daemon->addrbuff;
|
a = daemon->addrbuff;
|
||||||
sprintf(a, "%5u %3u %3u %u", cache->addr.key.keytag,
|
sprintf(a, "%5u %3u %3u", cache->addr.key.keytag,
|
||||||
cache->addr.key.algo, cache->addr.key.digest, cache->uid);
|
cache->addr.key.algo, cache->addr.key.digest);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
else
|
else if (!(cache->flags & F_NEG) || !(cache->flags & F_FORWARD))
|
||||||
{
|
{
|
||||||
a = daemon->addrbuff;
|
a = daemon->addrbuff;
|
||||||
if (cache->flags & F_IPV4)
|
if (cache->flags & F_IPV4)
|
||||||
@@ -1291,6 +1311,10 @@ void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
|
|||||||
|
|
||||||
if (addr)
|
if (addr)
|
||||||
{
|
{
|
||||||
|
if (flags & F_KEYTAG)
|
||||||
|
sprintf(daemon->addrbuff, arg, addr->addr.keytag);
|
||||||
|
else
|
||||||
|
{
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
|
inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
|
||||||
addr, daemon->addrbuff, ADDRSTRLEN);
|
addr, daemon->addrbuff, ADDRSTRLEN);
|
||||||
@@ -1298,6 +1322,9 @@ void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
|
|||||||
strncpy(daemon->addrbuff, inet_ntoa(addr->addr.addr4), ADDRSTRLEN);
|
strncpy(daemon->addrbuff, inet_ntoa(addr->addr.addr4), ADDRSTRLEN);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
dest = arg;
|
||||||
|
|
||||||
if (flags & F_REVERSE)
|
if (flags & F_REVERSE)
|
||||||
{
|
{
|
||||||
@@ -1339,6 +1366,8 @@ void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
|
|||||||
source = arg;
|
source = arg;
|
||||||
else if (flags & F_UPSTREAM)
|
else if (flags & F_UPSTREAM)
|
||||||
source = "reply";
|
source = "reply";
|
||||||
|
else if (flags & F_SECSTAT)
|
||||||
|
source = "validation";
|
||||||
else if (flags & F_AUTH)
|
else if (flags & F_AUTH)
|
||||||
source = "auth";
|
source = "auth";
|
||||||
else if (flags & F_SERVER)
|
else if (flags & F_SERVER)
|
||||||
@@ -1351,6 +1380,11 @@ void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
|
|||||||
source = arg;
|
source = arg;
|
||||||
verb = "from";
|
verb = "from";
|
||||||
}
|
}
|
||||||
|
else if (flags & F_DNSSEC)
|
||||||
|
{
|
||||||
|
source = arg;
|
||||||
|
verb = "to";
|
||||||
|
}
|
||||||
else
|
else
|
||||||
source = "cached";
|
source = "cached";
|
||||||
|
|
||||||
@@ -1422,6 +1456,21 @@ void blockdata_free(struct blockdata *blocks)
|
|||||||
keyblock_free = blocks;
|
keyblock_free = blocks;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void blockdata_retrieve(struct blockdata *block, size_t len, void *data)
|
||||||
|
{
|
||||||
|
size_t blen;
|
||||||
|
struct blockdata *b;
|
||||||
|
|
||||||
|
for (b = block; len > 0 && b; b = b->next)
|
||||||
|
{
|
||||||
|
blen = len > KEYBLOCK_LEN ? KEYBLOCK_LEN : len;
|
||||||
|
memcpy(data, b->key, blen);
|
||||||
|
data += blen;
|
||||||
|
len -= blen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -385,7 +385,12 @@ static char *compile_opts =
|
|||||||
#ifndef HAVE_AUTH
|
#ifndef HAVE_AUTH
|
||||||
"no-"
|
"no-"
|
||||||
#endif
|
#endif
|
||||||
"auth";
|
"auth "
|
||||||
|
#ifndef HAVE_DNSSEC
|
||||||
|
"no-"
|
||||||
|
#endif
|
||||||
|
"DNSSEC";
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -242,6 +242,7 @@ struct all_addr {
|
|||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
struct in6_addr addr6;
|
struct in6_addr addr6;
|
||||||
#endif
|
#endif
|
||||||
|
unsigned int keytag;
|
||||||
} addr;
|
} addr;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -286,6 +287,12 @@ struct cname {
|
|||||||
struct cname *next;
|
struct cname *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct dnskey {
|
||||||
|
char *name, *key;
|
||||||
|
int keylen, algo, flags;
|
||||||
|
struct dnskey *next;
|
||||||
|
};
|
||||||
|
|
||||||
#define ADDRLIST_LITERAL 1
|
#define ADDRLIST_LITERAL 1
|
||||||
#define ADDRLIST_IPV6 2
|
#define ADDRLIST_IPV6 2
|
||||||
|
|
||||||
@@ -360,7 +367,7 @@ struct crec {
|
|||||||
} key;
|
} key;
|
||||||
} addr;
|
} addr;
|
||||||
time_t ttd; /* time to die */
|
time_t ttd; /* time to die */
|
||||||
/* used as keylen if F_DS or F_DNSKEY, index to source for F_HOSTS */
|
/* used as keylen ifF_DNSKEY, index to source for F_HOSTS */
|
||||||
int uid;
|
int uid;
|
||||||
unsigned short flags;
|
unsigned short flags;
|
||||||
union {
|
union {
|
||||||
@@ -395,6 +402,9 @@ struct crec {
|
|||||||
#define F_QUERY (1u<<19)
|
#define F_QUERY (1u<<19)
|
||||||
#define F_NOERR (1u<<20)
|
#define F_NOERR (1u<<20)
|
||||||
#define F_AUTH (1u<<21)
|
#define F_AUTH (1u<<21)
|
||||||
|
#define F_DNSSEC (1u<<22)
|
||||||
|
#define F_KEYTAG (1u<<23)
|
||||||
|
#define F_SECSTAT (1u<<24)
|
||||||
|
|
||||||
/* composites */
|
/* composites */
|
||||||
#define F_TYPE (F_IPV4 | F_IPV6 | F_DNSKEY | F_DS) /* Only one may be set */
|
#define F_TYPE (F_IPV4 | F_IPV6 | F_DNSKEY | F_DS) /* Only one may be set */
|
||||||
@@ -896,6 +906,9 @@ extern struct daemon {
|
|||||||
#ifdef OPTION6_PREFIX_CLASS
|
#ifdef OPTION6_PREFIX_CLASS
|
||||||
struct prefix_class *prefix_classes;
|
struct prefix_class *prefix_classes;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAVE_DNSSEC
|
||||||
|
struct dnskey *dnskeys;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* globally used stuff for DNS */
|
/* globally used stuff for DNS */
|
||||||
char *packet; /* packet buffer */
|
char *packet; /* packet buffer */
|
||||||
@@ -977,6 +990,7 @@ struct crec *cache_enumerate(int init);
|
|||||||
#ifdef HAVE_DNSSEC
|
#ifdef HAVE_DNSSEC
|
||||||
struct blockdata *blockdata_alloc(char *data, size_t len);
|
struct blockdata *blockdata_alloc(char *data, size_t len);
|
||||||
size_t blockdata_walk(struct blockdata **key, unsigned char **p, size_t cnt);
|
size_t blockdata_walk(struct blockdata **key, unsigned char **p, size_t cnt);
|
||||||
|
void blockdata_retrieve(struct blockdata *block, size_t len, void *data);
|
||||||
void blockdata_free(struct blockdata *blocks);
|
void blockdata_free(struct blockdata *blocks);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -1000,7 +1014,7 @@ size_t setup_reply(struct dns_header *header, size_t qlen,
|
|||||||
unsigned long local_ttl);
|
unsigned long local_ttl);
|
||||||
int extract_addresses(struct dns_header *header, size_t qlen, char *namebuff,
|
int extract_addresses(struct dns_header *header, size_t qlen, char *namebuff,
|
||||||
time_t now, char **ipsets, int is_sign, int checkrebind,
|
time_t now, char **ipsets, int is_sign, int checkrebind,
|
||||||
int checking_disabled);
|
int no_cache, int secure);
|
||||||
size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||||
struct in_addr local_addr, struct in_addr local_netmask, time_t now);
|
struct in_addr local_addr, struct in_addr local_netmask, time_t now);
|
||||||
int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
|
int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
|
||||||
@@ -1034,11 +1048,13 @@ int in_zone(struct auth_zone *zone, char *name, char **cut);
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* dnssec.c */
|
/* dnssec.c */
|
||||||
size_t dnssec_generate_query(struct dns_header *header, char *name, int class, int type);
|
size_t dnssec_generate_query(struct dns_header *header, char *name, int class, int type, union mysockaddr *addr);
|
||||||
int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t n, char *name, char *keyname, int class);
|
int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t n, char *name, char *keyname, int class);
|
||||||
int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class);
|
int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class);
|
||||||
int validate_rrset(time_t now, struct dns_header *header, size_t plen, int class, int type, char *name, char *keyname);
|
int validate_rrset(time_t now, struct dns_header *header, size_t plen, int class,
|
||||||
int dnssec_validate_reply(struct dns_header *header, size_t plen, char *name, char *keyname, int *class);
|
int type, char *name, char *keyname, struct blockdata *key, int keylen, int algo, int keytag);
|
||||||
|
int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int *class);
|
||||||
|
int dnskey_keytag(int alg, int flags, unsigned char *rdata, int rdlen);
|
||||||
|
|
||||||
/* util.c */
|
/* util.c */
|
||||||
void rand_init(void);
|
void rand_init(void);
|
||||||
@@ -1065,6 +1081,9 @@ void prettyprint_time(char *buf, unsigned int t);
|
|||||||
int prettyprint_addr(union mysockaddr *addr, char *buf);
|
int prettyprint_addr(union mysockaddr *addr, char *buf);
|
||||||
int parse_hex(char *in, unsigned char *out, int maxlen,
|
int parse_hex(char *in, unsigned char *out, int maxlen,
|
||||||
unsigned int *wildcard_mask, int *mac_type);
|
unsigned int *wildcard_mask, int *mac_type);
|
||||||
|
#ifdef HAVE_DNSSEC
|
||||||
|
int parse_base64(char *in, char *out);
|
||||||
|
#endif
|
||||||
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);
|
int expand_buf(struct iovec *iov, size_t size);
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
#ifndef DNSSEC_CRYPTO_H
|
#ifndef DNSSEC_CRYPTO_H
|
||||||
#define DNSSEC_CRYPTO_H
|
#define DNSSEC_CRYPTO_H
|
||||||
|
|
||||||
struct keydata;
|
struct blockdata;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* vtable for a signature verification algorithm.
|
* vtable for a signature verification algorithm.
|
||||||
@@ -49,7 +49,7 @@ typedef struct VerifyAlgCtx VerifyAlgCtx;
|
|||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
int digest_algo;
|
int digest_algo;
|
||||||
int (*verify)(VerifyAlgCtx *ctx, struct keydata *key, unsigned key_len);
|
int (*verify)(VerifyAlgCtx *ctx, struct blockdata *key, unsigned key_len);
|
||||||
} VerifyAlg;
|
} VerifyAlg;
|
||||||
|
|
||||||
struct VerifyAlgCtx
|
struct VerifyAlgCtx
|
||||||
@@ -74,9 +74,9 @@ int verifyalg_algonum(VerifyAlgCtx *a);
|
|||||||
#define DIGESTALG_SHA512 257
|
#define DIGESTALG_SHA512 257
|
||||||
|
|
||||||
int digestalg_supported(int algo);
|
int digestalg_supported(int algo);
|
||||||
int digestalg_begin(int algo);
|
void digestalg_begin(int algo);
|
||||||
void digestalg_add_data(void *data, unsigned len);
|
void digestalg_add_data(void *data, unsigned len);
|
||||||
void digestalg_add_keydata(struct keydata *key, size_t len);
|
void digestalg_add_keydata(struct blockdata *key, size_t len);
|
||||||
unsigned char *digestalg_final(void);
|
unsigned char *digestalg_final(void);
|
||||||
int digestalg_len(void);
|
int digestalg_len(void);
|
||||||
|
|
||||||
|
|||||||
@@ -14,13 +14,16 @@
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include "dnsmasq.h"
|
#include "dnsmasq.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_DNSSEC
|
||||||
|
|
||||||
#include "dnssec-crypto.h"
|
#include "dnssec-crypto.h"
|
||||||
#include <openssl/evp.h>
|
#include <openssl/evp.h>
|
||||||
#include <openssl/rsa.h>
|
#include <openssl/rsa.h>
|
||||||
#include <openssl/dsa.h>
|
#include <openssl/dsa.h>
|
||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#define POOL_SIZE 1
|
#define POOL_SIZE 1
|
||||||
static union _Pool
|
static union _Pool
|
||||||
@@ -39,20 +42,20 @@ static void print_hex(unsigned char *data, unsigned len)
|
|||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static int keydata_to_bn(BIGNUM *ret, struct keydata **key_data, unsigned char **p, unsigned len)
|
static int keydata_to_bn(BIGNUM *ret, struct blockdata **key_data, unsigned char **p, unsigned len)
|
||||||
{
|
{
|
||||||
size_t cnt;
|
size_t cnt;
|
||||||
BIGNUM temp;
|
BIGNUM temp;
|
||||||
|
|
||||||
BN_init(ret);
|
BN_init(ret);
|
||||||
|
|
||||||
cnt = keydata_walk(key_data, p, len);
|
cnt = blockdata_walk(key_data, p, len);
|
||||||
BN_bin2bn(*p, cnt, ret);
|
BN_bin2bn(*p, cnt, ret);
|
||||||
len -= cnt;
|
len -= cnt;
|
||||||
*p += cnt;
|
*p += cnt;
|
||||||
while (len > 0)
|
while (len > 0)
|
||||||
{
|
{
|
||||||
if (!(cnt = keydata_walk(key_data, p, len)))
|
if (!(cnt = blockdata_walk(key_data, p, len)))
|
||||||
return 0;
|
return 0;
|
||||||
BN_lshift(ret, ret, cnt*8);
|
BN_lshift(ret, ret, cnt*8);
|
||||||
BN_init(&temp);
|
BN_init(&temp);
|
||||||
@@ -64,7 +67,7 @@ static int keydata_to_bn(BIGNUM *ret, struct keydata **key_data, unsigned char *
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rsasha1_parse_key(BIGNUM *exp, BIGNUM *mod, struct keydata *key_data, unsigned key_len)
|
static int rsasha1_parse_key(BIGNUM *exp, BIGNUM *mod, struct blockdata *key_data, unsigned key_len)
|
||||||
{
|
{
|
||||||
unsigned char *p = key_data->key;
|
unsigned char *p = key_data->key;
|
||||||
size_t exp_len, mod_len;
|
size_t exp_len, mod_len;
|
||||||
@@ -80,7 +83,7 @@ static int rsasha1_parse_key(BIGNUM *exp, BIGNUM *mod, struct keydata *key_data,
|
|||||||
keydata_to_bn(mod, &key_data, &p, mod_len);
|
keydata_to_bn(mod, &key_data, &p, mod_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dsasha1_parse_key(BIGNUM *Q, BIGNUM *P, BIGNUM *G, BIGNUM *Y, struct keydata *key_data, unsigned key_len)
|
static int dsasha1_parse_key(BIGNUM *Q, BIGNUM *P, BIGNUM *G, BIGNUM *Y, struct blockdata *key_data, unsigned key_len)
|
||||||
{
|
{
|
||||||
unsigned char *p = key_data->key;
|
unsigned char *p = key_data->key;
|
||||||
int T;
|
int T;
|
||||||
@@ -93,7 +96,7 @@ static int dsasha1_parse_key(BIGNUM *Q, BIGNUM *P, BIGNUM *G, BIGNUM *Y, struct
|
|||||||
keydata_to_bn(Y, &key_data, &p, 64+T*8);
|
keydata_to_bn(Y, &key_data, &p, 64+T*8);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rsa_verify(VerifyAlgCtx *ctx, struct keydata *key_data, unsigned key_len, int nid, int dlen)
|
static int rsa_verify(VerifyAlgCtx *ctx, struct blockdata *key_data, unsigned key_len, int nid, int dlen)
|
||||||
{
|
{
|
||||||
int validated = 0;
|
int validated = 0;
|
||||||
|
|
||||||
@@ -108,27 +111,27 @@ static int rsa_verify(VerifyAlgCtx *ctx, struct keydata *key_data, unsigned key_
|
|||||||
return validated;
|
return validated;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rsamd5_verify(VerifyAlgCtx *ctx, struct keydata *key_data, unsigned key_len)
|
static int rsamd5_verify(VerifyAlgCtx *ctx, struct blockdata *key_data, unsigned key_len)
|
||||||
{
|
{
|
||||||
return rsa_verify(ctx, key_data, key_len, NID_md5, 16);
|
return rsa_verify(ctx, key_data, key_len, NID_md5, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rsasha1_verify(VerifyAlgCtx *ctx, struct keydata *key_data, unsigned key_len)
|
static int rsasha1_verify(VerifyAlgCtx *ctx, struct blockdata *key_data, unsigned key_len)
|
||||||
{
|
{
|
||||||
return rsa_verify(ctx, key_data, key_len, NID_sha1, 20);
|
return rsa_verify(ctx, key_data, key_len, NID_sha1, 20);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rsasha256_verify(VerifyAlgCtx *ctx, struct keydata *key_data, unsigned key_len)
|
static int rsasha256_verify(VerifyAlgCtx *ctx, struct blockdata *key_data, unsigned key_len)
|
||||||
{
|
{
|
||||||
return rsa_verify(ctx, key_data, key_len, NID_sha256, 32);
|
return rsa_verify(ctx, key_data, key_len, NID_sha256, 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rsasha512_verify(VerifyAlgCtx *ctx, struct keydata *key_data, unsigned key_len)
|
static int rsasha512_verify(VerifyAlgCtx *ctx, struct blockdata *key_data, unsigned key_len)
|
||||||
{
|
{
|
||||||
return rsa_verify(ctx, key_data, key_len, NID_sha512, 64);
|
return rsa_verify(ctx, key_data, key_len, NID_sha512, 64);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dsasha1_verify(VerifyAlgCtx *ctx, struct keydata *key_data, unsigned key_len)
|
static int dsasha1_verify(VerifyAlgCtx *ctx, struct blockdata *key_data, unsigned key_len)
|
||||||
{
|
{
|
||||||
static unsigned char asn1_signature[] =
|
static unsigned char asn1_signature[] =
|
||||||
{
|
{
|
||||||
@@ -222,9 +225,6 @@ VerifyAlgCtx* verifyalg_alloc(int algo)
|
|||||||
int i;
|
int i;
|
||||||
VerifyAlgCtx *ret = 0;
|
VerifyAlgCtx *ret = 0;
|
||||||
|
|
||||||
if (!verifyalg_supported(algo))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (pool_used == (1<<POOL_SIZE)-1)
|
if (pool_used == (1<<POOL_SIZE)-1)
|
||||||
ret = whine_malloc(valgctx_size[algo]);
|
ret = whine_malloc(valgctx_size[algo]);
|
||||||
else
|
else
|
||||||
@@ -271,7 +271,7 @@ int digestalg_supported(int algo)
|
|||||||
algo == DIGESTALG_SHA512);
|
algo == DIGESTALG_SHA512);
|
||||||
}
|
}
|
||||||
|
|
||||||
int digestalg_begin(int algo)
|
void digestalg_begin(int algo)
|
||||||
{
|
{
|
||||||
EVP_MD_CTX_init(&digctx);
|
EVP_MD_CTX_init(&digctx);
|
||||||
if (algo == DIGESTALG_SHA1)
|
if (algo == DIGESTALG_SHA1)
|
||||||
@@ -282,9 +282,6 @@ int digestalg_begin(int algo)
|
|||||||
EVP_DigestInit_ex(&digctx, EVP_sha512(), NULL);
|
EVP_DigestInit_ex(&digctx, EVP_sha512(), NULL);
|
||||||
else if (algo == DIGESTALG_MD5)
|
else if (algo == DIGESTALG_MD5)
|
||||||
EVP_DigestInit_ex(&digctx, EVP_md5(), NULL);
|
EVP_DigestInit_ex(&digctx, EVP_md5(), NULL);
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int digestalg_len()
|
int digestalg_len()
|
||||||
@@ -297,12 +294,12 @@ void digestalg_add_data(void *data, unsigned len)
|
|||||||
EVP_DigestUpdate(&digctx, data, len);
|
EVP_DigestUpdate(&digctx, data, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
void digestalg_add_keydata(struct keydata *key, size_t len)
|
void digestalg_add_keydata(struct blockdata *key, size_t len)
|
||||||
{
|
{
|
||||||
size_t cnt; unsigned char *p = NULL;
|
size_t cnt; unsigned char *p = NULL;
|
||||||
while (len)
|
while (len)
|
||||||
{
|
{
|
||||||
cnt = keydata_walk(&key, &p, len);
|
cnt = blockdata_walk(&key, &p, len);
|
||||||
EVP_DigestUpdate(&digctx, p, cnt);
|
EVP_DigestUpdate(&digctx, p, cnt);
|
||||||
p += cnt;
|
p += cnt;
|
||||||
len -= cnt;
|
len -= cnt;
|
||||||
@@ -316,3 +313,4 @@ unsigned char* digestalg_final(void)
|
|||||||
return digest;
|
return digest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif /* HAVE_DNSSEC */
|
||||||
|
|||||||
879
src/dnssec.c
879
src/dnssec.c
File diff suppressed because it is too large
Load Diff
@@ -344,7 +344,10 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||||||
|
|
||||||
#ifdef HAVE_DNSSEC
|
#ifdef HAVE_DNSSEC
|
||||||
if (option_bool(OPT_DNSSEC_VALID))
|
if (option_bool(OPT_DNSSEC_VALID))
|
||||||
|
{
|
||||||
plen = add_do_bit(header, plen, ((char *) header) + PACKETSZ);
|
plen = add_do_bit(header, plen, ((char *) header) + PACKETSZ);
|
||||||
|
header->hb4 |= HB4_CD;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
@@ -550,7 +553,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
|||||||
SET_RCODE(header, NOERROR);
|
SET_RCODE(header, NOERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (extract_addresses(header, n, daemon->namebuff, now, sets, is_sign, check_rebind, no_cache))
|
if (extract_addresses(header, n, daemon->namebuff, now, sets, is_sign, check_rebind, no_cache, cache_secure))
|
||||||
{
|
{
|
||||||
my_syslog(LOG_WARNING, _("possible DNS-rebind attack detected: %s"), daemon->namebuff);
|
my_syslog(LOG_WARNING, _("possible DNS-rebind attack detected: %s"), daemon->namebuff);
|
||||||
munged = 1;
|
munged = 1;
|
||||||
@@ -678,41 +681,51 @@ void reply_query(int fd, int family, time_t now)
|
|||||||
if (option_bool(OPT_DNSSEC_VALID) && !(forward->flags & FREC_CHECKING_DISABLED))
|
if (option_bool(OPT_DNSSEC_VALID) && !(forward->flags & FREC_CHECKING_DISABLED))
|
||||||
{
|
{
|
||||||
int status;
|
int status;
|
||||||
int class;
|
|
||||||
|
/* We've had a reply already, which we're validating. Ignore this duplicate */
|
||||||
|
if (forward->stash)
|
||||||
|
return;
|
||||||
|
|
||||||
if (forward->flags & FREC_DNSKEY_QUERY)
|
if (forward->flags & FREC_DNSKEY_QUERY)
|
||||||
status = dnssec_validate_by_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
|
status = dnssec_validate_by_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
|
||||||
else if (forward->flags & FREC_DS_QUERY)
|
else if (forward->flags & FREC_DS_QUERY)
|
||||||
status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
|
status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
|
||||||
else
|
else
|
||||||
status = dnssec_validate_reply(header, n, daemon->namebuff, daemon->keyname, &forward->class);
|
status = dnssec_validate_reply(now, header, n, daemon->namebuff, daemon->keyname, &forward->class);
|
||||||
|
|
||||||
/* Can't validate, as we're missing key data. Put this
|
/* Can't validate, as we're missing key data. Put this
|
||||||
answer aside, whilst we get that. */
|
answer aside, whilst we get that. */
|
||||||
if (status == STAT_NEED_DS || status == STAT_NEED_KEY)
|
if (status == STAT_NEED_DS || status == STAT_NEED_KEY)
|
||||||
{
|
{
|
||||||
struct frec *new;
|
struct frec *new;
|
||||||
if ((forward->stash = blockdata_alloc((char *)header, n)))
|
|
||||||
{
|
|
||||||
forward->stash_len = n;
|
|
||||||
|
|
||||||
if ((new = get_new_frec(now, NULL, 1)))
|
if ((new = get_new_frec(now, NULL, 1)))
|
||||||
|
{
|
||||||
|
struct frec *next = new->next;
|
||||||
|
*new = *forward; /* copy everything, then overwrite */
|
||||||
|
new->next = next;
|
||||||
|
new->stash = NULL;
|
||||||
|
new->blocking_query = NULL;
|
||||||
|
new->flags &= ~(FREC_DNSKEY_QUERY | FREC_DS_QUERY);
|
||||||
|
|
||||||
|
if ((forward->stash = blockdata_alloc((char *)header, n)))
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
new = forward; /* copy everything, then overwrite */
|
forward->stash_len = n;
|
||||||
|
|
||||||
new->dependent = forward; /* to find query awaiting new one. */
|
new->dependent = forward; /* to find query awaiting new one. */
|
||||||
forward->blocking_query = new; /* for garbage cleaning */
|
forward->blocking_query = new; /* for garbage cleaning */
|
||||||
/* validate routines leave name of required record in daemon->namebuff */
|
/* validate routines leave name of required record in daemon->keyname */
|
||||||
if (status == STAT_NEED_KEY)
|
if (status == STAT_NEED_KEY)
|
||||||
{
|
{
|
||||||
new->flags |= FREC_DNSKEY_QUERY;
|
new->flags |= FREC_DNSKEY_QUERY;
|
||||||
nn = dnssec_generate_query(header, daemon->namebuff, class, T_DNSKEY);
|
nn = dnssec_generate_query(header, daemon->keyname, forward->class, T_DNSKEY, &server->addr);
|
||||||
}
|
}
|
||||||
else if (status == STAT_NEED_DS)
|
else if (status == STAT_NEED_DS)
|
||||||
{
|
{
|
||||||
new->flags |= FREC_DS_QUERY;
|
new->flags |= FREC_DS_QUERY;
|
||||||
nn = dnssec_generate_query(header, daemon->namebuff, class, T_DS);
|
nn = dnssec_generate_query(header, daemon->keyname, forward->class, T_DS, &server->addr);
|
||||||
}
|
}
|
||||||
new->crc = questions_crc(header, nn, daemon->namebuff);
|
new->crc = questions_crc(header, nn, daemon->namebuff);
|
||||||
new->new_id = get_id(new->crc);
|
new->new_id = get_id(new->crc);
|
||||||
@@ -740,8 +753,10 @@ void reply_query(int fd, int family, time_t now)
|
|||||||
|
|
||||||
/* Send DNSSEC query to same server as original query */
|
/* Send DNSSEC query to same server as original query */
|
||||||
while (sendto(fd, (char *)header, nn, 0, &server->addr.sa, sa_len(&server->addr)) == -1 && retry_send());
|
while (sendto(fd, (char *)header, nn, 0, &server->addr.sa, sa_len(&server->addr)) == -1 && retry_send());
|
||||||
|
server->queries++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -750,35 +765,56 @@ void reply_query(int fd, int family, time_t now)
|
|||||||
and validate them with the new data. Failure to find needed data here is an internal error.
|
and validate them with the new data. Failure to find needed data here is an internal error.
|
||||||
Once we get to the original answer (FREC_DNSSEC_QUERY not set) and it validates,
|
Once we get to the original answer (FREC_DNSSEC_QUERY not set) and it validates,
|
||||||
return it to the original requestor. */
|
return it to the original requestor. */
|
||||||
|
if (forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY))
|
||||||
|
{
|
||||||
while (forward->dependent)
|
while (forward->dependent)
|
||||||
{
|
{
|
||||||
struct frec *prev = forward->dependent;
|
struct frec *prev;
|
||||||
free_frec(forward);
|
|
||||||
forward = prev;
|
|
||||||
blockdata_retrieve_and_free(forward->stash, forward->stash_len, (void *)header);
|
|
||||||
n = forward->stash_len;
|
|
||||||
if (status == STAT_SECURE)
|
if (status == STAT_SECURE)
|
||||||
{
|
{
|
||||||
if (forward->flags & FREC_DNSKEY_QUERY)
|
if (forward->flags & FREC_DNSKEY_QUERY)
|
||||||
status = dnssec_validate_by_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
|
status = dnssec_validate_by_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
|
||||||
else if (forward->flags & FREC_DS_QUERY)
|
else if (forward->flags & FREC_DS_QUERY)
|
||||||
status = dnssec_validate_dnskey(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
|
status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
|
||||||
|
|
||||||
if (status == STAT_NEED_DS || status == STAT_NEED_KEY)
|
|
||||||
my_syslog(LOG_ERR, _("Unexpected missing data for DNSSEC validation"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
prev = forward->dependent;
|
||||||
|
free_frec(forward);
|
||||||
|
forward = prev;
|
||||||
|
forward->blocking_query = NULL; /* already gone */
|
||||||
|
blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
|
||||||
|
n = forward->stash_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* All DNSKEY and DS records done and in cache, now finally validate original
|
/* All DNSKEY and DS records done and in cache, now finally validate original
|
||||||
answer, provided last DNSKEY is OK. */
|
answer, provided last DNSKEY is OK. */
|
||||||
if (status == STAT_SECURE)
|
if (status == STAT_SECURE)
|
||||||
status = dnssec_validate_reply(header, n, daemon->namebuff, daemon->keyname, &forward->class);
|
status = dnssec_validate_reply(now, header, n, daemon->namebuff, daemon->keyname, &forward->class);
|
||||||
|
|
||||||
|
if (status == STAT_NEED_DS || status == STAT_NEED_KEY)
|
||||||
|
{
|
||||||
|
my_syslog(LOG_ERR, _("Unexpected missing data for DNSSEC validation"));
|
||||||
|
status = STAT_INSECURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log_query(F_KEYTAG | F_SECSTAT, "result", NULL,
|
||||||
|
status == STAT_SECURE ? "SECURE" : (status == STAT_INSECURE ? "INSECURE" : "BOGUS"));
|
||||||
|
|
||||||
|
no_cache_dnssec = 0;
|
||||||
|
|
||||||
if (status == STAT_SECURE)
|
if (status == STAT_SECURE)
|
||||||
cache_secure = 1;
|
cache_secure = 1;
|
||||||
/* TODO return SERVFAIL here */
|
/* TODO return SERVFAIL here */
|
||||||
else if (status == STAT_BOGUS)
|
else if (status == STAT_BOGUS)
|
||||||
no_cache_dnssec = 1;
|
no_cache_dnssec = 1;
|
||||||
|
|
||||||
|
/* restore CD bit to the value in the query */
|
||||||
|
if (forward->flags & FREC_CHECKING_DISABLED)
|
||||||
|
header->hb4 |= HB4_CD;
|
||||||
|
else
|
||||||
|
header->hb4 &= ~HB4_CD;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -1342,7 +1378,6 @@ static struct randfd *allocate_rfd(int family)
|
|||||||
|
|
||||||
return NULL; /* doom */
|
return NULL; /* doom */
|
||||||
}
|
}
|
||||||
|
|
||||||
static void free_frec(struct frec *f)
|
static void free_frec(struct frec *f)
|
||||||
{
|
{
|
||||||
if (f->rfd4 && --(f->rfd4->refcount) == 0)
|
if (f->rfd4 && --(f->rfd4->refcount) == 0)
|
||||||
@@ -1361,7 +1396,10 @@ static void free_frec(struct frec *f)
|
|||||||
|
|
||||||
#ifdef HAVE_DNSSEC
|
#ifdef HAVE_DNSSEC
|
||||||
if (f->stash)
|
if (f->stash)
|
||||||
|
{
|
||||||
blockdata_free(f->stash);
|
blockdata_free(f->stash);
|
||||||
|
f->stash = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* Anything we're waiting on is pointless now, too */
|
/* Anything we're waiting on is pointless now, too */
|
||||||
if (f->blocking_query)
|
if (f->blocking_query)
|
||||||
|
|||||||
30
src/option.c
30
src/option.c
@@ -139,6 +139,7 @@ struct myoption {
|
|||||||
#define LOPT_QUIET_DHCP6 327
|
#define LOPT_QUIET_DHCP6 327
|
||||||
#define LOPT_QUIET_RA 328
|
#define LOPT_QUIET_RA 328
|
||||||
#define LOPT_SEC_VALID 329
|
#define LOPT_SEC_VALID 329
|
||||||
|
#define LOPT_DNSKEY 330
|
||||||
|
|
||||||
|
|
||||||
#ifdef HAVE_GETOPT_LONG
|
#ifdef HAVE_GETOPT_LONG
|
||||||
@@ -276,6 +277,7 @@ static const struct myoption opts[] =
|
|||||||
{ "ipset", 1, 0, LOPT_IPSET },
|
{ "ipset", 1, 0, LOPT_IPSET },
|
||||||
{ "synth-domain", 1, 0, LOPT_SYNTH },
|
{ "synth-domain", 1, 0, LOPT_SYNTH },
|
||||||
{ "dnssec", 0, 0, LOPT_SEC_VALID },
|
{ "dnssec", 0, 0, LOPT_SEC_VALID },
|
||||||
|
{ "dnskey", 1, 0, LOPT_DNSKEY },
|
||||||
#ifdef OPTION6_PREFIX_CLASS
|
#ifdef OPTION6_PREFIX_CLASS
|
||||||
{ "dhcp-prefix-class", 1, 0, LOPT_PREF_CLSS },
|
{ "dhcp-prefix-class", 1, 0, LOPT_PREF_CLSS },
|
||||||
#endif
|
#endif
|
||||||
@@ -428,6 +430,7 @@ static struct {
|
|||||||
{ LOPT_SYNTH, ARG_DUP, "<domain>,<range>,[<prefix>]", gettext_noop("Specify a domain and address range for synthesised names"), NULL },
|
{ LOPT_SYNTH, ARG_DUP, "<domain>,<range>,[<prefix>]", gettext_noop("Specify a domain and address range for synthesised names"), NULL },
|
||||||
#ifdef HAVE_DNSSEC
|
#ifdef HAVE_DNSSEC
|
||||||
{ LOPT_SEC_VALID, OPT_DNSSEC_VALID, NULL, gettext_noop("Activate DNSSEC validation"), NULL },
|
{ LOPT_SEC_VALID, OPT_DNSSEC_VALID, NULL, gettext_noop("Activate DNSSEC validation"), NULL },
|
||||||
|
{ LOPT_DNSKEY, ARG_DUP, "<domain>,<algo>,<key>", gettext_noop("Specify trust anchor DNSKEY"), NULL },
|
||||||
#endif
|
#endif
|
||||||
#ifdef OPTION6_PREFIX_CLASS
|
#ifdef OPTION6_PREFIX_CLASS
|
||||||
{ LOPT_PREF_CLSS, ARG_DUP, "set:tag,<class>", gettext_noop("Specify DHCPv6 prefix class"), NULL },
|
{ LOPT_PREF_CLSS, ARG_DUP, "set:tag,<class>", gettext_noop("Specify DHCPv6 prefix class"), NULL },
|
||||||
@@ -3671,8 +3674,33 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_DNSSEC
|
||||||
|
case LOPT_DNSKEY:
|
||||||
|
{
|
||||||
|
struct dnskey *new = opt_malloc(sizeof(struct dnskey));
|
||||||
|
char *key64, *algo;
|
||||||
|
|
||||||
|
if (!(comma = split(arg)) || !(algo = split(comma)) || !(key64 = split(algo)) ||
|
||||||
|
!atoi_check16(comma, &new->flags) || !atoi_check16(algo, &new->algo) ||
|
||||||
|
!(new->name = canonicalise_opt(arg)))
|
||||||
|
ret_err(_("bad DNSKEY"));
|
||||||
|
|
||||||
|
|
||||||
|
/* Upper bound on length */
|
||||||
|
new->key = opt_malloc((3*strlen(key64)/4));
|
||||||
|
unhide_metas(key64);
|
||||||
|
if ((new->keylen = parse_base64(key64, new->key)) == -1)
|
||||||
|
ret_err(_("bad base64 in DNSKEY"));
|
||||||
|
|
||||||
|
new->next = daemon->dnskeys;
|
||||||
|
daemon->dnskeys = new;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ret_err(_("unsupported option (check that dnsmasq was compiled with DHCP/TFTP/DBus support)"));
|
ret_err(_("unsupported option (check that dnsmasq was compiled with DHCP/TFTP/DNSSEC/DBus support)"));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -577,10 +577,13 @@ static size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned
|
|||||||
return plen; /* Too big */
|
return plen; /* Too big */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (optno != 0)
|
||||||
|
{
|
||||||
PUTSHORT(optno, p);
|
PUTSHORT(optno, p);
|
||||||
PUTSHORT(optlen, p);
|
PUTSHORT(optlen, p);
|
||||||
memcpy(p, opt, optlen);
|
memcpy(p, opt, optlen);
|
||||||
p += optlen;
|
p += optlen;
|
||||||
|
}
|
||||||
|
|
||||||
PUTSHORT(p - datap, lenp);
|
PUTSHORT(p - datap, lenp);
|
||||||
return p - (unsigned char *)header;
|
return p - (unsigned char *)header;
|
||||||
@@ -889,7 +892,7 @@ static int find_soa(struct dns_header *header, size_t qlen, char *name)
|
|||||||
expired and cleaned out that way.
|
expired and cleaned out that way.
|
||||||
Return 1 if we reject an address because it look like part of dns-rebinding attack. */
|
Return 1 if we reject an address because it look like part of dns-rebinding attack. */
|
||||||
int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t now,
|
int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t now,
|
||||||
char **ipsets, int is_sign, int check_rebind, int no_cache_dnssec)
|
char **ipsets, int is_sign, int check_rebind, int no_cache_dnssec, int secure)
|
||||||
{
|
{
|
||||||
unsigned char *p, *p1, *endrr, *namep;
|
unsigned char *p, *p1, *endrr, *namep;
|
||||||
int i, j, qtype, qclass, aqtype, aqclass, ardlen, res, searched_soa = 0;
|
int i, j, qtype, qclass, aqtype, aqclass, ardlen, res, searched_soa = 0;
|
||||||
@@ -920,6 +923,12 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
|||||||
int flags = RCODE(header) == NXDOMAIN ? F_NXDOMAIN : 0;
|
int flags = RCODE(header) == NXDOMAIN ? F_NXDOMAIN : 0;
|
||||||
unsigned long cttl = ULONG_MAX, attl;
|
unsigned long cttl = ULONG_MAX, attl;
|
||||||
|
|
||||||
|
if (RCODE(header) == NXDOMAIN)
|
||||||
|
flags |= F_NXDOMAIN;
|
||||||
|
|
||||||
|
if (secure)
|
||||||
|
flags |= F_DNSSECOK;
|
||||||
|
|
||||||
namep = p;
|
namep = p;
|
||||||
if (!extract_name(header, qlen, &p, name, 1, 4))
|
if (!extract_name(header, qlen, &p, name, 1, 4))
|
||||||
return 0; /* bad packet */
|
return 0; /* bad packet */
|
||||||
@@ -1446,7 +1455,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
|||||||
int dryrun = 0, sec_reqd = 0;
|
int dryrun = 0, sec_reqd = 0;
|
||||||
int is_sign;
|
int is_sign;
|
||||||
struct crec *crecp;
|
struct crec *crecp;
|
||||||
int nxdomain = 0, auth = 1, trunc = 0;
|
int nxdomain = 0, auth = 1, trunc = 0, sec_data = 1;
|
||||||
struct mx_srv_record *rec;
|
struct mx_srv_record *rec;
|
||||||
|
|
||||||
/* If there is an RFC2671 pseudoheader then it will be overwritten by
|
/* If there is an RFC2671 pseudoheader then it will be overwritten by
|
||||||
@@ -1621,6 +1630,9 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
|||||||
if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP)))
|
if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (!(crecp->flags & F_DNSSECOK))
|
||||||
|
sec_data = 0;
|
||||||
|
|
||||||
if (crecp->flags & F_NEG)
|
if (crecp->flags & F_NEG)
|
||||||
{
|
{
|
||||||
ans = 1;
|
ans = 1;
|
||||||
@@ -1794,6 +1806,9 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
|||||||
if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
|
if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
if (!(crecp->flags & F_DNSSECOK))
|
||||||
|
sec_data = 0;
|
||||||
|
|
||||||
if (crecp->flags & F_CNAME)
|
if (crecp->flags & F_CNAME)
|
||||||
{
|
{
|
||||||
char *cname_target = cache_get_cname_target(crecp);
|
char *cname_target = cache_get_cname_target(crecp);
|
||||||
@@ -1868,6 +1883,9 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
|||||||
if ((crecp = cache_find_by_name(NULL, name, now, F_CNAME)) &&
|
if ((crecp = cache_find_by_name(NULL, name, now, F_CNAME)) &&
|
||||||
(qtype == T_CNAME || (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))))
|
(qtype == T_CNAME || (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))))
|
||||||
{
|
{
|
||||||
|
if (!(crecp->flags & F_DNSSECOK))
|
||||||
|
sec_data = 0;
|
||||||
|
|
||||||
ans = 1;
|
ans = 1;
|
||||||
if (!dryrun)
|
if (!dryrun)
|
||||||
{
|
{
|
||||||
@@ -2047,6 +2065,12 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
|||||||
if (trunc)
|
if (trunc)
|
||||||
header->hb3 |= HB3_TC;
|
header->hb3 |= HB3_TC;
|
||||||
|
|
||||||
|
header->hb4 &= ~HB4_AD;
|
||||||
|
|
||||||
|
if (option_bool(OPT_DNSSEC_VALID) || option_bool(OPT_DNSSEC_PROXY))
|
||||||
|
if (sec_data)
|
||||||
|
header->hb4 |= HB4_AD;
|
||||||
|
|
||||||
if (nxdomain)
|
if (nxdomain)
|
||||||
SET_RCODE(header, NXDOMAIN);
|
SET_RCODE(header, NXDOMAIN);
|
||||||
else
|
else
|
||||||
|
|||||||
62
src/util.c
62
src/util.c
@@ -109,8 +109,8 @@ static int check_name(char *in)
|
|||||||
|
|
||||||
if (in[l-1] == '.')
|
if (in[l-1] == '.')
|
||||||
{
|
{
|
||||||
if (l == 1) return 0;
|
|
||||||
in[l-1] = 0;
|
in[l-1] = 0;
|
||||||
|
nowhite = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (; (c = *in); in++)
|
for (; (c = *in); in++)
|
||||||
@@ -482,6 +482,66 @@ int parse_hex(char *in, unsigned char *out, int maxlen,
|
|||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_DNSSEC
|
||||||
|
static int charval(char c)
|
||||||
|
{
|
||||||
|
if (c >= 'A' && c <= 'Z')
|
||||||
|
return c - 'A';
|
||||||
|
|
||||||
|
if (c >= 'a' && c <= 'z')
|
||||||
|
return c - 'a' + 26;
|
||||||
|
|
||||||
|
if (c >= '0' && c <= '9')
|
||||||
|
return c - '0' + 52;
|
||||||
|
|
||||||
|
if (c == '+')
|
||||||
|
return 62;
|
||||||
|
|
||||||
|
if (c == '/')
|
||||||
|
return 63;
|
||||||
|
|
||||||
|
if (c == '=')
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int parse_base64(char *in, char *out)
|
||||||
|
{
|
||||||
|
char *p = out;
|
||||||
|
int i, val[4];
|
||||||
|
|
||||||
|
while (*in)
|
||||||
|
{
|
||||||
|
for (i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
while (*in == ' ')
|
||||||
|
in++;
|
||||||
|
if (*in == 0)
|
||||||
|
return -1;
|
||||||
|
if ((val[i] = charval(*in++)) == -2)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (*in == ' ')
|
||||||
|
in++;
|
||||||
|
|
||||||
|
if (val[1] == -1)
|
||||||
|
return -1; /* too much padding */
|
||||||
|
|
||||||
|
*p++ = (val[0] << 2) | (val[1] >> 4);
|
||||||
|
|
||||||
|
if (val[2] != -1)
|
||||||
|
*p++ = (val[1] << 4) | ( val[2] >> 2);
|
||||||
|
|
||||||
|
if (val[3] != -1)
|
||||||
|
*p++ = (val[2] << 6) | val[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
return p - out;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* return 0 for no match, or (no matched octets) + 1 */
|
/* return 0 for no match, or (no matched octets) + 1 */
|
||||||
int memcmp_masked(unsigned char *a, unsigned char *b, int len, unsigned int mask)
|
int memcmp_masked(unsigned char *a, unsigned char *b, int len, unsigned int mask)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user