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
c3e0b9b6
Commit
c3e0b9b6
authored
Dec 31, 2013
by
Simon Kelley
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
backup
parent
963c380d
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
413 additions
and
34 deletions
+413
-34
src/cache.c
src/cache.c
+10
-10
src/dns-protocol.h
src/dns-protocol.h
+6
-0
src/dnsmasq.c
src/dnsmasq.c
+6
-0
src/dnsmasq.h
src/dnsmasq.h
+11
-3
src/dnssec.c
src/dnssec.c
+359
-0
src/forward.c
src/forward.c
+21
-14
src/rfc1035.c
src/rfc1035.c
+0
-7
No files found.
src/cache.c
View file @
c3e0b9b6
...
@@ -26,7 +26,7 @@ static union bigname *big_free = NULL;
...
@@ -26,7 +26,7 @@ static union bigname *big_free = NULL;
static
int
bignames_left
,
hash_size
;
static
int
bignames_left
,
hash_size
;
static
int
uid
=
1
;
static
int
uid
=
1
;
#ifdef HAVE_DNSSEC
#ifdef HAVE_DNSSEC
static
struct
key
data
*
keyblock_free
=
NULL
;
static
struct
block
data
*
keyblock_free
=
NULL
;
#endif
#endif
/* type->string mapping: this is also used by the name-hash function as a mixing table. */
/* type->string mapping: this is also used by the name-hash function as a mixing table. */
...
@@ -198,7 +198,7 @@ static void cache_free(struct crec *crecp)
...
@@ -198,7 +198,7 @@ static void cache_free(struct crec *crecp)
}
}
#ifdef HAVE_DNSSEC
#ifdef HAVE_DNSSEC
else
if
(
crecp
->
flags
&
(
F_DNSKEY
|
F_DS
))
else
if
(
crecp
->
flags
&
(
F_DNSKEY
|
F_DS
))
key
data_free
(
crecp
->
addr
.
key
.
keydata
);
block
data_free
(
crecp
->
addr
.
key
.
keydata
);
#endif
#endif
}
}
...
@@ -1361,10 +1361,10 @@ void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
...
@@ -1361,10 +1361,10 @@ void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
}
}
#ifdef HAVE_DNSSEC
#ifdef HAVE_DNSSEC
struct
keydata
*
key
data_alloc
(
char
*
data
,
size_t
len
)
struct
blockdata
*
block
data_alloc
(
char
*
data
,
size_t
len
)
{
{
struct
key
data
*
block
,
*
ret
=
NULL
;
struct
block
data
*
block
,
*
ret
=
NULL
;
struct
key
data
**
prev
=
&
ret
;
struct
block
data
**
prev
=
&
ret
;
size_t
blen
;
size_t
blen
;
while
(
len
>
0
)
while
(
len
>
0
)
...
@@ -1375,12 +1375,12 @@ struct keydata *keydata_alloc(char *data, size_t len)
...
@@ -1375,12 +1375,12 @@ struct keydata *keydata_alloc(char *data, size_t len)
keyblock_free
=
block
->
next
;
keyblock_free
=
block
->
next
;
}
}
else
else
block
=
whine_malloc
(
sizeof
(
struct
key
data
));
block
=
whine_malloc
(
sizeof
(
struct
block
data
));
if
(
!
block
)
if
(
!
block
)
{
{
/* failed to alloc, free partial chain */
/* failed to alloc, free partial chain */
key
data_free
(
ret
);
block
data_free
(
ret
);
return
NULL
;
return
NULL
;
}
}
...
@@ -1396,7 +1396,7 @@ struct keydata *keydata_alloc(char *data, size_t len)
...
@@ -1396,7 +1396,7 @@ struct keydata *keydata_alloc(char *data, size_t len)
return
ret
;
return
ret
;
}
}
size_t
keydata_walk
(
struct
key
data
**
key
,
unsigned
char
**
p
,
size_t
cnt
)
size_t
blockdata_walk
(
struct
block
data
**
key
,
unsigned
char
**
p
,
size_t
cnt
)
{
{
if
(
*
p
==
NULL
)
if
(
*
p
==
NULL
)
*
p
=
(
*
key
)
->
key
;
*
p
=
(
*
key
)
->
key
;
...
@@ -1411,9 +1411,9 @@ size_t keydata_walk(struct keydata **key, unsigned char **p, size_t cnt)
...
@@ -1411,9 +1411,9 @@ size_t keydata_walk(struct keydata **key, unsigned char **p, size_t cnt)
return
MIN
(
cnt
,
(
*
key
)
->
key
+
KEYBLOCK_LEN
-
(
*
p
));
return
MIN
(
cnt
,
(
*
key
)
->
key
+
KEYBLOCK_LEN
-
(
*
p
));
}
}
void
keydata_free
(
struct
key
data
*
blocks
)
void
blockdata_free
(
struct
block
data
*
blocks
)
{
{
struct
key
data
*
tmp
;
struct
block
data
*
tmp
;
if
(
blocks
)
if
(
blocks
)
{
{
...
...
src/dns-protocol.h
View file @
c3e0b9b6
...
@@ -140,3 +140,9 @@ struct dns_header {
...
@@ -140,3 +140,9 @@ struct dns_header {
GETLONG(var, ptr); \
GETLONG(var, ptr); \
(len) -= 4; \
(len) -= 4; \
} while (0)
} while (0)
#define CHECK_LEN(header, pp, plen, len) \
((size_t)((pp) - (unsigned char *)(header) + (len)) <= (plen))
#define ADD_RDLEN(header, pp, plen, len) \
(!CHECK_LEN(header, pp, plen, len) ? 0 : (((pp) += (len)), 1))
src/dnsmasq.c
View file @
c3e0b9b6
...
@@ -81,8 +81,14 @@ int main (int argc, char **argv)
...
@@ -81,8 +81,14 @@ int main (int argc, char **argv)
umask
(
022
);
/* known umask, create leases and pid files as 0644 */
umask
(
022
);
/* known umask, create leases and pid files as 0644 */
read_opts
(
argc
,
argv
,
compile_opts
);
read_opts
(
argc
,
argv
,
compile_opts
);
#ifdef HAVE_DNSSEC
if
(
option_bool
(
OPT_DNSSEC_VALID
))
if
(
option_bool
(
OPT_DNSSEC_VALID
))
if
(
daemon
->
doctors
)
exit
(
1
);
/* TODO */
if
(
daemon
->
doctors
)
exit
(
1
);
/* TODO */
daemon
->
keyname
=
safe_malloc
(
MAXDNAME
);
#endif
if
(
daemon
->
edns_pktsz
<
PACKETSZ
)
if
(
daemon
->
edns_pktsz
<
PACKETSZ
)
daemon
->
edns_pktsz
=
option_bool
(
OPT_DNSSEC_VALID
)
?
EDNS_PKTSZ
:
PACKETSZ
;
daemon
->
edns_pktsz
=
option_bool
(
OPT_DNSSEC_VALID
)
?
EDNS_PKTSZ
:
PACKETSZ
;
daemon
->
packet_buff_sz
=
daemon
->
edns_pktsz
>
DNSMASQ_PACKETSZ
?
daemon
->
packet_buff_sz
=
daemon
->
edns_pktsz
>
DNSMASQ_PACKETSZ
?
...
...
src/dnsmasq.h
View file @
c3e0b9b6
...
@@ -335,8 +335,8 @@ union bigname {
...
@@ -335,8 +335,8 @@ union bigname {
union
bigname
*
next
;
/* freelist */
union
bigname
*
next
;
/* freelist */
};
};
struct
key
data
{
struct
block
data
{
struct
key
data
*
next
;
struct
block
data
*
next
;
unsigned
char
key
[
KEYBLOCK_LEN
];
unsigned
char
key
[
KEYBLOCK_LEN
];
};
};
...
@@ -528,6 +528,7 @@ struct frec {
...
@@ -528,6 +528,7 @@ struct frec {
unsigned
int
crc
;
unsigned
int
crc
;
time_t
time
;
time_t
time
;
#ifdef HAVE_DNSSEC
#ifdef HAVE_DNSSEC
int
class
;
struct
blockdata
*
stash
;
/* Saved reply, whilst we validate */
struct
blockdata
*
stash
;
/* Saved reply, whilst we validate */
size_t
stash_len
;
size_t
stash_len
;
struct
frec
*
dependent
;
/* Query awaiting internally-generated DNSKEY or DS query */
struct
frec
*
dependent
;
/* Query awaiting internally-generated DNSKEY or DS query */
...
@@ -900,6 +901,9 @@ extern struct daemon {
...
@@ -900,6 +901,9 @@ extern struct daemon {
char
*
packet
;
/* packet buffer */
char
*
packet
;
/* packet buffer */
int
packet_buff_sz
;
/* size of above */
int
packet_buff_sz
;
/* size of above */
char
*
namebuff
;
/* MAXDNAME size buffer */
char
*
namebuff
;
/* MAXDNAME size buffer */
#ifdef HAVE_DNSSEC
char
*
keyname
;
/* MAXDNAME size buffer */
#endif
unsigned
int
local_answer
,
queries_forwarded
,
auth_answer
;
unsigned
int
local_answer
,
queries_forwarded
,
auth_answer
;
struct
frec
*
frec_list
;
struct
frec
*
frec_list
;
struct
serverfd
*
sfds
;
struct
serverfd
*
sfds
;
...
@@ -1030,7 +1034,11 @@ int in_zone(struct auth_zone *zone, char *name, char **cut);
...
@@ -1030,7 +1034,11 @@ int in_zone(struct auth_zone *zone, char *name, char **cut);
#endif
#endif
/* dnssec.c */
/* dnssec.c */
int
dnssec_validate
(
int
flags
,
struct
dns_header
*
header
,
size_t
plen
);
size_t
dnssec_generate_query
(
struct
dns_header
*
header
,
char
*
name
,
int
class
,
int
type
);
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
);
/* util.c */
/* util.c */
void
rand_init
(
void
);
void
rand_init
(
void
);
...
...
src/dnssec.c
View file @
c3e0b9b6
...
@@ -21,11 +21,15 @@
...
@@ -21,11 +21,15 @@
/* Maximum length in octects of a domain name, in wire format */
/* Maximum length in octects of a domain name, in wire format */
#define MAXCDNAME 256
#define MAXCDNAME 256
#define MAXRRSET 16
#define SERIAL_UNDEF -100
#define SERIAL_UNDEF -100
#define SERIAL_EQ 0
#define SERIAL_EQ 0
#define SERIAL_LT -1
#define SERIAL_LT -1
#define SERIAL_GT 1
#define SERIAL_GT 1
static
int
dnskey_keytag
(
int
alg
,
unsigned
char
*
rdata
,
int
rdlen
);
/* Implement RFC1982 wrapped compare for 32-bit numbers */
/* Implement RFC1982 wrapped compare for 32-bit numbers */
static
int
serial_compare_32
(
unsigned
long
s1
,
unsigned
long
s2
)
static
int
serial_compare_32
(
unsigned
long
s1
,
unsigned
long
s2
)
{
{
...
@@ -494,7 +498,359 @@ static int digestalg_add_rdata(int sigtype, struct dns_header *header, size_t pk
...
@@ -494,7 +498,359 @@ static int digestalg_add_rdata(int sigtype, struct dns_header *header, size_t pk
return
1
;
return
1
;
}
}
size_t
dnssec_generate_query
(
struct
dns_header
*
header
,
char
*
name
,
int
class
,
int
type
)
{
unsigned
char
*
p
;
header
->
qdcount
=
htons
(
1
);
header
->
ancount
=
htons
(
0
);
header
->
nscount
=
htons
(
0
);
header
->
arcount
=
htons
(
0
);
header
->
hb3
=
HB3_RD
;
SET_OPCODE
(
header
,
QUERY
);
header
->
hb4
=
0
;
/* ID filled in later */
p
=
(
unsigned
char
*
)(
header
+
1
);
p
=
do_rfc1035_name
(
p
,
name
);
PUTSHORT
(
type
,
p
);
PUTSHORT
(
class
,
p
);
return
add_do_bit
(
header
,
p
-
(
unsigned
char
*
)
header
,
((
char
*
)
header
)
+
PACKETSZ
);
}
/* The DNS packet is expected to contain the answer to a DNSKEY query
Put all DNSKEYs in the answer which are valid into the cache.
return codes:
STAT_INSECURE bad packet, no DNSKEYs in reply.
STAT_SECURE At least one valid DNSKEY found and in cache.
STAT_BOGUS At least one DNSKEY found, which fails validation.
STAT_NEED_DS DS records to validate a key not found, name in namebuff
*/
int
dnssec_validate_by_ds
(
time_t
now
,
struct
dns_header
*
header
,
size_t
plen
,
char
*
name
,
char
*
keyname
,
int
class
)
{
unsigned
char
*
p
;
struct
crec
*
crecp
,
*
recp1
;
int
j
,
qtype
,
qclass
,
ttl
,
rdlen
,
flags
,
protocol
,
algo
,
gotone
;
struct
blockdata
*
key
;
if
(
ntohs
(
header
->
qdcount
)
!=
1
)
return
STAT_INSECURE
;
if
(
!
extract_name
(
header
,
plen
,
&
p
,
name
,
1
,
4
))
return
STAT_INSECURE
;
GETSHORT
(
qtype
,
p
);
GETSHORT
(
qclass
,
p
);
if
(
qtype
!=
T_DNSKEY
||
qclass
!=
class
)
return
STAT_INSECURE
;
cache_start_insert
();
for
(
gotone
=
0
,
j
=
ntohs
(
header
->
ancount
);
j
!=
0
;
j
--
)
{
/* Ensure we have type, class TTL and length */
if
(
!
extract_name
(
header
,
plen
,
&
p
,
name
,
1
,
10
))
return
STAT_INSECURE
;
/* bad packet */
GETSHORT
(
qtype
,
p
);
GETSHORT
(
qclass
,
p
);
GETLONG
(
ttl
,
p
);
GETSHORT
(
rdlen
,
p
);
if
(
qclass
!=
class
||
qtype
!=
T_DNSKEY
||
rdlen
<
4
)
{
/* skip all records other than DNSKEY */
p
+=
rdlen
;
continue
;
}
crecp
=
cache_find_by_name
(
NULL
,
name
,
now
,
F_DS
);
/* length at least covers flags, protocol and algo now. */
GETSHORT
(
flags
,
p
);
protocol
=
*
p
++
;
algo
=
*
p
++
;
/* See if we have cached a DS record which validates this key */
for
(
recp1
=
crecp
;
recp1
;
recp1
=
cache_find_by_name
(
recp1
,
name
,
now
,
F_DS
))
if
(
recp1
->
addr
.
key
.
algo
==
algo
&&
is_supported_digest
(
recp1
->
addr
.
key
.
digest
))
break
;
/* DS record needed to validate key is missing, return name of DS in namebuff */
if
(
!
recp1
)
return
STAT_NEED_DS
;
else
{
int
valid
=
1
;
/* calculate digest of canonicalised DNSKEY data using digest in (recp1->addr.key.digest)
and see if it equals digest stored in recp1
*/
if
(
!
valid
)
return
STAT_BOGUS
;
}
if
((
key
=
blockdata_alloc
((
char
*
)
p
,
rdlen
)))
{
/* We've proved that the KEY is OK, store it in the cache */
if
((
crecp
=
cache_insert
(
name
,
NULL
,
now
,
ttl
,
F_FORWARD
|
F_DNSKEY
)))
{
crecp
->
uid
=
rdlen
;
crecp
->
addr
.
key
.
keydata
=
key
;
crecp
->
addr
.
key
.
algo
=
algo
;
crecp
->
addr
.
key
.
keytag
=
dnskey_keytag
(
algo
,
(
char
*
)
p
,
rdlen
);
gotone
=
1
;
}
}
}
cache_end_insert
();
return
gotone
?
STAT_SECURE
:
STAT_INSECURE
;
}
/* The DNS packet is expected to contain the answer to a DS query
Put all DSs in the answer which are valid into the cache.
return codes:
STAT_INSECURE bad packet, no DNSKEYs in reply.
STAT_SECURE At least one valid DS found and in cache.
STAT_BOGUS At least one DS found, which fails validation.
STAT_NEED_DNSKEY DNSKEY records to validate a DS not found, name in keyname
*/
int
dnssec_validate_ds
(
time_t
now
,
struct
dns_header
*
header
,
size_t
plen
,
char
*
name
,
char
*
keyname
,
int
class
)
{
unsigned
char
*
p
=
(
unsigned
char
*
)(
header
+
1
);
struct
crec
*
crecp
,
*
recp1
;
int
qtype
,
qclass
,
val
,
j
,
gotone
;
struct
blockdata
*
key
;
if
(
ntohs
(
header
->
qdcount
)
!=
1
)
return
STAT_INSECURE
;
if
(
!
extract_name
(
header
,
plen
,
&
p
,
name
,
1
,
4
))
return
STAT_INSECURE
;
GETSHORT
(
qtype
,
p
);
GETSHORT
(
qclass
,
p
);
if
(
qtype
!=
T_DS
||
qclass
!=
class
)
return
STAT_INSECURE
;
val
=
validate_rrset
(
header
,
plen
,
class
,
T_DS
,
name
,
keyname
);
/* failed to validate or missing key. */
if
(
val
!=
STAT_SECURE
)
return
val
;
cache_start_insert
();
for
(
gotone
=
0
,
j
=
ntohs
(
header
->
ancount
);
j
!=
0
;
j
--
)
{
int
ttl
,
rdlen
,
rc
,
algo
;
/* Ensure we have type, class TTL and length */
if
(
!
(
rc
=
extract_name
(
header
,
plen
,
&
p
,
name
,
0
,
10
)))
return
STAT_INSECURE
;
/* bad packet */
GETSHORT
(
qtype
,
p
);
GETSHORT
(
qclass
,
p
);
GETLONG
(
ttl
,
p
);
GETSHORT
(
rdlen
,
p
);
/* check type, class and name, skip if not in DS rrset */
if
(
qclass
!=
class
||
qtype
!=
T_DS
||
rc
==
2
)
{
p
+=
rdlen
;
continue
;
}
if
((
key
=
blockdata_alloc
((
char
*
)
p
,
rdlen
)))
{
/* We've proved that the DS is OK, store it in the cache */
if
((
crecp
=
cache_insert
(
name
,
NULL
,
now
,
ttl
,
F_FORWARD
|
F_DS
)))
{
crecp
->
uid
=
rdlen
;
crecp
->
addr
.
key
.
keydata
=
key
;
crecp
->
addr
.
key
.
algo
=
algo
;
crecp
->
addr
.
key
.
keytag
=
dnskey_keytag
(
algo
,
(
char
*
)
p
,
rdlen
);
gotone
=
1
;
}
}
}
cache_end_insert
();
return
gotone
?
STAT_SECURE
:
STAT_INSECURE
;
}
/* Validate a single RRset (class, type, name) in the supplied DNS reply
Return code:
STAT_SECURE if it validates.
STAT_INSECURE can't validate (no RRSIG, bad packet).
STAT_BOGUS signature is wrong.
STAT_NEED_KEY need DNSKEY to complete validation (name is returned in keyname)
*/
int
validate_rrset
(
time_t
now
,
struct
dns_header
*
header
,
size_t
plen
,
int
class
,
int
type
,
char
*
name
,
char
*
keyname
)
{
unsigned
char
*
p
,
*
psav
,
*
sig
;
int
rrsetidx
,
res
,
sigttl
,
sig_data_len
,
j
;
struct
crec
*
crecp
;
void
*
rrset
[
MAXRRSET
];
/* TODO: max RRset size? */
int
type_covered
,
algo
,
labels
,
orig_ttl
,
sig_expiration
,
sig_inception
,
key_tag
;
if
(
!
(
p
=
skip_questions
(
header
,
plen
)))
return
STAT_INSECURE
;
/* look for an RRSIG record for this RRset and get pointers to each record */
for
(
rrsetidx
=
0
,
sig
=
NULL
,
j
=
ntohs
(
header
->
ancount
)
+
ntohs
(
header
->
nscount
);
j
!=
0
;
j
--
)
{
unsigned
char
*
pstart
=
p
;
int
stype
,
sclass
,
sttl
,
rdlen
;
if
(
!
(
res
=
extract_name
(
header
,
plen
,
&
p
,
name
,
0
,
10
)))
return
STAT_INSECURE
;
/* bad packet */
GETSHORT
(
stype
,
p
);
GETSHORT
(
sclass
,
p
);
GETLONG
(
sttl
,
p
);
GETSHORT
(
rdlen
,
p
);
if
(
!
CHECK_LEN
(
header
,
p
,
plen
,
rdlen
))
return
STAT_INSECURE
;
/* bad packet */
if
(
res
==
2
||
htons
(
stype
)
!=
T_RRSIG
||
htons
(
sclass
)
!=
class
)
continue
;
if
(
htons
(
stype
)
==
type
)
{
rrset
[
rrsetidx
++
]
=
pstart
;
if
(
rrsetidx
==
MAXRRSET
)
return
STAT_INSECURE
;
/* RRSET too big TODO */
}
if
(
htons
(
stype
)
==
T_RRSIG
)
{
/* name matches, RRSIG for correct class */
/* enough data? */
if
(
rdlen
<
18
)
return
STAT_INSECURE
;
GETSHORT
(
type_covered
,
p
);
algo
=
*
p
++
;
labels
=
*
p
++
;
GETLONG
(
orig_ttl
,
p
);
GETLONG
(
sig_expiration
,
p
);
GETLONG
(
sig_inception
,
p
);
GETSHORT
(
key_tag
,
p
);
if
(
type_covered
!=
type
||
!
check_date_range
(
sig_inception
,
sig_expiration
))
{
/* covers wrong type or out of date - skip */
p
=
psav
;
if
(
!
ADD_RDLEN
(
header
,
p
,
plen
,
rdlen
))
return
STAT_INSECURE
;
continue
;
}
if
(
!
extract_name
(
header
,
plen
,
&
p
,
keyname
,
1
,
0
))
return
STAT_INSECURE
;
/* OK, we have the signature record, see if the
relevant DNSKEY is in the cache. */
for
(
crecp
=
cache_find_by_name
(
NULL
,
keyname
,
now
,
F_DNSKEY
);
crecp
;
crecp
=
cache_find_by_name
(
crecp
,
keyname
,
now
,
F_DNSKEY
))
if
(
crecp
->
addr
.
key
.
algo
==
algo
&&
crecp
->
addr
.
key
.
keytag
==
key_tag
)
break
;
/* No, abort for now whilst we get it */
if
(
!
crecp
)
return
STAT_NEED_KEY
;
/* Save point to signature data */
sig
=
p
;
sig_data_len
=
rdlen
-
(
p
-
psav
);
sigttl
=
sttl
;
/* next record */
p
=
psav
;
if
(
!
ADD_RDLEN
(
header
,
p
,
plen
,
rdlen
))
return
STAT_INSECURE
;
}
}
/* Didn't find RRSIG or RRset is empty */
if
(
!
sig
||
rrsetidx
==
0
)
return
STAT_INSECURE
;
/* OK, we have an RRSIG and an RRset and we have a the DNSKEY that validates them. */
/* Sort RRset records in canonical order. */
rrset_canonical_order_ctx
.
header
=
header
;
rrset_canonical_order_ctx
.
pktlen
=
plen
;
qsort
(
rrset
,
rrsetidx
,
sizeof
(
void
*
),
rrset_canonical_order
);
/* Now initialize the signature verification algorithm and process the whole
RRset */
VerifyAlgCtx
*
alg
=
verifyalg_alloc
(
algo
);
if
(
!
alg
)
return
STAT_INSECURE
;
alg
->
sig
=
sig
;
alg
->
siglen
=
sig_data_len
;
u16
ntype
=
htons
(
type
);
u16
nclass
=
htons
(
class
);
u32
nsigttl
=
htonl
(
sigttl
);
/* TODO: we shouldn't need to convert this to wire here. Best solution would be:
- Use process_name() instead of extract_name() everywhere in dnssec code
- Convert from wire format to representation format only for querying/storing cache
*/
unsigned
char
owner_wire
[
MAXCDNAME
];
int
owner_wire_len
=
convert_domain_to_wire
(
name
,
owner_wire
);
digestalg_begin
(
alg
->
vtbl
->
digest_algo
);
digestalg_add_data
(
sigrdata
,
18
+
signer_name_rdlen
);
for
(
i
=
0
;
i
<
rrsetidx
;
++
i
)
{
p
=
(
unsigned
char
*
)(
rrset
[
i
]);
digestalg_add_data
(
owner_wire
,
owner_wire_len
);
digestalg_add_data
(
&
ntype
,
2
);
digestalg_add_data
(
&
nclass
,
2
);
digestalg_add_data
(
&
nsigttl
,
4
);
p
+=
8
;
if
(
!
digestalg_add_rdata
(
ntohs
(
sigtype
),
header
,
pktlen
,
p
))
return
0
;
}
int
digest_len
=
digestalg_len
();
memcpy
(
alg
->
digest
,
digestalg_final
(),
digest_len
);
if
(
alg
->
vtbl
->
verify
(
alg
,
crecp
->
addr
.
key
.
keydata
,
crecp_uid
))
return
STAT_SECURE
;
return
STAT_INSECURE
;
}
#if 0
static int begin_rrsig_validation(struct dns_header *header, size_t pktlen,
static int begin_rrsig_validation(struct dns_header *header, size_t pktlen,
unsigned char *reply, int count, char *owner,
unsigned char *reply, int count, char *owner,
int sigclass, int sigrdlen, unsigned char *sig,
int sigclass, int sigrdlen, unsigned char *sig,
...
@@ -624,6 +980,7 @@ static int end_rrsig_validation(PendingRRSIGValidation *val, struct crec *crec_d
...
@@ -624,6 +980,7 @@ static int end_rrsig_validation(PendingRRSIGValidation *val, struct crec *crec_d
return val->alg->vtbl->verify(val->alg, crec_dnskey->addr.key.keydata, crec_dnskey->uid);
return val->alg->vtbl->verify(val->alg, crec_dnskey->addr.key.keydata, crec_dnskey->uid);
}
}
static void dnssec_parserrsig(struct dns_header *header, size_t pktlen,
static void dnssec_parserrsig(struct dns_header *header, size_t pktlen,
unsigned char *reply, int count, char *owner,
unsigned char *reply, int count, char *owner,
int sigclass, int sigrdlen, unsigned char *sig)
int sigclass, int sigrdlen, unsigned char *sig)
...
@@ -663,6 +1020,8 @@ static void dnssec_parserrsig(struct dns_header *header, size_t pktlen,
...
@@ -663,6 +1020,8 @@ static void dnssec_parserrsig(struct dns_header *header, size_t pktlen,
}
}
}
}
#endif /* comment out */
/* Compute keytag (checksum to quickly index a key). See RFC4034 */
/* Compute keytag (checksum to quickly index a key). See RFC4034 */
static
int
dnskey_keytag
(
int
alg
,
unsigned
char
*
rdata
,
int
rdlen
)
static
int
dnskey_keytag
(
int
alg
,
unsigned
char
*
rdata
,
int
rdlen
)
{
{
...
...
src/forward.c
View file @
c3e0b9b6
...
@@ -678,15 +678,14 @@ void reply_query(int fd, int family, time_t now)
...
@@ -678,15 +678,14 @@ 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
;
char
rrbitmap
[
256
/
8
];
int
class
;
int
class
;
if
(
forward
->
flags
&
&
FREC_DNS
SKEY_QUERY
)
if
(
forward
->
flags
&
FREC_DN
SKEY_QUERY
)
status
=
dnssec_validate_by_ds
(
header
,
n
,
daemon
->
namebuff
,
&
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_d
nskey
(
header
,
n
,
daemon
->
namebuff
,
&
class
);
status
=
dnssec_validate_d
s
(
now
,
header
,
n
,
daemon
->
namebuff
,
daemon
->
keyname
,
forward
->
class
);
else
else
status
=
dnssec_validate_reply
(
&
rrbitmap
,
header
,
n
,
daemon
->
namebuff
,
&
class
);
status
=
dnssec_validate_reply
(
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. */
...
@@ -717,7 +716,7 @@ void reply_query(int fd, int family, time_t now)
...
@@ -717,7 +716,7 @@ void reply_query(int fd, int family, time_t now)
}
}
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
);
header
->
id
=
htons
(
new
->
id
);
header
->
id
=
htons
(
new
->
new_
id
);
/* Don't resend this. */
/* Don't resend this. */
daemon
->
srv_save
=
NULL
;
daemon
->
srv_save
=
NULL
;
...
@@ -751,22 +750,30 @@ void reply_query(int fd, int family, time_t now)
...
@@ -751,22 +750,30 @@ 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. */
while
(
forward
->
flags
&
FREC_DNSSEC_QUERY
)
while
(
forward
->
dependent
)
{
{
if
(
status
==
STAT_SECURE
)
struct
frec
*
prev
=
forward
->
dependent
;
extract_dnssec_replies
();
free_frec
(
forward
);
free_frec
(
forward
);
forward
=
forward
->
dependent
;
forward
=
prev
;
blockdata_retrieve_and_free
(
forward
->
stash
,
forward
->
stash_len
,
(
void
*
)
header
);
blockdata_retrieve_and_free
(
forward
->
stash
,
forward
->
stash_len
,
(
void
*
)
header
);
n
=
forward
->
stash_len
;
n
=
forward
->
stash_len
;
if
(
status
==
STAT_SECURE
)
if
(
status
==
STAT_SECURE
)
{
{
status
=
dnssec_validate
(
forward
->
flags
,
header
,
n
);
if
(
forward
->
flags
&
FREC_DNSKEY_QUERY
)
if
(
status
==
STAT_NEED_DS
||
status
==
STAT_NEED_KEY
)
status
=
dnssec_validate_by_ds
(
now
,
header
,
n
,
daemon
->
namebuff
,
daemon
->
keyname
,
forward
->
class
);
my_syslog
(
LOG_ERR
,
_
(
"Unexpected missing data for DNSSEC validation"
));
else
if
(
forward
->
flags
&
FREC_DS_QUERY
)
status
=
dnssec_validate_dnskey
(
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"
));
}
}
}
}
/* 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
);
if
(
status
==
STAT_SECURE
)
if
(
status
==
STAT_SECURE
)
cache_secure
=
1
;
cache_secure
=
1
;
/* TODO return SERVFAIL here */
/* TODO return SERVFAIL here */
...
...
src/rfc1035.c
View file @
c3e0b9b6
...
@@ -16,13 +16,6 @@
...
@@ -16,13 +16,6 @@
#include "dnsmasq.h"
#include "dnsmasq.h"
#define CHECK_LEN(header, pp, plen, len) \
((size_t)((pp) - (unsigned char *)(header) + (len)) <= (plen))
#define ADD_RDLEN(header, pp, plen, len) \
(!CHECK_LEN(header, pp, plen, len) ? 0 : (((pp) += (len)), 1))
int
extract_name
(
struct
dns_header
*
header
,
size_t
plen
,
unsigned
char
**
pp
,
int
extract_name
(
struct
dns_header
*
header
,
size_t
plen
,
unsigned
char
**
pp
,
char
*
name
,
int
isExtract
,
int
extrabytes
)
char
*
name
,
int
isExtract
,
int
extrabytes
)
{
{
...
...
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