Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
D
Dnsmasq
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
List
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nanahira
Dnsmasq
Commits
0fc2f313
Commit
0fc2f313
authored
Jan 08, 2014
by
Simon Kelley
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
First functional DNSSEC - highly alpha.
parent
c3e0b9b6
Changes
10
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
674 additions
and
692 deletions
+674
-692
src/cache.c
src/cache.c
+66
-17
src/config.h
src/config.h
+8
-3
src/dnsmasq.h
src/dnsmasq.h
+24
-5
src/dnssec-crypto.h
src/dnssec-crypto.h
+4
-4
src/dnssec-openssl.c
src/dnssec-openssl.c
+19
-21
src/dnssec.c
src/dnssec.c
+359
-598
src/forward.c
src/forward.c
+71
-33
src/option.c
src/option.c
+30
-2
src/rfc1035.c
src/rfc1035.c
+31
-7
src/util.c
src/util.c
+62
-2
No files found.
src/cache.c
View file @
0fc2f313
...
...
@@ -56,6 +56,8 @@ static const struct {
{
38
,
"A6"
},
{
39
,
"DNAME"
},
{
41
,
"OPT"
},
{
43
,
"DS"
},
{
46
,
"RRSIG"
},
{
48
,
"DNSKEY"
},
{
249
,
"TKEY"
},
{
250
,
"TSIG"
},
...
...
@@ -916,12 +918,19 @@ void cache_reload(void)
struct
name_list
*
nl
;
struct
cname
*
a
;
struct
interface_name
*
intr
;
#ifdef HAVE_DNSSEC
struct
dnskey
*
key
;
#endif
cache_inserted
=
cache_live_freed
=
0
;
for
(
i
=
0
;
i
<
hash_size
;
i
++
)
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
;
if
(
cache
->
flags
&
(
F_HOSTS
|
F_CONFIG
))
{
...
...
@@ -948,13 +957,27 @@ void cache_reload(void)
if
(
hostname_isequal
(
a
->
target
,
intr
->
name
)
&&
((
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
->
addr
.
cname
.
target
.
int_name
=
intr
;
cache
->
addr
.
cname
.
uid
=
-
1
;
cache_hash
(
cache
);
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 */
memset
(
daemon
->
packet
,
0
,
daemon
->
packet_buff_sz
);
...
...
@@ -1197,16 +1220,13 @@ void dump_cache(time_t now)
for
(
i
=
0
;
i
<
hash_size
;
i
++
)
for
(
cache
=
hash_table
[
i
];
cache
;
cache
=
cache
->
hash_next
)
{
char
*
a
,
*
p
=
daemon
->
namebuff
;
p
+=
sprintf
(
p
,
"%-40.40s "
,
cache_get_name
(
cache
));
if
((
cache
->
flags
&
F_NEG
)
&&
(
cache
->
flags
&
F_FORWARD
))
a
=
""
;
else
if
(
cache
->
flags
&
F_CNAME
)
{
a
=
""
;
if
(
!
is_outdated_cname_pointer
(
cache
))
a
=
cache_get_cname_target
(
cache
);
}
char
*
a
=
daemon
->
addrbuff
,
*
p
=
daemon
->
namebuff
,
*
n
=
cache_get_name
(
cache
);
*
a
=
0
;
if
(
strlen
(
n
)
==
0
)
n
=
"<Root>"
;
p
+=
sprintf
(
p
,
"%-40.40s "
,
n
);
if
((
cache
->
flags
&
F_CNAME
)
&&
!
is_outdated_cname_pointer
(
cache
))
a
=
cache_get_cname_target
(
cache
);
#ifdef HAVE_DNSSEC
else
if
(
cache
->
flags
&
F_DNSKEY
)
{
...
...
@@ -1216,11 +1236,11 @@ void dump_cache(time_t now)
else
if
(
cache
->
flags
&
F_DS
)
{
a
=
daemon
->
addrbuff
;
sprintf
(
a
,
"%5u %3u %3u
%u
"
,
cache
->
addr
.
key
.
keytag
,
cache
->
addr
.
key
.
algo
,
cache
->
addr
.
key
.
digest
,
cache
->
uid
);
sprintf
(
a
,
"%5u %3u %3u"
,
cache
->
addr
.
key
.
keytag
,
cache
->
addr
.
key
.
algo
,
cache
->
addr
.
key
.
digest
);
}
#endif
else
else
if
(
!
(
cache
->
flags
&
F_NEG
)
||
!
(
cache
->
flags
&
F_FORWARD
))
{
a
=
daemon
->
addrbuff
;
if
(
cache
->
flags
&
F_IPV4
)
...
...
@@ -1291,13 +1311,20 @@ void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
if
(
addr
)
{
if
(
flags
&
F_KEYTAG
)
sprintf
(
daemon
->
addrbuff
,
arg
,
addr
->
addr
.
keytag
);
else
{
#ifdef HAVE_IPV6
inet_ntop
(
flags
&
F_IPV4
?
AF_INET
:
AF_INET6
,
addr
,
daemon
->
addrbuff
,
ADDRSTRLEN
);
inet_ntop
(
flags
&
F_IPV4
?
AF_INET
:
AF_INET6
,
addr
,
daemon
->
addrbuff
,
ADDRSTRLEN
);
#else
strncpy
(
daemon
->
addrbuff
,
inet_ntoa
(
addr
->
addr
.
addr4
),
ADDRSTRLEN
);
strncpy
(
daemon
->
addrbuff
,
inet_ntoa
(
addr
->
addr
.
addr4
),
ADDRSTRLEN
);
#endif
}
}
else
dest
=
arg
;
if
(
flags
&
F_REVERSE
)
{
...
...
@@ -1339,6 +1366,8 @@ void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
source
=
arg
;
else
if
(
flags
&
F_UPSTREAM
)
source
=
"reply"
;
else
if
(
flags
&
F_SECSTAT
)
source
=
"validation"
;
else
if
(
flags
&
F_AUTH
)
source
=
"auth"
;
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
;
verb
=
"from"
;
}
else
if
(
flags
&
F_DNSSEC
)
{
source
=
arg
;
verb
=
"to"
;
}
else
source
=
"cached"
;
...
...
@@ -1422,6 +1456,21 @@ void blockdata_free(struct blockdata *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
src/config.h
View file @
0fc2f313
...
...
@@ -139,8 +139,8 @@ RESOLVFILE
/* #define HAVE_DBUS */
/* #define HAVE_IDN */
/* #define HAVE_CONNTRACK */
#define HAVE_DNSSEC
#define HAVE_OPENSSL
#define HAVE_DNSSEC
#define HAVE_OPENSSL
/* Default locations for important system files. */
...
...
@@ -385,7 +385,12 @@ static char *compile_opts =
#ifndef HAVE_AUTH
"no-"
#endif
"auth"
;
"auth "
#ifndef HAVE_DNSSEC
"no-"
#endif
"DNSSEC"
;
#endif
...
...
src/dnsmasq.h
View file @
0fc2f313
...
...
@@ -242,6 +242,7 @@ struct all_addr {
#ifdef HAVE_IPV6
struct
in6_addr
addr6
;
#endif
unsigned
int
keytag
;
}
addr
;
};
...
...
@@ -286,6 +287,12 @@ struct cname {
struct
cname
*
next
;
};
struct
dnskey
{
char
*
name
,
*
key
;
int
keylen
,
algo
,
flags
;
struct
dnskey
*
next
;
};
#define ADDRLIST_LITERAL 1
#define ADDRLIST_IPV6 2
...
...
@@ -360,7 +367,7 @@ struct crec {
}
key
;
}
addr
;
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
;
unsigned
short
flags
;
union
{
...
...
@@ -395,6 +402,9 @@ struct crec {
#define F_QUERY (1u<<19)
#define F_NOERR (1u<<20)
#define F_AUTH (1u<<21)
#define F_DNSSEC (1u<<22)
#define F_KEYTAG (1u<<23)
#define F_SECSTAT (1u<<24)
/* composites */
#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
struct
prefix_class
*
prefix_classes
;
#endif
#ifdef HAVE_DNSSEC
struct
dnskey
*
dnskeys
;
#endif
/* globally used stuff for DNS */
char
*
packet
;
/* packet buffer */
...
...
@@ -977,6 +990,7 @@ struct crec *cache_enumerate(int init);
#ifdef HAVE_DNSSEC
struct
blockdata
*
blockdata_alloc
(
char
*
data
,
size_t
len
);
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
);
#endif
...
...
@@ -1000,7 +1014,7 @@ size_t setup_reply(struct dns_header *header, size_t qlen,
unsigned
long
local_ttl
);
int
extract_addresses
(
struct
dns_header
*
header
,
size_t
qlen
,
char
*
namebuff
,
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
,
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
,
...
...
@@ -1034,11 +1048,13 @@ int in_zone(struct auth_zone *zone, char *name, char **cut);
#endif
/* 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_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
dnssec_validate_reply
(
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
,
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 */
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
parse_hex
(
char
*
in
,
unsigned
char
*
out
,
int
maxlen
,
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
,
unsigned
int
mask
);
int
expand_buf
(
struct
iovec
*
iov
,
size_t
size
);
...
...
src/dnssec-crypto.h
View file @
0fc2f313
...
...
@@ -17,7 +17,7 @@
#ifndef DNSSEC_CRYPTO_H
#define DNSSEC_CRYPTO_H
struct
key
data
;
struct
block
data
;
/*
* vtable for a signature verification algorithm.
...
...
@@ -49,7 +49,7 @@ typedef struct VerifyAlgCtx VerifyAlgCtx;
typedef
struct
{
int
digest_algo
;
int
(
*
verify
)(
VerifyAlgCtx
*
ctx
,
struct
key
data
*
key
,
unsigned
key_len
);
int
(
*
verify
)(
VerifyAlgCtx
*
ctx
,
struct
block
data
*
key
,
unsigned
key_len
);
}
VerifyAlg
;
struct
VerifyAlgCtx
...
...
@@ -74,9 +74,9 @@ int verifyalg_algonum(VerifyAlgCtx *a);
#define DIGESTALG_SHA512 257
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_keydata
(
struct
key
data
*
key
,
size_t
len
);
void
digestalg_add_keydata
(
struct
block
data
*
key
,
size_t
len
);
unsigned
char
*
digestalg_final
(
void
);
int
digestalg_len
(
void
);
...
...
src/dnssec-openssl.c
View file @
0fc2f313
...
...
@@ -14,13 +14,16 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "dnsmasq.h"
#ifdef HAVE_DNSSEC
#include "dnssec-crypto.h"
#include <openssl/evp.h>
#include <openssl/rsa.h>
#include <openssl/dsa.h>
#include <openssl/err.h>
#include <string.h>
#define POOL_SIZE 1
static
union
_Pool
...
...
@@ -39,20 +42,20 @@ static void print_hex(unsigned char *data, unsigned len)
printf
(
"
\n
"
);
}
static
int
keydata_to_bn
(
BIGNUM
*
ret
,
struct
key
data
**
key_data
,
unsigned
char
**
p
,
unsigned
len
)
static
int
keydata_to_bn
(
BIGNUM
*
ret
,
struct
block
data
**
key_data
,
unsigned
char
**
p
,
unsigned
len
)
{
size_t
cnt
;
BIGNUM
temp
;
BN_init
(
ret
);
cnt
=
key
data_walk
(
key_data
,
p
,
len
);
cnt
=
block
data_walk
(
key_data
,
p
,
len
);
BN_bin2bn
(
*
p
,
cnt
,
ret
);
len
-=
cnt
;
*
p
+=
cnt
;
while
(
len
>
0
)
{
if
(
!
(
cnt
=
key
data_walk
(
key_data
,
p
,
len
)))
if
(
!
(
cnt
=
block
data_walk
(
key_data
,
p
,
len
)))
return
0
;
BN_lshift
(
ret
,
ret
,
cnt
*
8
);
BN_init
(
&
temp
);
...
...
@@ -64,7 +67,7 @@ static int keydata_to_bn(BIGNUM *ret, struct keydata **key_data, unsigned char *
return
1
;
}
static
int
rsasha1_parse_key
(
BIGNUM
*
exp
,
BIGNUM
*
mod
,
struct
key
data
*
key_data
,
unsigned
key_len
)
static
int
rsasha1_parse_key
(
BIGNUM
*
exp
,
BIGNUM
*
mod
,
struct
block
data
*
key_data
,
unsigned
key_len
)
{
unsigned
char
*
p
=
key_data
->
key
;
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
);
}
static
int
dsasha1_parse_key
(
BIGNUM
*
Q
,
BIGNUM
*
P
,
BIGNUM
*
G
,
BIGNUM
*
Y
,
struct
key
data
*
key_data
,
unsigned
key_len
)
static
int
dsasha1_parse_key
(
BIGNUM
*
Q
,
BIGNUM
*
P
,
BIGNUM
*
G
,
BIGNUM
*
Y
,
struct
block
data
*
key_data
,
unsigned
key_len
)
{
unsigned
char
*
p
=
key_data
->
key
;
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
);
}
static
int
rsa_verify
(
VerifyAlgCtx
*
ctx
,
struct
key
data
*
key_data
,
unsigned
key_len
,
int
nid
,
int
dlen
)
static
int
rsa_verify
(
VerifyAlgCtx
*
ctx
,
struct
block
data
*
key_data
,
unsigned
key_len
,
int
nid
,
int
dlen
)
{
int
validated
=
0
;
...
...
@@ -108,27 +111,27 @@ static int rsa_verify(VerifyAlgCtx *ctx, struct keydata *key_data, unsigned key_
return
validated
;
}
static
int
rsamd5_verify
(
VerifyAlgCtx
*
ctx
,
struct
key
data
*
key_data
,
unsigned
key_len
)
static
int
rsamd5_verify
(
VerifyAlgCtx
*
ctx
,
struct
block
data
*
key_data
,
unsigned
key_len
)
{
return
rsa_verify
(
ctx
,
key_data
,
key_len
,
NID_md5
,
16
);
}
static
int
rsasha1_verify
(
VerifyAlgCtx
*
ctx
,
struct
key
data
*
key_data
,
unsigned
key_len
)
static
int
rsasha1_verify
(
VerifyAlgCtx
*
ctx
,
struct
block
data
*
key_data
,
unsigned
key_len
)
{
return
rsa_verify
(
ctx
,
key_data
,
key_len
,
NID_sha1
,
20
);
}
static
int
rsasha256_verify
(
VerifyAlgCtx
*
ctx
,
struct
key
data
*
key_data
,
unsigned
key_len
)
static
int
rsasha256_verify
(
VerifyAlgCtx
*
ctx
,
struct
block
data
*
key_data
,
unsigned
key_len
)
{
return
rsa_verify
(
ctx
,
key_data
,
key_len
,
NID_sha256
,
32
);
}
static
int
rsasha512_verify
(
VerifyAlgCtx
*
ctx
,
struct
key
data
*
key_data
,
unsigned
key_len
)
static
int
rsasha512_verify
(
VerifyAlgCtx
*
ctx
,
struct
block
data
*
key_data
,
unsigned
key_len
)
{
return
rsa_verify
(
ctx
,
key_data
,
key_len
,
NID_sha512
,
64
);
}
static
int
dsasha1_verify
(
VerifyAlgCtx
*
ctx
,
struct
key
data
*
key_data
,
unsigned
key_len
)
static
int
dsasha1_verify
(
VerifyAlgCtx
*
ctx
,
struct
block
data
*
key_data
,
unsigned
key_len
)
{
static
unsigned
char
asn1_signature
[]
=
{
...
...
@@ -222,9 +225,6 @@ VerifyAlgCtx* verifyalg_alloc(int algo)
int
i
;
VerifyAlgCtx
*
ret
=
0
;
if
(
!
verifyalg_supported
(
algo
))
return
0
;
if
(
pool_used
==
(
1
<<
POOL_SIZE
)
-
1
)
ret
=
whine_malloc
(
valgctx_size
[
algo
]);
else
...
...
@@ -271,7 +271,7 @@ int digestalg_supported(int algo)
algo
==
DIGESTALG_SHA512
);
}
int
digestalg_begin
(
int
algo
)
void
digestalg_begin
(
int
algo
)
{
EVP_MD_CTX_init
(
&
digctx
);
if
(
algo
==
DIGESTALG_SHA1
)
...
...
@@ -282,9 +282,6 @@ int digestalg_begin(int algo)
EVP_DigestInit_ex
(
&
digctx
,
EVP_sha512
(),
NULL
);
else
if
(
algo
==
DIGESTALG_MD5
)
EVP_DigestInit_ex
(
&
digctx
,
EVP_md5
(),
NULL
);
else
return
0
;
return
1
;
}
int
digestalg_len
()
...
...
@@ -297,12 +294,12 @@ void digestalg_add_data(void *data, unsigned len)
EVP_DigestUpdate
(
&
digctx
,
data
,
len
);
}
void
digestalg_add_keydata
(
struct
key
data
*
key
,
size_t
len
)
void
digestalg_add_keydata
(
struct
block
data
*
key
,
size_t
len
)
{
size_t
cnt
;
unsigned
char
*
p
=
NULL
;
while
(
len
)
{
cnt
=
key
data_walk
(
&
key
,
&
p
,
len
);
cnt
=
block
data_walk
(
&
key
,
&
p
,
len
);
EVP_DigestUpdate
(
&
digctx
,
p
,
cnt
);
p
+=
cnt
;
len
-=
cnt
;
...
...
@@ -316,3 +313,4 @@ unsigned char* digestalg_final(void)
return
digest
;
}
#endif
/* HAVE_DNSSEC */
src/dnssec.c
View file @
0fc2f313
This diff is collapsed.
Click to expand it.
src/forward.c
View file @
0fc2f313
...
...
@@ -344,7 +344,10 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
#ifdef HAVE_DNSSEC
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
while
(
1
)
...
...
@@ -550,7 +553,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
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
);
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
))
{
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
)
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
)
status
=
dnssec_validate_ds
(
now
,
header
,
n
,
daemon
->
namebuff
,
daemon
->
keyname
,
forward
->
class
);
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
answer aside, whilst we get that. */
if
(
status
==
STAT_NEED_DS
||
status
==
STAT_NEED_KEY
)
{
struct
frec
*
new
;
if
((
forward
->
stash
=
blockdata_alloc
((
char
*
)
header
,
n
)))
if
((
new
=
get_new_frec
(
now
,
NULL
,
1
)))
{
forward
->
stash_len
=
n
;
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
((
new
=
get_new_frec
(
now
,
NULL
,
1
)))
if
((
forward
->
stash
=
blockdata_alloc
((
char
*
)
header
,
n
)))
{
int
fd
;
new
=
forward
;
/* copy everything, then overwrite */
forward
->
stash_len
=
n
;
new
->
dependent
=
forward
;
/* to find query awaiting new one. */
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
)
{
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
)
{
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
->
new_id
=
get_id
(
new
->
crc
);
...
...
@@ -739,9 +752,11 @@ void reply_query(int fd, int family, time_t now)
}
/* 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
;
}
...
...
@@ -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.
Once we get to the original answer (FREC_DNSSEC_QUERY not set) and it validates,
return it to the original requestor. */
while
(
forward
->
dependent
)
if
(
forward
->
flags
&
(
FREC_DNSKEY_QUERY
|
FREC_DS_QUERY
)
)
{
struct
frec
*
prev
=
forward
->
dependent
;
free_frec
(
forward
);
forward
=
prev
;
blockdata_retrieve_and_free
(
forward
->
stash
,
forward
->
stash_len
,
(
void
*
)
header
);
n
=
forward
->
stash_len
;
if
(
status
==
STAT_SECURE
)
while
(
forward
->
dependent
)
{
if
(
forward
->
flags
&
FREC_DNSKEY_QUERY
)
status
=
dnssec_validate_by_ds
(
now
,
header
,
n
,
daemon
->
namebuff
,
daemon
->
keyname
,
forward
->
class
);
else
if
(
forward
->
flags
&
FREC_DS_QUERY
)
status
=
dnssec_validate_dnskey
(
now
,
header
,
n
,
daemon
->
namebuff
,
daemon
->
keyname
,
forward
->
class
);
struct
frec
*
prev
;
if
(
status
==
STAT_NEED_DS
||
status
==
STAT_NEED_KEY
)
my_syslog
(
LOG_ERR
,
_
(
"Unexpected missing data for DNSSEC validation"
));
if
(
status
==
STAT_SECURE
)
{
if
(
forward
->
flags
&
FREC_DNSKEY_QUERY
)
status
=
dnssec_validate_by_ds
(
now
,
header
,
n
,
daemon
->
namebuff
,
daemon
->
keyname
,
forward
->
class
);
else
if
(
forward
->
flags
&
FREC_DS_QUERY
)
status
=
dnssec_validate_ds
(
now
,
header
,
n
,
daemon
->
namebuff
,
daemon
->
keyname
,
forward
->
class
);
}
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
answer, provided last DNSKEY is OK. */
if
(
status
==
STAT_SECURE
)
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
;
}
}
/* All DNSKEY and DS records done and in cache, now finally validate original
answer, provided last DNSKEY is OK. */
if
(
status
==
STAT_SECURE
)
status
=
dnssec_validate_reply
(
header
,
n
,
daemon
->
namebuff
,
daemon
->
keyname
,
&
forward
->
class
)
;
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
)
cache_secure
=
1
;
/* TODO return SERVFAIL here */
else
if
(
status
==
STAT_BOGUS
)
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
...
...
@@ -1342,7 +1378,6 @@ static struct randfd *allocate_rfd(int family)
return
NULL
;
/* doom */
}
static
void
free_frec
(
struct
frec
*
f
)
{
if
(
f
->
rfd4
&&
--
(
f
->
rfd4
->
refcount
)
==
0
)
...
...
@@ -1361,7 +1396,10 @@ static void free_frec(struct frec *f)
#ifdef HAVE_DNSSEC
if
(
f
->
stash
)
blockdata_free
(
f
->
stash
);
{
blockdata_free
(
f
->
stash
);
f
->
stash
=
NULL
;
}
/* Anything we're waiting on is pointless now, too */
if
(
f
->
blocking_query
)
...
...
src/option.c
View file @
0fc2f313
...
...
@@ -139,6 +139,7 @@ struct myoption {
#define LOPT_QUIET_DHCP6 327
#define LOPT_QUIET_RA 328
#define LOPT_SEC_VALID 329
#define LOPT_DNSKEY 330
#ifdef HAVE_GETOPT_LONG
...
...
@@ -276,6 +277,7 @@ static const struct myoption opts[] =
{
"ipset"
,
1
,
0
,
LOPT_IPSET
},
{
"synth-domain"
,
1
,
0
,
LOPT_SYNTH
},
{
"dnssec"
,
0
,
0
,
LOPT_SEC_VALID
},
{
"dnskey"
,
1
,
0
,
LOPT_DNSKEY
},
#ifdef OPTION6_PREFIX_CLASS
{
"dhcp-prefix-class"
,
1
,
0
,
LOPT_PREF_CLSS
},
#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
},
#ifdef HAVE_DNSSEC
{
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
#ifdef OPTION6_PREFIX_CLASS
{
LOPT_PREF_CLSS
,
ARG_DUP
,
"set:tag,<class>"
,
gettext_noop
(
"Specify DHCPv6 prefix class"
),
NULL
},
...
...
@@ -3670,9 +3673,34 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
daemon
->
host_records_tail
=
new
;
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:
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/D
NSSEC/D
Bus support)"
));
}
...
...
src/rfc1035.c
View file @
0fc2f313
...
...
@@ -577,10 +577,13 @@ static size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned
return
plen
;
/* Too big */
}
PUTSHORT
(
optno
,
p
);
PUTSHORT
(
optlen
,
p
);
memcpy
(
p
,
opt
,
optlen
);
p
+=
optlen
;
if
(
optno
!=
0
)
{
PUTSHORT
(
optno
,
p
);
PUTSHORT
(
optlen
,
p
);
memcpy
(
p
,
opt
,
optlen
);
p
+=
optlen
;
}
PUTSHORT
(
p
-
datap
,
lenp
);
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.
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
,
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
;
int
i
,
j
,
qtype
,
qclass
,
aqtype
,
aqclass
,
ardlen
,
res
,
searched_soa
=
0
;
...
...
@@ -919,6 +922,12 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
struct
crec
*
cpp
=
NULL
;
int
flags
=
RCODE
(
header
)
==
NXDOMAIN
?
F_NXDOMAIN
:
0
;
unsigned
long
cttl
=
ULONG_MAX
,
attl
;
if
(
RCODE
(
header
)
==
NXDOMAIN
)
flags
|=
F_NXDOMAIN
;
if
(
secure
)
flags
|=
F_DNSSECOK
;
namep
=
p
;
if
(
!
extract_name
(
header
,
qlen
,
&
p
,
name
,
1
,
4
))
...
...
@@ -1446,7 +1455,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
int
dryrun
=
0
,
sec_reqd
=
0
;
int
is_sign
;
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
;
/* 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
)))
continue
;
if
(
!
(
crecp
->
flags
&
F_DNSSECOK
))
sec_data
=
0
;
if
(
crecp
->
flags
&
F_NEG
)
{
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
)))
break
;
if
(
!
(
crecp
->
flags
&
F_DNSSECOK
))
sec_data
=
0
;
if
(
crecp
->
flags
&
F_CNAME
)
{
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
))
&&
(
qtype
==
T_CNAME
||
(
crecp
->
flags
&
(
F_HOSTS
|
F_DHCP
|
F_CONFIG
))))
{
if
(
!
(
crecp
->
flags
&
F_DNSSECOK
))
sec_data
=
0
;
ans
=
1
;
if
(
!
dryrun
)
{
...
...
@@ -2046,7 +2064,13 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
/* truncation */
if
(
trunc
)
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
)
SET_RCODE
(
header
,
NXDOMAIN
);
else
...
...
src/util.c
View file @
0fc2f313
...
...
@@ -109,10 +109,10 @@ static int check_name(char *in)
if
(
in
[
l
-
1
]
==
'.'
)
{
if
(
l
==
1
)
return
0
;
in
[
l
-
1
]
=
0
;
nowhite
=
1
;
}
for
(;
(
c
=
*
in
);
in
++
)
{
if
(
c
==
'.'
)
...
...
@@ -482,6 +482,66 @@ int parse_hex(char *in, unsigned char *out, int maxlen,
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 */
int
memcmp_masked
(
unsigned
char
*
a
,
unsigned
char
*
b
,
int
len
,
unsigned
int
mask
)
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment